src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java

Mon, 30 Aug 2010 18:03:35 -0700

author
jjg
date
Mon, 30 Aug 2010 18:03:35 -0700
changeset 664
4124840b35fe
parent 663
eb7c263aab73
child 696
d4df3b6ee729
permissions
-rw-r--r--

6403465: javac should defer diagnostics until it can be determined they are persistent
Reviewed-by: mcimadamore, darcy

     1 /*
     2  * Copyright (c) 2005, 2009, 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  */
    26 package com.sun.tools.javac.processing;
    28 import java.lang.reflect.*;
    29 import java.util.*;
    30 import java.util.regex.*;
    32 import java.net.URL;
    33 import java.io.Closeable;
    34 import java.io.File;
    35 import java.io.PrintWriter;
    36 import java.io.IOException;
    37 import java.net.MalformedURLException;
    38 import java.io.StringWriter;
    40 import javax.annotation.processing.*;
    41 import javax.lang.model.SourceVersion;
    42 import javax.lang.model.element.AnnotationMirror;
    43 import javax.lang.model.element.Element;
    44 import javax.lang.model.element.TypeElement;
    45 import javax.lang.model.element.PackageElement;
    46 import javax.lang.model.util.*;
    47 import javax.tools.JavaFileManager;
    48 import javax.tools.StandardJavaFileManager;
    49 import javax.tools.JavaFileObject;
    50 import javax.tools.DiagnosticListener;
    52 import com.sun.source.util.AbstractTypeProcessor;
    53 import com.sun.source.util.TaskEvent;
    54 import com.sun.source.util.TaskListener;
    55 import com.sun.tools.javac.api.JavacTaskImpl;
    56 import com.sun.tools.javac.code.*;
    57 import com.sun.tools.javac.code.Symbol.*;
    58 import com.sun.tools.javac.file.JavacFileManager;
    59 import com.sun.tools.javac.jvm.*;
    60 import com.sun.tools.javac.main.JavaCompiler;
    61 import com.sun.tools.javac.main.JavaCompiler.CompileState;
    62 import com.sun.tools.javac.model.JavacElements;
    63 import com.sun.tools.javac.model.JavacTypes;
    64 import com.sun.tools.javac.parser.*;
    65 import com.sun.tools.javac.tree.*;
    66 import com.sun.tools.javac.tree.JCTree.*;
    67 import com.sun.tools.javac.util.Abort;
    68 import com.sun.tools.javac.util.Context;
    69 import com.sun.tools.javac.util.Convert;
    70 import com.sun.tools.javac.util.FatalError;
    71 import com.sun.tools.javac.util.JCDiagnostic;
    72 import com.sun.tools.javac.util.List;
    73 import com.sun.tools.javac.util.Log;
    74 import com.sun.tools.javac.util.JavacMessages;
    75 import com.sun.tools.javac.util.Name;
    76 import com.sun.tools.javac.util.Names;
    77 import com.sun.tools.javac.util.Options;
    79 import static javax.tools.StandardLocation.*;
    80 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
    82 /**
    83  * Objects of this class hold and manage the state needed to support
    84  * annotation processing.
    85  *
    86  * <p><b>This is NOT part of any supported API.
    87  * If you write code that depends on this, you do so at your own risk.
    88  * This code and its internal interfaces are subject to change or
    89  * deletion without notice.</b>
    90  */
    91 public class JavacProcessingEnvironment implements ProcessingEnvironment, Closeable {
    92     Options options;
    94     private final boolean printProcessorInfo;
    95     private final boolean printRounds;
    96     private final boolean verbose;
    97     private final boolean lint;
    98     private final boolean procOnly;
    99     private final boolean fatalErrors;
   100     private final boolean werror;
   101     private final boolean showResolveErrors;
   102     private boolean foundTypeProcessors;
   104     private final JavacFiler filer;
   105     private final JavacMessager messager;
   106     private final JavacElements elementUtils;
   107     private final JavacTypes typeUtils;
   109     /**
   110      * Holds relevant state history of which processors have been
   111      * used.
   112      */
   113     private DiscoveredProcessors discoveredProcs;
   115     /**
   116      * Map of processor-specific options.
   117      */
   118     private final Map<String, String> processorOptions;
   120     /**
   121      */
   122     private final Set<String> unmatchedProcessorOptions;
   124     /**
   125      * Annotations implicitly processed and claimed by javac.
   126      */
   127     private final Set<String> platformAnnotations;
   129     /**
   130      * Set of packages given on command line.
   131      */
   132     private Set<PackageSymbol> specifiedPackages = Collections.emptySet();
   134     /** The log to be used for error reporting.
   135      */
   136     Log log;
   138     /** Diagnostic factory.
   139      */
   140     JCDiagnostic.Factory diags;
   142     /**
   143      * Source level of the compile.
   144      */
   145     Source source;
   147     private ClassLoader processorClassLoader;
   149     /**
   150      * JavacMessages object used for localization
   151      */
   152     private JavacMessages messages;
   154     private Context context;
   156     public JavacProcessingEnvironment(Context context, Iterable<? extends Processor> processors) {
   157         this.context = context;
   158         log = Log.instance(context);
   159         source = Source.instance(context);
   160         diags = JCDiagnostic.Factory.instance(context);
   161         options = Options.instance(context);
   162         printProcessorInfo = options.get("-XprintProcessorInfo") != null;
   163         printRounds = options.get("-XprintRounds") != null;
   164         verbose = options.get("-verbose") != null;
   165         lint = options.lint("processing");
   166         procOnly = options.get("-proc:only") != null ||
   167             options.get("-Xprint") != null;
   168         fatalErrors = options.get("fatalEnterError") != null;
   169         showResolveErrors = options.get("showResolveErrors") != null;
   170         werror = options.get("-Werror") != null;
   171         platformAnnotations = initPlatformAnnotations();
   172         foundTypeProcessors = false;
   174         // Initialize services before any processors are initialzied
   175         // in case processors use them.
   176         filer = new JavacFiler(context);
   177         messager = new JavacMessager(context, this);
   178         elementUtils = new JavacElements(context);
   179         typeUtils = new JavacTypes(context);
   180         processorOptions = initProcessorOptions(context);
   181         unmatchedProcessorOptions = initUnmatchedProcessorOptions();
   182         messages = JavacMessages.instance(context);
   183         initProcessorIterator(context, processors);
   184     }
   186     private Set<String> initPlatformAnnotations() {
   187         Set<String> platformAnnotations = new HashSet<String>();
   188         platformAnnotations.add("java.lang.Deprecated");
   189         platformAnnotations.add("java.lang.Override");
   190         platformAnnotations.add("java.lang.SuppressWarnings");
   191         platformAnnotations.add("java.lang.annotation.Documented");
   192         platformAnnotations.add("java.lang.annotation.Inherited");
   193         platformAnnotations.add("java.lang.annotation.Retention");
   194         platformAnnotations.add("java.lang.annotation.Target");
   195         return Collections.unmodifiableSet(platformAnnotations);
   196     }
   198     private void initProcessorIterator(Context context, Iterable<? extends Processor> processors) {
   199         Log   log   = Log.instance(context);
   200         Iterator<? extends Processor> processorIterator;
   202         if (options.get("-Xprint") != null) {
   203             try {
   204                 Processor processor = PrintingProcessor.class.newInstance();
   205                 processorIterator = List.of(processor).iterator();
   206             } catch (Throwable t) {
   207                 AssertionError assertError =
   208                     new AssertionError("Problem instantiating PrintingProcessor.");
   209                 assertError.initCause(t);
   210                 throw assertError;
   211             }
   212         } else if (processors != null) {
   213             processorIterator = processors.iterator();
   214         } else {
   215             String processorNames = options.get("-processor");
   216             JavaFileManager fileManager = context.get(JavaFileManager.class);
   217             try {
   218                 // If processorpath is not explicitly set, use the classpath.
   219                 processorClassLoader = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH)
   220                     ? fileManager.getClassLoader(ANNOTATION_PROCESSOR_PATH)
   221                     : fileManager.getClassLoader(CLASS_PATH);
   223                 /*
   224                  * If the "-processor" option is used, search the appropriate
   225                  * path for the named class.  Otherwise, use a service
   226                  * provider mechanism to create the processor iterator.
   227                  */
   228                 if (processorNames != null) {
   229                     processorIterator = new NameProcessIterator(processorNames, processorClassLoader, log);
   230                 } else {
   231                     processorIterator = new ServiceIterator(processorClassLoader, log);
   232                 }
   233             } catch (SecurityException e) {
   234                 /*
   235                  * A security exception will occur if we can't create a classloader.
   236                  * Ignore the exception if, with hindsight, we didn't need it anyway
   237                  * (i.e. no processor was specified either explicitly, or implicitly,
   238                  * in service configuration file.) Otherwise, we cannot continue.
   239                  */
   240                 processorIterator = handleServiceLoaderUnavailability("proc.cant.create.loader", e);
   241             }
   242         }
   243         discoveredProcs = new DiscoveredProcessors(processorIterator);
   244     }
   246     /**
   247      * Returns an empty processor iterator if no processors are on the
   248      * relevant path, otherwise if processors are present, logs an
   249      * error.  Called when a service loader is unavailable for some
   250      * reason, either because a service loader class cannot be found
   251      * or because a security policy prevents class loaders from being
   252      * created.
   253      *
   254      * @param key The resource key to use to log an error message
   255      * @param e   If non-null, pass this exception to Abort
   256      */
   257     private Iterator<Processor> handleServiceLoaderUnavailability(String key, Exception e) {
   258         JavaFileManager fileManager = context.get(JavaFileManager.class);
   260         if (fileManager instanceof JavacFileManager) {
   261             StandardJavaFileManager standardFileManager = (JavacFileManager) fileManager;
   262             Iterable<? extends File> workingPath = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH)
   263                 ? standardFileManager.getLocation(ANNOTATION_PROCESSOR_PATH)
   264                 : standardFileManager.getLocation(CLASS_PATH);
   266             if (needClassLoader(options.get("-processor"), workingPath) )
   267                 handleException(key, e);
   269         } else {
   270             handleException(key, e);
   271         }
   273         java.util.List<Processor> pl = Collections.emptyList();
   274         return pl.iterator();
   275     }
   277     /**
   278      * Handle a security exception thrown during initializing the
   279      * Processor iterator.
   280      */
   281     private void handleException(String key, Exception e) {
   282         if (e != null) {
   283             log.error(key, e.getLocalizedMessage());
   284             throw new Abort(e);
   285         } else {
   286             log.error(key);
   287             throw new Abort();
   288         }
   289     }
   291     /**
   292      * Use a service loader appropriate for the platform to provide an
   293      * iterator over annotations processors.  If
   294      * java.util.ServiceLoader is present use it, otherwise, use
   295      * sun.misc.Service, otherwise fail if a loader is needed.
   296      */
   297     private class ServiceIterator implements Iterator<Processor> {
   298         // The to-be-wrapped iterator.
   299         private Iterator<?> iterator;
   300         private Log log;
   301         private Class<?> loaderClass;
   302         private boolean jusl;
   303         private Object loader;
   305         ServiceIterator(ClassLoader classLoader, Log log) {
   306             String loadMethodName;
   308             this.log = log;
   309             try {
   310                 try {
   311                     loaderClass = Class.forName("java.util.ServiceLoader");
   312                     loadMethodName = "load";
   313                     jusl = true;
   314                 } catch (ClassNotFoundException cnfe) {
   315                     try {
   316                         loaderClass = Class.forName("sun.misc.Service");
   317                         loadMethodName = "providers";
   318                         jusl = false;
   319                     } catch (ClassNotFoundException cnfe2) {
   320                         // Fail softly if a loader is not actually needed.
   321                         this.iterator = handleServiceLoaderUnavailability("proc.no.service",
   322                                                                           null);
   323                         return;
   324                     }
   325                 }
   327                 // java.util.ServiceLoader.load or sun.misc.Service.providers
   328                 Method loadMethod = loaderClass.getMethod(loadMethodName,
   329                                                           Class.class,
   330                                                           ClassLoader.class);
   332                 Object result = loadMethod.invoke(null,
   333                                                   Processor.class,
   334                                                   classLoader);
   336                 // For java.util.ServiceLoader, we have to call another
   337                 // method to get the iterator.
   338                 if (jusl) {
   339                     loader = result; // Store ServiceLoader to call reload later
   340                     Method m = loaderClass.getMethod("iterator");
   341                     result = m.invoke(result); // serviceLoader.iterator();
   342                 }
   344                 // The result should now be an iterator.
   345                 this.iterator = (Iterator<?>) result;
   346             } catch (Throwable t) {
   347                 log.error("proc.service.problem");
   348                 throw new Abort(t);
   349             }
   350         }
   352         public boolean hasNext() {
   353             try {
   354                 return iterator.hasNext();
   355             } catch (Throwable t) {
   356                 if ("ServiceConfigurationError".
   357                     equals(t.getClass().getSimpleName())) {
   358                     log.error("proc.bad.config.file", t.getLocalizedMessage());
   359                 }
   360                 throw new Abort(t);
   361             }
   362         }
   364         public Processor next() {
   365             try {
   366                 return (Processor)(iterator.next());
   367             } catch (Throwable t) {
   368                 if ("ServiceConfigurationError".
   369                     equals(t.getClass().getSimpleName())) {
   370                     log.error("proc.bad.config.file", t.getLocalizedMessage());
   371                 } else {
   372                     log.error("proc.processor.constructor.error", t.getLocalizedMessage());
   373                 }
   374                 throw new Abort(t);
   375             }
   376         }
   378         public void remove() {
   379             throw new UnsupportedOperationException();
   380         }
   382         public void close() {
   383             if (jusl) {
   384                 try {
   385                     // Call java.util.ServiceLoader.reload
   386                     Method reloadMethod = loaderClass.getMethod("reload");
   387                     reloadMethod.invoke(loader);
   388                 } catch(Exception e) {
   389                     ; // Ignore problems during a call to reload.
   390                 }
   391             }
   392         }
   393     }
   396     private static class NameProcessIterator implements Iterator<Processor> {
   397         Processor nextProc = null;
   398         Iterator<String> names;
   399         ClassLoader processorCL;
   400         Log log;
   402         NameProcessIterator(String names, ClassLoader processorCL, Log log) {
   403             this.names = Arrays.asList(names.split(",")).iterator();
   404             this.processorCL = processorCL;
   405             this.log = log;
   406         }
   408         public boolean hasNext() {
   409             if (nextProc != null)
   410                 return true;
   411             else {
   412                 if (!names.hasNext())
   413                     return false;
   414                 else {
   415                     String processorName = names.next();
   417                     Processor processor;
   418                     try {
   419                         try {
   420                             processor =
   421                                 (Processor) (processorCL.loadClass(processorName).newInstance());
   422                         } catch (ClassNotFoundException cnfe) {
   423                             log.error("proc.processor.not.found", processorName);
   424                             return false;
   425                         } catch (ClassCastException cce) {
   426                             log.error("proc.processor.wrong.type", processorName);
   427                             return false;
   428                         } catch (Exception e ) {
   429                             log.error("proc.processor.cant.instantiate", processorName);
   430                             return false;
   431                         }
   432                     } catch(Throwable t) {
   433                         throw new AnnotationProcessingError(t);
   434                     }
   435                     nextProc = processor;
   436                     return true;
   437                 }
   439             }
   440         }
   442         public Processor next() {
   443             if (hasNext()) {
   444                 Processor p = nextProc;
   445                 nextProc = null;
   446                 return p;
   447             } else
   448                 throw new NoSuchElementException();
   449         }
   451         public void remove () {
   452             throw new UnsupportedOperationException();
   453         }
   454     }
   456     public boolean atLeastOneProcessor() {
   457         return discoveredProcs.iterator().hasNext();
   458     }
   460     private Map<String, String> initProcessorOptions(Context context) {
   461         Options options = Options.instance(context);
   462         Set<String> keySet = options.keySet();
   463         Map<String, String> tempOptions = new LinkedHashMap<String, String>();
   465         for(String key : keySet) {
   466             if (key.startsWith("-A") && key.length() > 2) {
   467                 int sepIndex = key.indexOf('=');
   468                 String candidateKey = null;
   469                 String candidateValue = null;
   471                 if (sepIndex == -1)
   472                     candidateKey = key.substring(2);
   473                 else if (sepIndex >= 3) {
   474                     candidateKey = key.substring(2, sepIndex);
   475                     candidateValue = (sepIndex < key.length()-1)?
   476                         key.substring(sepIndex+1) : null;
   477                 }
   478                 tempOptions.put(candidateKey, candidateValue);
   479             }
   480         }
   482         return Collections.unmodifiableMap(tempOptions);
   483     }
   485     private Set<String> initUnmatchedProcessorOptions() {
   486         Set<String> unmatchedProcessorOptions = new HashSet<String>();
   487         unmatchedProcessorOptions.addAll(processorOptions.keySet());
   488         return unmatchedProcessorOptions;
   489     }
   491     /**
   492      * State about how a processor has been used by the tool.  If a
   493      * processor has been used on a prior round, its process method is
   494      * called on all subsequent rounds, perhaps with an empty set of
   495      * annotations to process.  The {@code annotatedSupported} method
   496      * caches the supported annotation information from the first (and
   497      * only) getSupportedAnnotationTypes call to the processor.
   498      */
   499     static class ProcessorState {
   500         public Processor processor;
   501         public boolean   contributed;
   502         private ArrayList<Pattern> supportedAnnotationPatterns;
   503         private ArrayList<String>  supportedOptionNames;
   505         ProcessorState(Processor p, Log log, Source source, ProcessingEnvironment env) {
   506             processor = p;
   507             contributed = false;
   509             try {
   510                 processor.init(env);
   512                 checkSourceVersionCompatibility(source, log);
   514                 supportedAnnotationPatterns = new ArrayList<Pattern>();
   515                 for (String importString : processor.getSupportedAnnotationTypes()) {
   516                     supportedAnnotationPatterns.add(importStringToPattern(importString,
   517                                                                           processor,
   518                                                                           log));
   519                 }
   521                 supportedOptionNames = new ArrayList<String>();
   522                 for (String optionName : processor.getSupportedOptions() ) {
   523                     if (checkOptionName(optionName, log))
   524                         supportedOptionNames.add(optionName);
   525                 }
   527             } catch (Throwable t) {
   528                 throw new AnnotationProcessingError(t);
   529             }
   530         }
   532         /**
   533          * Checks whether or not a processor's source version is
   534          * compatible with the compilation source version.  The
   535          * processor's source version needs to be greater than or
   536          * equal to the source version of the compile.
   537          */
   538         private void checkSourceVersionCompatibility(Source source, Log log) {
   539             SourceVersion procSourceVersion = processor.getSupportedSourceVersion();
   541             if (procSourceVersion.compareTo(Source.toSourceVersion(source)) < 0 )  {
   542                 log.warning("proc.processor.incompatible.source.version",
   543                             procSourceVersion,
   544                             processor.getClass().getName(),
   545                             source.name);
   546             }
   547         }
   549         private boolean checkOptionName(String optionName, Log log) {
   550             boolean valid = isValidOptionName(optionName);
   551             if (!valid)
   552                 log.error("proc.processor.bad.option.name",
   553                             optionName,
   554                             processor.getClass().getName());
   555             return valid;
   556         }
   558         public boolean annotationSupported(String annotationName) {
   559             for(Pattern p: supportedAnnotationPatterns) {
   560                 if (p.matcher(annotationName).matches())
   561                     return true;
   562             }
   563             return false;
   564         }
   566         /**
   567          * Remove options that are matched by this processor.
   568          */
   569         public void removeSupportedOptions(Set<String> unmatchedProcessorOptions) {
   570             unmatchedProcessorOptions.removeAll(supportedOptionNames);
   571         }
   572     }
   574     // TODO: These two classes can probably be rewritten better...
   575     /**
   576      * This class holds information about the processors that have
   577      * been discoverd so far as well as the means to discover more, if
   578      * necessary.  A single iterator should be used per round of
   579      * annotation processing.  The iterator first visits already
   580      * discovered processors then fails over to the service provider
   581      * mechanism if additional queries are made.
   582      */
   583     class DiscoveredProcessors implements Iterable<ProcessorState> {
   585         class ProcessorStateIterator implements Iterator<ProcessorState> {
   586             DiscoveredProcessors psi;
   587             Iterator<ProcessorState> innerIter;
   588             boolean onProcInterator;
   590             ProcessorStateIterator(DiscoveredProcessors psi) {
   591                 this.psi = psi;
   592                 this.innerIter = psi.procStateList.iterator();
   593                 this.onProcInterator = false;
   594             }
   596             public ProcessorState next() {
   597                 if (!onProcInterator) {
   598                     if (innerIter.hasNext())
   599                         return innerIter.next();
   600                     else
   601                         onProcInterator = true;
   602                 }
   604                 if (psi.processorIterator.hasNext()) {
   605                     ProcessorState ps = new ProcessorState(psi.processorIterator.next(),
   606                                                            log, source, JavacProcessingEnvironment.this);
   607                     psi.procStateList.add(ps);
   608                     return ps;
   609                 } else
   610                     throw new NoSuchElementException();
   611             }
   613             public boolean hasNext() {
   614                 if (onProcInterator)
   615                     return  psi.processorIterator.hasNext();
   616                 else
   617                     return innerIter.hasNext() || psi.processorIterator.hasNext();
   618             }
   620             public void remove () {
   621                 throw new UnsupportedOperationException();
   622             }
   624             /**
   625              * Run all remaining processors on the procStateList that
   626              * have not already run this round with an empty set of
   627              * annotations.
   628              */
   629             public void runContributingProcs(RoundEnvironment re) {
   630                 if (!onProcInterator) {
   631                     Set<TypeElement> emptyTypeElements = Collections.emptySet();
   632                     while(innerIter.hasNext()) {
   633                         ProcessorState ps = innerIter.next();
   634                         if (ps.contributed)
   635                             callProcessor(ps.processor, emptyTypeElements, re);
   636                     }
   637                 }
   638             }
   639         }
   641         Iterator<? extends Processor> processorIterator;
   642         ArrayList<ProcessorState>  procStateList;
   644         public ProcessorStateIterator iterator() {
   645             return new ProcessorStateIterator(this);
   646         }
   648         DiscoveredProcessors(Iterator<? extends Processor> processorIterator) {
   649             this.processorIterator = processorIterator;
   650             this.procStateList = new ArrayList<ProcessorState>();
   651         }
   653         /**
   654          * Free jar files, etc. if using a service loader.
   655          */
   656         public void close() {
   657             if (processorIterator != null &&
   658                 processorIterator instanceof ServiceIterator) {
   659                 ((ServiceIterator) processorIterator).close();
   660             }
   661         }
   662     }
   664     private void discoverAndRunProcs(Context context,
   665                                      Set<TypeElement> annotationsPresent,
   666                                      List<ClassSymbol> topLevelClasses,
   667                                      List<PackageSymbol> packageInfoFiles) {
   668         Map<String, TypeElement> unmatchedAnnotations =
   669             new HashMap<String, TypeElement>(annotationsPresent.size());
   671         for(TypeElement a  : annotationsPresent) {
   672                 unmatchedAnnotations.put(a.getQualifiedName().toString(),
   673                                          a);
   674         }
   676         // Give "*" processors a chance to match
   677         if (unmatchedAnnotations.size() == 0)
   678             unmatchedAnnotations.put("", null);
   680         DiscoveredProcessors.ProcessorStateIterator psi = discoveredProcs.iterator();
   681         // TODO: Create proper argument values; need past round
   682         // information to fill in this constructor.  Note that the 1
   683         // st round of processing could be the last round if there
   684         // were parse errors on the initial source files; however, we
   685         // are not doing processing in that case.
   687         Set<Element> rootElements = new LinkedHashSet<Element>();
   688         rootElements.addAll(topLevelClasses);
   689         rootElements.addAll(packageInfoFiles);
   690         rootElements = Collections.unmodifiableSet(rootElements);
   692         RoundEnvironment renv = new JavacRoundEnvironment(false,
   693                                                           false,
   694                                                           rootElements,
   695                                                           JavacProcessingEnvironment.this);
   697         while(unmatchedAnnotations.size() > 0 && psi.hasNext() ) {
   698             ProcessorState ps = psi.next();
   699             Set<String>  matchedNames = new HashSet<String>();
   700             Set<TypeElement> typeElements = new LinkedHashSet<TypeElement>();
   702             for (Map.Entry<String, TypeElement> entry: unmatchedAnnotations.entrySet()) {
   703                 String unmatchedAnnotationName = entry.getKey();
   704                 if (ps.annotationSupported(unmatchedAnnotationName) ) {
   705                     matchedNames.add(unmatchedAnnotationName);
   706                     TypeElement te = entry.getValue();
   707                     if (te != null)
   708                         typeElements.add(te);
   709                 }
   710             }
   712             if (matchedNames.size() > 0 || ps.contributed) {
   713                 foundTypeProcessors = foundTypeProcessors || (ps.processor instanceof AbstractTypeProcessor);
   714                 boolean processingResult = callProcessor(ps.processor, typeElements, renv);
   715                 ps.contributed = true;
   716                 ps.removeSupportedOptions(unmatchedProcessorOptions);
   718                 if (printProcessorInfo || verbose) {
   719                     log.printNoteLines("x.print.processor.info",
   720                             ps.processor.getClass().getName(),
   721                             matchedNames.toString(),
   722                             processingResult);
   723                 }
   725                 if (processingResult) {
   726                     unmatchedAnnotations.keySet().removeAll(matchedNames);
   727                 }
   729             }
   730         }
   731         unmatchedAnnotations.remove("");
   733         if (lint && unmatchedAnnotations.size() > 0) {
   734             // Remove annotations processed by javac
   735             unmatchedAnnotations.keySet().removeAll(platformAnnotations);
   736             if (unmatchedAnnotations.size() > 0) {
   737                 log = Log.instance(context);
   738                 log.warning("proc.annotations.without.processors",
   739                             unmatchedAnnotations.keySet());
   740             }
   741         }
   743         // Run contributing processors that haven't run yet
   744         psi.runContributingProcs(renv);
   746         // Debugging
   747         if (options.get("displayFilerState") != null)
   748             filer.displayState();
   749     }
   751     /**
   752      * Computes the set of annotations on the symbol in question.
   753      * Leave class public for external testing purposes.
   754      */
   755     public static class ComputeAnnotationSet extends
   756         ElementScanner7<Set<TypeElement>, Set<TypeElement>> {
   757         final Elements elements;
   759         public ComputeAnnotationSet(Elements elements) {
   760             super();
   761             this.elements = elements;
   762         }
   764         @Override
   765         public Set<TypeElement> visitPackage(PackageElement e, Set<TypeElement> p) {
   766             // Don't scan enclosed elements of a package
   767             return p;
   768         }
   770         @Override
   771         public Set<TypeElement> scan(Element e, Set<TypeElement> p) {
   772             for (AnnotationMirror annotationMirror :
   773                      elements.getAllAnnotationMirrors(e) ) {
   774                 Element e2 = annotationMirror.getAnnotationType().asElement();
   775                 p.add((TypeElement) e2);
   776             }
   777             return super.scan(e, p);
   778         }
   779     }
   781     private boolean callProcessor(Processor proc,
   782                                          Set<? extends TypeElement> tes,
   783                                          RoundEnvironment renv) {
   784         try {
   785             return proc.process(tes, renv);
   786         } catch (CompletionFailure ex) {
   787             StringWriter out = new StringWriter();
   788             ex.printStackTrace(new PrintWriter(out));
   789             log.error("proc.cant.access", ex.sym, ex.getDetailValue(), out.toString());
   790             return false;
   791         } catch (Throwable t) {
   792             throw new AnnotationProcessingError(t);
   793         }
   794     }
   796     /**
   797      * Helper object for a single round of annotation processing.
   798      */
   799     class Round {
   800         /** The round number. */
   801         final int number;
   802         /** The context for the round. */
   803         final Context context;
   804         /** The compiler for the round. */
   805         final JavaCompiler compiler;
   806         /** The log for the round. */
   807         final Log log;
   808         /** The number of warnings in the previous round. */
   809         final int priorWarnings;
   811         /** The ASTs to be compiled. */
   812         List<JCCompilationUnit> roots;
   813         /** The classes to be compiler that have were generated. */
   814         Map<String, JavaFileObject> genClassFiles;
   816         /** The set of annotations to be processed this round. */
   817         Set<TypeElement> annotationsPresent;
   818         /** The set of top level classes to be processed this round. */
   819         List<ClassSymbol> topLevelClasses;
   820         /** The set of package-info files to be processed this round. */
   821         List<PackageSymbol> packageInfoFiles;
   823         /** Create a round (common code). */
   824         private Round(Context context, int number, int priorWarnings) {
   825             this.context = context;
   826             this.number = number;
   827             this.priorWarnings = priorWarnings;
   829             compiler = JavaCompiler.instance(context);
   830             log = Log.instance(context);
   831             log.deferDiagnostics = true;
   833             // the following is for the benefit of JavacProcessingEnvironment.getContext()
   834             JavacProcessingEnvironment.this.context = context;
   836             // the following will be populated as needed
   837             topLevelClasses  = List.nil();
   838             packageInfoFiles = List.nil();
   839         }
   841         /** Create the first round. */
   842         Round(Context context, List<JCCompilationUnit> roots, List<ClassSymbol> classSymbols) {
   843             this(context, 1, 0);
   844             this.roots = roots;
   845             genClassFiles = new HashMap<String,JavaFileObject>();
   847             compiler.todo.clear(); // free the compiler's resources
   849             // The reverse() in the following line is to maintain behavioural
   850             // compatibility with the previous revision of the code. Strictly speaking,
   851             // it should not be necessary, but a javah golden file test fails without it.
   852             topLevelClasses =
   853                 getTopLevelClasses(roots).prependList(classSymbols.reverse());
   855             packageInfoFiles = getPackageInfoFiles(roots);
   857             findAnnotationsPresent();
   858         }
   860         /** Create a new round. */
   861         private Round(Round prev,
   862                 Set<JavaFileObject> newSourceFiles, Map<String,JavaFileObject> newClassFiles) {
   863             this(prev.nextContext(), prev.number+1, prev.compiler.log.nwarnings);
   864             this.genClassFiles = prev.genClassFiles;
   866             updateProcessingState();
   868             List<JCCompilationUnit> parsedFiles = compiler.parseFiles(newSourceFiles);
   869             roots = cleanTrees(prev.roots).appendList(parsedFiles);
   871             // Check for errors after parsing
   872             if (unrecoverableError())
   873                 return;
   875             enterClassFiles(genClassFiles);
   876             List<ClassSymbol> newClasses = enterClassFiles(newClassFiles);
   877             genClassFiles.putAll(newClassFiles);
   878             enterTrees(roots);
   880             if (unrecoverableError())
   881                 return;
   883             topLevelClasses = join(
   884                     getTopLevelClasses(parsedFiles),
   885                     getTopLevelClassesFromClasses(newClasses));
   887             packageInfoFiles = join(
   888                     getPackageInfoFiles(parsedFiles),
   889                     getPackageInfoFilesFromClasses(newClasses));
   891             findAnnotationsPresent();
   892         }
   894         /** Create the next round to be used. */
   895         Round next(Set<JavaFileObject> newSourceFiles, Map<String, JavaFileObject> newClassFiles) {
   896             try {
   897                 return new Round(this, newSourceFiles, newClassFiles);
   898             } finally {
   899                 compiler.close(false);
   900             }
   901         }
   903         /** Create the compiler to be used for the final compilation. */
   904         JavaCompiler finalCompiler(boolean errorStatus) {
   905             try {
   906                 JavaCompiler c = JavaCompiler.instance(nextContext());
   907                 if (errorStatus) {
   908                     c.log.nwarnings += priorWarnings + compiler.log.nwarnings;
   909                     c.log.nerrors += compiler.log.nerrors;
   910                 }
   911                 return c;
   912             } finally {
   913                 compiler.close(false);
   914             }
   915         }
   917         /** Return the number of errors found so far in this round.
   918          * This may include uncoverable errors, such as parse errors,
   919          * and transient errors, such as missing symbols. */
   920         int errorCount() {
   921             return compiler.errorCount();
   922         }
   924         /** Return the number of warnings found so far in this round. */
   925         int warningCount() {
   926             return compiler.warningCount();
   927         }
   929         /** Return whether or not an unrecoverable error has occurred. */
   930         boolean unrecoverableError() {
   931             if (messager.errorRaised())
   932                 return true;
   934             for (JCDiagnostic d: log.deferredDiagnostics) {
   935                 switch (d.getKind()) {
   936                     case WARNING:
   937                         if (werror)
   938                             return true;
   939                         break;
   941                     case ERROR:
   942                         if (fatalErrors || !d.isFlagSet(RESOLVE_ERROR))
   943                             return true;
   944                         break;
   945                 }
   946             }
   948             return false;
   949         }
   951         /** Find the set of annotations present in the set of top level
   952          *  classes and package info files to be processed this round. */
   953         void findAnnotationsPresent() {
   954             ComputeAnnotationSet annotationComputer = new ComputeAnnotationSet(elementUtils);
   955             // Use annotation processing to compute the set of annotations present
   956             annotationsPresent = new LinkedHashSet<TypeElement>();
   957             for (ClassSymbol classSym : topLevelClasses)
   958                 annotationComputer.scan(classSym, annotationsPresent);
   959             for (PackageSymbol pkgSym : packageInfoFiles)
   960                 annotationComputer.scan(pkgSym, annotationsPresent);
   961         }
   963         /** Enter a set of generated class files. */
   964         private List<ClassSymbol> enterClassFiles(Map<String, JavaFileObject> classFiles) {
   965             ClassReader reader = ClassReader.instance(context);
   966             Names names = Names.instance(context);
   967             List<ClassSymbol> list = List.nil();
   969             for (Map.Entry<String,JavaFileObject> entry : classFiles.entrySet()) {
   970                 Name name = names.fromString(entry.getKey());
   971                 JavaFileObject file = entry.getValue();
   972                 if (file.getKind() != JavaFileObject.Kind.CLASS)
   973                     throw new AssertionError(file);
   974                 ClassSymbol cs;
   975                 if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) {
   976                     Name packageName = Convert.packagePart(name);
   977                     PackageSymbol p = reader.enterPackage(packageName);
   978                     if (p.package_info == null)
   979                         p.package_info = reader.enterClass(Convert.shortName(name), p);
   980                     cs = p.package_info;
   981                     if (cs.classfile == null)
   982                         cs.classfile = file;
   983                 } else
   984                     cs = reader.enterClass(name, file);
   985                 list = list.prepend(cs);
   986             }
   987             return list.reverse();
   988         }
   990         /** Enter a set of syntax trees. */
   991         private void enterTrees(List<JCCompilationUnit> roots) {
   992             compiler.enterTrees(roots);
   993         }
   995         /** Run a processing round. */
   996         void run(boolean lastRound, boolean errorStatus) {
   997             printRoundInfo(lastRound);
   999             TaskListener taskListener = context.get(TaskListener.class);
  1000             if (taskListener != null)
  1001                 taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
  1003             try {
  1004                 if (lastRound) {
  1005                     filer.setLastRound(true);
  1006                     Set<Element> emptyRootElements = Collections.emptySet(); // immutable
  1007                     RoundEnvironment renv = new JavacRoundEnvironment(true,
  1008                             errorStatus,
  1009                             emptyRootElements,
  1010                             JavacProcessingEnvironment.this);
  1011                     discoveredProcs.iterator().runContributingProcs(renv);
  1012                 } else {
  1013                     discoverAndRunProcs(context, annotationsPresent, topLevelClasses, packageInfoFiles);
  1015             } finally {
  1016                 if (taskListener != null)
  1017                     taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
  1021         void showDiagnostics(boolean showAll) {
  1022             Set<JCDiagnostic.Kind> kinds = EnumSet.allOf(JCDiagnostic.Kind.class);
  1023             if (!showAll) {
  1024                 // suppress errors, which are all presumed to be transient resolve errors
  1025                 kinds.remove(JCDiagnostic.Kind.ERROR);
  1027             log.reportDeferredDiagnostics(kinds);
  1030         /** Update the processing state for the current context. */
  1031         private void updateProcessingState() {
  1032             filer.newRound(context);
  1033             messager.newRound(context);
  1035             elementUtils.setContext(context);
  1036             typeUtils.setContext(context);
  1039         /** Print info about this round. */
  1040         private void printRoundInfo(boolean lastRound) {
  1041             if (printRounds || verbose) {
  1042                 List<ClassSymbol> tlc = lastRound ? List.<ClassSymbol>nil() : topLevelClasses;
  1043                 Set<TypeElement> ap = lastRound ? Collections.<TypeElement>emptySet() : annotationsPresent;
  1044                 log.printNoteLines("x.print.rounds",
  1045                         number,
  1046                         "{" + tlc.toString(", ") + "}",
  1047                         ap,
  1048                         lastRound);
  1052         /** Get the context for the next round of processing.
  1053          * Important values are propogated from round to round;
  1054          * other values are implicitly reset.
  1055          */
  1056         private Context nextContext() {
  1057             Context next = new Context();
  1059             Options options = Options.instance(context);
  1060             assert options != null;
  1061             next.put(Options.optionsKey, options);
  1063             PrintWriter out = context.get(Log.outKey);
  1064             assert out != null;
  1065             next.put(Log.outKey, out);
  1067             final boolean shareNames = true;
  1068             if (shareNames) {
  1069                 Names names = Names.instance(context);
  1070                 assert names != null;
  1071                 next.put(Names.namesKey, names);
  1074             DiagnosticListener<?> dl = context.get(DiagnosticListener.class);
  1075             if (dl != null)
  1076                 next.put(DiagnosticListener.class, dl);
  1078             TaskListener tl = context.get(TaskListener.class);
  1079             if (tl != null)
  1080                 next.put(TaskListener.class, tl);
  1082             JavaFileManager jfm = context.get(JavaFileManager.class);
  1083             assert jfm != null;
  1084             next.put(JavaFileManager.class, jfm);
  1085             if (jfm instanceof JavacFileManager) {
  1086                 ((JavacFileManager)jfm).setContext(next);
  1089             Names names = Names.instance(context);
  1090             assert names != null;
  1091             next.put(Names.namesKey, names);
  1093             Keywords keywords = Keywords.instance(context);
  1094             assert(keywords != null);
  1095             next.put(Keywords.keywordsKey, keywords);
  1097             JavaCompiler oldCompiler = JavaCompiler.instance(context);
  1098             JavaCompiler nextCompiler = JavaCompiler.instance(next);
  1099             nextCompiler.initRound(oldCompiler);
  1101             JavacTaskImpl task = context.get(JavacTaskImpl.class);
  1102             if (task != null) {
  1103                 next.put(JavacTaskImpl.class, task);
  1104                 task.updateContext(next);
  1107             context.clear();
  1108             return next;
  1113     // TODO: internal catch clauses?; catch and rethrow an annotation
  1114     // processing error
  1115     public JavaCompiler doProcessing(Context context,
  1116                                      List<JCCompilationUnit> roots,
  1117                                      List<ClassSymbol> classSymbols,
  1118                                      Iterable<? extends PackageSymbol> pckSymbols) {
  1120         TaskListener taskListener = context.get(TaskListener.class);
  1121         log = Log.instance(context);
  1123         Set<PackageSymbol> specifiedPackages = new LinkedHashSet<PackageSymbol>();
  1124         for (PackageSymbol psym : pckSymbols)
  1125             specifiedPackages.add(psym);
  1126         this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages);
  1128         Round round = new Round(context, roots, classSymbols);
  1130         boolean errorStatus;
  1131         boolean moreToDo;
  1132         do {
  1133             // Run processors for round n
  1134             round.run(false, false);
  1136             // Processors for round n have run to completion.
  1137             // Check for errors and whether there is more work to do.
  1138             errorStatus = round.unrecoverableError();
  1139             moreToDo = moreToDo();
  1141             round.showDiagnostics(errorStatus || showResolveErrors);
  1143             // Set up next round.
  1144             // Copy mutable collections returned from filer.
  1145             round = round.next(
  1146                     new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects()),
  1147                     new LinkedHashMap<String,JavaFileObject>(filer.getGeneratedClasses()));
  1149              // Check for errors during setup.
  1150             if (round.unrecoverableError())
  1151                 errorStatus = true;
  1153         } while (moreToDo && !errorStatus);
  1155         // run last round
  1156         round.run(true, errorStatus);
  1157         round.showDiagnostics(true);
  1159         filer.warnIfUnclosedFiles();
  1160         warnIfUnmatchedOptions();
  1162         /*
  1163          * If an annotation processor raises an error in a round,
  1164          * that round runs to completion and one last round occurs.
  1165          * The last round may also occur because no more source or
  1166          * class files have been generated.  Therefore, if an error
  1167          * was raised on either of the last *two* rounds, the compile
  1168          * should exit with a nonzero exit code.  The current value of
  1169          * errorStatus holds whether or not an error was raised on the
  1170          * second to last round; errorRaised() gives the error status
  1171          * of the last round.
  1172          */
  1173         if (messager.errorRaised()
  1174                 || werror && round.warningCount() > 0 && round.errorCount() > 0)
  1175             errorStatus = true;
  1177         Set<JavaFileObject> newSourceFiles =
  1178                 new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects());
  1179         roots = cleanTrees(round.roots);
  1181         JavaCompiler compiler = round.finalCompiler(errorStatus);
  1183         if (newSourceFiles.size() > 0)
  1184             roots = roots.appendList(compiler.parseFiles(newSourceFiles));
  1186         errorStatus = errorStatus || (compiler.errorCount() > 0);
  1188         // Free resources
  1189         this.close();
  1191         if (taskListener != null)
  1192             taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
  1194         if (errorStatus) {
  1195             if (compiler.errorCount() == 0)
  1196                 compiler.log.nerrors++;
  1197             return compiler;
  1200         if (procOnly && !foundTypeProcessors) {
  1201             compiler.todo.clear();
  1202         } else {
  1203             if (procOnly && foundTypeProcessors)
  1204                 compiler.shouldStopPolicy = CompileState.FLOW;
  1206             compiler.enterTrees(roots);
  1209         return compiler;
  1212     private void warnIfUnmatchedOptions() {
  1213         if (!unmatchedProcessorOptions.isEmpty()) {
  1214             log.warning("proc.unmatched.processor.options", unmatchedProcessorOptions.toString());
  1218     /**
  1219      * Free resources related to annotation processing.
  1220      */
  1221     public void close() {
  1222         filer.close();
  1223         if (discoveredProcs != null) // Make calling close idempotent
  1224             discoveredProcs.close();
  1225         discoveredProcs = null;
  1226         if (processorClassLoader != null && processorClassLoader instanceof Closeable) {
  1227             try {
  1228                 ((Closeable) processorClassLoader).close();
  1229             } catch (IOException e) {
  1230                 JCDiagnostic msg = diags.fragment("fatal.err.cant.close.loader");
  1231                 throw new FatalError(msg, e);
  1236     private List<ClassSymbol> getTopLevelClasses(List<? extends JCCompilationUnit> units) {
  1237         List<ClassSymbol> classes = List.nil();
  1238         for (JCCompilationUnit unit : units) {
  1239             for (JCTree node : unit.defs) {
  1240                 if (node.getTag() == JCTree.CLASSDEF) {
  1241                     ClassSymbol sym = ((JCClassDecl) node).sym;
  1242                     assert sym != null;
  1243                     classes = classes.prepend(sym);
  1247         return classes.reverse();
  1250     private List<ClassSymbol> getTopLevelClassesFromClasses(List<? extends ClassSymbol> syms) {
  1251         List<ClassSymbol> classes = List.nil();
  1252         for (ClassSymbol sym : syms) {
  1253             if (!isPkgInfo(sym)) {
  1254                 classes = classes.prepend(sym);
  1257         return classes.reverse();
  1260     private List<PackageSymbol> getPackageInfoFiles(List<? extends JCCompilationUnit> units) {
  1261         List<PackageSymbol> packages = List.nil();
  1262         for (JCCompilationUnit unit : units) {
  1263             if (isPkgInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE)) {
  1264                 packages = packages.prepend(unit.packge);
  1267         return packages.reverse();
  1270     private List<PackageSymbol> getPackageInfoFilesFromClasses(List<? extends ClassSymbol> syms) {
  1271         List<PackageSymbol> packages = List.nil();
  1272         for (ClassSymbol sym : syms) {
  1273             if (isPkgInfo(sym)) {
  1274                 packages = packages.prepend((PackageSymbol) sym.owner);
  1277         return packages.reverse();
  1280     // avoid unchecked warning from use of varargs
  1281     private static <T> List<T> join(List<T> list1, List<T> list2) {
  1282         return list1.appendList(list2);
  1285     private boolean isPkgInfo(JavaFileObject fo, JavaFileObject.Kind kind) {
  1286         return fo.isNameCompatible("package-info", kind);
  1289     private boolean isPkgInfo(ClassSymbol sym) {
  1290         return isPkgInfo(sym.classfile, JavaFileObject.Kind.CLASS) && (sym.packge().package_info == sym);
  1293     /*
  1294      * Called retroactively to determine if a class loader was required,
  1295      * after we have failed to create one.
  1296      */
  1297     private boolean needClassLoader(String procNames, Iterable<? extends File> workingpath) {
  1298         if (procNames != null)
  1299             return true;
  1301         String procPath;
  1302         URL[] urls = new URL[1];
  1303         for(File pathElement : workingpath) {
  1304             try {
  1305                 urls[0] = pathElement.toURI().toURL();
  1306                 if (ServiceProxy.hasService(Processor.class, urls))
  1307                     return true;
  1308             } catch (MalformedURLException ex) {
  1309                 throw new AssertionError(ex);
  1311             catch (ServiceProxy.ServiceConfigurationError e) {
  1312                 log.error("proc.bad.config.file", e.getLocalizedMessage());
  1313                 return true;
  1317         return false;
  1320     private static <T extends JCTree> List<T> cleanTrees(List<T> nodes) {
  1321         for (T node : nodes)
  1322             treeCleaner.scan(node);
  1323         return nodes;
  1326     private static TreeScanner treeCleaner = new TreeScanner() {
  1327             public void scan(JCTree node) {
  1328                 super.scan(node);
  1329                 if (node != null)
  1330                     node.type = null;
  1332             public void visitTopLevel(JCCompilationUnit node) {
  1333                 node.packge = null;
  1334                 super.visitTopLevel(node);
  1336             public void visitClassDef(JCClassDecl node) {
  1337                 node.sym = null;
  1338                 super.visitClassDef(node);
  1340             public void visitMethodDef(JCMethodDecl node) {
  1341                 node.sym = null;
  1342                 super.visitMethodDef(node);
  1344             public void visitVarDef(JCVariableDecl node) {
  1345                 node.sym = null;
  1346                 super.visitVarDef(node);
  1348             public void visitNewClass(JCNewClass node) {
  1349                 node.constructor = null;
  1350                 super.visitNewClass(node);
  1352             public void visitAssignop(JCAssignOp node) {
  1353                 node.operator = null;
  1354                 super.visitAssignop(node);
  1356             public void visitUnary(JCUnary node) {
  1357                 node.operator = null;
  1358                 super.visitUnary(node);
  1360             public void visitBinary(JCBinary node) {
  1361                 node.operator = null;
  1362                 super.visitBinary(node);
  1364             public void visitSelect(JCFieldAccess node) {
  1365                 node.sym = null;
  1366                 super.visitSelect(node);
  1368             public void visitIdent(JCIdent node) {
  1369                 node.sym = null;
  1370                 super.visitIdent(node);
  1372         };
  1375     private boolean moreToDo() {
  1376         return filer.newFiles();
  1379     /**
  1380      * {@inheritdoc}
  1382      * Command line options suitable for presenting to annotation
  1383      * processors.  "-Afoo=bar" should be "-Afoo" => "bar".
  1384      */
  1385     public Map<String,String> getOptions() {
  1386         return processorOptions;
  1389     public Messager getMessager() {
  1390         return messager;
  1393     public Filer getFiler() {
  1394         return filer;
  1397     public JavacElements getElementUtils() {
  1398         return elementUtils;
  1401     public JavacTypes getTypeUtils() {
  1402         return typeUtils;
  1405     public SourceVersion getSourceVersion() {
  1406         return Source.toSourceVersion(source);
  1409     public Locale getLocale() {
  1410         return messages.getCurrentLocale();
  1413     public Set<Symbol.PackageSymbol> getSpecifiedPackages() {
  1414         return specifiedPackages;
  1417     private static final Pattern allMatches = Pattern.compile(".*");
  1418     public static final Pattern noMatches  = Pattern.compile("(\\P{all})+");
  1420     /**
  1421      * Convert import-style string for supported annotations into a
  1422      * regex matching that string.  If the string is a valid
  1423      * import-style string, return a regex that won't match anything.
  1424      */
  1425     private static Pattern importStringToPattern(String s, Processor p, Log log) {
  1426         if (isValidImportString(s)) {
  1427             return validImportStringToPattern(s);
  1428         } else {
  1429             log.warning("proc.malformed.supported.string", s, p.getClass().getName());
  1430             return noMatches; // won't match any valid identifier
  1434     /**
  1435      * Return true if the argument string is a valid import-style
  1436      * string specifying claimed annotations; return false otherwise.
  1437      */
  1438     public static boolean isValidImportString(String s) {
  1439         if (s.equals("*"))
  1440             return true;
  1442         boolean valid = true;
  1443         String t = s;
  1444         int index = t.indexOf('*');
  1446         if (index != -1) {
  1447             // '*' must be last character...
  1448             if (index == t.length() -1) {
  1449                 // ... any and preceding character must be '.'
  1450                 if ( index-1 >= 0 ) {
  1451                     valid = t.charAt(index-1) == '.';
  1452                     // Strip off ".*$" for identifier checks
  1453                     t = t.substring(0, t.length()-2);
  1455             } else
  1456                 return false;
  1459         // Verify string is off the form (javaId \.)+ or javaId
  1460         if (valid) {
  1461             String[] javaIds = t.split("\\.", t.length()+2);
  1462             for(String javaId: javaIds)
  1463                 valid &= SourceVersion.isIdentifier(javaId);
  1465         return valid;
  1468     public static Pattern validImportStringToPattern(String s) {
  1469         if (s.equals("*")) {
  1470             return allMatches;
  1471         } else {
  1472             String s_prime = s.replace(".", "\\.");
  1474             if (s_prime.endsWith("*")) {
  1475                 s_prime =  s_prime.substring(0, s_prime.length() - 1) + ".+";
  1478             return Pattern.compile(s_prime);
  1482     /**
  1483      * For internal use only.  This method will be
  1484      * removed without warning.
  1485      */
  1486     public Context getContext() {
  1487         return context;
  1490     public String toString() {
  1491         return "javac ProcessingEnvironment";
  1494     public static boolean isValidOptionName(String optionName) {
  1495         for(String s : optionName.split("\\.", -1)) {
  1496             if (!SourceVersion.isIdentifier(s))
  1497                 return false;
  1499         return true;

mercurial