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