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