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