Save This Page
Home » openjdk-7 » com.sun.tools » apt » comp » [javadoc | source]
    1   /*
    2    * Copyright (c) 2004, 2010, 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.warnWriter;
  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   }

Save This Page
Home » openjdk-7 » com.sun.tools » apt » comp » [javadoc | source]