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