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