Thu, 04 Feb 2010 10:14:28 -0800
6923080: TreeScanner.visitNewClass should scan tree.typeargs
Reviewed-by: darcy
duke@1 | 1 | /* |
xdono@229 | 2 | * Copyright 2004-2009 Sun Microsystems, Inc. All Rights Reserved. |
duke@1 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
duke@1 | 4 | * |
duke@1 | 5 | * This code is free software; you can redistribute it and/or modify it |
duke@1 | 6 | * under the terms of the GNU General Public License version 2 only, as |
duke@1 | 7 | * published by the Free Software Foundation. Sun designates this |
duke@1 | 8 | * particular file as subject to the "Classpath" exception as provided |
duke@1 | 9 | * by Sun in the LICENSE file that accompanied this code. |
duke@1 | 10 | * |
duke@1 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
duke@1 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
duke@1 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
duke@1 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
duke@1 | 15 | * accompanied this code). |
duke@1 | 16 | * |
duke@1 | 17 | * You should have received a copy of the GNU General Public License version |
duke@1 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
duke@1 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
duke@1 | 20 | * |
duke@1 | 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
duke@1 | 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
duke@1 | 23 | * have any questions. |
duke@1 | 24 | */ |
duke@1 | 25 | |
duke@1 | 26 | package com.sun.tools.apt.comp; |
duke@1 | 27 | |
duke@1 | 28 | import com.sun.tools.javac.code.*; |
duke@1 | 29 | import com.sun.tools.javac.comp.*; |
duke@1 | 30 | import com.sun.tools.javac.tree.*; |
duke@1 | 31 | import com.sun.tools.javac.util.*; |
duke@1 | 32 | import com.sun.tools.javac.tree.TreeScanner; |
duke@1 | 33 | import com.sun.tools.javac.util.Context; |
duke@1 | 34 | import com.sun.tools.apt.util.Bark; |
duke@1 | 35 | import com.sun.tools.javac.util.Position; |
duke@1 | 36 | |
duke@1 | 37 | import java.util.*; |
duke@1 | 38 | import java.util.regex.*; |
duke@1 | 39 | import java.lang.reflect.*; |
duke@1 | 40 | import java.lang.reflect.InvocationTargetException; |
duke@1 | 41 | import java.io.IOException; |
duke@1 | 42 | |
duke@1 | 43 | import com.sun.tools.apt.*; |
duke@1 | 44 | import com.sun.tools.apt.comp.*; |
duke@1 | 45 | import com.sun.tools.javac.code.Symbol.*; |
duke@1 | 46 | |
duke@1 | 47 | import com.sun.mirror.declaration.TypeDeclaration; |
duke@1 | 48 | import com.sun.mirror.declaration.AnnotationTypeDeclaration; |
duke@1 | 49 | import com.sun.mirror.apt.*; |
duke@1 | 50 | // import com.sun.mirror.apt.AnnotationProcessorFactory; |
duke@1 | 51 | import com.sun.mirror.apt.AnnotationProcessors; |
duke@1 | 52 | |
duke@1 | 53 | import com.sun.tools.apt.mirror.AptEnv; |
duke@1 | 54 | import com.sun.tools.apt.mirror.apt.FilerImpl; |
duke@1 | 55 | import com.sun.tools.apt.mirror.apt.AnnotationProcessorEnvironmentImpl; |
duke@1 | 56 | |
duke@1 | 57 | |
duke@1 | 58 | import static com.sun.tools.apt.mirror.declaration.DeclarationMaker.isJavaIdentifier; |
duke@1 | 59 | |
duke@1 | 60 | /** |
duke@1 | 61 | * Apt compiler phase. |
duke@1 | 62 | * |
duke@1 | 63 | * <p><b>This is NOT part of any API supported by Sun Microsystems. |
duke@1 | 64 | * If you write code that depends on this, you do so at your own |
duke@1 | 65 | * risk. This code and its internal interfaces are subject to change |
duke@1 | 66 | * or deletion without notice.</b> |
duke@1 | 67 | */ |
darcy@331 | 68 | @SuppressWarnings("deprecation") |
duke@1 | 69 | public class Apt extends ListBuffer<Env<AttrContext>> { |
duke@1 | 70 | java.util.Set<String> genSourceFileNames = new java.util.LinkedHashSet<String>(); |
duke@1 | 71 | public java.util.Set<String> getSourceFileNames() { |
duke@1 | 72 | return genSourceFileNames; |
duke@1 | 73 | } |
duke@1 | 74 | |
duke@1 | 75 | /** List of names of generated class files. |
duke@1 | 76 | */ |
duke@1 | 77 | java.util.Set<String> genClassFileNames = new java.util.LinkedHashSet<String>(); |
duke@1 | 78 | public java.util.Set<String> getClassFileNames() { |
duke@1 | 79 | return genClassFileNames; |
duke@1 | 80 | } |
duke@1 | 81 | |
duke@1 | 82 | /* AptEnvironment */ |
duke@1 | 83 | AptEnv aptenv; |
duke@1 | 84 | |
duke@1 | 85 | private Context context; |
duke@1 | 86 | |
duke@1 | 87 | /** The context key for the todo list. */ |
duke@1 | 88 | |
duke@1 | 89 | protected static final Context.Key<Apt> aptKey = |
duke@1 | 90 | new Context.Key<Apt>(); |
duke@1 | 91 | |
duke@1 | 92 | /** Get the Apt instance for this context. */ |
duke@1 | 93 | public static Apt instance(Context context) { |
duke@1 | 94 | Apt instance = context.get(aptKey); |
duke@1 | 95 | if (instance == null) |
duke@1 | 96 | instance = new Apt(context); |
duke@1 | 97 | return instance; |
duke@1 | 98 | } |
duke@1 | 99 | |
duke@1 | 100 | /** Create a new apt list. */ |
duke@1 | 101 | protected Apt(Context context) { |
duke@1 | 102 | this.context = context; |
duke@1 | 103 | |
duke@1 | 104 | context.put(aptKey, this); |
duke@1 | 105 | aptenv = AptEnv.instance(context); |
duke@1 | 106 | } |
duke@1 | 107 | |
duke@1 | 108 | /** |
duke@1 | 109 | * Used to scan javac trees to build data structures needed for |
duke@1 | 110 | * bootstrapping the apt environment. In particular: |
duke@1 | 111 | * |
duke@1 | 112 | * <ul> |
duke@1 | 113 | * |
duke@1 | 114 | * <li> Generate list of canonical names of annotation types that |
duke@1 | 115 | * appear in source files given on the command line |
duke@1 | 116 | * |
duke@1 | 117 | * <li> Collect list of javac symbols representing source files |
duke@1 | 118 | * given on the command line |
duke@1 | 119 | * |
duke@1 | 120 | * </ul> |
duke@1 | 121 | */ |
duke@1 | 122 | static class AptTreeScanner extends TreeScanner { |
duke@1 | 123 | |
duke@1 | 124 | // Set of fully qualified names of annotation types present in |
duke@1 | 125 | // examined source |
duke@1 | 126 | private Set<String> annotationSet; |
duke@1 | 127 | |
duke@1 | 128 | // Symbols to build bootstrapping declaration list |
duke@1 | 129 | private Collection<ClassSymbol> specifiedDeclCollection; |
duke@1 | 130 | private Collection<ClassSymbol> declCollection; |
duke@1 | 131 | |
duke@1 | 132 | public Set<String> getAnnotationSet() { |
duke@1 | 133 | return annotationSet; |
duke@1 | 134 | } |
duke@1 | 135 | |
duke@1 | 136 | public AptTreeScanner() { |
duke@1 | 137 | annotationSet = new LinkedHashSet<String>(); |
duke@1 | 138 | specifiedDeclCollection = new LinkedHashSet<ClassSymbol>(); |
duke@1 | 139 | declCollection = new LinkedHashSet<ClassSymbol>(); |
duke@1 | 140 | } |
duke@1 | 141 | |
duke@1 | 142 | public void visitTopLevel(JCTree.JCCompilationUnit tree) { |
duke@1 | 143 | super.visitTopLevel(tree); |
duke@1 | 144 | // Print out contents -- what are we dealing with? |
duke@1 | 145 | |
duke@1 | 146 | for(JCTree d: tree.defs) { |
duke@1 | 147 | if (d instanceof JCTree.JCClassDecl) |
duke@1 | 148 | specifiedDeclCollection.add(((JCTree.JCClassDecl) d).sym); |
duke@1 | 149 | } |
duke@1 | 150 | |
duke@1 | 151 | } |
duke@1 | 152 | |
duke@1 | 153 | public void visitBlock(JCTree.JCBlock tree) { |
duke@1 | 154 | ; // Do nothing. |
duke@1 | 155 | } |
duke@1 | 156 | |
duke@1 | 157 | |
duke@1 | 158 | // should add nested classes to packages, etc. |
duke@1 | 159 | public void visitClassDef(JCTree.JCClassDecl tree) { |
duke@1 | 160 | if (tree.sym == null) { |
duke@1 | 161 | // could be an anon class w/in an initializer |
duke@1 | 162 | return; |
duke@1 | 163 | } |
duke@1 | 164 | |
duke@1 | 165 | super.visitClassDef(tree); |
duke@1 | 166 | |
duke@1 | 167 | declCollection.add(tree.sym); |
duke@1 | 168 | } |
duke@1 | 169 | |
duke@1 | 170 | public void visitMethodDef(JCTree.JCMethodDecl tree) { |
duke@1 | 171 | super.visitMethodDef(tree); |
duke@1 | 172 | } |
duke@1 | 173 | |
duke@1 | 174 | public void visitVarDef(JCTree.JCVariableDecl tree) { |
duke@1 | 175 | super.visitVarDef(tree); |
duke@1 | 176 | } |
duke@1 | 177 | |
duke@1 | 178 | public void visitAnnotation(JCTree.JCAnnotation tree) { |
duke@1 | 179 | super.visitAnnotation(tree); |
duke@1 | 180 | annotationSet.add(tree.type.tsym.toString()); |
duke@1 | 181 | } |
duke@1 | 182 | } |
duke@1 | 183 | |
duke@1 | 184 | Set<String> computeAnnotationSet(Collection<ClassSymbol> classSymbols) { |
duke@1 | 185 | Set<String> annotationSet = new HashSet<String>(); |
duke@1 | 186 | |
duke@1 | 187 | for(ClassSymbol classSymbol: classSymbols) { |
duke@1 | 188 | computeAnnotationSet(classSymbol, annotationSet); |
duke@1 | 189 | } |
duke@1 | 190 | return annotationSet; |
duke@1 | 191 | } |
duke@1 | 192 | |
duke@1 | 193 | void computeAnnotationSet(Symbol symbol, Set<String> annotationSet) { |
duke@1 | 194 | if (symbol != null ) { |
duke@1 | 195 | if (symbol.getAnnotationMirrors() != null) |
duke@1 | 196 | for(Attribute.Compound compound: symbol.getAnnotationMirrors()) |
duke@1 | 197 | annotationSet.add(compound.type.tsym.toString()); // should fullName be used instead of toString? |
duke@1 | 198 | |
duke@1 | 199 | if (symbol instanceof Symbol.MethodSymbol) // add parameter annotations |
duke@1 | 200 | for(Symbol param: ((MethodSymbol) symbol).params()) |
duke@1 | 201 | computeAnnotationSet(param, annotationSet); |
duke@1 | 202 | |
duke@1 | 203 | if (symbol.members() != null) { |
jjg@419 | 204 | for(Scope.Entry e = symbol.members().elems; e != null; e = e.sibling) |
duke@1 | 205 | computeAnnotationSet(e.sym, annotationSet); |
duke@1 | 206 | } |
duke@1 | 207 | } |
duke@1 | 208 | } |
duke@1 | 209 | |
duke@1 | 210 | public void main(com.sun.tools.javac.util.List<JCTree.JCCompilationUnit> treeList, |
duke@1 | 211 | ListBuffer<ClassSymbol> classes, |
duke@1 | 212 | Map<String, String> origOptions, |
duke@1 | 213 | ClassLoader aptCL, |
duke@1 | 214 | AnnotationProcessorFactory providedFactory, |
duke@1 | 215 | java.util.Set<Class<? extends AnnotationProcessorFactory> > productiveFactories) { |
duke@1 | 216 | Bark bark = Bark.instance(context); |
duke@1 | 217 | java.io.PrintWriter out = bark.warnWriter; |
duke@1 | 218 | Options options = Options.instance(context); |
duke@1 | 219 | |
duke@1 | 220 | Collection<TypeDeclaration> spectypedecls = new LinkedHashSet<TypeDeclaration>(); |
duke@1 | 221 | Collection<TypeDeclaration> typedecls = new LinkedHashSet<TypeDeclaration>(); |
duke@1 | 222 | Set<String> unmatchedAnnotations = new LinkedHashSet<String>(); |
duke@1 | 223 | Set<AnnotationTypeDeclaration> emptyATDS = Collections.emptySet(); |
duke@1 | 224 | Set<Class<? extends AnnotationProcessorFactory> > currentRoundFactories = |
duke@1 | 225 | new LinkedHashSet<Class<? extends AnnotationProcessorFactory> >(); |
duke@1 | 226 | |
duke@1 | 227 | // Determine what annotations are present on the input source |
duke@1 | 228 | // files, create collections of specified type declarations, |
duke@1 | 229 | // and type declarations. |
duke@1 | 230 | AptTreeScanner ats = new AptTreeScanner(); |
duke@1 | 231 | for(JCTree t: treeList) { |
duke@1 | 232 | t.accept(ats); |
duke@1 | 233 | } |
duke@1 | 234 | |
duke@1 | 235 | // Turn collection of ClassSymbols into Collection of apt decls |
duke@1 | 236 | for (ClassSymbol cs : ats.specifiedDeclCollection) { |
duke@1 | 237 | TypeDeclaration decl = aptenv.declMaker.getTypeDeclaration(cs); |
duke@1 | 238 | spectypedecls.add(decl); |
duke@1 | 239 | } |
duke@1 | 240 | |
duke@1 | 241 | for (ClassSymbol cs : ats.declCollection) { |
duke@1 | 242 | TypeDeclaration decl = aptenv.declMaker.getTypeDeclaration(cs); |
duke@1 | 243 | typedecls.add(decl); |
duke@1 | 244 | } |
duke@1 | 245 | |
duke@1 | 246 | unmatchedAnnotations.addAll(ats.getAnnotationSet()); |
duke@1 | 247 | |
duke@1 | 248 | // Process input class files |
duke@1 | 249 | for(ClassSymbol cs : classes) { |
duke@1 | 250 | TypeDeclaration decl = aptenv.declMaker.getTypeDeclaration(cs); |
duke@1 | 251 | // System.out.println("Adding a class to spectypedecls"); |
duke@1 | 252 | spectypedecls.add(decl); |
duke@1 | 253 | typedecls.add(decl); |
duke@1 | 254 | computeAnnotationSet(cs, unmatchedAnnotations); |
duke@1 | 255 | } |
duke@1 | 256 | |
duke@1 | 257 | if (options.get("-XListAnnotationTypes") != null) { |
duke@1 | 258 | out.println("Set of annotations found:" + |
duke@1 | 259 | (new TreeSet<String>(unmatchedAnnotations)).toString()); |
duke@1 | 260 | } |
duke@1 | 261 | |
duke@1 | 262 | AnnotationProcessorEnvironmentImpl trivAPE = |
duke@1 | 263 | new AnnotationProcessorEnvironmentImpl(spectypedecls, typedecls, origOptions, context); |
duke@1 | 264 | |
duke@1 | 265 | if (options.get("-XListDeclarations") != null) { |
duke@1 | 266 | out.println("Set of Specified Declarations:" + |
duke@1 | 267 | spectypedecls); |
duke@1 | 268 | |
duke@1 | 269 | out.println("Set of Included Declarations: " + |
duke@1 | 270 | typedecls); |
duke@1 | 271 | } |
duke@1 | 272 | |
duke@1 | 273 | if (options.get("-print") != null) { |
duke@1 | 274 | if (spectypedecls.size() == 0 ) |
duke@1 | 275 | throw new UsageMessageNeededException(); |
duke@1 | 276 | |
duke@1 | 277 | // Run the printing processor |
duke@1 | 278 | AnnotationProcessor proc = (new BootstrapAPF()).getProcessorFor(new HashSet<AnnotationTypeDeclaration>(), |
duke@1 | 279 | trivAPE); |
duke@1 | 280 | proc.process(); |
duke@1 | 281 | } else { |
duke@1 | 282 | // Discovery process |
duke@1 | 283 | |
duke@1 | 284 | // List of annotation processory factory instances |
mcimadamore@184 | 285 | java.util.Iterator<AnnotationProcessorFactory> providers = null; |
duke@1 | 286 | { |
duke@1 | 287 | /* |
duke@1 | 288 | * If a factory is provided by the user, the |
duke@1 | 289 | * "-factory" and "-factorypath" options are not used. |
duke@1 | 290 | * |
duke@1 | 291 | * Otherwise, if the "-factory" option is used, search |
duke@1 | 292 | * the appropriate path for the named class. |
duke@1 | 293 | * Otherwise, use sun.misc.Service to implement the |
duke@1 | 294 | * default discovery policy. |
duke@1 | 295 | */ |
duke@1 | 296 | |
duke@1 | 297 | java.util.List<AnnotationProcessorFactory> list = |
duke@1 | 298 | new LinkedList<AnnotationProcessorFactory>(); |
duke@1 | 299 | String factoryName = options.get("-factory"); |
duke@1 | 300 | |
duke@1 | 301 | if (providedFactory != null) { |
duke@1 | 302 | list.add(providedFactory); |
duke@1 | 303 | providers = list.iterator(); |
duke@1 | 304 | } else if (factoryName != null) { |
duke@1 | 305 | try { |
duke@1 | 306 | AnnotationProcessorFactory factory = |
duke@1 | 307 | (AnnotationProcessorFactory) (aptCL.loadClass(factoryName).newInstance()); |
duke@1 | 308 | list.add(factory); |
duke@1 | 309 | } catch (ClassNotFoundException cnfe) { |
duke@1 | 310 | bark.aptWarning("FactoryNotFound", factoryName); |
duke@1 | 311 | } catch (ClassCastException cce) { |
duke@1 | 312 | bark.aptWarning("FactoryWrongType", factoryName); |
duke@1 | 313 | } catch (Exception e ) { |
duke@1 | 314 | bark.aptWarning("FactoryCantInstantiate", factoryName); |
duke@1 | 315 | } catch(Throwable t) { |
duke@1 | 316 | throw new AnnotationProcessingError(t); |
duke@1 | 317 | } |
duke@1 | 318 | |
duke@1 | 319 | providers = list.iterator(); |
jjg@198 | 320 | } else { |
jjg@198 | 321 | @SuppressWarnings("unchecked") |
jjg@198 | 322 | Iterator<AnnotationProcessorFactory> iter = |
jjg@198 | 323 | sun.misc.Service.providers(AnnotationProcessorFactory.class, aptCL); |
jjg@198 | 324 | providers = iter; |
jjg@198 | 325 | |
jjg@198 | 326 | } |
duke@1 | 327 | } |
duke@1 | 328 | |
duke@1 | 329 | java.util.Map<AnnotationProcessorFactory, Set<AnnotationTypeDeclaration>> factoryToAnnotation = |
duke@1 | 330 | new LinkedHashMap<AnnotationProcessorFactory, Set<AnnotationTypeDeclaration>>(); |
duke@1 | 331 | |
duke@1 | 332 | if (!providers.hasNext() && productiveFactories.size() == 0) { |
duke@1 | 333 | if (unmatchedAnnotations.size() > 0) |
duke@1 | 334 | bark.aptWarning("NoAnnotationProcessors"); |
duke@1 | 335 | if (spectypedecls.size() == 0) |
duke@1 | 336 | throw new UsageMessageNeededException(); |
duke@1 | 337 | return; // no processors; nothing else to do |
duke@1 | 338 | } else { |
duke@1 | 339 | // If there are no annotations, still give |
duke@1 | 340 | // processors that match everything a chance to |
duke@1 | 341 | // run. |
duke@1 | 342 | |
duke@1 | 343 | if(unmatchedAnnotations.size() == 0) |
duke@1 | 344 | unmatchedAnnotations.add(""); |
duke@1 | 345 | |
duke@1 | 346 | Set<String> emptyStringSet = new HashSet<String>(); |
duke@1 | 347 | emptyStringSet.add(""); |
duke@1 | 348 | emptyStringSet = Collections.unmodifiableSet(emptyStringSet); |
duke@1 | 349 | |
duke@1 | 350 | while (providers.hasNext() ) { |
duke@1 | 351 | Object provider = providers.next(); |
duke@1 | 352 | try { |
duke@1 | 353 | Set<String> matchedStrings = new HashSet<String>(); |
duke@1 | 354 | |
duke@1 | 355 | AnnotationProcessorFactory apf = (AnnotationProcessorFactory) provider; |
duke@1 | 356 | Collection<String> supportedTypes = apf.supportedAnnotationTypes(); |
duke@1 | 357 | |
duke@1 | 358 | Collection<Pattern> supportedTypePatterns = new LinkedList<Pattern>(); |
duke@1 | 359 | for(String s: supportedTypes) |
duke@1 | 360 | supportedTypePatterns.add(importStringToPattern(s)); |
duke@1 | 361 | |
duke@1 | 362 | for(String s: unmatchedAnnotations) { |
duke@1 | 363 | for(Pattern p: supportedTypePatterns) { |
duke@1 | 364 | if (p.matcher(s).matches()) { |
duke@1 | 365 | matchedStrings.add(s); |
duke@1 | 366 | break; |
duke@1 | 367 | } |
duke@1 | 368 | } |
duke@1 | 369 | } |
duke@1 | 370 | |
duke@1 | 371 | unmatchedAnnotations.removeAll(matchedStrings); |
duke@1 | 372 | |
duke@1 | 373 | if (options.get("-XPrintFactoryInfo") != null) { |
duke@1 | 374 | out.println("Factory " + apf.getClass().getName() + |
duke@1 | 375 | " matches " + |
duke@1 | 376 | ((matchedStrings.size() == 0)? |
duke@1 | 377 | "nothing.": matchedStrings)); |
duke@1 | 378 | } |
duke@1 | 379 | |
duke@1 | 380 | if (matchedStrings.size() > 0) { |
duke@1 | 381 | // convert annotation names to annotation |
duke@1 | 382 | // type decls |
duke@1 | 383 | Set<AnnotationTypeDeclaration> atds = new HashSet<AnnotationTypeDeclaration>(); |
duke@1 | 384 | |
duke@1 | 385 | // If a "*" processor is called on the |
duke@1 | 386 | // empty string, pass in an empty set of |
duke@1 | 387 | // annotation type declarations. |
duke@1 | 388 | if (!matchedStrings.equals(emptyStringSet)) { |
duke@1 | 389 | for(String s: matchedStrings) { |
duke@1 | 390 | TypeDeclaration decl = aptenv.declMaker.getTypeDeclaration(s); |
duke@1 | 391 | AnnotationTypeDeclaration annotdecl; |
duke@1 | 392 | if (decl == null) { |
duke@1 | 393 | bark.aptError("DeclarationCreation", s); |
duke@1 | 394 | } else { |
duke@1 | 395 | try { |
duke@1 | 396 | annotdecl = (AnnotationTypeDeclaration)decl; |
duke@1 | 397 | atds.add(annotdecl); |
duke@1 | 398 | |
duke@1 | 399 | } catch (ClassCastException cce) { |
duke@1 | 400 | bark.aptError("BadDeclaration", s); |
duke@1 | 401 | } |
duke@1 | 402 | } |
duke@1 | 403 | } |
duke@1 | 404 | } |
duke@1 | 405 | |
duke@1 | 406 | currentRoundFactories.add(apf.getClass()); |
duke@1 | 407 | productiveFactories.add(apf.getClass()); |
duke@1 | 408 | factoryToAnnotation.put(apf, atds); |
duke@1 | 409 | } else if (productiveFactories.contains(apf.getClass())) { |
duke@1 | 410 | // If a factory provided a processor in a |
duke@1 | 411 | // previous round but doesn't match any |
duke@1 | 412 | // annotations this round, call it with an |
duke@1 | 413 | // empty set of declarations. |
duke@1 | 414 | currentRoundFactories.add(apf.getClass()); |
duke@1 | 415 | factoryToAnnotation.put(apf, emptyATDS ); |
duke@1 | 416 | } |
duke@1 | 417 | |
duke@1 | 418 | if (unmatchedAnnotations.size() == 0) |
duke@1 | 419 | break; |
duke@1 | 420 | |
duke@1 | 421 | } catch (ClassCastException cce) { |
duke@1 | 422 | bark.aptWarning("BadFactory", cce); |
duke@1 | 423 | } |
duke@1 | 424 | } |
duke@1 | 425 | |
duke@1 | 426 | unmatchedAnnotations.remove(""); |
duke@1 | 427 | } |
duke@1 | 428 | |
duke@1 | 429 | // If the set difference of productiveFactories and |
duke@1 | 430 | // currentRoundFactories is non-empty, call the remaining |
duke@1 | 431 | // productive factories with an empty set of declarations. |
duke@1 | 432 | { |
duke@1 | 433 | java.util.Set<Class<? extends AnnotationProcessorFactory> > neglectedFactories = |
duke@1 | 434 | new LinkedHashSet<Class<? extends AnnotationProcessorFactory>>(productiveFactories); |
duke@1 | 435 | neglectedFactories.removeAll(currentRoundFactories); |
duke@1 | 436 | for(Class<? extends AnnotationProcessorFactory> working : neglectedFactories) { |
duke@1 | 437 | try { |
duke@1 | 438 | AnnotationProcessorFactory factory = working.newInstance(); |
duke@1 | 439 | factoryToAnnotation.put(factory, emptyATDS); |
duke@1 | 440 | } catch (Exception e ) { |
duke@1 | 441 | bark.aptWarning("FactoryCantInstantiate", working.getName()); |
duke@1 | 442 | } catch(Throwable t) { |
duke@1 | 443 | throw new AnnotationProcessingError(t); |
duke@1 | 444 | } |
duke@1 | 445 | } |
duke@1 | 446 | } |
duke@1 | 447 | |
duke@1 | 448 | if (unmatchedAnnotations.size() > 0) |
duke@1 | 449 | bark.aptWarning("AnnotationsWithoutProcessors", unmatchedAnnotations); |
duke@1 | 450 | |
duke@1 | 451 | Set<AnnotationProcessor> processors = new LinkedHashSet<AnnotationProcessor>(); |
duke@1 | 452 | |
duke@1 | 453 | // If there were no source files AND no factory matching "*", |
duke@1 | 454 | // make sure the usage message is printed |
duke@1 | 455 | if (spectypedecls.size() == 0 && |
duke@1 | 456 | factoryToAnnotation.keySet().size() == 0 ) |
duke@1 | 457 | throw new UsageMessageNeededException(); |
duke@1 | 458 | |
duke@1 | 459 | try { |
duke@1 | 460 | for(AnnotationProcessorFactory apFactory: factoryToAnnotation.keySet()) { |
duke@1 | 461 | AnnotationProcessor processor = apFactory.getProcessorFor(factoryToAnnotation.get(apFactory), |
duke@1 | 462 | trivAPE); |
duke@1 | 463 | if (processor != null) |
duke@1 | 464 | processors.add(processor); |
duke@1 | 465 | else |
duke@1 | 466 | bark.aptWarning("NullProcessor", apFactory.getClass().getName()); |
duke@1 | 467 | } |
duke@1 | 468 | } catch(Throwable t) { |
duke@1 | 469 | throw new AnnotationProcessingError(t); |
duke@1 | 470 | } |
duke@1 | 471 | |
duke@1 | 472 | LinkedList<AnnotationProcessor> temp = new LinkedList<AnnotationProcessor>(); |
duke@1 | 473 | temp.addAll(processors); |
duke@1 | 474 | |
duke@1 | 475 | AnnotationProcessor proc = AnnotationProcessors.getCompositeAnnotationProcessor(temp); |
duke@1 | 476 | |
duke@1 | 477 | try { |
duke@1 | 478 | proc.process(); |
duke@1 | 479 | } catch (Throwable t) { |
duke@1 | 480 | throw new AnnotationProcessingError(t); |
duke@1 | 481 | } |
duke@1 | 482 | |
duke@1 | 483 | // Invoke listener callback mechanism |
duke@1 | 484 | trivAPE.roundComplete(); |
duke@1 | 485 | |
duke@1 | 486 | FilerImpl filerimpl = (FilerImpl)trivAPE.getFiler(); |
duke@1 | 487 | genSourceFileNames = filerimpl.getSourceFileNames(); |
duke@1 | 488 | genClassFileNames = filerimpl.getClassFileNames(); |
duke@1 | 489 | filerimpl.flush(); // Make sure new files are written out |
duke@1 | 490 | } |
duke@1 | 491 | } |
duke@1 | 492 | |
duke@1 | 493 | /** |
duke@1 | 494 | * Convert import-style string to regex matching that string. If |
duke@1 | 495 | * the string is a valid import-style string, return a regex that |
duke@1 | 496 | * won't match anything. |
duke@1 | 497 | */ |
duke@1 | 498 | Pattern importStringToPattern(String s) { |
duke@1 | 499 | if (s.equals("*")) { |
duke@1 | 500 | return allMatches; |
duke@1 | 501 | } else { |
duke@1 | 502 | String t = s; |
duke@1 | 503 | boolean star = false; |
duke@1 | 504 | |
duke@1 | 505 | /* |
duke@1 | 506 | * Validate string from factory is legal. If the string |
duke@1 | 507 | * has more than one asterisks or the asterisks does not |
duke@1 | 508 | * appear as the last character (preceded by a period), |
duke@1 | 509 | * the string is not legal. |
duke@1 | 510 | */ |
duke@1 | 511 | |
duke@1 | 512 | boolean valid = true; |
duke@1 | 513 | int index = t.indexOf('*'); |
duke@1 | 514 | if (index != -1) { |
duke@1 | 515 | // '*' must be last character... |
duke@1 | 516 | if (index == t.length() -1) { |
duke@1 | 517 | // ... and preceeding character must be '.' |
duke@1 | 518 | if ( index-1 >= 0 ) { |
duke@1 | 519 | valid = t.charAt(index-1) == '.'; |
duke@1 | 520 | // Strip off ".*$" for identifier checks |
duke@1 | 521 | t = t.substring(0, t.length()-2); |
duke@1 | 522 | } |
duke@1 | 523 | } else |
duke@1 | 524 | valid = false; |
duke@1 | 525 | } |
duke@1 | 526 | |
duke@1 | 527 | // Verify string is off the form (javaId \.)+ or javaId |
duke@1 | 528 | if (valid) { |
duke@1 | 529 | String[] javaIds = t.split("\\.", t.length()+2); |
duke@1 | 530 | for(String javaId: javaIds) |
duke@1 | 531 | valid &= isJavaIdentifier(javaId); |
duke@1 | 532 | } |
duke@1 | 533 | |
duke@1 | 534 | if (!valid) { |
duke@1 | 535 | Bark bark = Bark.instance(context); |
duke@1 | 536 | bark.aptWarning("MalformedSupportedString", s); |
duke@1 | 537 | return noMatches; // won't match any valid identifier |
duke@1 | 538 | } |
duke@1 | 539 | |
duke@1 | 540 | String s_prime = s.replaceAll("\\.", "\\\\."); |
duke@1 | 541 | |
duke@1 | 542 | if (s_prime.endsWith("*")) { |
duke@1 | 543 | s_prime = s_prime.substring(0, s_prime.length() - 1) + ".+"; |
duke@1 | 544 | } |
duke@1 | 545 | |
duke@1 | 546 | return Pattern.compile(s_prime); |
duke@1 | 547 | } |
duke@1 | 548 | } |
duke@1 | 549 | |
duke@1 | 550 | private static final Pattern allMatches = Pattern.compile(".*"); |
duke@1 | 551 | private static final Pattern noMatches = Pattern.compile("(\\P{all})+"); |
duke@1 | 552 | } |