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