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