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