src/share/classes/com/sun/tools/apt/comp/Apt.java

Thu, 04 Feb 2010 10:14:28 -0800

author
jjg
date
Thu, 04 Feb 2010 10:14:28 -0800
changeset 489
4b4e282a3146
parent 419
c6d0c55b1aba
child 497
16b9b7f45933
permissions
-rw-r--r--

6923080: TreeScanner.visitNewClass should scan tree.typeargs
Reviewed-by: darcy

     1 /*
     2  * Copyright 2004-2009 Sun Microsystems, Inc.  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.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any questions.
    24  */
    26 package com.sun.tools.apt.comp;
    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;
    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;
    43 import com.sun.tools.apt.*;
    44 import com.sun.tools.apt.comp.*;
    45 import com.sun.tools.javac.code.Symbol.*;
    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;
    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;
    58 import static com.sun.tools.apt.mirror.declaration.DeclarationMaker.isJavaIdentifier;
    60 /**
    61  * Apt compiler phase.
    62  *
    63  *  <p><b>This is NOT part of any API supported by Sun Microsystems.
    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     }
    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     }
    82     /* AptEnvironment */
    83     AptEnv aptenv;
    85     private Context context;
    87     /** The context key for the todo list. */
    89     protected static final Context.Key<Apt> aptKey =
    90         new Context.Key<Apt>();
    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     }
   100     /** Create a new apt list. */
   101     protected Apt(Context context) {
   102         this.context = context;
   104         context.put(aptKey, this);
   105         aptenv = AptEnv.instance(context);
   106     }
   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 {
   124         // Set of fully qualified names of annotation types present in
   125         // examined source
   126         private Set<String> annotationSet;
   128         // Symbols to build bootstrapping declaration list
   129         private Collection<ClassSymbol> specifiedDeclCollection;
   130         private Collection<ClassSymbol> declCollection;
   132         public Set<String> getAnnotationSet() {
   133             return annotationSet;
   134         }
   136         public AptTreeScanner() {
   137             annotationSet = new  LinkedHashSet<String>();
   138             specifiedDeclCollection = new LinkedHashSet<ClassSymbol>();
   139             declCollection = new LinkedHashSet<ClassSymbol>();
   140         }
   142         public void visitTopLevel(JCTree.JCCompilationUnit tree) {
   143             super.visitTopLevel(tree);
   144             // Print out contents -- what are we dealing with?
   146             for(JCTree d: tree.defs) {
   147                 if (d instanceof JCTree.JCClassDecl)
   148                     specifiedDeclCollection.add(((JCTree.JCClassDecl) d).sym);
   149             }
   151         }
   153         public void visitBlock(JCTree.JCBlock tree) {
   154             ; // Do nothing.
   155         }
   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             }
   165             super.visitClassDef(tree);
   167             declCollection.add(tree.sym);
   168         }
   170         public void visitMethodDef(JCTree.JCMethodDecl tree) {
   171             super.visitMethodDef(tree);
   172         }
   174         public void visitVarDef(JCTree.JCVariableDecl tree) {
   175             super.visitVarDef(tree);
   176         }
   178         public void visitAnnotation(JCTree.JCAnnotation tree) {
   179             super.visitAnnotation(tree);
   180             annotationSet.add(tree.type.tsym.toString());
   181         }
   182     }
   184     Set<String> computeAnnotationSet(Collection<ClassSymbol> classSymbols) {
   185         Set<String> annotationSet = new HashSet<String>();
   187         for(ClassSymbol classSymbol: classSymbols) {
   188             computeAnnotationSet(classSymbol, annotationSet);
   189         }
   190         return annotationSet;
   191     }
   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?
   199             if (symbol instanceof Symbol.MethodSymbol) // add parameter annotations
   200                 for(Symbol param: ((MethodSymbol) symbol).params())
   201                     computeAnnotationSet(param, annotationSet);
   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     }
   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.warnWriter;
   218         Options options = Options.instance(context);
   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> >();
   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         }
   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         }
   241         for (ClassSymbol cs : ats.declCollection) {
   242             TypeDeclaration decl = aptenv.declMaker.getTypeDeclaration(cs);
   243             typedecls.add(decl);
   244         }
   246         unmatchedAnnotations.addAll(ats.getAnnotationSet());
   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         }
   257         if (options.get("-XListAnnotationTypes") != null) {
   258             out.println("Set of annotations found:" +
   259                         (new TreeSet<String>(unmatchedAnnotations)).toString());
   260         }
   262         AnnotationProcessorEnvironmentImpl trivAPE =
   263             new AnnotationProcessorEnvironmentImpl(spectypedecls, typedecls, origOptions, context);
   265         if (options.get("-XListDeclarations") != null) {
   266             out.println("Set of Specified Declarations:" +
   267                         spectypedecls);
   269             out.println("Set of Included Declarations: " +
   270                            typedecls);
   271         }
   273         if (options.get("-print") != null) {
   274             if (spectypedecls.size() == 0 )
   275                 throw new UsageMessageNeededException();
   277             // Run the printing processor
   278             AnnotationProcessor proc = (new BootstrapAPF()).getProcessorFor(new HashSet<AnnotationTypeDeclaration>(),
   279                                                                             trivAPE);
   280             proc.process();
   281         } else {
   282             // Discovery process
   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                  */
   297                 java.util.List<AnnotationProcessorFactory> list =
   298                     new LinkedList<AnnotationProcessorFactory>();
   299                 String factoryName = options.get("-factory");
   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                     }
   319                     providers = list.iterator();
   320                 } else {
   321                     @SuppressWarnings("unchecked")
   322                     Iterator<AnnotationProcessorFactory> iter =
   323                             sun.misc.Service.providers(AnnotationProcessorFactory.class, aptCL);
   324                     providers = iter;
   326                 }
   327             }
   329             java.util.Map<AnnotationProcessorFactory, Set<AnnotationTypeDeclaration>> factoryToAnnotation =
   330                 new LinkedHashMap<AnnotationProcessorFactory, Set<AnnotationTypeDeclaration>>();
   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.
   343                 if(unmatchedAnnotations.size() == 0)
   344                     unmatchedAnnotations.add("");
   346                 Set<String> emptyStringSet = new HashSet<String>();
   347                 emptyStringSet.add("");
   348                 emptyStringSet = Collections.unmodifiableSet(emptyStringSet);
   350                 while (providers.hasNext() ) {
   351                     Object provider = providers.next();
   352                     try {
   353                         Set<String> matchedStrings = new HashSet<String>();
   355                         AnnotationProcessorFactory apf = (AnnotationProcessorFactory) provider;
   356                         Collection<String> supportedTypes = apf.supportedAnnotationTypes();
   358                         Collection<Pattern> supportedTypePatterns = new LinkedList<Pattern>();
   359                         for(String s: supportedTypes)
   360                             supportedTypePatterns.add(importStringToPattern(s));
   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                         }
   371                         unmatchedAnnotations.removeAll(matchedStrings);
   373                         if (options.get("-XPrintFactoryInfo") != null) {
   374                             out.println("Factory " + apf.getClass().getName() +
   375                                         " matches " +
   376                                         ((matchedStrings.size() == 0)?
   377                                          "nothing.": matchedStrings));
   378                         }
   380                         if (matchedStrings.size() > 0) {
   381                             // convert annotation names to annotation
   382                             // type decls
   383                             Set<AnnotationTypeDeclaration> atds = new HashSet<AnnotationTypeDeclaration>();
   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);
   399                                         } catch (ClassCastException cce) {
   400                                             bark.aptError("BadDeclaration", s);
   401                                         }
   402                                     }
   403                                 }
   404                             }
   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                         }
   418                         if (unmatchedAnnotations.size() == 0)
   419                             break;
   421                     } catch (ClassCastException cce) {
   422                         bark.aptWarning("BadFactory", cce);
   423                     }
   424                 }
   426                 unmatchedAnnotations.remove("");
   427             }
   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             }
   448             if (unmatchedAnnotations.size() > 0)
   449                 bark.aptWarning("AnnotationsWithoutProcessors", unmatchedAnnotations);
   451             Set<AnnotationProcessor> processors = new LinkedHashSet<AnnotationProcessor>();
   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();
   459             try {
   460                 for(AnnotationProcessorFactory apFactory: factoryToAnnotation.keySet()) {
   461                     AnnotationProcessor processor = apFactory.getProcessorFor(factoryToAnnotation.get(apFactory),
   462                                                                               trivAPE);
   463                     if (processor != null)
   464                         processors.add(processor);
   465                     else
   466                         bark.aptWarning("NullProcessor", apFactory.getClass().getName());
   467                 }
   468             } catch(Throwable t) {
   469                 throw new AnnotationProcessingError(t);
   470             }
   472             LinkedList<AnnotationProcessor> temp = new LinkedList<AnnotationProcessor>();
   473             temp.addAll(processors);
   475             AnnotationProcessor proc = AnnotationProcessors.getCompositeAnnotationProcessor(temp);
   477             try {
   478                 proc.process();
   479             } catch (Throwable t) {
   480                 throw new AnnotationProcessingError(t);
   481             }
   483             // Invoke listener callback mechanism
   484             trivAPE.roundComplete();
   486             FilerImpl filerimpl = (FilerImpl)trivAPE.getFiler();
   487             genSourceFileNames = filerimpl.getSourceFileNames();
   488             genClassFileNames = filerimpl.getClassFileNames();
   489             filerimpl.flush(); // Make sure new files are written out
   490         }
   491     }
   493     /**
   494      * Convert import-style string to regex matching that string.  If
   495      * the string is a valid import-style string, return a regex that
   496      * won't match anything.
   497      */
   498     Pattern importStringToPattern(String s) {
   499         if (s.equals("*")) {
   500             return allMatches;
   501         } else {
   502             String t = s;
   503             boolean star = false;
   505             /*
   506              * Validate string from factory is legal.  If the string
   507              * has more than one asterisks or the asterisks does not
   508              * appear as the last character (preceded by a period),
   509              * the string is not legal.
   510              */
   512             boolean valid = true;
   513             int index = t.indexOf('*');
   514             if (index != -1) {
   515                 // '*' must be last character...
   516                 if (index == t.length() -1) {
   517                      // ... and preceeding character must be '.'
   518                     if ( index-1 >= 0 ) {
   519                         valid = t.charAt(index-1) == '.';
   520                         // Strip off ".*$" for identifier checks
   521                         t = t.substring(0, t.length()-2);
   522                     }
   523                 } else
   524                     valid = false;
   525             }
   527             // Verify string is off the form (javaId \.)+ or javaId
   528             if (valid) {
   529                 String[] javaIds = t.split("\\.", t.length()+2);
   530                 for(String javaId: javaIds)
   531                     valid &= isJavaIdentifier(javaId);
   532             }
   534             if (!valid) {
   535                 Bark bark = Bark.instance(context);
   536                 bark.aptWarning("MalformedSupportedString", s);
   537                 return noMatches; // won't match any valid identifier
   538             }
   540             String s_prime = s.replaceAll("\\.", "\\\\.");
   542             if (s_prime.endsWith("*")) {
   543                 s_prime =  s_prime.substring(0, s_prime.length() - 1) + ".+";
   544             }
   546             return Pattern.compile(s_prime);
   547         }
   548     }
   550     private static final Pattern allMatches = Pattern.compile(".*");
   551     private static final Pattern noMatches  = Pattern.compile("(\\P{all})+");
   552 }

mercurial