1 /*
   2  * Copyright (c) 1999, 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.main;
  27 
  28 import java.io.*;
  29 import java.lang.module.Configuration;
  30 import java.nio.file.FileSystemNotFoundException;
  31 import java.nio.file.InvalidPathException;
  32 import java.nio.file.ReadOnlyFileSystemException;
  33 import java.util.Collection;
  34 import java.util.Comparator;
  35 import java.util.HashMap;
  36 import java.util.HashSet;
  37 import java.util.LinkedHashMap;
  38 import java.util.LinkedHashSet;
  39 import java.util.Map;
  40 import java.util.MissingResourceException;
  41 import java.util.Optional;
  42 import java.util.Queue;
  43 import java.util.ResourceBundle;
  44 import java.util.ServiceLoader;
  45 import java.util.Set;
  46 import java.util.function.Function;
  47 import java.util.function.ToIntFunction;
  48 
  49 import javax.annotation.processing.Processor;
  50 import javax.lang.model.SourceVersion;
  51 import javax.lang.model.element.ElementVisitor;
  52 import javax.tools.DiagnosticListener;
  53 import javax.tools.JavaFileManager;
  54 import javax.tools.JavaFileObject;
  55 import javax.tools.JavaFileObject.Kind;
  56 import javax.tools.StandardLocation;
  57 
  58 import com.sun.source.util.TaskEvent;
  59 import com.sun.tools.javac.api.MultiTaskListener;
  60 import com.sun.tools.javac.code.*;
  61 import com.sun.tools.javac.code.Lint.LintCategory;
  62 import com.sun.tools.javac.code.Source.Feature;
  63 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  64 import com.sun.tools.javac.code.Symbol.CompletionFailure;
  65 import com.sun.tools.javac.code.Symbol.PackageSymbol;
  66 import com.sun.tools.javac.comp.*;
  67 import com.sun.tools.javac.comp.CompileStates.CompileState;
  68 import com.sun.tools.javac.file.JavacFileManager;
  69 import com.sun.tools.javac.jvm.*;
  70 import com.sun.tools.javac.parser.*;
  71 import com.sun.tools.javac.platform.PlatformDescription;
  72 import com.sun.tools.javac.processing.*;
  73 import com.sun.tools.javac.tree.*;
  74 import com.sun.tools.javac.tree.JCTree.JCClassDecl;
  75 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
  76 import com.sun.tools.javac.tree.JCTree.JCExpression;
  77 import com.sun.tools.javac.tree.JCTree.JCLambda;
  78 import com.sun.tools.javac.tree.JCTree.JCMemberReference;
  79 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
  80 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
  81 import com.sun.tools.javac.util.*;
  82 import com.sun.tools.javac.util.Context.Key;
  83 import com.sun.tools.javac.util.DefinedBy.Api;
  84 import com.sun.tools.javac.util.JCDiagnostic.Factory;
  85 import com.sun.tools.javac.util.Log.DiagnosticHandler;
  86 import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler;
  87 import com.sun.tools.javac.util.Log.WriterKind;
  88 
  89 import static com.sun.tools.javac.code.Kinds.Kind.*;
  90 
  91 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
  92 
  93 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  94 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  95 import com.sun.tools.javac.resources.CompilerProperties.Notes;
  96 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  97 
  98 import static com.sun.tools.javac.code.TypeTag.CLASS;
  99 import static com.sun.tools.javac.main.Option.*;
 100 import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
 101 import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
 102 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
 103 
 104 import static javax.tools.StandardLocation.CLASS_OUTPUT;
 105 import static javax.tools.StandardLocation.ANNOTATION_PROCESSOR_PATH;
 106 
 107 import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
 108 import com.sun.tools.javac.tree.JCTree.JCRecordPattern;
 109 import com.sun.tools.javac.tree.JCTree.JCSwitch;
 110 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
 111 
 112 /** This class could be the main entry point for GJC when GJC is used as a
 113  *  component in a larger software system. It provides operations to
 114  *  construct a new compiler, and to run a new compiler on a set of source
 115  *  files.
 116  *
 117  *  <p><b>This is NOT part of any supported API.
 118  *  If you write code that depends on this, you do so at your own risk.
 119  *  This code and its internal interfaces are subject to change or
 120  *  deletion without notice.</b>
 121  */
 122 public class JavaCompiler {
 123     /** The context key for the compiler. */
 124     public static final Context.Key<JavaCompiler> compilerKey = new Context.Key<>();
 125 
 126     /** Get the JavaCompiler instance for this context. */
 127     public static JavaCompiler instance(Context context) {
 128         JavaCompiler instance = context.get(compilerKey);
 129         if (instance == null)
 130             instance = new JavaCompiler(context);
 131         return instance;
 132     }
 133 
 134     /** The current version number as a string.
 135      */
 136     public static String version() {
 137         return version("release");  // mm.nn.oo[-milestone]
 138     }
 139 
 140     /** The current full version number as a string.
 141      */
 142     public static String fullVersion() {
 143         return version("full"); // mm.mm.oo[-milestone]-build
 144     }
 145 
 146     private static final String versionRBName = "com.sun.tools.javac.resources.version";
 147     private static ResourceBundle versionRB;
 148 
 149     private static String version(String key) {
 150         if (versionRB == null) {
 151             try {
 152                 versionRB = ResourceBundle.getBundle(versionRBName);
 153             } catch (MissingResourceException e) {
 154                 return Log.getLocalizedString("version.not.available");
 155             }
 156         }
 157         try {
 158             return versionRB.getString(key);
 159         }
 160         catch (MissingResourceException e) {
 161             return Log.getLocalizedString("version.not.available");
 162         }
 163     }
 164 
 165     /**
 166      * Control how the compiler's latter phases (attr, flow, desugar, generate)
 167      * are connected. Each individual file is processed by each phase in turn,
 168      * but with different compile policies, you can control the order in which
 169      * each class is processed through its next phase.
 170      *
 171      * <p>Generally speaking, the compiler will "fail fast" in the face of
 172      * errors, although not aggressively so. flow, desugar, etc become no-ops
 173      * once any errors have occurred. No attempt is currently made to determine
 174      * if it might be safe to process a class through its next phase because
 175      * it does not depend on any unrelated errors that might have occurred.
 176      */
 177     protected static enum CompilePolicy {
 178         /**
 179          * Attribute everything, then do flow analysis for everything,
 180          * then desugar everything, and only then generate output.
 181          * This means no output will be generated if there are any
 182          * errors in any classes.
 183          */
 184         SIMPLE,
 185 
 186         /**
 187          * Groups the classes for each source file together, then process
 188          * each group in a manner equivalent to the {@code SIMPLE} policy.
 189          * This means no output will be generated if there are any
 190          * errors in any of the classes in a source file.
 191          */
 192         BY_FILE,
 193 
 194         /**
 195          * Completely process each entry on the todo list in turn.
 196          * -- this is the same for 1.5.
 197          * Means output might be generated for some classes in a compilation unit
 198          * and not others.
 199          */
 200         BY_TODO;
 201 
 202         static CompilePolicy decode(String option) {
 203             if (option == null)
 204                 return DEFAULT_COMPILE_POLICY;
 205             else if (option.equals("simple"))
 206                 return SIMPLE;
 207             else if (option.equals("byfile"))
 208                 return BY_FILE;
 209             else if (option.equals("bytodo"))
 210                 return BY_TODO;
 211             else
 212                 return DEFAULT_COMPILE_POLICY;
 213         }
 214     }
 215 
 216     private static final CompilePolicy DEFAULT_COMPILE_POLICY = CompilePolicy.BY_TODO;
 217 
 218     protected static enum ImplicitSourcePolicy {
 219         /** Don't generate or process implicitly read source files. */
 220         NONE,
 221         /** Generate classes for implicitly read source files. */
 222         CLASS,
 223         /** Like CLASS, but generate warnings if annotation processing occurs */
 224         UNSET;
 225 
 226         static ImplicitSourcePolicy decode(String option) {
 227             if (option == null)
 228                 return UNSET;
 229             else if (option.equals("none"))
 230                 return NONE;
 231             else if (option.equals("class"))
 232                 return CLASS;
 233             else
 234                 return UNSET;
 235         }
 236     }
 237 
 238     /** The log to be used for error reporting.
 239      */
 240     public Log log;
 241 
 242     /** Factory for creating diagnostic objects
 243      */
 244     JCDiagnostic.Factory diagFactory;
 245 
 246     /** The tree factory module.
 247      */
 248     protected TreeMaker make;
 249 
 250     /** The class finder.
 251      */
 252     protected ClassFinder finder;
 253 
 254     /** The class reader.
 255      */
 256     protected ClassReader reader;
 257 
 258     /** The class writer.
 259      */
 260     protected ClassWriter writer;
 261 
 262     /** The native header writer.
 263      */
 264     protected JNIWriter jniWriter;
 265 
 266     /** The module for the symbol table entry phases.
 267      */
 268     protected Enter enter;
 269 
 270     /** The symbol table.
 271      */
 272     protected Symtab syms;
 273 
 274     /** The language version.
 275      */
 276     protected Source source;
 277 
 278     /** The preview language version.
 279      */
 280     protected Preview preview;
 281 
 282     /** The module for code generation.
 283      */
 284     protected Gen gen;
 285 
 286     /** The name table.
 287      */
 288     protected Names names;
 289 
 290     /** The attributor.
 291      */
 292     protected Attr attr;
 293 
 294     /** The analyzer
 295      */
 296     protected Analyzer analyzer;
 297 
 298     /** The attributor.
 299      */
 300     protected Check chk;
 301 
 302     /** The flow analyzer.
 303      */
 304     protected Flow flow;
 305 
 306     /** The warning analyzer.
 307      */
 308     protected WarningAnalyzer warningAnalyzer;
 309 
 310     /** The modules visitor
 311      */
 312     protected Modules modules;
 313 
 314     /** The module finder
 315      */
 316     protected ModuleFinder moduleFinder;
 317 
 318     /** The diagnostics factory
 319      */
 320     protected JCDiagnostic.Factory diags;
 321 
 322     protected DeferredCompletionFailureHandler dcfh;
 323 
 324     /** The type eraser.
 325      */
 326     protected TransTypes transTypes;
 327 
 328     /** The syntactic sugar desweetener.
 329      */
 330     protected Lower lower;
 331 
 332     /** The annotation annotator.
 333      */
 334     protected Annotate annotate;
 335 
 336     /** Force a completion failure on this name
 337      */
 338     protected final Name completionFailureName;
 339 
 340     /** Type utilities.
 341      */
 342     protected Types types;
 343 
 344     /** Access to file objects.
 345      */
 346     protected JavaFileManager fileManager;
 347 
 348     /** Factory for parsers.
 349      */
 350     protected ParserFactory parserFactory;
 351 
 352     /** Broadcasting listener for progress events
 353      */
 354     protected MultiTaskListener taskListener;
 355 
 356     /**
 357      * SourceCompleter that delegates to the readSourceFile method of this class.
 358      */
 359     protected final Symbol.Completer sourceCompleter =
 360             sym -> readSourceFile((ClassSymbol) sym);
 361 
 362     /**
 363      * Command line options.
 364      */
 365     protected Options options;
 366 
 367     protected Context context;
 368 
 369     /**
 370      * Flag set if any annotation processing occurred.
 371      **/
 372     protected boolean annotationProcessingOccurred;
 373 
 374     /**
 375      * Flag set if any implicit source files read.
 376      **/
 377     protected boolean implicitSourceFilesRead;
 378 
 379     private boolean enterDone;
 380 
 381     protected CompileStates compileStates;
 382 
 383     private boolean hasCodeReflectionModule;
 384 
 385     /** Construct a new compiler using a shared context.
 386      */
 387     @SuppressWarnings("this-escape")
 388     public JavaCompiler(Context context) {
 389         this.context = context;
 390         context.put(compilerKey, this);
 391 
 392         // if fileManager not already set, register the JavacFileManager to be used
 393         if (context.get(JavaFileManager.class) == null)
 394             JavacFileManager.preRegister(context);
 395 
 396         names = Names.instance(context);
 397         log = Log.instance(context);
 398         diagFactory = JCDiagnostic.Factory.instance(context);
 399         finder = ClassFinder.instance(context);
 400         reader = ClassReader.instance(context);
 401         make = TreeMaker.instance(context);
 402         writer = ClassWriter.instance(context);
 403         jniWriter = JNIWriter.instance(context);
 404         enter = Enter.instance(context);
 405         todo = Todo.instance(context);
 406 
 407         fileManager = context.get(JavaFileManager.class);
 408         parserFactory = ParserFactory.instance(context);
 409         compileStates = CompileStates.instance(context);
 410 
 411         try {
 412             // catch completion problems with predefineds
 413             syms = Symtab.instance(context);
 414         } catch (CompletionFailure ex) {
 415             // inlined Check.completionError as it is not initialized yet
 416             log.error(Errors.CantAccess(ex.sym, ex.getDetailValue()));
 417         }
 418         source = Source.instance(context);
 419         preview = Preview.instance(context);
 420         attr = Attr.instance(context);
 421         analyzer = Analyzer.instance(context);
 422         chk = Check.instance(context);
 423         gen = Gen.instance(context);
 424         flow = Flow.instance(context);
 425         warningAnalyzer = WarningAnalyzer.instance(context);
 426         transTypes = TransTypes.instance(context);
 427         lower = Lower.instance(context);
 428         annotate = Annotate.instance(context);
 429         types = Types.instance(context);
 430         taskListener = MultiTaskListener.instance(context);
 431         modules = Modules.instance(context);
 432         moduleFinder = ModuleFinder.instance(context);
 433         diags = Factory.instance(context);
 434         dcfh = DeferredCompletionFailureHandler.instance(context);
 435 
 436         finder.sourceCompleter = sourceCompleter;
 437         modules.findPackageInFile = this::findPackageInFile;
 438         moduleFinder.moduleNameFromSourceReader = this::readModuleName;
 439 
 440         options = Options.instance(context);
 441 
 442         verbose       = options.isSet(VERBOSE);
 443         sourceOutput  = options.isSet(PRINTSOURCE); // used to be -s
 444         lineDebugInfo = options.isUnset(G_CUSTOM) ||
 445                         options.isSet(G_CUSTOM, "lines");
 446         genEndPos     = options.isSet(XJCOV) ||
 447                         context.get(DiagnosticListener.class) != null;
 448         devVerbose    = options.isSet("dev");
 449         processPcks   = options.isSet("process.packages");
 450         werror        = options.isSet(WERROR);
 451 
 452         verboseCompilePolicy = options.isSet("verboseCompilePolicy");
 453 
 454         compilePolicy = CompilePolicy.decode(options.get("compilePolicy"));
 455 
 456         implicitSourcePolicy = ImplicitSourcePolicy.decode(options.get("-implicit"));
 457 
 458         completionFailureName =
 459             options.isSet("failcomplete")
 460             ? names.fromString(options.get("failcomplete"))
 461             : null;
 462 
 463         shouldStopPolicyIfError =
 464             options.isSet("should-stop.at") // backwards compatible
 465             ? CompileState.valueOf(options.get("should-stop.at"))
 466             : options.isSet("should-stop.ifError")
 467             ? CompileState.valueOf(options.get("should-stop.ifError"))
 468             : CompileState.INIT;
 469         shouldStopPolicyIfNoError =
 470             options.isSet("should-stop.ifNoError")
 471             ? CompileState.valueOf(options.get("should-stop.ifNoError"))
 472             : CompileState.GENERATE;
 473 
 474         if (options.isUnset("diags.legacy"))
 475             log.setDiagnosticFormatter(RichDiagnosticFormatter.instance(context));
 476 
 477         PlatformDescription platformProvider = context.get(PlatformDescription.class);
 478 
 479         if (platformProvider != null)
 480             closeables = closeables.prepend(platformProvider);
 481 
 482         silentFail = new Symbol(ABSENT_TYP, 0, names.empty, Type.noType, syms.rootPackage) {
 483             @DefinedBy(Api.LANGUAGE_MODEL)
 484             public <R, P> R accept(ElementVisitor<R, P> v, P p) {
 485                 return v.visitUnknown(this, p);
 486             }
 487             @Override
 488             public boolean exists() {
 489                 return false;
 490             }
 491         };
 492 
 493     }
 494 
 495     /* Switches:
 496      */
 497 
 498     /** Verbose output.
 499      */
 500     public boolean verbose;
 501 
 502     /** Emit plain Java source files rather than class files.
 503      */
 504     public boolean sourceOutput;
 505 
 506 
 507     /** Generate code with the LineNumberTable attribute for debugging
 508      */
 509     public boolean lineDebugInfo;
 510 
 511     /** Switch: should we store the ending positions?
 512      */
 513     public boolean genEndPos;
 514 
 515     /** Switch: should we debug ignored exceptions
 516      */
 517     protected boolean devVerbose;
 518 
 519     /** Switch: should we (annotation) process packages as well
 520      */
 521     protected boolean processPcks;
 522 
 523     /** Switch: treat warnings as errors
 524      */
 525     protected boolean werror;
 526 
 527     /** Switch: is annotation processing requested explicitly via
 528      * CompilationTask.setProcessors?
 529      */
 530     protected boolean explicitAnnotationProcessingRequested = false;
 531 
 532     /**
 533      * The policy for the order in which to perform the compilation
 534      */
 535     protected CompilePolicy compilePolicy;
 536 
 537     /**
 538      * The policy for what to do with implicitly read source files
 539      */
 540     protected ImplicitSourcePolicy implicitSourcePolicy;
 541 
 542     /**
 543      * Report activity related to compilePolicy
 544      */
 545     public boolean verboseCompilePolicy;
 546 
 547     /**
 548      * Policy of how far to continue compilation after errors have occurred.
 549      * Set this to minimum CompileState (INIT) to stop as soon as possible
 550      * after errors.
 551      */
 552     public CompileState shouldStopPolicyIfError;
 553 
 554     /**
 555      * Policy of how far to continue compilation when no errors have occurred.
 556      * Set this to maximum CompileState (GENERATE) to perform full compilation.
 557      * Set this lower to perform partial compilation, such as -proc:only.
 558      */
 559     public CompileState shouldStopPolicyIfNoError;
 560 
 561     /** A queue of all as yet unattributed classes.
 562      */
 563     public Todo todo;
 564 
 565     /** A list of items to be closed when the compilation is complete.
 566      */
 567     public List<Closeable> closeables = List.nil();
 568 
 569     /** The set of currently compiled inputfiles, needed to ensure
 570      *  we don't accidentally overwrite an input file when -s is set.
 571      *  initialized by `compile'.
 572      */
 573     protected Set<JavaFileObject> inputFiles = new HashSet<>();
 574 
 575     /** Used by the resolveBinaryNameOrIdent to say that the given type cannot be found, and that
 576      *  an error has already been produced about that.
 577      */
 578     private final Symbol silentFail;
 579 
 580     protected boolean shouldStop(CompileState cs) {
 581         CompileState shouldStopPolicy = (errorCount() > 0 || unrecoverableError())
 582             ? shouldStopPolicyIfError
 583             : shouldStopPolicyIfNoError;
 584         return cs.isAfter(shouldStopPolicy);
 585     }
 586 
 587     /** The number of errors reported so far.
 588      */
 589     public int errorCount() {
 590         if (werror && log.nerrors == 0 && log.nwarnings > 0) {
 591             log.error(Errors.WarningsAndWerror);
 592         }
 593         return log.nerrors;
 594     }
 595 
 596     protected final <T> Queue<T> stopIfError(CompileState cs, Queue<T> queue) {
 597         return shouldStop(cs) ? new ListBuffer<T>() : queue;
 598     }
 599 
 600     protected final <T> List<T> stopIfError(CompileState cs, List<T> list) {
 601         return shouldStop(cs) ? List.nil() : list;
 602     }
 603 
 604     /** The number of warnings reported so far.
 605      */
 606     public int warningCount() {
 607         return log.nwarnings;
 608     }
 609 
 610     /** Try to open input stream with given name.
 611      *  Report an error if this fails.
 612      *  @param filename   The file name of the input stream to be opened.
 613      */
 614     public CharSequence readSource(JavaFileObject filename) {
 615         try {
 616             inputFiles.add(filename);
 617             return filename.getCharContent(false);
 618         } catch (IOException e) {
 619             log.error(Errors.ErrorReadingFile(filename, JavacFileManager.getMessage(e)));
 620             return null;
 621         }
 622     }
 623 
 624     /** Parse contents of input stream.
 625      *  @param filename     The name of the file from which input stream comes.
 626      *  @param content      The characters to be parsed.
 627      */
 628     protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) {
 629         return parse(filename, content, false);
 630     }
 631 
 632     /** Parse contents of input stream.
 633      *  @param filename     The name of the file from which input stream comes.
 634      *  @param content      The characters to be parsed.
 635      *  @param silent       true if TaskListeners should not be notified
 636      */
 637     private JCCompilationUnit parse(JavaFileObject filename, CharSequence content, boolean silent) {
 638         long msec = now();
 639         JCCompilationUnit tree = make.TopLevel(List.nil());
 640         if (content != null) {
 641             if (verbose) {
 642                 log.printVerbose("parsing.started", filename);
 643             }
 644             if (!taskListener.isEmpty() && !silent) {
 645                 TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, filename);
 646                 taskListener.started(e);
 647                 keepComments = true;
 648                 genEndPos = true;
 649             }
 650             Parser parser = parserFactory.newParser(content, keepComments(), genEndPos,
 651                                 lineDebugInfo, filename.isNameCompatible("module-info", Kind.SOURCE));
 652             tree = parser.parseCompilationUnit();
 653             if (verbose) {
 654                 log.printVerbose("parsing.done", Long.toString(elapsed(msec)));
 655             }
 656         }
 657 
 658         tree.sourcefile = filename;
 659 
 660         if (content != null && !taskListener.isEmpty() && !silent) {
 661             TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree);
 662             taskListener.finished(e);
 663         }
 664 
 665         return tree;
 666     }
 667     // where
 668         public boolean keepComments = false;
 669         protected boolean keepComments() {
 670             return keepComments || sourceOutput;
 671         }
 672 
 673 
 674     /** Parse contents of file.
 675      *  @param filename     The name of the file to be parsed.
 676      */
 677     @Deprecated
 678     public JCTree.JCCompilationUnit parse(String filename) {
 679         JavacFileManager fm = (JavacFileManager)fileManager;
 680         return parse(fm.getJavaFileObjectsFromStrings(List.of(filename)).iterator().next());
 681     }
 682 
 683     /** Parse contents of file.
 684      *  @param filename     The name of the file to be parsed.
 685      */
 686     public JCTree.JCCompilationUnit parse(JavaFileObject filename) {
 687         JavaFileObject prev = log.useSource(filename);
 688         try {
 689             JCTree.JCCompilationUnit t = parse(filename, readSource(filename));
 690             if (t.endPositions != null)
 691                 log.setEndPosTable(filename, t.endPositions);
 692             return t;
 693         } finally {
 694             log.useSource(prev);
 695         }
 696     }
 697 
 698     /** Resolve an identifier which may be the binary name of a class or
 699      * the Java name of a class or package.
 700      * @param name      The name to resolve
 701      */
 702     public Symbol resolveBinaryNameOrIdent(String name) {
 703         ModuleSymbol msym;
 704         String typeName;
 705         int sep = name.indexOf('/');
 706         if (sep == -1) {
 707             msym = modules.getDefaultModule();
 708             typeName = name;
 709         } else if (Feature.MODULES.allowedInSource(source)) {
 710             Name modName = names.fromString(name.substring(0, sep));
 711 
 712             msym = moduleFinder.findModule(modName);
 713             typeName = name.substring(sep + 1);
 714         } else {
 715             log.error(Errors.InvalidModuleSpecifier(name));
 716             return silentFail;
 717         }
 718 
 719         return resolveBinaryNameOrIdent(msym, typeName);
 720     }
 721 
 722     /** Resolve an identifier which may be the binary name of a class or
 723      * the Java name of a class or package.
 724      * @param msym      The module in which the search should be performed
 725      * @param name      The name to resolve
 726      */
 727     public Symbol resolveBinaryNameOrIdent(ModuleSymbol msym, String name) {
 728         try {
 729             Name flatname = names.fromString(name.replace("/", "."));
 730             return finder.loadClass(msym, flatname);
 731         } catch (CompletionFailure ignore) {
 732             return resolveIdent(msym, name);
 733         }
 734     }
 735 
 736     /** Resolve an identifier.
 737      * @param msym      The module in which the search should be performed
 738      * @param name      The identifier to resolve
 739      */
 740     public Symbol resolveIdent(ModuleSymbol msym, String name) {
 741         if (name.equals(""))
 742             return syms.errSymbol;
 743         JavaFileObject prev = log.useSource(null);
 744         try {
 745             JCExpression tree = null;
 746             for (String s : name.split("\\.", -1)) {
 747                 if (!SourceVersion.isIdentifier(s)) // TODO: check for keywords
 748                     return syms.errSymbol;
 749                 tree = (tree == null) ? make.Ident(names.fromString(s))
 750                                       : make.Select(tree, names.fromString(s));
 751             }
 752             JCCompilationUnit toplevel =
 753                 make.TopLevel(List.nil());
 754             toplevel.modle = msym;
 755             toplevel.packge = msym.unnamedPackage;
 756             return attr.attribIdent(tree, toplevel);
 757         } finally {
 758             log.useSource(prev);
 759         }
 760     }
 761 
 762     /** Generate code and emit a class file for a given class
 763      *  @param env    The attribution environment of the outermost class
 764      *                containing this class.
 765      *  @param cdef   The class definition from which code is generated.
 766      */
 767     JavaFileObject genCode(Env<AttrContext> env, JCClassDecl cdef) throws IOException {
 768         try {
 769             if (gen.genClass(env, cdef) && (errorCount() == 0))
 770                 return writer.writeClass(cdef.sym);
 771         } catch (ClassWriter.PoolOverflow ex) {
 772             log.error(cdef.pos(), Errors.LimitPool);
 773         } catch (ClassWriter.StringOverflow ex) {
 774             log.error(cdef.pos(),
 775                       Errors.LimitStringOverflow(ex.value.substring(0, 20)));
 776         } catch (CompletionFailure ex) {
 777             chk.completionError(cdef.pos(), ex);
 778         }
 779         return null;
 780     }
 781 
 782     /** Emit plain Java source for a class.
 783      *  @param env    The attribution environment of the outermost class
 784      *                containing this class.
 785      *  @param cdef   The class definition to be printed.
 786      */
 787     JavaFileObject printSource(Env<AttrContext> env, JCClassDecl cdef) throws IOException {
 788         JavaFileObject outFile
 789            = fileManager.getJavaFileForOutput(CLASS_OUTPUT,
 790                                                cdef.sym.flatname.toString(),
 791                                                JavaFileObject.Kind.SOURCE,
 792                                                null);
 793         if (inputFiles.contains(outFile)) {
 794             log.error(cdef.pos(), Errors.SourceCantOverwriteInputFile(outFile));
 795             return null;
 796         } else {
 797             try (BufferedWriter out = new BufferedWriter(outFile.openWriter())) {
 798                 new Pretty(out, true).printUnit(env.toplevel, cdef);
 799                 if (verbose)
 800                     log.printVerbose("wrote.file", outFile.getName());
 801             }
 802             return outFile;
 803         }
 804     }
 805 
 806     /** Compile a source file that has been accessed by the class finder.
 807      *  @param c          The class the source file of which needs to be compiled.
 808      */
 809     private void readSourceFile(ClassSymbol c) throws CompletionFailure {
 810         readSourceFile(null, c);
 811     }
 812 
 813     /** Compile a ClassSymbol from source, optionally using the given compilation unit as
 814      *  the source tree.
 815      *  @param tree the compilation unit in which the given ClassSymbol resides,
 816      *              or null if should be parsed from source
 817      *  @param c    the ClassSymbol to complete
 818      */
 819     public void readSourceFile(JCCompilationUnit tree, ClassSymbol c) throws CompletionFailure {
 820         if (completionFailureName == c.fullname) {
 821             throw new CompletionFailure(
 822                 c, () -> diagFactory.fragment(Fragments.UserSelectedCompletionFailure), dcfh);
 823         }
 824         JavaFileObject filename = c.classfile;
 825         JavaFileObject prev = log.useSource(filename);
 826 
 827         if (tree == null) {
 828             try {
 829                 tree = parse(filename, filename.getCharContent(false));
 830             } catch (IOException e) {
 831                 log.error(Errors.ErrorReadingFile(filename, JavacFileManager.getMessage(e)));
 832                 tree = make.TopLevel(List.<JCTree>nil());
 833             } finally {
 834                 log.useSource(prev);
 835             }
 836         }
 837 
 838         if (!taskListener.isEmpty()) {
 839             TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
 840             taskListener.started(e);
 841         }
 842 
 843         // Process module declarations.
 844         // If module resolution fails, ignore trees, and if trying to
 845         // complete a specific symbol, throw CompletionFailure.
 846         // Note that if module resolution failed, we may not even
 847         // have enough modules available to access java.lang, and
 848         // so risk getting FatalError("no.java.lang") from MemberEnter.
 849         if (!modules.enter(List.of(tree), c)) {
 850             throw new CompletionFailure(c, () -> diags.fragment(Fragments.CantResolveModules), dcfh);
 851         }
 852 
 853         enter.complete(List.of(tree), c);
 854 
 855         if (!taskListener.isEmpty()) {
 856             TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
 857             taskListener.finished(e);
 858         }
 859 
 860         if (enter.getEnv(c) == null) {
 861             boolean isPkgInfo =
 862                 tree.sourcefile.isNameCompatible("package-info",
 863                                                  JavaFileObject.Kind.SOURCE);
 864             boolean isModuleInfo =
 865                 tree.sourcefile.isNameCompatible("module-info",
 866                                                  JavaFileObject.Kind.SOURCE);
 867             if (isModuleInfo) {
 868                 if (enter.getEnv(tree.modle) == null) {
 869                     JCDiagnostic diag =
 870                         diagFactory.fragment(Fragments.FileDoesNotContainModule);
 871                     throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory, dcfh);
 872                 }
 873             } else if (isPkgInfo) {
 874                 if (enter.getEnv(tree.packge) == null) {
 875                     JCDiagnostic diag =
 876                         diagFactory.fragment(Fragments.FileDoesNotContainPackage(c.location()));
 877                     throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory, dcfh);
 878                 }
 879             } else {
 880                 JCDiagnostic diag =
 881                         diagFactory.fragment(Fragments.FileDoesntContainClass(c.getQualifiedName()));
 882                 throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory, dcfh);
 883             }
 884         }
 885 
 886         implicitSourceFilesRead = true;
 887     }
 888 
 889     /** Track when the JavaCompiler has been used to compile something. */
 890     private boolean hasBeenUsed = false;
 891     private long start_msec = 0;
 892     public long elapsed_msec = 0;
 893 
 894     public void compile(List<JavaFileObject> sourceFileObject)
 895         throws Throwable {
 896         compile(sourceFileObject, List.nil(), null, List.nil());
 897     }
 898 
 899     /**
 900      * Main method: compile a list of files, return all compiled classes
 901      *
 902      * @param sourceFileObjects file objects to be compiled
 903      * @param classnames class names to process for annotations
 904      * @param processors user provided annotation processors to bypass
 905      * discovery, {@code null} means that no processors were provided
 906      * @param addModules additional root modules to be used during
 907      * module resolution.
 908      */
 909     public void compile(Collection<JavaFileObject> sourceFileObjects,
 910                         Collection<String> classnames,
 911                         Iterable<? extends Processor> processors,
 912                         Collection<String> addModules)
 913     {
 914         if (!taskListener.isEmpty()) {
 915             taskListener.started(new TaskEvent(TaskEvent.Kind.COMPILATION));
 916         }
 917 
 918         // as a JavaCompiler can only be used once, throw an exception if
 919         // it has been used before.
 920         if (hasBeenUsed)
 921             checkReusable();
 922         hasBeenUsed = true;
 923 
 924         start_msec = now();
 925 
 926         try {
 927             initProcessAnnotations(processors, sourceFileObjects, classnames);
 928 
 929             for (String className : classnames) {
 930                 int sep = className.indexOf('/');
 931                 if (sep != -1) {
 932                     modules.addExtraAddModules(className.substring(0, sep));
 933                 }
 934             }
 935 
 936             for (String moduleName : addModules) {
 937                 modules.addExtraAddModules(moduleName);
 938             }
 939 
 940             // These method calls must be chained to avoid memory leaks
 941             processAnnotations(
 942                 enterTrees(
 943                         stopIfError(CompileState.ENTER,
 944                                 initModules(stopIfError(CompileState.ENTER, parseFiles(sourceFileObjects))))
 945                 ),
 946                 classnames
 947             );
 948 
 949             // If it's safe to do so, skip attr / flow / gen for implicit classes
 950             if (taskListener.isEmpty() &&
 951                     implicitSourcePolicy == ImplicitSourcePolicy.NONE) {
 952                 todo.retainFiles(inputFiles);
 953             }
 954 
 955             if (!CompileState.ATTR.isAfter(shouldStopPolicyIfNoError)) {
 956                 switch (compilePolicy) {
 957                 case SIMPLE:
 958                     generate(desugar(warn(flow(attribute(todo)))));
 959                     break;
 960 
 961                 case BY_FILE: {
 962                         Queue<Queue<Env<AttrContext>>> q = todo.groupByFile();
 963                         while (!q.isEmpty() && !shouldStop(CompileState.ATTR)) {
 964                             generate(desugar(warn(flow(attribute(q.remove())))));
 965                         }
 966                     }
 967                     break;
 968 
 969                 case BY_TODO:
 970                     while (!todo.isEmpty())
 971                         generate(desugar(warn(flow(attribute(todo.remove())))));
 972                     break;
 973 
 974                 default:
 975                     Assert.error("unknown compile policy");
 976                 }
 977             }
 978         } catch (Abort ex) {
 979             if (devVerbose)
 980                 ex.printStackTrace(System.err);
 981 
 982             // In case an Abort was thrown before processAnnotations could be called,
 983             // we could have deferred diagnostics that haven't been reported.
 984             reportDeferredDiagnosticAndClearHandler();
 985         } finally {
 986             if (verbose) {
 987                 elapsed_msec = elapsed(start_msec);
 988                 log.printVerbose("total", Long.toString(elapsed_msec));
 989             }
 990 
 991             reportDeferredDiagnostics();
 992 
 993             if (!log.hasDiagnosticListener()) {
 994                 printCount("error", errorCount());
 995                 printCount("warn", warningCount());
 996                 printSuppressedCount(errorCount(), log.nsuppressederrors, "count.error.recompile");
 997                 printSuppressedCount(warningCount(), log.nsuppressedwarns, "count.warn.recompile");
 998             }
 999             if (!taskListener.isEmpty()) {
1000                 taskListener.finished(new TaskEvent(TaskEvent.Kind.COMPILATION));
1001             }
1002             close();
1003             if (procEnvImpl != null)
1004                 procEnvImpl.close();
1005         }
1006     }
1007 
1008     protected void checkReusable() {
1009         throw new AssertionError("attempt to reuse JavaCompiler");
1010     }
1011 
1012     /**
1013      * The list of classes explicitly supplied on the command line for compilation.
1014      * Not always populated.
1015      */
1016     private List<JCClassDecl> rootClasses;
1017 
1018     /**
1019      * Parses a list of files.
1020      */
1021    public List<JCCompilationUnit> parseFiles(Iterable<JavaFileObject> fileObjects) {
1022        return InitialFileParser.instance(context).parse(fileObjects);
1023    }
1024 
1025    public List<JCCompilationUnit> parseFiles(Iterable<JavaFileObject> fileObjects, boolean force) {
1026        if (!force && shouldStop(CompileState.PARSE))
1027            return List.nil();
1028 
1029         //parse all files
1030         ListBuffer<JCCompilationUnit> trees = new ListBuffer<>();
1031         Set<JavaFileObject> filesSoFar = new HashSet<>();
1032         for (JavaFileObject fileObject : fileObjects) {
1033             if (!filesSoFar.contains(fileObject)) {
1034                 filesSoFar.add(fileObject);
1035                 trees.append(parse(fileObject));
1036             }
1037         }
1038         return trees.toList();
1039     }
1040 
1041    /**
1042     * Returns true iff the compilation will continue after annotation processing
1043     * is done.
1044     */
1045     public boolean continueAfterProcessAnnotations() {
1046         return !shouldStop(CompileState.ATTR);
1047     }
1048 
1049     public List<JCCompilationUnit> initModules(List<JCCompilationUnit> roots) {
1050         modules.initModules(roots);
1051 
1052         if (modules.modulesInitialized()) {
1053             // This has to happen precisely here. At this point, we have all we need to
1054             // determine whether jdk.incubator.module is part of the module graph
1055             // but we have yet to trigger an ENTER event. This gives the code reflection plugin
1056             // a window to check whether code reflection should be enabled for this compilation unit.
1057             hasCodeReflectionModule = modules.getObservableModule(names.jdk_incubator_code) != null;
1058         }
1059 
1060         if (roots.isEmpty()) {
1061             enterDone();
1062         }
1063         return roots;
1064     }
1065 
1066     /**
1067      * Enter the symbols found in a list of parse trees.
1068      * As a side-effect, this puts elements on the "todo" list.
1069      * Also stores a list of all top level classes in rootClasses.
1070      */
1071     public List<JCCompilationUnit> enterTrees(List<JCCompilationUnit> roots) {
1072         //enter symbols for all files
1073         if (!taskListener.isEmpty()) {
1074             for (JCCompilationUnit unit: roots) {
1075                 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
1076                 taskListener.started(e);
1077             }
1078         }
1079 
1080         enter.main(roots);
1081 
1082         enterDone();
1083 
1084         if (!taskListener.isEmpty()) {
1085             for (JCCompilationUnit unit: roots) {
1086                 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
1087                 taskListener.finished(e);
1088             }
1089         }
1090 
1091         // If generating source, or if tracking public apis,
1092         // then remember the classes declared in
1093         // the original compilation units listed on the command line.
1094         if (sourceOutput) {
1095             ListBuffer<JCClassDecl> cdefs = new ListBuffer<>();
1096             for (JCCompilationUnit unit : roots) {
1097                 for (List<JCTree> defs = unit.defs;
1098                      defs.nonEmpty();
1099                      defs = defs.tail) {
1100                     if (defs.head instanceof JCClassDecl classDecl)
1101                         cdefs.append(classDecl);
1102                 }
1103             }
1104             rootClasses = cdefs.toList();
1105         }
1106 
1107         // Ensure the input files have been recorded. Although this is normally
1108         // done by readSource, it may not have been done if the trees were read
1109         // in a prior round of annotation processing, and the trees have been
1110         // cleaned and are being reused.
1111         for (JCCompilationUnit unit : roots) {
1112             inputFiles.add(unit.sourcefile);
1113         }
1114 
1115         return roots;
1116     }
1117 
1118     /**
1119      * Set to true to enable skeleton annotation processing code.
1120      * Currently, we assume this variable will be replaced more
1121      * advanced logic to figure out if annotation processing is
1122      * needed.
1123      */
1124     boolean processAnnotations = false;
1125 
1126     Log.DeferredDiagnosticHandler deferredDiagnosticHandler;
1127 
1128     /**
1129      * Object to handle annotation processing.
1130      */
1131     private JavacProcessingEnvironment procEnvImpl = null;
1132 
1133     /**
1134      * Check if we should process annotations.
1135      * If so, and if no scanner is yet registered, then set up the DocCommentScanner
1136      * to catch doc comments, and set keepComments so the parser records them in
1137      * the compilation unit.
1138      *
1139      * @param processors user provided annotation processors to bypass
1140      * discovery, {@code null} means that no processors were provided
1141      */
1142     public void initProcessAnnotations(Iterable<? extends Processor> processors,
1143                                        Collection<? extends JavaFileObject> initialFiles,
1144                                        Collection<String> initialClassNames) {
1145         if (processors != null && processors.iterator().hasNext())
1146             explicitAnnotationProcessingRequested = true;
1147 
1148         if (options.isSet(PROC, "none")) {
1149             processAnnotations = false;
1150         } else if (procEnvImpl == null) {
1151             procEnvImpl = JavacProcessingEnvironment.instance(context);
1152             procEnvImpl.setProcessors(processors);
1153 
1154             // Process annotations if processing is requested and there
1155             // is at least one Processor available.
1156             processAnnotations = procEnvImpl.atLeastOneProcessor() &&
1157                 explicitAnnotationProcessingRequested();
1158 
1159             if (processAnnotations) {
1160                 options.put("parameters", "parameters");
1161                 reader.saveParameterNames = true;
1162                 keepComments = true;
1163                 genEndPos = true;
1164                 if (!taskListener.isEmpty())
1165                     taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
1166                 deferredDiagnosticHandler = log.new DeferredDiagnosticHandler();
1167                 procEnvImpl.getFiler().setInitialState(initialFiles, initialClassNames);
1168             }
1169         } else { // free resources
1170             procEnvImpl.close();
1171         }
1172     }
1173 
1174     // TODO: called by JavacTaskImpl
1175     public void processAnnotations(List<JCCompilationUnit> roots) {
1176         processAnnotations(roots, List.nil());
1177     }
1178 
1179     /**
1180      * Process any annotations found in the specified compilation units.
1181      * @param roots a list of compilation units
1182      */
1183     // Implementation note: when this method is called, log.deferredDiagnostics
1184     // will have been set true by initProcessAnnotations, meaning that any diagnostics
1185     // that are reported will go into the log.deferredDiagnostics queue.
1186     // By the time this method exits, log.deferDiagnostics must be set back to false,
1187     // and all deferredDiagnostics must have been handled: i.e. either reported
1188     // or determined to be transient, and therefore suppressed.
1189     public void processAnnotations(List<JCCompilationUnit> roots,
1190                                    Collection<String> classnames) {
1191         if (shouldStop(CompileState.PROCESS)) {
1192             // Errors were encountered.
1193             // Unless all the errors are resolve errors, the errors were parse errors
1194             // or other errors during enter which cannot be fixed by running
1195             // any annotation processors.
1196             if (processAnnotations) {
1197                 reportDeferredDiagnosticAndClearHandler();
1198                 return ;
1199             }
1200         }
1201 
1202         // ASSERT: processAnnotations and procEnvImpl should have been set up by
1203         // by initProcessAnnotations
1204 
1205         // NOTE: The !classnames.isEmpty() checks should be refactored to Main.
1206 
1207         if (!processAnnotations) {
1208             // If there are no annotation processors present, and
1209             // annotation processing is to occur with compilation,
1210             // emit a warning.
1211             if (options.isSet(PROC, "only")) {
1212                 log.warning(Warnings.ProcProcOnlyRequestedNoProcs);
1213                 todo.clear();
1214             }
1215             // If not processing annotations, classnames must be empty
1216             if (!classnames.isEmpty()) {
1217                 log.error(Errors.ProcNoExplicitAnnotationProcessingRequested(classnames));
1218             }
1219             Assert.checkNull(deferredDiagnosticHandler);
1220             return ; // continue regular compilation
1221         }
1222 
1223         Assert.checkNonNull(deferredDiagnosticHandler);
1224 
1225         try {
1226             List<ClassSymbol> classSymbols = List.nil();
1227             List<PackageSymbol> pckSymbols = List.nil();
1228             if (!classnames.isEmpty()) {
1229                  // Check for explicit request for annotation
1230                  // processing
1231                 if (!explicitAnnotationProcessingRequested()) {
1232                     log.error(Errors.ProcNoExplicitAnnotationProcessingRequested(classnames));
1233                     reportDeferredDiagnosticAndClearHandler();
1234                     return ; // TODO: Will this halt compilation?
1235                 } else {
1236                     boolean errors = false;
1237                     for (String nameStr : classnames) {
1238                         Symbol sym = resolveBinaryNameOrIdent(nameStr);
1239                         if (sym == null ||
1240                             (sym.kind == PCK && !processPcks) ||
1241                             sym.kind == ABSENT_TYP) {
1242                             if (sym != silentFail)
1243                                 log.error(Errors.ProcCantFindClass(nameStr));
1244                             errors = true;
1245                             continue;
1246                         }
1247                         try {
1248                             if (sym.kind == PCK)
1249                                 sym.complete();
1250                             if (sym.exists()) {
1251                                 if (sym.kind == PCK)
1252                                     pckSymbols = pckSymbols.prepend((PackageSymbol)sym);
1253                                 else
1254                                     classSymbols = classSymbols.prepend((ClassSymbol)sym);
1255                                 continue;
1256                             }
1257                             Assert.check(sym.kind == PCK);
1258                             log.warning(Warnings.ProcPackageDoesNotExist(nameStr));
1259                             pckSymbols = pckSymbols.prepend((PackageSymbol)sym);
1260                         } catch (CompletionFailure e) {
1261                             log.error(Errors.ProcCantFindClass(nameStr));
1262                             errors = true;
1263                             continue;
1264                         }
1265                     }
1266                     if (errors) {
1267                         reportDeferredDiagnosticAndClearHandler();
1268                         return ;
1269                     }
1270                 }
1271             }
1272             try {
1273                 annotationProcessingOccurred =
1274                         procEnvImpl.doProcessing(roots,
1275                                                  classSymbols,
1276                                                  pckSymbols,
1277                                                  deferredDiagnosticHandler);
1278                 // doProcessing will have handled deferred diagnostics
1279             } finally {
1280                 procEnvImpl.close();
1281             }
1282         } catch (CompletionFailure ex) {
1283             log.error(Errors.CantAccess(ex.sym, ex.getDetailValue()));
1284             reportDeferredDiagnosticAndClearHandler();
1285         }
1286     }
1287 
1288     private boolean unrecoverableError() {
1289         if (deferredDiagnosticHandler != null) {
1290             for (JCDiagnostic d: deferredDiagnosticHandler.getDiagnostics()) {
1291                 if (d.getKind() == JCDiagnostic.Kind.ERROR && !d.isFlagSet(RECOVERABLE))
1292                     return true;
1293             }
1294         }
1295         return false;
1296     }
1297 
1298     boolean explicitAnnotationProcessingRequested() {
1299         return
1300             explicitAnnotationProcessingRequested ||
1301             explicitAnnotationProcessingRequested(options, fileManager);
1302     }
1303 
1304     static boolean explicitAnnotationProcessingRequested(Options options, JavaFileManager fileManager) {
1305         return
1306             options.isSet(PROCESSOR) ||
1307             options.isSet(PROCESSOR_PATH) ||
1308             options.isSet(PROCESSOR_MODULE_PATH) ||
1309             options.isSet(PROC, "only") ||
1310             options.isSet(PROC, "full") ||
1311             options.isSet(A) ||
1312             options.isSet(XPRINT) ||
1313             fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH);
1314         // Skipping -XprintRounds and -XprintProcessorInfo
1315     }
1316 
1317     public void setDeferredDiagnosticHandler(Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
1318         this.deferredDiagnosticHandler = deferredDiagnosticHandler;
1319     }
1320 
1321     /**
1322      * Attribute a list of parse trees, such as found on the "todo" list.
1323      * Note that attributing classes may cause additional files to be
1324      * parsed and entered via the SourceCompleter.
1325      * Attribution of the entries in the list does not stop if any errors occur.
1326      * @return a list of environments for attribute classes.
1327      */
1328     public Queue<Env<AttrContext>> attribute(Queue<Env<AttrContext>> envs) {
1329         ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1330         while (!envs.isEmpty())
1331             results.append(attribute(envs.remove()));
1332         return stopIfError(CompileState.ATTR, results);
1333     }
1334 
1335     /**
1336      * Attribute a parse tree.
1337      * @return the attributed parse tree
1338      */
1339     public Env<AttrContext> attribute(Env<AttrContext> env) {
1340         if (compileStates.isDone(env, CompileState.ATTR))
1341             return env;
1342 
1343         if (verboseCompilePolicy)
1344             printNote("[attribute " + env.enclClass.sym + "]");
1345         if (verbose)
1346             log.printVerbose("checking.attribution", env.enclClass.sym);
1347 
1348         if (!taskListener.isEmpty()) {
1349             TaskEvent e = newAnalyzeTaskEvent(env);
1350             taskListener.started(e);
1351         }
1352 
1353         JavaFileObject prev = log.useSource(
1354                                   env.enclClass.sym.sourcefile != null ?
1355                                   env.enclClass.sym.sourcefile :
1356                                   env.toplevel.sourcefile);
1357         try {
1358             attr.attrib(env);
1359             if (errorCount() > 0 && !shouldStop(CompileState.ATTR)) {
1360                 //if in fail-over mode, ensure that AST expression nodes
1361                 //are correctly initialized (e.g. they have a type/symbol)
1362                 attr.postAttr(env.tree);
1363             }
1364             compileStates.put(env, CompileState.ATTR);
1365         }
1366         finally {
1367             log.useSource(prev);
1368         }
1369 
1370         return env;
1371     }
1372 
1373     /**
1374      * Perform dataflow checks on attributed parse trees.
1375      * These include checks for definite assignment and unreachable statements.
1376      * If any errors occur, an empty list will be returned.
1377      * @return the list of attributed parse trees
1378      */
1379     public Queue<Env<AttrContext>> flow(Queue<Env<AttrContext>> envs) {
1380         ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1381         for (Env<AttrContext> env: envs) {
1382             flow(env, results);
1383         }
1384         return stopIfError(CompileState.FLOW, results);
1385     }
1386 
1387     /**
1388      * Perform dataflow checks on an attributed parse tree.
1389      */
1390     public Queue<Env<AttrContext>> flow(Env<AttrContext> env) {
1391         ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1392         flow(env, results);
1393         return stopIfError(CompileState.FLOW, results);
1394     }
1395 
1396     /**
1397      * Perform dataflow checks on an attributed parse tree.
1398      */
1399     protected void flow(Env<AttrContext> env, Queue<Env<AttrContext>> results) {
1400         if (compileStates.isDone(env, CompileState.FLOW)) {
1401             results.add(env);
1402             return;
1403         }
1404 
1405         try {
1406             if (shouldStop(CompileState.FLOW))
1407                 return;
1408 
1409             if (verboseCompilePolicy)
1410                 printNote("[flow " + env.enclClass.sym + "]");
1411             JavaFileObject prev = log.useSource(
1412                                                 env.enclClass.sym.sourcefile != null ?
1413                                                 env.enclClass.sym.sourcefile :
1414                                                 env.toplevel.sourcefile);
1415             try {
1416                 make.at(Position.FIRSTPOS);
1417                 TreeMaker localMake = make.forToplevel(env.toplevel);
1418                 flow.analyzeTree(env, localMake);
1419                 compileStates.put(env, CompileState.FLOW);
1420 
1421                 if (shouldStop(CompileState.FLOW))
1422                     return;
1423 
1424                 analyzer.flush(env);
1425 
1426                 results.add(env);
1427             }
1428             finally {
1429                 log.useSource(prev);
1430             }
1431         }
1432         finally {
1433             if (!taskListener.isEmpty()) {
1434                 TaskEvent e = newAnalyzeTaskEvent(env);
1435                 taskListener.finished(e);
1436             }
1437         }
1438     }
1439 
1440     /**
1441      * Check for various things to warn about.
1442      *
1443      * @return the list of attributed parse trees
1444      */
1445     public Queue<Env<AttrContext>> warn(Queue<Env<AttrContext>> envs) {
1446         ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1447         for (Env<AttrContext> env: envs) {
1448             warn(env, results);
1449         }
1450         return stopIfError(CompileState.WARN, results);
1451     }
1452 
1453     /**
1454      * Check for various things to warn about in an attributed parse tree.
1455      */
1456     public Queue<Env<AttrContext>> warn(Env<AttrContext> env) {
1457         ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1458         warn(env, results);
1459         return stopIfError(CompileState.WARN, results);
1460     }
1461 
1462     /**
1463      * Check for various things to warn about in an attributed parse tree.
1464      */
1465     protected void warn(Env<AttrContext> env, Queue<Env<AttrContext>> results) {
1466         if (compileStates.isDone(env, CompileState.WARN)) {
1467             results.add(env);
1468             return;
1469         }
1470 
1471         if (shouldStop(CompileState.WARN))
1472             return;
1473 
1474         if (verboseCompilePolicy)
1475             printNote("[warn " + env.enclClass.sym + "]");
1476         JavaFileObject prev = log.useSource(
1477                                             env.enclClass.sym.sourcefile != null ?
1478                                             env.enclClass.sym.sourcefile :
1479                                             env.toplevel.sourcefile);
1480         try {
1481             warningAnalyzer.analyzeTree(env);
1482             compileStates.put(env, CompileState.WARN);
1483             results.add(env);
1484         }
1485         finally {
1486             log.useSource(prev);
1487         }
1488     }
1489 
1490     private TaskEvent newAnalyzeTaskEvent(Env<AttrContext> env) {
1491         JCCompilationUnit toplevel = env.toplevel;
1492         ClassSymbol sym;
1493         if (env.enclClass.sym == syms.predefClass) {
1494             if (TreeInfo.isModuleInfo(toplevel)) {
1495                 sym = toplevel.modle.module_info;
1496             } else if (TreeInfo.isPackageInfo(toplevel)) {
1497                 sym = toplevel.packge.package_info;
1498             } else {
1499                 throw new IllegalStateException("unknown env.toplevel");
1500             }
1501         } else {
1502             sym = env.enclClass.sym;
1503         }
1504 
1505         return new TaskEvent(TaskEvent.Kind.ANALYZE, toplevel, sym);
1506     }
1507 
1508     /**
1509      * Prepare attributed parse trees, in conjunction with their attribution contexts,
1510      * for source or code generation.
1511      * If any errors occur, an empty list will be returned.
1512      * @return a list containing the classes to be generated
1513      */
1514     public Queue<Pair<Env<AttrContext>, JCClassDecl>> desugar(Queue<Env<AttrContext>> envs) {
1515         ListBuffer<Pair<Env<AttrContext>, JCClassDecl>> results = new ListBuffer<>();
1516         for (Env<AttrContext> env: envs)
1517             desugar(env, results);
1518         return stopIfError(CompileState.FLOW, results);
1519     }
1520 
1521     HashMap<Env<AttrContext>, Queue<Pair<Env<AttrContext>, JCClassDecl>>> desugaredEnvs = new HashMap<>();
1522 
1523     /**
1524      * Prepare attributed parse trees, in conjunction with their attribution contexts,
1525      * for source or code generation. If the file was not listed on the command line,
1526      * the current implicitSourcePolicy is taken into account.
1527      * The preparation stops as soon as an error is found.
1528      */
1529     protected void desugar(final Env<AttrContext> env, Queue<Pair<Env<AttrContext>, JCClassDecl>> results) {
1530         if (shouldStop(CompileState.TRANSTYPES))
1531             return;
1532 
1533         if (implicitSourcePolicy == ImplicitSourcePolicy.NONE
1534                 && !inputFiles.contains(env.toplevel.sourcefile)) {
1535             return;
1536         }
1537 
1538         if (!modules.multiModuleMode && env.toplevel.modle != modules.getDefaultModule()) {
1539             //can only generate classfiles for a single module:
1540             return;
1541         }
1542 
1543         if (compileStates.isDone(env, CompileState.LOWER)) {
1544             results.addAll(desugaredEnvs.get(env));
1545             return;
1546         }
1547 
1548         // Ensure the file has reached the WARN state
1549         if (!compileStates.isDone(env, CompileState.WARN))
1550             warn(env);
1551 
1552         /**
1553          * Ensure that superclasses of C are desugared before C itself. This is
1554          * required for two reasons: (i) as erasure (TransTypes) destroys
1555          * information needed in flow analysis and (ii) as some checks carried
1556          * out during lowering require that all synthetic fields/methods have
1557          * already been added to C and its superclasses.
1558          */
1559         class ScanNested extends TreeScanner {
1560             Set<Env<AttrContext>> dependencies = new LinkedHashSet<>();
1561             protected boolean hasLambdas;
1562             protected boolean hasPatterns;
1563             @Override
1564             public void visitClassDef(JCClassDecl node) {
1565                 Type st = types.supertype(node.sym.type);
1566                 boolean envForSuperTypeFound = false;
1567                 while (!envForSuperTypeFound && st.hasTag(CLASS)) {
1568                     ClassSymbol c = st.tsym.outermostClass();
1569                     Env<AttrContext> stEnv = enter.getEnv(c);
1570                     if (stEnv != null && env != stEnv) {
1571                         if (dependencies.add(stEnv)) {
1572                             boolean prevHasLambdas = hasLambdas;
1573                             boolean prevHasPatterns = hasPatterns;
1574                             try {
1575                                 scan(stEnv.tree);
1576                             } finally {
1577                                 /*
1578                                  * ignore any updates to hasLambdas and hasPatterns
1579                                  * made during the nested scan, this ensures an
1580                                  * initialized LambdaToMethod or TransPatterns is
1581                                  * available only to those classes that contain
1582                                  * lambdas or patterns, respectivelly
1583                                  */
1584                                 hasLambdas = prevHasLambdas;
1585                                 hasPatterns = prevHasPatterns;
1586                             }
1587                         }
1588                         envForSuperTypeFound = true;
1589                     }
1590                     st = types.supertype(st);
1591                 }
1592                 super.visitClassDef(node);
1593             }
1594             @Override
1595             public void visitLambda(JCLambda tree) {
1596                 hasLambdas = true;
1597                 super.visitLambda(tree);
1598             }
1599             @Override
1600             public void visitReference(JCMemberReference tree) {
1601                 hasLambdas = true;
1602                 super.visitReference(tree);
1603             }
1604             @Override
1605             public void visitBindingPattern(JCBindingPattern tree) {
1606                 hasPatterns = true;
1607                 super.visitBindingPattern(tree);
1608             }
1609             @Override
1610             public void visitTypeTest(JCInstanceOf tree) {
1611                 if (tree.pattern.type.isPrimitive()) {
1612                     hasPatterns = true;
1613                 }
1614                 super.visitTypeTest(tree);
1615             }
1616             @Override
1617             public void visitRecordPattern(JCRecordPattern that) {
1618                 hasPatterns = true;
1619                 super.visitRecordPattern(that);
1620             }
1621             @Override
1622             public void visitSwitch(JCSwitch tree) {
1623                 hasPatterns |= tree.patternSwitch;
1624                 super.visitSwitch(tree);
1625             }
1626             @Override
1627             public void visitSwitchExpression(JCSwitchExpression tree) {
1628                 hasPatterns |= tree.patternSwitch;
1629                 super.visitSwitchExpression(tree);
1630             }
1631         }
1632         ScanNested scanner = new ScanNested();
1633         scanner.scan(env.tree);
1634         for (Env<AttrContext> dep: scanner.dependencies) {
1635         if (!compileStates.isDone(dep, CompileState.WARN))
1636             desugaredEnvs.put(dep, desugar(warn(flow(attribute(dep)))));
1637         }
1638 
1639         //We need to check for error another time as more classes might
1640         //have been attributed and analyzed at this stage
1641         if (shouldStop(CompileState.TRANSTYPES))
1642             return;
1643 
1644         if (verboseCompilePolicy)
1645             printNote("[desugar " + env.enclClass.sym + "]");
1646 
1647         JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ?
1648                                   env.enclClass.sym.sourcefile :
1649                                   env.toplevel.sourcefile);
1650         try {
1651             //save tree prior to rewriting
1652             JCTree untranslated = env.tree;
1653 
1654             make.at(Position.FIRSTPOS);
1655             TreeMaker localMake = make.forToplevel(env.toplevel);
1656 
1657             if (env.tree.hasTag(JCTree.Tag.PACKAGEDEF) || env.tree.hasTag(JCTree.Tag.MODULEDEF)) {
1658                 if (!(sourceOutput)) {
1659                     if (shouldStop(CompileState.LOWER))
1660                         return;
1661                     List<JCTree> def = lower.translateTopLevelClass(env, env.tree, localMake);
1662                     if (def.head != null) {
1663                         Assert.check(def.tail.isEmpty());
1664                         results.add(new Pair<>(env, (JCClassDecl)def.head));
1665                     }
1666                 }
1667                 return;
1668             }
1669 
1670             if (shouldStop(CompileState.TRANSTYPES))
1671                 return;
1672 
1673             if (Feature.REFLECT_METHODS.allowedInSource(source)) {
1674                 Optional<CodeReflectionTransformer> reflectMethods = reflectMethods();
1675                 if (reflectMethods.isPresent()) {
1676                     env.tree = reflectMethods.get().translateTopLevelClass(context, env.tree, localMake);
1677                 }
1678             }
1679 
1680             env.tree = transTypes.translateTopLevelClass(env.tree, localMake);
1681             compileStates.put(env, CompileState.TRANSTYPES);
1682 
1683             if (shouldStop(CompileState.TRANSPATTERNS))
1684                 return;
1685 
1686             if (scanner.hasPatterns) {
1687                 env.tree = TransPatterns.instance(context)
1688                         .translateTopLevelClass(env, env.tree, localMake);
1689             }
1690 
1691             compileStates.put(env, CompileState.TRANSPATTERNS);
1692 
1693             if (shouldStop(CompileState.LOWER))
1694                 return;
1695 
1696             if (sourceOutput) {
1697                 //emit standard Java source file, only for compilation
1698                 //units enumerated explicitly on the command line
1699                 JCClassDecl cdef = (JCClassDecl)env.tree;
1700                 if (untranslated instanceof JCClassDecl classDecl &&
1701                     rootClasses.contains(classDecl)) {
1702                     results.add(new Pair<>(env, cdef));
1703                 }
1704                 return;
1705             }
1706 
1707             //translate out inner classes
1708             List<JCTree> cdefs = lower.translateTopLevelClass(env, env.tree, localMake);
1709             compileStates.put(env, CompileState.LOWER);
1710 
1711             if (shouldStop(CompileState.LOWER))
1712                 return;
1713 
1714             if (scanner.hasLambdas) {
1715                 if (shouldStop(CompileState.UNLAMBDA))
1716                     return;
1717 
1718                 for (JCTree def : cdefs) {
1719                     LambdaToMethod.instance(context).translateTopLevelClass(env, def, localMake);
1720                 }
1721                 compileStates.put(env, CompileState.UNLAMBDA);
1722             }
1723 
1724             //generate code for each class
1725             for (List<JCTree> l = cdefs; l.nonEmpty(); l = l.tail) {
1726                 JCClassDecl cdef = (JCClassDecl)l.head;
1727                 results.add(new Pair<>(env, cdef));
1728             }
1729         }
1730         finally {
1731             log.useSource(prev);
1732         }
1733 
1734     }
1735 
1736     Optional<CodeReflectionTransformer> reflectMethods() {
1737         return CodeReflectionSupport.CODE_LAYER != null ?
1738                 ServiceLoader.load(CodeReflectionSupport.CODE_LAYER, CodeReflectionTransformer.class).findFirst() :
1739                 Optional.empty();
1740     }
1741 
1742     static class CodeReflectionSupport {
1743         static final ModuleLayer CODE_LAYER;
1744 
1745         static {
1746             if (ModuleLayer.boot().findModule("jdk.incubator.code").isPresent()) {
1747                 // we are in an exploded build, so just use the boot layer
1748                 CODE_LAYER = ModuleLayer.boot();
1749             } else if (java.lang.module.ModuleFinder.ofSystem().find("jdk.incubator.code").isPresent()) {
1750                 // the code module is installed, but not in the boot layer, create a new layer which contains it
1751                 ModuleLayer parent = ModuleLayer.boot();
1752                 Configuration cf = parent.configuration()
1753                         .resolve(java.lang.module.ModuleFinder.of(), java.lang.module.ModuleFinder.ofSystem(), Set.of("jdk.incubator.code"));
1754                 ClassLoader scl = ClassLoader.getSystemClassLoader();
1755                 CODE_LAYER = parent.defineModulesWithOneLoader(cf, scl);
1756                 Module codeReflectionModule = CODE_LAYER.findModule("jdk.incubator.code").get();
1757                 Module jdkCompilerModule = JavaCompiler.class.getModule();
1758                 // We need to add exports all jdk.compiler packages so that the plugin can use them
1759                 for (String packageName : jdkCompilerModule.getPackages()) {
1760                     jdkCompilerModule.addExports(packageName, codeReflectionModule);
1761                 }
1762             } else {
1763                 // if we run in bootstrap mode, there might be no jdk.incubator.code
1764                 CODE_LAYER = null;
1765             }
1766         }
1767     }
1768 
1769     /** Generates the source or class file for a list of classes.
1770      * The decision to generate a source file or a class file is
1771      * based upon the compiler's options.
1772      * Generation stops if an error occurs while writing files.
1773      */
1774     public void generate(Queue<Pair<Env<AttrContext>, JCClassDecl>> queue) {
1775         generate(queue, null);
1776     }
1777 
1778     public void generate(Queue<Pair<Env<AttrContext>, JCClassDecl>> queue, Queue<JavaFileObject> results) {
1779         if (shouldStop(CompileState.GENERATE))
1780             return;
1781 
1782         for (Pair<Env<AttrContext>, JCClassDecl> x: queue) {
1783             Env<AttrContext> env = x.fst;
1784             JCClassDecl cdef = x.snd;
1785 
1786             if (verboseCompilePolicy) {
1787                 printNote("[generate " + (sourceOutput ? " source" : "code") + " " + cdef.sym + "]");
1788             }
1789 
1790             if (!taskListener.isEmpty()) {
1791                 TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
1792                 taskListener.started(e);
1793             }
1794 
1795             JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ?
1796                                       env.enclClass.sym.sourcefile :
1797                                       env.toplevel.sourcefile);
1798             try {
1799                 JavaFileObject file;
1800                 if (sourceOutput) {
1801                     file = printSource(env, cdef);
1802                 } else {
1803                     if (fileManager.hasLocation(StandardLocation.NATIVE_HEADER_OUTPUT)
1804                             && jniWriter.needsHeader(cdef.sym)) {
1805                         jniWriter.write(cdef.sym);
1806                     }
1807                     file = genCode(env, cdef);
1808                 }
1809                 if (results != null && file != null)
1810                     results.add(file);
1811             } catch (IOException
1812                     | UncheckedIOException
1813                     | FileSystemNotFoundException
1814                     | InvalidPathException
1815                     | ReadOnlyFileSystemException ex) {
1816                 log.error(cdef.pos(),
1817                           Errors.ClassCantWrite(cdef.sym, ex.getMessage()));
1818                 return;
1819             } finally {
1820                 log.useSource(prev);
1821             }
1822 
1823             if (!taskListener.isEmpty()) {
1824                 TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
1825                 taskListener.finished(e);
1826             }
1827         }
1828     }
1829 
1830         // where
1831         Map<JCCompilationUnit, Queue<Env<AttrContext>>> groupByFile(Queue<Env<AttrContext>> envs) {
1832             // use a LinkedHashMap to preserve the order of the original list as much as possible
1833             Map<JCCompilationUnit, Queue<Env<AttrContext>>> map = new LinkedHashMap<>();
1834             for (Env<AttrContext> env: envs) {
1835                 Queue<Env<AttrContext>> sublist = map.get(env.toplevel);
1836                 if (sublist == null) {
1837                     sublist = new ListBuffer<>();
1838                     map.put(env.toplevel, sublist);
1839                 }
1840                 sublist.add(env);
1841             }
1842             return map;
1843         }
1844 
1845         JCClassDecl removeMethodBodies(JCClassDecl cdef) {
1846             final boolean isInterface = (cdef.mods.flags & Flags.INTERFACE) != 0;
1847             class MethodBodyRemover extends TreeTranslator {
1848                 @Override
1849                 public void visitMethodDef(JCMethodDecl tree) {
1850                     tree.mods.flags &= ~Flags.SYNCHRONIZED;
1851                     for (JCVariableDecl vd : tree.params)
1852                         vd.mods.flags &= ~Flags.FINAL;
1853                     tree.body = null;
1854                     super.visitMethodDef(tree);
1855                 }
1856                 @Override
1857                 public void visitVarDef(JCVariableDecl tree) {
1858                     if (tree.init != null && tree.init.type.constValue() == null)
1859                         tree.init = null;
1860                     super.visitVarDef(tree);
1861                 }
1862                 @Override
1863                 public void visitClassDef(JCClassDecl tree) {
1864                     ListBuffer<JCTree> newdefs = new ListBuffer<>();
1865                     for (List<JCTree> it = tree.defs; it.tail != null; it = it.tail) {
1866                         JCTree t = it.head;
1867                         switch (t.getTag()) {
1868                         case CLASSDEF:
1869                             if (isInterface ||
1870                                 (((JCClassDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1871                                 (((JCClassDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCClassDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1872                                 newdefs.append(t);
1873                             break;
1874                         case METHODDEF:
1875                             if (isInterface ||
1876                                 (((JCMethodDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1877                                 ((JCMethodDecl) t).sym.name == names.init ||
1878                                 (((JCMethodDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCMethodDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1879                                 newdefs.append(t);
1880                             break;
1881                         case VARDEF:
1882                             if (isInterface || (((JCVariableDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1883                                 (((JCVariableDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCVariableDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1884                                 newdefs.append(t);
1885                             break;
1886                         default:
1887                             break;
1888                         }
1889                     }
1890                     tree.defs = newdefs.toList();
1891                     super.visitClassDef(tree);
1892                 }
1893             }
1894             MethodBodyRemover r = new MethodBodyRemover();
1895             return r.translate(cdef);
1896         }
1897 
1898     public void reportDeferredDiagnostics() {
1899         if (errorCount() == 0
1900                 && annotationProcessingOccurred
1901                 && implicitSourceFilesRead
1902                 && implicitSourcePolicy == ImplicitSourcePolicy.UNSET) {
1903             if (explicitAnnotationProcessingRequested())
1904                 log.warning(Warnings.ProcUseImplicit);
1905             else
1906                 log.warning(Warnings.ProcUseProcOrImplicit);
1907         }
1908         chk.reportDeferredDiagnostics();
1909         preview.reportDeferredDiagnostics();
1910         if (log.compressedOutput) {
1911             log.mandatoryNote(null, Notes.CompressedDiags);
1912         }
1913     }
1914 
1915     public void enterDone() {
1916         enterDone = true;
1917         annotate.enterDone();
1918     }
1919 
1920     public boolean isEnterDone() {
1921         return enterDone;
1922     }
1923 
1924     public boolean hasCodeReflectionModule() {
1925         return hasCodeReflectionModule;
1926     }
1927 
1928     private Name readModuleName(JavaFileObject fo) {
1929         return parseAndGetName(fo, t -> {
1930             JCModuleDecl md = t.getModuleDecl();
1931 
1932             return md != null ? TreeInfo.fullName(md.getName()) : null;
1933         });
1934     }
1935 
1936     private Name findPackageInFile(JavaFileObject fo) {
1937         return parseAndGetName(fo, t -> t.getPackage() != null ?
1938                                         TreeInfo.fullName(t.getPackage().getPackageName()) : null);
1939     }
1940 
1941     private Name parseAndGetName(JavaFileObject fo,
1942                                  Function<JCTree.JCCompilationUnit, Name> tree2Name) {
1943         DiagnosticHandler dh = log.new DiscardDiagnosticHandler();
1944         JavaFileObject prevSource = log.useSource(fo);
1945         try {
1946             JCTree.JCCompilationUnit t = parse(fo, fo.getCharContent(false), true);
1947             return tree2Name.apply(t);
1948         } catch (IOException e) {
1949             return null;
1950         } finally {
1951             log.popDiagnosticHandler(dh);
1952             log.useSource(prevSource);
1953         }
1954     }
1955 
1956     public void reportDeferredDiagnosticAndClearHandler() {
1957         if (deferredDiagnosticHandler != null) {
1958             ToIntFunction<JCDiagnostic> diagValue =
1959                     d -> d.isFlagSet(RECOVERABLE) ? 1 : 0;
1960             Comparator<JCDiagnostic> compareDiags =
1961                     (d1, d2) -> diagValue.applyAsInt(d1) - diagValue.applyAsInt(d2);
1962             deferredDiagnosticHandler.reportDeferredDiagnostics(compareDiags);
1963             log.popDiagnosticHandler(deferredDiagnosticHandler);
1964             deferredDiagnosticHandler = null;
1965         }
1966     }
1967 
1968     /** Close the compiler, flushing the logs
1969      */
1970     public void close() {
1971         rootClasses = null;
1972         finder = null;
1973         reader = null;
1974         make = null;
1975         writer = null;
1976         enter = null;
1977         if (todo != null)
1978             todo.clear();
1979         todo = null;
1980         parserFactory = null;
1981         syms = null;
1982         source = null;
1983         attr = null;
1984         chk = null;
1985         gen = null;
1986         flow = null;
1987         transTypes = null;
1988         lower = null;
1989         annotate = null;
1990         types = null;
1991 
1992         log.flush();
1993         try {
1994             fileManager.flush();
1995         } catch (IOException e) {
1996             throw new Abort(e);
1997         } finally {
1998             if (names != null)
1999                 names.dispose();
2000             names = null;
2001 
2002             FatalError fatalError = null;
2003             for (Closeable c: closeables) {
2004                 try {
2005                     c.close();
2006                 } catch (IOException e) {
2007                     if (fatalError == null) {
2008                         JCDiagnostic msg = diagFactory.fragment(Fragments.FatalErrCantClose);
2009                         fatalError = new FatalError(msg, e);
2010                     } else {
2011                         fatalError.addSuppressed(e);
2012                     }
2013                 }
2014             }
2015             if (fatalError != null) {
2016                 throw fatalError;
2017             }
2018             closeables = List.nil();
2019         }
2020     }
2021 
2022     protected void printNote(String lines) {
2023         log.printRawLines(Log.WriterKind.NOTICE, lines);
2024     }
2025 
2026     /** Print numbers of errors and warnings.
2027      */
2028     public void printCount(String kind, int count) {
2029         if (count != 0) {
2030             String key;
2031             if (count == 1)
2032                 key = "count." + kind;
2033             else
2034                 key = "count." + kind + ".plural";
2035             log.printLines(WriterKind.ERROR, key, String.valueOf(count));
2036             log.flush(Log.WriterKind.ERROR);
2037         }
2038     }
2039 
2040     private void printSuppressedCount(int shown, int suppressed, String diagKey) {
2041         if (suppressed > 0) {
2042             int total = shown + suppressed;
2043             log.printLines(WriterKind.ERROR, diagKey,
2044                     String.valueOf(shown), String.valueOf(total));
2045             log.flush(Log.WriterKind.ERROR);
2046         }
2047     }
2048 
2049     private static long now() {
2050         return System.currentTimeMillis();
2051     }
2052 
2053     private static long elapsed(long then) {
2054         return now() - then;
2055     }
2056 
2057     public void newRound() {
2058         inputFiles.clear();
2059         todo.clear();
2060     }
2061 
2062     public interface InitialFileParserIntf {
2063         public List<JCCompilationUnit> parse(Iterable<JavaFileObject> files);
2064     }
2065 
2066     public static class InitialFileParser implements InitialFileParserIntf {
2067 
2068         public static final Key<InitialFileParserIntf> initialParserKey = new Key<>();
2069 
2070         public static InitialFileParserIntf instance(Context context) {
2071             InitialFileParserIntf instance = context.get(initialParserKey);
2072             if (instance == null)
2073                 instance = new InitialFileParser(context);
2074             return instance;
2075         }
2076 
2077         private final JavaCompiler compiler;
2078 
2079         private InitialFileParser(Context context) {
2080             context.put(initialParserKey, this);
2081             this.compiler = JavaCompiler.instance(context);
2082         }
2083 
2084         @Override
2085         public List<JCCompilationUnit> parse(Iterable<JavaFileObject> fileObjects) {
2086            return compiler.parseFiles(fileObjects, false);
2087         }
2088     }
2089 }