1 /*
   2  * Copyright (c) 2005, 2019, 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.javac.processing;
  27 
  28 import java.io.Closeable;
  29 import java.io.File;
  30 import java.io.PrintWriter;
  31 import java.io.StringWriter;
  32 import java.net.MalformedURLException;
  33 import java.net.URL;
  34 import java.util.*;
  35 import java.util.regex.*;
  36 
  37 import javax.annotation.processing.*;
  38 import javax.lang.model.SourceVersion;
  39 import javax.lang.model.element.*;
  40 import javax.lang.model.util.*;
  41 import javax.tools.DiagnosticListener;
  42 import javax.tools.JavaFileManager;
  43 import javax.tools.JavaFileObject;
  44 import javax.tools.StandardJavaFileManager;
  45 import static javax.tools.StandardLocation.*;
  46 
  47 import com.sun.source.util.JavacTask;
  48 import com.sun.source.util.TaskEvent;
  49 import com.sun.tools.javac.api.BasicJavacTask;
  50 import com.sun.tools.javac.api.JavacTrees;
  51 import com.sun.tools.javac.api.MultiTaskListener;
  52 import com.sun.tools.javac.code.*;
  53 import com.sun.tools.javac.code.Symbol.*;
  54 import com.sun.tools.javac.file.FSInfo;
  55 import com.sun.tools.javac.file.JavacFileManager;
  56 import com.sun.tools.javac.jvm.*;
  57 import com.sun.tools.javac.jvm.ClassReader.BadClassFile;
  58 import com.sun.tools.javac.main.JavaCompiler;
  59 import com.sun.tools.javac.model.JavacElements;
  60 import com.sun.tools.javac.model.JavacTypes;
  61 import com.sun.tools.javac.parser.*;
  62 import com.sun.tools.javac.tree.*;
  63 import com.sun.tools.javac.tree.JCTree.*;
  64 import com.sun.tools.javac.util.Abort;
  65 import com.sun.tools.javac.util.Assert;
  66 import com.sun.tools.javac.util.ClientCodeException;
  67 import com.sun.tools.javac.util.Context;
  68 import com.sun.tools.javac.util.Convert;
  69 import com.sun.tools.javac.util.JCDiagnostic;
  70 import com.sun.tools.javac.util.JavacMessages;
  71 import com.sun.tools.javac.util.List;
  72 import com.sun.tools.javac.util.Log;
  73 import com.sun.tools.javac.util.Name;
  74 import com.sun.tools.javac.util.Names;
  75 import com.sun.tools.javac.util.Options;
  76 import com.sun.tools.javac.util.ServiceLoader;
  77 import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING;
  78 import static com.sun.tools.javac.main.Option.*;
  79 import static com.sun.tools.javac.comp.CompileStates.CompileState;
  80 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
  81 
  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     private final Options options;
  93 
  94     private final boolean printProcessorInfo;
  95     private final boolean printRounds;
  96     private final boolean verbose;
  97     private final boolean lint;
  98     private final boolean fatalErrors;
  99     private final boolean werror;
 100     private final boolean showResolveErrors;
 101 
 102     private final JavacFiler filer;
 103     private final JavacMessager messager;
 104     private final JavacElements elementUtils;
 105     private final JavacTypes typeUtils;
 106 
 107     /**
 108      * Holds relevant state history of which processors have been
 109      * used.
 110      */
 111     private DiscoveredProcessors discoveredProcs;
 112 
 113     /**
 114      * Map of processor-specific options.
 115      */
 116     private final Map<String, String> processorOptions;
 117 
 118     /**
 119      */
 120     private final Set<String> unmatchedProcessorOptions;
 121 
 122     /**
 123      * Annotations implicitly processed and claimed by javac.
 124      */
 125     private final Set<String> platformAnnotations;
 126 
 127     /**
 128      * Set of packages given on command line.
 129      */
 130     private Set<PackageSymbol> specifiedPackages = Collections.emptySet();
 131 
 132     /** The log to be used for error reporting.
 133      */
 134     Log log;
 135 
 136     /** Diagnostic factory.
 137      */
 138     JCDiagnostic.Factory diags;
 139 
 140     /**
 141      * Source level of the compile.
 142      */
 143     Source source;
 144 
 145     private ClassLoader processorClassLoader;
 146     private SecurityException processorClassLoaderException;
 147 
 148     /**
 149      * JavacMessages object used for localization
 150      */
 151     private JavacMessages messages;
 152 
 153     private MultiTaskListener taskListener;
 154 
 155     private Context context;
 156 
 157     /** Get the JavacProcessingEnvironment instance for this context. */
 158     public static JavacProcessingEnvironment instance(Context context) {
 159         JavacProcessingEnvironment instance = context.get(JavacProcessingEnvironment.class);
 160         if (instance == null)
 161             instance = new JavacProcessingEnvironment(context);
 162         return instance;
 163     }
 164 
 165     protected JavacProcessingEnvironment(Context context) {
 166         this.context = context;
 167         context.put(JavacProcessingEnvironment.class, this);
 168         log = Log.instance(context);
 169         source = Source.instance(context);
 170         diags = JCDiagnostic.Factory.instance(context);
 171         options = Options.instance(context);
 172         printProcessorInfo = options.isSet(XPRINTPROCESSORINFO);
 173         printRounds = options.isSet(XPRINTROUNDS);
 174         verbose = options.isSet(VERBOSE);
 175         lint = Lint.instance(context).isEnabled(PROCESSING);
 176         if (options.isSet(PROC, "only") || options.isSet(XPRINT)) {
 177             JavaCompiler compiler = JavaCompiler.instance(context);
 178             compiler.shouldStopPolicyIfNoError = CompileState.PROCESS;
 179         }
 180         fatalErrors = options.isSet("fatalEnterError");
 181         showResolveErrors = options.isSet("showResolveErrors");
 182         werror = options.isSet(WERROR);
 183         platformAnnotations = initPlatformAnnotations();
 184 
 185         // Initialize services before any processors are initialized
 186         // in case processors use them.
 187         filer = new JavacFiler(context);
 188         messager = new JavacMessager(context, this);
 189         elementUtils = JavacElements.instance(context);
 190         typeUtils = JavacTypes.instance(context);
 191         processorOptions = initProcessorOptions(context);
 192         unmatchedProcessorOptions = initUnmatchedProcessorOptions();
 193         messages = JavacMessages.instance(context);
 194         taskListener = MultiTaskListener.instance(context);
 195         initProcessorClassLoader();
 196     }
 197 
 198     public void setProcessors(Iterable<? extends Processor> processors) {
 199         Assert.checkNull(discoveredProcs);
 200         initProcessorIterator(context, processors);
 201     }
 202 
 203     private Set<String> initPlatformAnnotations() {
 204         Set<String> platformAnnotations = new HashSet<String>();
 205         platformAnnotations.add("java.lang.Deprecated");
 206         platformAnnotations.add("java.lang.Override");
 207         platformAnnotations.add("java.lang.SuppressWarnings");
 208         platformAnnotations.add("java.lang.annotation.Documented");
 209         platformAnnotations.add("java.lang.annotation.Inherited");
 210         platformAnnotations.add("java.lang.annotation.Retention");
 211         platformAnnotations.add("java.lang.annotation.Target");
 212         return Collections.unmodifiableSet(platformAnnotations);
 213     }
 214 
 215     private void initProcessorClassLoader() {
 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);
 222 
 223             if (processorClassLoader != null && processorClassLoader instanceof Closeable) {
 224                 JavaCompiler compiler = JavaCompiler.instance(context);
 225                 compiler.closeables = compiler.closeables.prepend((Closeable) processorClassLoader);
 226             }
 227         } catch (SecurityException e) {
 228             processorClassLoaderException = e;
 229         }
 230     }
 231 
 232     private void initProcessorIterator(Context context, Iterable<? extends Processor> processors) {
 233         Log   log   = Log.instance(context);
 234         Iterator<? extends Processor> processorIterator;
 235 
 236         if (options.isSet(XPRINT)) {
 237             try {
 238                 Processor processor = PrintingProcessor.class.newInstance();
 239                 processorIterator = List.of(processor).iterator();
 240             } catch (Throwable t) {
 241                 AssertionError assertError =
 242                     new AssertionError("Problem instantiating PrintingProcessor.");
 243                 assertError.initCause(t);
 244                 throw assertError;
 245             }
 246         } else if (processors != null) {
 247             processorIterator = processors.iterator();
 248         } else {
 249             String processorNames = options.get(PROCESSOR);
 250             if (processorClassLoaderException == null) {
 251                 /*
 252                  * If the "-processor" option is used, search the appropriate
 253                  * path for the named class.  Otherwise, use a service
 254                  * provider mechanism to create the processor iterator.
 255                  */
 256                 if (processorNames != null) {
 257                     processorIterator = new NameProcessIterator(processorNames, processorClassLoader, log);
 258                 } else {
 259                     processorIterator = new ServiceIterator(processorClassLoader, log);
 260                 }
 261             } else {
 262                 /*
 263                  * A security exception will occur if we can't create a classloader.
 264                  * Ignore the exception if, with hindsight, we didn't need it anyway
 265                  * (i.e. no processor was specified either explicitly, or implicitly,
 266                  * in service configuration file.) Otherwise, we cannot continue.
 267                  */
 268                 processorIterator = handleServiceLoaderUnavailability("proc.cant.create.loader",
 269                         processorClassLoaderException);
 270             }
 271         }
 272         discoveredProcs = new DiscoveredProcessors(processorIterator);
 273     }
 274 
 275     /**
 276      * Returns an empty processor iterator if no processors are on the
 277      * relevant path, otherwise if processors are present, logs an
 278      * error.  Called when a service loader is unavailable for some
 279      * reason, either because a service loader class cannot be found
 280      * or because a security policy prevents class loaders from being
 281      * created.
 282      *
 283      * @param key The resource key to use to log an error message
 284      * @param e   If non-null, pass this exception to Abort
 285      */
 286     private Iterator<Processor> handleServiceLoaderUnavailability(String key, Exception e) {
 287         JavaFileManager fileManager = context.get(JavaFileManager.class);
 288 
 289         if (fileManager instanceof JavacFileManager) {
 290             StandardJavaFileManager standardFileManager = (JavacFileManager) fileManager;
 291             Iterable<? extends File> workingPath = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH)
 292                 ? standardFileManager.getLocation(ANNOTATION_PROCESSOR_PATH)
 293                 : standardFileManager.getLocation(CLASS_PATH);
 294 
 295             if (needClassLoader(options.get(PROCESSOR), workingPath) )
 296                 handleException(key, e);
 297 
 298         } else {
 299             handleException(key, e);
 300         }
 301 
 302         java.util.List<Processor> pl = Collections.emptyList();
 303         return pl.iterator();
 304     }
 305 
 306     /**
 307      * Handle a security exception thrown during initializing the
 308      * Processor iterator.
 309      */
 310     private void handleException(String key, Exception e) {
 311         if (e != null) {
 312             log.error(key, e.getLocalizedMessage());
 313             throw new Abort(e);
 314         } else {
 315             log.error(key);
 316             throw new Abort();
 317         }
 318     }
 319 
 320     /**
 321      * Use a service loader appropriate for the platform to provide an
 322      * iterator over annotations processors; fails if a loader is
 323      * needed but unavailable.
 324      */
 325     private class ServiceIterator implements Iterator<Processor> {
 326         private Iterator<Processor> iterator;
 327         private Log log;
 328         private ServiceLoader<Processor> loader;
 329 
 330         ServiceIterator(ClassLoader classLoader, Log log) {
 331             this.log = log;
 332             try {
 333                 try {
 334                     loader = ServiceLoader.load(Processor.class, classLoader);
 335                     this.iterator = loader.iterator();
 336                 } catch (Exception e) {
 337                     // Fail softly if a loader is not actually needed.
 338                     this.iterator = handleServiceLoaderUnavailability("proc.no.service", null);
 339                 }
 340             } catch (Throwable t) {
 341                 log.error("proc.service.problem");
 342                 throw new Abort(t);
 343             }
 344         }
 345 
 346         public boolean hasNext() {
 347             try {
 348                 return iterator.hasNext();
 349             } catch(ServiceConfigurationError sce) {
 350                 log.error("proc.bad.config.file", sce.getLocalizedMessage());
 351                 throw new Abort(sce);
 352             } catch (Throwable t) {
 353                 log.error("proc.bad.config.file", t.getLocalizedMessage());
 354                 throw new Abort(t);
 355             }
 356         }
 357 
 358         public Processor next() {
 359             try {
 360                 return iterator.next();
 361             } catch (ServiceConfigurationError sce) {
 362                 log.error("proc.bad.config.file", sce.getLocalizedMessage());
 363                 throw new Abort(sce);
 364             } catch (UnsupportedClassVersionError ucve) {
 365                 log.error("proc.cant.load.class", ucve.getLocalizedMessage());
 366                 throw new Abort(ucve);
 367             } catch (ClassFormatError cfe) {
 368                 log.error("proc.cant.load.class", cfe.getLocalizedMessage());
 369                 throw new Abort(cfe);
 370             } catch (Throwable t) {
 371                 log.error("proc.bad.config.file", t.getLocalizedMessage());
 372                 throw new Abort(t);
 373             }
 374         }
 375 
 376         public void remove() {
 377             throw new UnsupportedOperationException();
 378         }
 379 
 380         public void close() {
 381             if (loader != null) {
 382                 try {
 383                     loader.reload();
 384                 } catch(Exception e) {
 385                     ; // Ignore problems during a call to reload.
 386                 }
 387             }
 388         }
 389     }
 390 
 391 
 392     private static class NameProcessIterator implements Iterator<Processor> {
 393         Processor nextProc = null;
 394         Iterator<String> names;
 395         ClassLoader processorCL;
 396         Log log;
 397 
 398         NameProcessIterator(String names, ClassLoader processorCL, Log log) {
 399             this.names = Arrays.asList(names.split(",")).iterator();
 400             this.processorCL = processorCL;
 401             this.log = log;
 402         }
 403 
 404         public boolean hasNext() {
 405             if (nextProc != null)
 406                 return true;
 407             else {
 408                 if (!names.hasNext())
 409                     return false;
 410                 else {
 411                     String processorName = names.next();
 412 
 413                     Processor processor;
 414                     try {
 415                         try {
 416                             processor =
 417                                 (Processor) (processorCL.loadClass(processorName).newInstance());
 418                         } catch (ClassNotFoundException cnfe) {
 419                             log.error("proc.processor.not.found", processorName);
 420                             return false;
 421                         } catch (ClassCastException cce) {
 422                             log.error("proc.processor.wrong.type", processorName);
 423                             return false;
 424                         } catch (Exception e ) {
 425                             log.error("proc.processor.cant.instantiate", processorName);
 426                             return false;
 427                         }
 428                     } catch(ClientCodeException e) {
 429                         throw e;
 430                     } catch(Throwable t) {
 431                         throw new AnnotationProcessingError(t);
 432                     }
 433                     nextProc = processor;
 434                     return true;
 435                 }
 436 
 437             }
 438         }
 439 
 440         public Processor next() {
 441             if (hasNext()) {
 442                 Processor p = nextProc;
 443                 nextProc = null;
 444                 return p;
 445             } else
 446                 throw new NoSuchElementException();
 447         }
 448 
 449         public void remove () {
 450             throw new UnsupportedOperationException();
 451         }
 452     }
 453 
 454     public boolean atLeastOneProcessor() {
 455         return discoveredProcs.iterator().hasNext();
 456     }
 457 
 458     private Map<String, String> initProcessorOptions(Context context) {
 459         Options options = Options.instance(context);
 460         Set<String> keySet = options.keySet();
 461         Map<String, String> tempOptions = new LinkedHashMap<String, String>();
 462 
 463         for(String key : keySet) {
 464             if (key.startsWith("-A") && key.length() > 2) {
 465                 int sepIndex = key.indexOf('=');
 466                 String candidateKey = null;
 467                 String candidateValue = null;
 468 
 469                 if (sepIndex == -1)
 470                     candidateKey = key.substring(2);
 471                 else if (sepIndex >= 3) {
 472                     candidateKey = key.substring(2, sepIndex);
 473                     candidateValue = (sepIndex < key.length()-1)?
 474                         key.substring(sepIndex+1) : null;
 475                 }
 476                 tempOptions.put(candidateKey, candidateValue);
 477             }
 478         }
 479 
 480         return Collections.unmodifiableMap(tempOptions);
 481     }
 482 
 483     private Set<String> initUnmatchedProcessorOptions() {
 484         Set<String> unmatchedProcessorOptions = new HashSet<String>();
 485         unmatchedProcessorOptions.addAll(processorOptions.keySet());
 486         return unmatchedProcessorOptions;
 487     }
 488 
 489     /**
 490      * State about how a processor has been used by the tool.  If a
 491      * processor has been used on a prior round, its process method is
 492      * called on all subsequent rounds, perhaps with an empty set of
 493      * annotations to process.  The {@code annotationSupported} method
 494      * caches the supported annotation information from the first (and
 495      * only) getSupportedAnnotationTypes call to the processor.
 496      */
 497     static class ProcessorState {
 498         public Processor processor;
 499         public boolean   contributed;
 500         private ArrayList<Pattern> supportedAnnotationPatterns;
 501         private ArrayList<String>  supportedOptionNames;
 502 
 503         ProcessorState(Processor p, Log log, Source source, ProcessingEnvironment env) {
 504             processor = p;
 505             contributed = false;
 506 
 507             try {
 508                 processor.init(env);
 509 
 510                 checkSourceVersionCompatibility(source, log);
 511 
 512                 supportedAnnotationPatterns = new ArrayList<Pattern>();
 513                 for (String importString : processor.getSupportedAnnotationTypes()) {
 514                     supportedAnnotationPatterns.add(importStringToPattern(importString,
 515                                                                           processor,
 516                                                                           log));
 517                 }
 518 
 519                 supportedOptionNames = new ArrayList<String>();
 520                 for (String optionName : processor.getSupportedOptions() ) {
 521                     if (checkOptionName(optionName, log))
 522                         supportedOptionNames.add(optionName);
 523                 }
 524 
 525             } catch (ClientCodeException e) {
 526                 throw e;
 527             } catch (Throwable t) {
 528                 throw new AnnotationProcessingError(t);
 529             }
 530         }
 531 
 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();
 540 
 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         }
 548 
 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         }
 557 
 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         }
 565 
 566         /**
 567          * Remove options that are matched by this processor.
 568          */
 569         public void removeSupportedOptions(Set<String> unmatchedProcessorOptions) {
 570             unmatchedProcessorOptions.removeAll(supportedOptionNames);
 571         }
 572     }
 573 
 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> {
 584 
 585         class ProcessorStateIterator implements Iterator<ProcessorState> {
 586             DiscoveredProcessors psi;
 587             Iterator<ProcessorState> innerIter;
 588             boolean onProcInterator;
 589 
 590             ProcessorStateIterator(DiscoveredProcessors psi) {
 591                 this.psi = psi;
 592                 this.innerIter = psi.procStateList.iterator();
 593                 this.onProcInterator = false;
 594             }
 595 
 596             public ProcessorState next() {
 597                 if (!onProcInterator) {
 598                     if (innerIter.hasNext())
 599                         return innerIter.next();
 600                     else
 601                         onProcInterator = true;
 602                 }
 603 
 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             }
 612 
 613             public boolean hasNext() {
 614                 if (onProcInterator)
 615                     return  psi.processorIterator.hasNext();
 616                 else
 617                     return innerIter.hasNext() || psi.processorIterator.hasNext();
 618             }
 619 
 620             public void remove () {
 621                 throw new UnsupportedOperationException();
 622             }
 623 
 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         }
 640 
 641         Iterator<? extends Processor> processorIterator;
 642         ArrayList<ProcessorState>  procStateList;
 643 
 644         public ProcessorStateIterator iterator() {
 645             return new ProcessorStateIterator(this);
 646         }
 647 
 648         DiscoveredProcessors(Iterator<? extends Processor> processorIterator) {
 649             this.processorIterator = processorIterator;
 650             this.procStateList = new ArrayList<ProcessorState>();
 651         }
 652 
 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     }
 663 
 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());
 670 
 671         for(TypeElement a  : annotationsPresent) {
 672                 unmatchedAnnotations.put(a.getQualifiedName().toString(),
 673                                          a);
 674         }
 675 
 676         // Give "*" processors a chance to match
 677         if (unmatchedAnnotations.size() == 0)
 678             unmatchedAnnotations.put("", null);
 679 
 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.
 686 
 687         Set<Element> rootElements = new LinkedHashSet<Element>();
 688         rootElements.addAll(topLevelClasses);
 689         rootElements.addAll(packageInfoFiles);
 690         rootElements = Collections.unmodifiableSet(rootElements);
 691 
 692         RoundEnvironment renv = new JavacRoundEnvironment(false,
 693                                                           false,
 694                                                           rootElements,
 695                                                           JavacProcessingEnvironment.this);
 696 
 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>();
 701 
 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             }
 711 
 712             if (matchedNames.size() > 0 || ps.contributed) {
 713                 boolean processingResult = callProcessor(ps.processor, typeElements, renv);
 714                 ps.contributed = true;
 715                 ps.removeSupportedOptions(unmatchedProcessorOptions);
 716 
 717                 if (printProcessorInfo || verbose) {
 718                     log.printLines("x.print.processor.info",
 719                             ps.processor.getClass().getName(),
 720                             matchedNames.toString(),
 721                             processingResult);
 722                 }
 723 
 724                 if (processingResult) {
 725                     unmatchedAnnotations.keySet().removeAll(matchedNames);
 726                 }
 727 
 728             }
 729         }
 730         unmatchedAnnotations.remove("");
 731 
 732         if (lint && unmatchedAnnotations.size() > 0) {
 733             // Remove annotations processed by javac
 734             unmatchedAnnotations.keySet().removeAll(platformAnnotations);
 735             if (unmatchedAnnotations.size() > 0) {
 736                 log = Log.instance(context);
 737                 log.warning("proc.annotations.without.processors",
 738                             unmatchedAnnotations.keySet());
 739             }
 740         }
 741 
 742         // Run contributing processors that haven't run yet
 743         psi.runContributingProcs(renv);
 744 
 745         // Debugging
 746         if (options.isSet("displayFilerState"))
 747             filer.displayState();
 748     }
 749 
 750     /**
 751      * Computes the set of annotations on the symbol in question.
 752      * Leave class public for external testing purposes.
 753      */
 754     public static class ComputeAnnotationSet extends
 755         ElementScanner8<Set<TypeElement>, Set<TypeElement>> {
 756         final Elements elements;
 757 
 758         public ComputeAnnotationSet(Elements elements) {
 759             super();
 760             this.elements = elements;
 761         }
 762 
 763         @Override
 764         public Set<TypeElement> visitPackage(PackageElement e, Set<TypeElement> p) {
 765             // Don't scan enclosed elements of a package
 766             return p;
 767         }
 768 
 769         @Override
 770         public Set<TypeElement> visitType(TypeElement e, Set<TypeElement> p) {
 771             // Type parameters are not considered to be enclosed by a type
 772             scan(e.getTypeParameters(), p);
 773             return super.visitType(e, p);
 774         }
 775 
 776         @Override
 777         public Set<TypeElement> visitExecutable(ExecutableElement e, Set<TypeElement> p) {
 778             // Type parameters are not considered to be enclosed by an executable
 779             scan(e.getTypeParameters(), p);
 780             return super.visitExecutable(e, p);
 781         }
 782 
 783         void addAnnotations(Element e, Set<TypeElement> p) {
 784             for (AnnotationMirror annotationMirror :
 785                      elements.getAllAnnotationMirrors(e) ) {
 786                 Element e2 = annotationMirror.getAnnotationType().asElement();
 787                 p.add((TypeElement) e2);
 788             }
 789         }
 790 
 791         @Override
 792         public Set<TypeElement> scan(Element e, Set<TypeElement> p) {
 793             addAnnotations(e, p);
 794             return super.scan(e, p);
 795         }
 796     }
 797 
 798     private boolean callProcessor(Processor proc,
 799                                          Set<? extends TypeElement> tes,
 800                                          RoundEnvironment renv) {
 801         try {
 802             return proc.process(tes, renv);
 803         } catch (BadClassFile ex) {
 804             log.error("proc.cant.access.1", ex.sym, ex.getDetailValue());
 805             return false;
 806         } catch (CompletionFailure ex) {
 807             StringWriter out = new StringWriter();
 808             ex.printStackTrace(new PrintWriter(out));
 809             log.error("proc.cant.access", ex.sym, ex.getDetailValue(), out.toString());
 810             return false;
 811         } catch (ClientCodeException e) {
 812             throw e;
 813         } catch (Throwable t) {
 814             throw new AnnotationProcessingError(t);
 815         }
 816     }
 817 
 818     /**
 819      * Helper object for a single round of annotation processing.
 820      */
 821     class Round {
 822         /** The round number. */
 823         final int number;
 824         /** The context for the round. */
 825         final Context context;
 826         /** The compiler for the round. */
 827         final JavaCompiler compiler;
 828         /** The log for the round. */
 829         final Log log;
 830         /** The diagnostic handler for the round. */
 831         final Log.DeferredDiagnosticHandler deferredDiagnosticHandler;
 832 
 833         /** The ASTs to be compiled. */
 834         List<JCCompilationUnit> roots;
 835         /** The classes to be compiler that have were generated. */
 836         Map<String, JavaFileObject> genClassFiles;
 837 
 838         /** The set of annotations to be processed this round. */
 839         Set<TypeElement> annotationsPresent;
 840         /** The set of top level classes to be processed this round. */
 841         List<ClassSymbol> topLevelClasses;
 842         /** The set of package-info files to be processed this round. */
 843         List<PackageSymbol> packageInfoFiles;
 844 
 845         /** Create a round (common code). */
 846         private Round(Context context, int number, int priorErrors, int priorWarnings,
 847                 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
 848             this.context = context;
 849             this.number = number;
 850 
 851             compiler = JavaCompiler.instance(context);
 852             log = Log.instance(context);
 853             log.nerrors = priorErrors;
 854             log.nwarnings = priorWarnings;
 855             if (number == 1) {
 856                 Assert.checkNonNull(deferredDiagnosticHandler);
 857                 this.deferredDiagnosticHandler = deferredDiagnosticHandler;
 858             } else {
 859                 this.deferredDiagnosticHandler = new Log.DeferredDiagnosticHandler(log);
 860             }
 861 
 862             // the following is for the benefit of JavacProcessingEnvironment.getContext()
 863             JavacProcessingEnvironment.this.context = context;
 864 
 865             // the following will be populated as needed
 866             topLevelClasses  = List.nil();
 867             packageInfoFiles = List.nil();
 868         }
 869 
 870         /** Create the first round. */
 871         Round(Context context, List<JCCompilationUnit> roots, List<ClassSymbol> classSymbols,
 872                 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
 873             this(context, 1, 0, 0, deferredDiagnosticHandler);
 874             this.roots = roots;
 875             genClassFiles = new HashMap<String,JavaFileObject>();
 876 
 877             compiler.todo.clear(); // free the compiler's resources
 878 
 879             // The reverse() in the following line is to maintain behavioural
 880             // compatibility with the previous revision of the code. Strictly speaking,
 881             // it should not be necessary, but a javah golden file test fails without it.
 882             topLevelClasses =
 883                 getTopLevelClasses(roots).prependList(classSymbols.reverse());
 884 
 885             packageInfoFiles = getPackageInfoFiles(roots);
 886 
 887             findAnnotationsPresent();
 888         }
 889 
 890         /** Create a new round. */
 891         private Round(Round prev,
 892                 Set<JavaFileObject> newSourceFiles, Map<String,JavaFileObject> newClassFiles) {
 893             this(prev.nextContext(),
 894                     prev.number+1,
 895                     prev.compiler.log.nerrors,
 896                     prev.compiler.log.nwarnings,
 897                     null);
 898             this.genClassFiles = prev.genClassFiles;
 899 
 900             List<JCCompilationUnit> parsedFiles = compiler.parseFiles(newSourceFiles);
 901             roots = cleanTrees(prev.roots).appendList(parsedFiles);
 902 
 903             // Check for errors after parsing
 904             if (unrecoverableError())
 905                 return;
 906 
 907             enterClassFiles(genClassFiles);
 908             List<ClassSymbol> newClasses = enterClassFiles(newClassFiles);
 909             genClassFiles.putAll(newClassFiles);
 910             enterTrees(roots);
 911 
 912             if (unrecoverableError())
 913                 return;
 914 
 915             topLevelClasses = join(
 916                     getTopLevelClasses(parsedFiles),
 917                     getTopLevelClassesFromClasses(newClasses));
 918 
 919             packageInfoFiles = join(
 920                     getPackageInfoFiles(parsedFiles),
 921                     getPackageInfoFilesFromClasses(newClasses));
 922 
 923             findAnnotationsPresent();
 924         }
 925 
 926         /** Create the next round to be used. */
 927         Round next(Set<JavaFileObject> newSourceFiles, Map<String, JavaFileObject> newClassFiles) {
 928             try {
 929                 return new Round(this, newSourceFiles, newClassFiles);
 930             } finally {
 931                 compiler.close(false);
 932             }
 933         }
 934 
 935         /** Create the compiler to be used for the final compilation. */
 936         JavaCompiler finalCompiler() {
 937             try {
 938                 Context nextCtx = nextContext();
 939                 JavacProcessingEnvironment.this.context = nextCtx;
 940                 JavaCompiler c = JavaCompiler.instance(nextCtx);
 941                 c.log.initRound(compiler.log);
 942                 return c;
 943             } finally {
 944                 compiler.close(false);
 945             }
 946         }
 947 
 948         /** Return the number of errors found so far in this round.
 949          * This may include uncoverable errors, such as parse errors,
 950          * and transient errors, such as missing symbols. */
 951         int errorCount() {
 952             return compiler.errorCount();
 953         }
 954 
 955         /** Return the number of warnings found so far in this round. */
 956         int warningCount() {
 957             return compiler.warningCount();
 958         }
 959 
 960         /** Return whether or not an unrecoverable error has occurred. */
 961         boolean unrecoverableError() {
 962             if (messager.errorRaised())
 963                 return true;
 964 
 965             for (JCDiagnostic d: deferredDiagnosticHandler.getDiagnostics()) {
 966                 switch (d.getKind()) {
 967                     case WARNING:
 968                         if (werror)
 969                             return true;
 970                         break;
 971 
 972                     case ERROR:
 973                         if (fatalErrors || !d.isFlagSet(RECOVERABLE))
 974                             return true;
 975                         break;
 976                 }
 977             }
 978 
 979             return false;
 980         }
 981 
 982         /** Find the set of annotations present in the set of top level
 983          *  classes and package info files to be processed this round. */
 984         void findAnnotationsPresent() {
 985             ComputeAnnotationSet annotationComputer = new ComputeAnnotationSet(elementUtils);
 986             // Use annotation processing to compute the set of annotations present
 987             annotationsPresent = new LinkedHashSet<TypeElement>();
 988             for (ClassSymbol classSym : topLevelClasses)
 989                 annotationComputer.scan(classSym, annotationsPresent);
 990             for (PackageSymbol pkgSym : packageInfoFiles)
 991                 annotationComputer.scan(pkgSym, annotationsPresent);
 992         }
 993 
 994         /** Enter a set of generated class files. */
 995         private List<ClassSymbol> enterClassFiles(Map<String, JavaFileObject> classFiles) {
 996             ClassReader reader = ClassReader.instance(context);
 997             Names names = Names.instance(context);
 998             List<ClassSymbol> list = List.nil();
 999 
1000             for (Map.Entry<String,JavaFileObject> entry : classFiles.entrySet()) {
1001                 Name name = names.fromString(entry.getKey());
1002                 JavaFileObject file = entry.getValue();
1003                 if (file.getKind() != JavaFileObject.Kind.CLASS)
1004                     throw new AssertionError(file);
1005                 ClassSymbol cs;
1006                 if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) {
1007                     Name packageName = Convert.packagePart(name);
1008                     PackageSymbol p = reader.enterPackage(packageName);
1009                     if (p.package_info == null)
1010                         p.package_info = reader.enterClass(Convert.shortName(name), p);
1011                     cs = p.package_info;
1012                     if (cs.classfile == null)
1013                         cs.classfile = file;
1014                 } else
1015                     cs = reader.enterClass(name, file);
1016                 list = list.prepend(cs);
1017             }
1018             return list.reverse();
1019         }
1020 
1021         /** Enter a set of syntax trees. */
1022         private void enterTrees(List<JCCompilationUnit> roots) {
1023             compiler.enterTrees(roots);
1024         }
1025 
1026         /** Run a processing round. */
1027         void run(boolean lastRound, boolean errorStatus) {
1028             printRoundInfo(lastRound);
1029 
1030             if (!taskListener.isEmpty())
1031                 taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
1032 
1033             try {
1034                 if (lastRound) {
1035                     filer.setLastRound(true);
1036                     Set<Element> emptyRootElements = Collections.emptySet(); // immutable
1037                     RoundEnvironment renv = new JavacRoundEnvironment(true,
1038                             errorStatus,
1039                             emptyRootElements,
1040                             JavacProcessingEnvironment.this);
1041                     discoveredProcs.iterator().runContributingProcs(renv);
1042                 } else {
1043                     discoverAndRunProcs(context, annotationsPresent, topLevelClasses, packageInfoFiles);
1044                 }
1045             } catch (Throwable t) {
1046                 // we're specifically expecting Abort here, but if any Throwable
1047                 // comes by, we should flush all deferred diagnostics, rather than
1048                 // drop them on the ground.
1049                 deferredDiagnosticHandler.reportDeferredDiagnostics();
1050                 log.popDiagnosticHandler(deferredDiagnosticHandler);
1051                 throw t;
1052             } finally {
1053                 if (!taskListener.isEmpty())
1054                     taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
1055             }
1056         }
1057 
1058         void showDiagnostics(boolean showAll) {
1059             Set<JCDiagnostic.Kind> kinds = EnumSet.allOf(JCDiagnostic.Kind.class);
1060             if (!showAll) {
1061                 // suppress errors, which are all presumed to be transient resolve errors
1062                 kinds.remove(JCDiagnostic.Kind.ERROR);
1063             }
1064             deferredDiagnosticHandler.reportDeferredDiagnostics(kinds);
1065             log.popDiagnosticHandler(deferredDiagnosticHandler);
1066         }
1067 
1068         /** Print info about this round. */
1069         private void printRoundInfo(boolean lastRound) {
1070             if (printRounds || verbose) {
1071                 List<ClassSymbol> tlc = lastRound ? List.<ClassSymbol>nil() : topLevelClasses;
1072                 Set<TypeElement> ap = lastRound ? Collections.<TypeElement>emptySet() : annotationsPresent;
1073                 log.printLines("x.print.rounds",
1074                         number,
1075                         "{" + tlc.toString(", ") + "}",
1076                         ap,
1077                         lastRound);
1078             }
1079         }
1080 
1081         /** Get the context for the next round of processing.
1082          * Important values are propagated from round to round;
1083          * other values are implicitly reset.
1084          */
1085         private Context nextContext() {
1086             Context next = new Context(context);
1087 
1088             Options options = Options.instance(context);
1089             Assert.checkNonNull(options);
1090             next.put(Options.optionsKey, options);
1091 
1092             Locale locale = context.get(Locale.class);
1093             if (locale != null)
1094                 next.put(Locale.class, locale);
1095 
1096             Assert.checkNonNull(messages);
1097             next.put(JavacMessages.messagesKey, messages);
1098 
1099             final boolean shareNames = true;
1100             if (shareNames) {
1101                 Names names = Names.instance(context);
1102                 Assert.checkNonNull(names);
1103                 next.put(Names.namesKey, names);
1104             }
1105 
1106             DiagnosticListener<?> dl = context.get(DiagnosticListener.class);
1107             if (dl != null)
1108                 next.put(DiagnosticListener.class, dl);
1109 
1110             MultiTaskListener mtl = context.get(MultiTaskListener.taskListenerKey);
1111             if (mtl != null)
1112                 next.put(MultiTaskListener.taskListenerKey, mtl);
1113 
1114             FSInfo fsInfo = context.get(FSInfo.class);
1115             if (fsInfo != null)
1116                 next.put(FSInfo.class, fsInfo);
1117 
1118             JavaFileManager jfm = context.get(JavaFileManager.class);
1119             Assert.checkNonNull(jfm);
1120             next.put(JavaFileManager.class, jfm);
1121             if (jfm instanceof JavacFileManager) {
1122                 ((JavacFileManager)jfm).setContext(next);
1123             }
1124 
1125             Names names = Names.instance(context);
1126             Assert.checkNonNull(names);
1127             next.put(Names.namesKey, names);
1128 
1129             Tokens tokens = Tokens.instance(context);
1130             Assert.checkNonNull(tokens);
1131             next.put(Tokens.tokensKey, tokens);
1132 
1133             Log nextLog = Log.instance(next);
1134             nextLog.initRound(log);
1135 
1136             JavaCompiler oldCompiler = JavaCompiler.instance(context);
1137             JavaCompiler nextCompiler = JavaCompiler.instance(next);
1138             nextCompiler.initRound(oldCompiler);
1139 
1140             filer.newRound(next);
1141             messager.newRound(next);
1142             elementUtils.setContext(next);
1143             typeUtils.setContext(next);
1144 
1145             JavacTask task = context.get(JavacTask.class);
1146             if (task != null) {
1147                 next.put(JavacTask.class, task);
1148                 if (task instanceof BasicJavacTask)
1149                     ((BasicJavacTask) task).updateContext(next);
1150             }
1151 
1152             JavacTrees trees = context.get(JavacTrees.class);
1153             if (trees != null) {
1154                 next.put(JavacTrees.class, trees);
1155                 trees.updateContext(next);
1156             }
1157 
1158             context.clear();
1159             return next;
1160         }
1161     }
1162 
1163 
1164     // TODO: internal catch clauses?; catch and rethrow an annotation
1165     // processing error
1166     public JavaCompiler doProcessing(Context context,
1167                                      List<JCCompilationUnit> roots,
1168                                      List<ClassSymbol> classSymbols,
1169                                      Iterable<? extends PackageSymbol> pckSymbols,
1170                                      Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
1171         log = Log.instance(context);
1172 
1173         Set<PackageSymbol> specifiedPackages = new LinkedHashSet<PackageSymbol>();
1174         for (PackageSymbol psym : pckSymbols)
1175             specifiedPackages.add(psym);
1176         this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages);
1177 
1178         Round round = new Round(context, roots, classSymbols, deferredDiagnosticHandler);
1179 
1180         boolean errorStatus;
1181         boolean moreToDo;
1182         do {
1183             // Run processors for round n
1184             round.run(false, false);
1185 
1186             // Processors for round n have run to completion.
1187             // Check for errors and whether there is more work to do.
1188             errorStatus = round.unrecoverableError();
1189             moreToDo = moreToDo();
1190 
1191             round.showDiagnostics(errorStatus || showResolveErrors);
1192 
1193             // Set up next round.
1194             // Copy mutable collections returned from filer.
1195             round = round.next(
1196                     new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects()),
1197                     new LinkedHashMap<String,JavaFileObject>(filer.getGeneratedClasses()));
1198 
1199              // Check for errors during setup.
1200             if (round.unrecoverableError())
1201                 errorStatus = true;
1202 
1203         } while (moreToDo && !errorStatus);
1204 
1205         // run last round
1206         round.run(true, errorStatus);
1207         round.showDiagnostics(true);
1208 
1209         filer.warnIfUnclosedFiles();
1210         warnIfUnmatchedOptions();
1211 
1212         /*
1213          * If an annotation processor raises an error in a round,
1214          * that round runs to completion and one last round occurs.
1215          * The last round may also occur because no more source or
1216          * class files have been generated.  Therefore, if an error
1217          * was raised on either of the last *two* rounds, the compile
1218          * should exit with a nonzero exit code.  The current value of
1219          * errorStatus holds whether or not an error was raised on the
1220          * second to last round; errorRaised() gives the error status
1221          * of the last round.
1222          */
1223         if (messager.errorRaised()
1224                 || werror && round.warningCount() > 0 && round.errorCount() > 0)
1225             errorStatus = true;
1226 
1227         Set<JavaFileObject> newSourceFiles =
1228                 new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects());
1229         roots = cleanTrees(round.roots);
1230 
1231         JavaCompiler compiler = round.finalCompiler();
1232 
1233         if (newSourceFiles.size() > 0)
1234             roots = roots.appendList(compiler.parseFiles(newSourceFiles));
1235 
1236         errorStatus = errorStatus || (compiler.errorCount() > 0);
1237 
1238         // Free resources
1239         this.close();
1240 
1241         if (!taskListener.isEmpty())
1242             taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
1243 
1244         if (errorStatus) {
1245             if (compiler.errorCount() == 0)
1246                 compiler.log.nerrors++;
1247             return compiler;
1248         }
1249 
1250         compiler.enterTreesIfNeeded(roots);
1251 
1252         return compiler;
1253     }
1254 
1255     private void warnIfUnmatchedOptions() {
1256         if (!unmatchedProcessorOptions.isEmpty()) {
1257             log.warning("proc.unmatched.processor.options", unmatchedProcessorOptions.toString());
1258         }
1259     }
1260 
1261     /**
1262      * Free resources related to annotation processing.
1263      */
1264     public void close() {
1265         filer.close();
1266         if (discoveredProcs != null) // Make calling close idempotent
1267             discoveredProcs.close();
1268         discoveredProcs = null;
1269     }
1270 
1271     private List<ClassSymbol> getTopLevelClasses(List<? extends JCCompilationUnit> units) {
1272         List<ClassSymbol> classes = List.nil();
1273         for (JCCompilationUnit unit : units) {
1274             for (JCTree node : unit.defs) {
1275                 if (node.hasTag(JCTree.Tag.CLASSDEF)) {
1276                     ClassSymbol sym = ((JCClassDecl) node).sym;
1277                     Assert.checkNonNull(sym);
1278                     classes = classes.prepend(sym);
1279                 }
1280             }
1281         }
1282         return classes.reverse();
1283     }
1284 
1285     private List<ClassSymbol> getTopLevelClassesFromClasses(List<? extends ClassSymbol> syms) {
1286         List<ClassSymbol> classes = List.nil();
1287         for (ClassSymbol sym : syms) {
1288             if (!isPkgInfo(sym)) {
1289                 classes = classes.prepend(sym);
1290             }
1291         }
1292         return classes.reverse();
1293     }
1294 
1295     private List<PackageSymbol> getPackageInfoFiles(List<? extends JCCompilationUnit> units) {
1296         List<PackageSymbol> packages = List.nil();
1297         for (JCCompilationUnit unit : units) {
1298             if (isPkgInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE)) {
1299                 packages = packages.prepend(unit.packge);
1300             }
1301         }
1302         return packages.reverse();
1303     }
1304 
1305     private List<PackageSymbol> getPackageInfoFilesFromClasses(List<? extends ClassSymbol> syms) {
1306         List<PackageSymbol> packages = List.nil();
1307         for (ClassSymbol sym : syms) {
1308             if (isPkgInfo(sym)) {
1309                 packages = packages.prepend((PackageSymbol) sym.owner);
1310             }
1311         }
1312         return packages.reverse();
1313     }
1314 
1315     // avoid unchecked warning from use of varargs
1316     private static <T> List<T> join(List<T> list1, List<T> list2) {
1317         return list1.appendList(list2);
1318     }
1319 
1320     private boolean isPkgInfo(JavaFileObject fo, JavaFileObject.Kind kind) {
1321         return fo.isNameCompatible("package-info", kind);
1322     }
1323 
1324     private boolean isPkgInfo(ClassSymbol sym) {
1325         return isPkgInfo(sym.classfile, JavaFileObject.Kind.CLASS) && (sym.packge().package_info == sym);
1326     }
1327 
1328     /*
1329      * Called retroactively to determine if a class loader was required,
1330      * after we have failed to create one.
1331      */
1332     private boolean needClassLoader(String procNames, Iterable<? extends File> workingpath) {
1333         if (procNames != null)
1334             return true;
1335 
1336         URL[] urls = new URL[1];
1337         for(File pathElement : workingpath) {
1338             try {
1339                 urls[0] = pathElement.toURI().toURL();
1340                 if (ServiceProxy.hasService(Processor.class, urls))
1341                     return true;
1342             } catch (MalformedURLException ex) {
1343                 throw new AssertionError(ex);
1344             }
1345             catch (ServiceProxy.ServiceConfigurationError e) {
1346                 log.error("proc.bad.config.file", e.getLocalizedMessage());
1347                 return true;
1348             }
1349         }
1350 
1351         return false;
1352     }
1353 
1354     private static <T extends JCTree> List<T> cleanTrees(List<T> nodes) {
1355         for (T node : nodes)
1356             treeCleaner.scan(node);
1357         return nodes;
1358     }
1359 
1360     private static final TreeScanner treeCleaner = new TreeScanner() {
1361             public void scan(JCTree node) {
1362                 super.scan(node);
1363                 if (node != null)
1364                     node.type = null;
1365             }
1366             public void visitTopLevel(JCCompilationUnit node) {
1367                 node.packge = null;
1368                 super.visitTopLevel(node);
1369             }
1370             public void visitClassDef(JCClassDecl node) {
1371                 node.sym = null;
1372                 super.visitClassDef(node);
1373             }
1374             public void visitMethodDef(JCMethodDecl node) {
1375                 node.sym = null;
1376                 super.visitMethodDef(node);
1377             }
1378             public void visitVarDef(JCVariableDecl node) {
1379                 node.sym = null;
1380                 super.visitVarDef(node);
1381             }
1382             public void visitNewClass(JCNewClass node) {
1383                 node.constructor = null;
1384                 super.visitNewClass(node);
1385             }
1386             public void visitAssignop(JCAssignOp node) {
1387                 node.operator = null;
1388                 super.visitAssignop(node);
1389             }
1390             public void visitUnary(JCUnary node) {
1391                 node.operator = null;
1392                 super.visitUnary(node);
1393             }
1394             public void visitBinary(JCBinary node) {
1395                 node.operator = null;
1396                 super.visitBinary(node);
1397             }
1398             public void visitSelect(JCFieldAccess node) {
1399                 node.sym = null;
1400                 super.visitSelect(node);
1401             }
1402             public void visitIdent(JCIdent node) {
1403                 node.sym = null;
1404                 super.visitIdent(node);
1405             }
1406             public void visitAnnotation(JCAnnotation node) {
1407                 node.attribute = null;
1408                 super.visitAnnotation(node);
1409             }
1410         };
1411 
1412 
1413     private boolean moreToDo() {
1414         return filer.newFiles();
1415     }
1416 
1417     /**
1418      * {@inheritdoc}
1419      *
1420      * Command line options suitable for presenting to annotation
1421      * processors.
1422      * {@literal "-Afoo=bar"} should be {@literal "-Afoo" => "bar"}.
1423      */
1424     public Map<String,String> getOptions() {
1425         return processorOptions;
1426     }
1427 
1428     public Messager getMessager() {
1429         return messager;
1430     }
1431 
1432     public Filer getFiler() {
1433         return filer;
1434     }
1435 
1436     public JavacElements getElementUtils() {
1437         return elementUtils;
1438     }
1439 
1440     public JavacTypes getTypeUtils() {
1441         return typeUtils;
1442     }
1443 
1444     public SourceVersion getSourceVersion() {
1445         return Source.toSourceVersion(source);
1446     }
1447 
1448     public Locale getLocale() {
1449         return messages.getCurrentLocale();
1450     }
1451 
1452     public Set<Symbol.PackageSymbol> getSpecifiedPackages() {
1453         return specifiedPackages;
1454     }
1455 
1456     private static final Pattern allMatches = Pattern.compile(".*");
1457     public static final Pattern noMatches  = Pattern.compile("(\\P{all})+");
1458 
1459     /**
1460      * Convert import-style string for supported annotations into a
1461      * regex matching that string.  If the string is a valid
1462      * import-style string, return a regex that won't match anything.
1463      */
1464     private static Pattern importStringToPattern(String s, Processor p, Log log) {
1465         if (isValidImportString(s)) {
1466             return validImportStringToPattern(s);
1467         } else {
1468             log.warning("proc.malformed.supported.string", s, p.getClass().getName());
1469             return noMatches; // won't match any valid identifier
1470         }
1471     }
1472 
1473     /**
1474      * Return true if the argument string is a valid import-style
1475      * string specifying claimed annotations; return false otherwise.
1476      */
1477     public static boolean isValidImportString(String s) {
1478         if (s.equals("*"))
1479             return true;
1480 
1481         boolean valid = true;
1482         String t = s;
1483         int index = t.indexOf('*');
1484 
1485         if (index != -1) {
1486             // '*' must be last character...
1487             if (index == t.length() -1) {
1488                 // ... any and preceding character must be '.'
1489                 if ( index-1 >= 0 ) {
1490                     valid = t.charAt(index-1) == '.';
1491                     // Strip off ".*$" for identifier checks
1492                     t = t.substring(0, t.length()-2);
1493                 }
1494             } else
1495                 return false;
1496         }
1497 
1498         // Verify string is off the form (javaId \.)+ or javaId
1499         if (valid) {
1500             String[] javaIds = t.split("\\.", t.length()+2);
1501             for(String javaId: javaIds)
1502                 valid &= SourceVersion.isIdentifier(javaId);
1503         }
1504         return valid;
1505     }
1506 
1507     public static Pattern validImportStringToPattern(String s) {
1508         if (s.equals("*")) {
1509             return allMatches;
1510         } else {
1511             String s_prime = s.replace(".", "\\.");
1512 
1513             if (s_prime.endsWith("*")) {
1514                 s_prime =  s_prime.substring(0, s_prime.length() - 1) + ".+";
1515             }
1516 
1517             return Pattern.compile(s_prime);
1518         }
1519     }
1520 
1521     /**
1522      * For internal use only.  This method may be removed without warning.
1523      */
1524     public Context getContext() {
1525         return context;
1526     }
1527 
1528     /**
1529      * For internal use only.  This method may be removed without warning.
1530      */
1531     public ClassLoader getProcessorClassLoader() {
1532         return processorClassLoader;
1533     }
1534 
1535     public String toString() {
1536         return "javac ProcessingEnvironment";
1537     }
1538 
1539     public static boolean isValidOptionName(String optionName) {
1540         for(String s : optionName.split("\\.", -1)) {
1541             if (!SourceVersion.isIdentifier(s))
1542                 return false;
1543         }
1544         return true;
1545     }
1546 }