1 /*
2 * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.javac.main;
27
28 import java.io.*;
29 import java.lang.module.Configuration;
30 import java.lang.reflect.Method;
31 import java.nio.file.FileSystemNotFoundException;
32 import java.nio.file.InvalidPathException;
33 import java.nio.file.ReadOnlyFileSystemException;
34 import java.util.Collection;
35 import java.util.Comparator;
36 import java.util.HashMap;
37 import java.util.HashSet;
38 import java.util.LinkedHashMap;
39 import java.util.LinkedHashSet;
40 import java.util.Map;
41 import java.util.MissingResourceException;
42 import java.util.Optional;
43 import java.util.Queue;
44 import java.util.ResourceBundle;
45 import java.util.ServiceLoader;
46 import java.util.Set;
47 import java.util.function.Function;
48 import java.util.function.ToIntFunction;
49
50 import javax.annotation.processing.Processor;
51 import javax.lang.model.SourceVersion;
52 import javax.lang.model.element.ElementVisitor;
53 import javax.tools.DiagnosticListener;
54 import javax.tools.JavaFileManager;
55 import javax.tools.JavaFileObject;
56 import javax.tools.JavaFileObject.Kind;
57 import javax.tools.StandardLocation;
58
59 import com.sun.source.util.TaskEvent;
60 import com.sun.tools.javac.api.MultiTaskListener;
61 import com.sun.tools.javac.code.*;
62 import com.sun.tools.javac.code.Lint.LintCategory;
63 import com.sun.tools.javac.code.Source.Feature;
64 import com.sun.tools.javac.code.Symbol.ClassSymbol;
65 import com.sun.tools.javac.code.Symbol.CompletionFailure;
66 import com.sun.tools.javac.code.Symbol.PackageSymbol;
67 import com.sun.tools.javac.comp.*;
68 import com.sun.tools.javac.comp.CompileStates.CompileState;
69 import com.sun.tools.javac.file.JavacFileManager;
70 import com.sun.tools.javac.jvm.*;
71 import com.sun.tools.javac.parser.*;
72 import com.sun.tools.javac.platform.PlatformDescription;
73 import com.sun.tools.javac.processing.*;
74 import com.sun.tools.javac.tree.*;
75 import com.sun.tools.javac.tree.JCTree.JCClassDecl;
76 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
77 import com.sun.tools.javac.tree.JCTree.JCExpression;
78 import com.sun.tools.javac.tree.JCTree.JCLambda;
79 import com.sun.tools.javac.tree.JCTree.JCMemberReference;
80 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
81 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
82 import com.sun.tools.javac.util.*;
83 import com.sun.tools.javac.util.Context.Key;
84 import com.sun.tools.javac.util.DefinedBy.Api;
85 import com.sun.tools.javac.util.JCDiagnostic.Factory;
86 import com.sun.tools.javac.util.Log.DiagnosticHandler;
87 import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler;
88 import com.sun.tools.javac.util.Log.WriterKind;
89
90 import static com.sun.tools.javac.code.Kinds.Kind.*;
91
92 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
93
94 import com.sun.tools.javac.resources.CompilerProperties.Errors;
95 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
96 import com.sun.tools.javac.resources.CompilerProperties.Notes;
97 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
98
99 import static com.sun.tools.javac.code.TypeTag.CLASS;
100 import static com.sun.tools.javac.main.Option.*;
101 import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
102 import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
103 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
104
105 import static javax.tools.StandardLocation.CLASS_OUTPUT;
106 import static javax.tools.StandardLocation.ANNOTATION_PROCESSOR_PATH;
107
108 import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
109 import com.sun.tools.javac.tree.JCTree.JCRecordPattern;
110 import com.sun.tools.javac.tree.JCTree.JCSwitch;
111 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
112
113 /** This class could be the main entry point for GJC when GJC is used as a
114 * component in a larger software system. It provides operations to
115 * construct a new compiler, and to run a new compiler on a set of source
116 * files.
117 *
118 * <p><b>This is NOT part of any supported API.
119 * If you write code that depends on this, you do so at your own risk.
120 * This code and its internal interfaces are subject to change or
121 * deletion without notice.</b>
122 */
123 public class JavaCompiler {
124 /** The context key for the compiler. */
125 public static final Context.Key<JavaCompiler> compilerKey = new Context.Key<>();
126
127 /** Get the JavaCompiler instance for this context. */
128 public static JavaCompiler instance(Context context) {
129 JavaCompiler instance = context.get(compilerKey);
130 if (instance == null)
131 instance = new JavaCompiler(context);
132 return instance;
133 }
134
135 /** The current version number as a string.
136 */
137 public static String version() {
138 return version("release"); // mm.nn.oo[-milestone]
139 }
140
141 /** The current full version number as a string.
142 */
143 public static String fullVersion() {
144 return version("full"); // mm.mm.oo[-milestone]-build
145 }
146
147 private static final String versionRBName = "com.sun.tools.javac.resources.version";
148 private static ResourceBundle versionRB;
149
150 private static String version(String key) {
151 if (versionRB == null) {
152 try {
153 versionRB = ResourceBundle.getBundle(versionRBName);
154 } catch (MissingResourceException e) {
155 return Log.getLocalizedString("version.not.available");
156 }
157 }
158 try {
159 return versionRB.getString(key);
160 }
161 catch (MissingResourceException e) {
162 return Log.getLocalizedString("version.not.available");
163 }
164 }
165
166 /**
167 * Control how the compiler's latter phases (attr, flow, desugar, generate)
168 * are connected. Each individual file is processed by each phase in turn,
169 * but with different compile policies, you can control the order in which
170 * each class is processed through its next phase.
171 *
172 * <p>Generally speaking, the compiler will "fail fast" in the face of
173 * errors, although not aggressively so. flow, desugar, etc become no-ops
174 * once any errors have occurred. No attempt is currently made to determine
175 * if it might be safe to process a class through its next phase because
176 * it does not depend on any unrelated errors that might have occurred.
177 */
178 protected static enum CompilePolicy {
179 /**
180 * Attribute everything, then do flow analysis for everything,
181 * then desugar everything, and only then generate output.
182 * This means no output will be generated if there are any
183 * errors in any classes.
184 */
185 SIMPLE,
186
187 /**
188 * Groups the classes for each source file together, then process
189 * each group in a manner equivalent to the {@code SIMPLE} policy.
190 * This means no output will be generated if there are any
191 * errors in any of the classes in a source file.
192 */
193 BY_FILE,
194
195 /**
196 * Completely process each entry on the todo list in turn.
197 * -- this is the same for 1.5.
198 * Means output might be generated for some classes in a compilation unit
199 * and not others.
200 */
201 BY_TODO;
202
203 static CompilePolicy decode(String option) {
204 if (option == null)
205 return DEFAULT_COMPILE_POLICY;
206 else if (option.equals("simple"))
207 return SIMPLE;
208 else if (option.equals("byfile"))
209 return BY_FILE;
210 else if (option.equals("bytodo"))
211 return BY_TODO;
212 else
213 return DEFAULT_COMPILE_POLICY;
214 }
215 }
216
217 private static final CompilePolicy DEFAULT_COMPILE_POLICY = CompilePolicy.BY_TODO;
218
219 protected static enum ImplicitSourcePolicy {
220 /** Don't generate or process implicitly read source files. */
221 NONE,
222 /** Generate classes for implicitly read source files. */
223 CLASS,
224 /** Like CLASS, but generate warnings if annotation processing occurs */
225 UNSET;
226
227 static ImplicitSourcePolicy decode(String option) {
228 if (option == null)
229 return UNSET;
230 else if (option.equals("none"))
231 return NONE;
232 else if (option.equals("class"))
233 return CLASS;
234 else
235 return UNSET;
236 }
237 }
238
239 /** The log to be used for error reporting.
240 */
241 public Log log;
242
243 /** Factory for creating diagnostic objects
244 */
245 JCDiagnostic.Factory diagFactory;
246
247 /** The tree factory module.
248 */
249 protected TreeMaker make;
250
251 /** The class finder.
252 */
253 protected ClassFinder finder;
254
255 /** The class reader.
256 */
257 protected ClassReader reader;
258
259 /** The class writer.
260 */
261 protected ClassWriter writer;
262
263 /** The native header writer.
264 */
265 protected JNIWriter jniWriter;
266
267 /** The module for the symbol table entry phases.
268 */
269 protected Enter enter;
270
271 /** The symbol table.
272 */
273 protected Symtab syms;
274
275 /** The language version.
276 */
277 protected Source source;
278
279 /** The preview language version.
280 */
281 protected Preview preview;
282
283 /** The module for code generation.
284 */
285 protected Gen gen;
286
287 /** The name table.
288 */
289 protected Names names;
290
291 /** The attributor.
292 */
293 protected Attr attr;
294
295 /** The analyzer
296 */
297 protected Analyzer analyzer;
298
299 /** The attributor.
300 */
301 protected Check chk;
302
303 /** The flow analyzer.
304 */
305 protected Flow flow;
306
307 /** The warning analyzer.
308 */
309 protected WarningAnalyzer warningAnalyzer;
310
311 /** The modules visitor
312 */
313 protected Modules modules;
314
315 /** The module finder
316 */
317 protected ModuleFinder moduleFinder;
318
319 /** The diagnostics factory
320 */
321 protected JCDiagnostic.Factory diags;
322
323 protected DeferredCompletionFailureHandler dcfh;
324
325 /** The type eraser.
326 */
327 protected TransTypes transTypes;
328
329 /** The syntactic sugar desweetener.
330 */
331 protected Lower lower;
332
333 /** The annotation annotator.
334 */
335 protected Annotate annotate;
336
337 /** Force a completion failure on this name
338 */
339 protected final Name completionFailureName;
340
341 /** Type utilities.
342 */
343 protected Types types;
344
345 /** Access to file objects.
346 */
347 protected JavaFileManager fileManager;
348
349 /** Factory for parsers.
350 */
351 protected ParserFactory parserFactory;
352
353 /** Broadcasting listener for progress events
354 */
355 protected MultiTaskListener taskListener;
356
357 /**
358 * SourceCompleter that delegates to the readSourceFile method of this class.
359 */
360 protected final Symbol.Completer sourceCompleter =
361 sym -> readSourceFile((ClassSymbol) sym);
362
363 /**
364 * Command line options.
365 */
366 protected Options options;
367
368 protected Context context;
369
370 /**
371 * Flag set if any annotation processing occurred.
372 **/
373 protected boolean annotationProcessingOccurred;
374
375 /**
376 * Flag set if any implicit source files read.
377 **/
378 protected boolean implicitSourceFilesRead;
379
380 private boolean enterDone;
381
382 protected CompileStates compileStates;
383
384 private boolean hasCodeReflectionModule;
385
386 /** Construct a new compiler using a shared context.
387 */
388 @SuppressWarnings("this-escape")
389 public JavaCompiler(Context context) {
390 this.context = context;
391 context.put(compilerKey, this);
392
393 // if fileManager not already set, register the JavacFileManager to be used
394 if (context.get(JavaFileManager.class) == null)
395 JavacFileManager.preRegister(context);
396
397 names = Names.instance(context);
398 log = Log.instance(context);
399 diagFactory = JCDiagnostic.Factory.instance(context);
400 finder = ClassFinder.instance(context);
401 reader = ClassReader.instance(context);
402 make = TreeMaker.instance(context);
403 writer = ClassWriter.instance(context);
404 jniWriter = JNIWriter.instance(context);
405 enter = Enter.instance(context);
406 todo = Todo.instance(context);
407
408 fileManager = context.get(JavaFileManager.class);
409 parserFactory = ParserFactory.instance(context);
410 compileStates = CompileStates.instance(context);
411
412 try {
413 // catch completion problems with predefineds
414 syms = Symtab.instance(context);
415 } catch (CompletionFailure ex) {
416 // inlined Check.completionError as it is not initialized yet
417 log.error(Errors.CantAccess(ex.sym, ex.getDetailValue()));
418 }
419 source = Source.instance(context);
420 preview = Preview.instance(context);
421 attr = Attr.instance(context);
422 analyzer = Analyzer.instance(context);
423 chk = Check.instance(context);
424 gen = Gen.instance(context);
425 flow = Flow.instance(context);
426 warningAnalyzer = WarningAnalyzer.instance(context);
427 transTypes = TransTypes.instance(context);
428 lower = Lower.instance(context);
429 annotate = Annotate.instance(context);
430 types = Types.instance(context);
431 taskListener = MultiTaskListener.instance(context);
432 modules = Modules.instance(context);
433 moduleFinder = ModuleFinder.instance(context);
434 diags = Factory.instance(context);
435 dcfh = DeferredCompletionFailureHandler.instance(context);
436
437 finder.sourceCompleter = sourceCompleter;
438 modules.findPackageInFile = this::findPackageInFile;
439 moduleFinder.moduleNameFromSourceReader = this::readModuleName;
440
441 options = Options.instance(context);
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 start_msec = now();
926
927 try {
928 initProcessAnnotations(processors, sourceFileObjects, classnames);
929
930 for (String className : classnames) {
931 int sep = className.indexOf('/');
932 if (sep != -1) {
933 modules.addExtraAddModules(className.substring(0, sep));
934 }
935 }
936
937 for (String moduleName : addModules) {
938 modules.addExtraAddModules(moduleName);
939 }
940
941 // These method calls must be chained to avoid memory leaks
942 processAnnotations(
943 enterTrees(
944 stopIfError(CompileState.ENTER,
945 initModules(stopIfError(CompileState.ENTER, parseFiles(sourceFileObjects))))
946 ),
947 classnames
948 );
949
950 // If it's safe to do so, skip attr / flow / gen for implicit classes
951 if (taskListener.isEmpty() &&
952 implicitSourcePolicy == ImplicitSourcePolicy.NONE) {
953 todo.retainFiles(inputFiles);
954 }
955
956 if (!CompileState.ATTR.isAfter(shouldStopPolicyIfNoError)) {
957 switch (compilePolicy) {
958 case SIMPLE:
959 generate(desugar(warn(flow(attribute(todo)))));
960 break;
961
962 case BY_FILE: {
963 Queue<Queue<Env<AttrContext>>> q = todo.groupByFile();
964 while (!q.isEmpty() && !shouldStop(CompileState.ATTR)) {
965 generate(desugar(warn(flow(attribute(q.remove())))));
966 }
967 }
968 break;
969
970 case BY_TODO:
971 while (!todo.isEmpty())
972 generate(desugar(warn(flow(attribute(todo.remove())))));
973 break;
974
975 default:
976 Assert.error("unknown compile policy");
977 }
978 }
979 } catch (Abort ex) {
980 if (devVerbose)
981 ex.printStackTrace(System.err);
982
983 // In case an Abort was thrown before processAnnotations could be called,
984 // we could have deferred diagnostics that haven't been reported.
985 reportDeferredDiagnosticAndClearHandler();
986 } finally {
987 if (verbose) {
988 elapsed_msec = elapsed(start_msec);
989 log.printVerbose("total", Long.toString(elapsed_msec));
990 }
991
992 reportDeferredDiagnostics();
993
994 if (!log.hasDiagnosticListener()) {
995 printCount("error", errorCount());
996 printCount("warn", warningCount());
997 printSuppressedCount(errorCount(), log.nsuppressederrors, "count.error.recompile");
998 printSuppressedCount(warningCount(), log.nsuppressedwarns, "count.warn.recompile");
999 }
1000 if (!taskListener.isEmpty()) {
1001 taskListener.finished(new TaskEvent(TaskEvent.Kind.COMPILATION));
1002 }
1003 close();
1004 if (procEnvImpl != null)
1005 procEnvImpl.close();
1006 }
1007 }
1008
1009 protected void checkReusable() {
1010 throw new AssertionError("attempt to reuse JavaCompiler");
1011 }
1012
1013 /**
1014 * The list of classes explicitly supplied on the command line for compilation.
1015 * Not always populated.
1016 */
1017 private List<JCClassDecl> rootClasses;
1018
1019 /**
1020 * Parses a list of files.
1021 */
1022 public List<JCCompilationUnit> parseFiles(Iterable<JavaFileObject> fileObjects) {
1023 return InitialFileParser.instance(context).parse(fileObjects);
1024 }
1025
1026 public List<JCCompilationUnit> parseFiles(Iterable<JavaFileObject> fileObjects, boolean force) {
1027 if (!force && shouldStop(CompileState.PARSE))
1028 return List.nil();
1029
1030 //parse all files
1031 ListBuffer<JCCompilationUnit> trees = new ListBuffer<>();
1032 Set<JavaFileObject> filesSoFar = new HashSet<>();
1033 for (JavaFileObject fileObject : fileObjects) {
1034 if (!filesSoFar.contains(fileObject)) {
1035 filesSoFar.add(fileObject);
1036 trees.append(parse(fileObject));
1037 }
1038 }
1039 return trees.toList();
1040 }
1041
1042 /**
1043 * Returns true iff the compilation will continue after annotation processing
1044 * is done.
1045 */
1046 public boolean continueAfterProcessAnnotations() {
1047 return !shouldStop(CompileState.ATTR);
1048 }
1049
1050 public List<JCCompilationUnit> initModules(List<JCCompilationUnit> roots) {
1051 modules.initModules(roots);
1052
1053 if (modules.modulesInitialized()) {
1054 // This has to happen precisely here. At this point, we have all we need to
1055 // determine whether jdk.incubator.module is part of the module graph
1056 // but we have yet to trigger an ENTER event. This gives the code reflection plugin
1057 // a window to check whether code reflection should be enabled for this compilation unit.
1058 hasCodeReflectionModule = modules.getObservableModule(names.jdk_incubator_code) != null;
1059 }
1060
1061 if (roots.isEmpty()) {
1062 enterDone();
1063 }
1064 return roots;
1065 }
1066
1067 /**
1068 * Enter the symbols found in a list of parse trees.
1069 * As a side-effect, this puts elements on the "todo" list.
1070 * Also stores a list of all top level classes in rootClasses.
1071 */
1072 public List<JCCompilationUnit> enterTrees(List<JCCompilationUnit> roots) {
1073 //enter symbols for all files
1074 if (!taskListener.isEmpty()) {
1075 for (JCCompilationUnit unit: roots) {
1076 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
1077 taskListener.started(e);
1078 }
1079 }
1080
1081 enter.main(roots);
1082
1083 enterDone();
1084
1085 if (!taskListener.isEmpty()) {
1086 for (JCCompilationUnit unit: roots) {
1087 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
1088 taskListener.finished(e);
1089 }
1090 }
1091
1092 // If generating source, or if tracking public apis,
1093 // then remember the classes declared in
1094 // the original compilation units listed on the command line.
1095 if (sourceOutput) {
1096 ListBuffer<JCClassDecl> cdefs = new ListBuffer<>();
1097 for (JCCompilationUnit unit : roots) {
1098 for (List<JCTree> defs = unit.defs;
1099 defs.nonEmpty();
1100 defs = defs.tail) {
1101 if (defs.head instanceof JCClassDecl classDecl)
1102 cdefs.append(classDecl);
1103 }
1104 }
1105 rootClasses = cdefs.toList();
1106 }
1107
1108 // Ensure the input files have been recorded. Although this is normally
1109 // done by readSource, it may not have been done if the trees were read
1110 // in a prior round of annotation processing, and the trees have been
1111 // cleaned and are being reused.
1112 for (JCCompilationUnit unit : roots) {
1113 inputFiles.add(unit.sourcefile);
1114 }
1115
1116 return roots;
1117 }
1118
1119 /**
1120 * Set to true to enable skeleton annotation processing code.
1121 * Currently, we assume this variable will be replaced more
1122 * advanced logic to figure out if annotation processing is
1123 * needed.
1124 */
1125 boolean processAnnotations = false;
1126
1127 Log.DeferredDiagnosticHandler deferredDiagnosticHandler;
1128
1129 /**
1130 * Object to handle annotation processing.
1131 */
1132 private JavacProcessingEnvironment procEnvImpl = null;
1133
1134 /**
1135 * Check if we should process annotations.
1136 * If so, and if no scanner is yet registered, then set up the DocCommentScanner
1137 * to catch doc comments, and set keepComments so the parser records them in
1138 * the compilation unit.
1139 *
1140 * @param processors user provided annotation processors to bypass
1141 * discovery, {@code null} means that no processors were provided
1142 */
1143 public void initProcessAnnotations(Iterable<? extends Processor> processors,
1144 Collection<? extends JavaFileObject> initialFiles,
1145 Collection<String> initialClassNames) {
1146 if (processors != null && processors.iterator().hasNext())
1147 explicitAnnotationProcessingRequested = true;
1148
1149 if (options.isSet(PROC, "none")) {
1150 processAnnotations = false;
1151 } else if (procEnvImpl == null) {
1152 procEnvImpl = JavacProcessingEnvironment.instance(context);
1153 procEnvImpl.setProcessors(processors);
1154
1155 // Process annotations if processing is requested and there
1156 // is at least one Processor available.
1157 processAnnotations = procEnvImpl.atLeastOneProcessor() &&
1158 explicitAnnotationProcessingRequested();
1159
1160 if (processAnnotations) {
1161 options.put("parameters", "parameters");
1162 reader.saveParameterNames = true;
1163 keepComments = true;
1164 genEndPos = true;
1165 if (!taskListener.isEmpty())
1166 taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
1167 deferredDiagnosticHandler = log.new DeferredDiagnosticHandler();
1168 procEnvImpl.getFiler().setInitialState(initialFiles, initialClassNames);
1169 }
1170 } else { // free resources
1171 procEnvImpl.close();
1172 }
1173 }
1174
1175 // TODO: called by JavacTaskImpl
1176 public void processAnnotations(List<JCCompilationUnit> roots) {
1177 processAnnotations(roots, List.nil());
1178 }
1179
1180 /**
1181 * Process any annotations found in the specified compilation units.
1182 * @param roots a list of compilation units
1183 */
1184 // Implementation note: when this method is called, log.deferredDiagnostics
1185 // will have been set true by initProcessAnnotations, meaning that any diagnostics
1186 // that are reported will go into the log.deferredDiagnostics queue.
1187 // By the time this method exits, log.deferDiagnostics must be set back to false,
1188 // and all deferredDiagnostics must have been handled: i.e. either reported
1189 // or determined to be transient, and therefore suppressed.
1190 public void processAnnotations(List<JCCompilationUnit> roots,
1191 Collection<String> classnames) {
1192 if (shouldStop(CompileState.PROCESS)) {
1193 // Errors were encountered.
1194 // Unless all the errors are resolve errors, the errors were parse errors
1195 // or other errors during enter which cannot be fixed by running
1196 // any annotation processors.
1197 if (processAnnotations) {
1198 reportDeferredDiagnosticAndClearHandler();
1199 return ;
1200 }
1201 }
1202
1203 // ASSERT: processAnnotations and procEnvImpl should have been set up by
1204 // by initProcessAnnotations
1205
1206 // NOTE: The !classnames.isEmpty() checks should be refactored to Main.
1207
1208 if (!processAnnotations) {
1209 // If there are no annotation processors present, and
1210 // annotation processing is to occur with compilation,
1211 // emit a warning.
1212 if (options.isSet(PROC, "only")) {
1213 log.warning(Warnings.ProcProcOnlyRequestedNoProcs);
1214 todo.clear();
1215 }
1216 // If not processing annotations, classnames must be empty
1217 if (!classnames.isEmpty()) {
1218 log.error(Errors.ProcNoExplicitAnnotationProcessingRequested(classnames));
1219 }
1220 Assert.checkNull(deferredDiagnosticHandler);
1221 return ; // continue regular compilation
1222 }
1223
1224 Assert.checkNonNull(deferredDiagnosticHandler);
1225
1226 try {
1227 List<ClassSymbol> classSymbols = List.nil();
1228 List<PackageSymbol> pckSymbols = List.nil();
1229 if (!classnames.isEmpty()) {
1230 // Check for explicit request for annotation
1231 // processing
1232 if (!explicitAnnotationProcessingRequested()) {
1233 log.error(Errors.ProcNoExplicitAnnotationProcessingRequested(classnames));
1234 reportDeferredDiagnosticAndClearHandler();
1235 return ; // TODO: Will this halt compilation?
1236 } else {
1237 boolean errors = false;
1238 for (String nameStr : classnames) {
1239 Symbol sym = resolveBinaryNameOrIdent(nameStr);
1240 if (sym == null ||
1241 (sym.kind == PCK && !processPcks) ||
1242 sym.kind == ABSENT_TYP) {
1243 if (sym != silentFail)
1244 log.error(Errors.ProcCantFindClass(nameStr));
1245 errors = true;
1246 continue;
1247 }
1248 try {
1249 if (sym.kind == PCK)
1250 sym.complete();
1251 if (sym.exists()) {
1252 if (sym.kind == PCK)
1253 pckSymbols = pckSymbols.prepend((PackageSymbol)sym);
1254 else
1255 classSymbols = classSymbols.prepend((ClassSymbol)sym);
1256 continue;
1257 }
1258 Assert.check(sym.kind == PCK);
1259 log.warning(Warnings.ProcPackageDoesNotExist(nameStr));
1260 pckSymbols = pckSymbols.prepend((PackageSymbol)sym);
1261 } catch (CompletionFailure e) {
1262 log.error(Errors.ProcCantFindClass(nameStr));
1263 errors = true;
1264 continue;
1265 }
1266 }
1267 if (errors) {
1268 reportDeferredDiagnosticAndClearHandler();
1269 return ;
1270 }
1271 }
1272 }
1273 try {
1274 annotationProcessingOccurred =
1275 procEnvImpl.doProcessing(roots,
1276 classSymbols,
1277 pckSymbols,
1278 deferredDiagnosticHandler);
1279 // doProcessing will have handled deferred diagnostics
1280 } finally {
1281 procEnvImpl.close();
1282 }
1283 } catch (CompletionFailure ex) {
1284 log.error(Errors.CantAccess(ex.sym, ex.getDetailValue()));
1285 reportDeferredDiagnosticAndClearHandler();
1286 }
1287 }
1288
1289 private boolean unrecoverableError() {
1290 if (deferredDiagnosticHandler != null) {
1291 for (JCDiagnostic d: deferredDiagnosticHandler.getDiagnostics()) {
1292 if (d.getKind() == JCDiagnostic.Kind.ERROR && !d.isFlagSet(RECOVERABLE))
1293 return true;
1294 }
1295 }
1296 return false;
1297 }
1298
1299 boolean explicitAnnotationProcessingRequested() {
1300 return
1301 explicitAnnotationProcessingRequested ||
1302 explicitAnnotationProcessingRequested(options, fileManager);
1303 }
1304
1305 static boolean explicitAnnotationProcessingRequested(Options options, JavaFileManager fileManager) {
1306 return
1307 options.isSet(PROCESSOR) ||
1308 options.isSet(PROCESSOR_PATH) ||
1309 options.isSet(PROCESSOR_MODULE_PATH) ||
1310 options.isSet(PROC, "only") ||
1311 options.isSet(PROC, "full") ||
1312 options.isSet(A) ||
1313 options.isSet(XPRINT) ||
1314 fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH);
1315 // Skipping -XprintRounds and -XprintProcessorInfo
1316 }
1317
1318 public void setDeferredDiagnosticHandler(Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
1319 this.deferredDiagnosticHandler = deferredDiagnosticHandler;
1320 }
1321
1322 /**
1323 * Attribute a list of parse trees, such as found on the "todo" list.
1324 * Note that attributing classes may cause additional files to be
1325 * parsed and entered via the SourceCompleter.
1326 * Attribution of the entries in the list does not stop if any errors occur.
1327 * @return a list of environments for attribute classes.
1328 */
1329 public Queue<Env<AttrContext>> attribute(Queue<Env<AttrContext>> envs) {
1330 ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1331 while (!envs.isEmpty())
1332 results.append(attribute(envs.remove()));
1333 return stopIfError(CompileState.ATTR, results);
1334 }
1335
1336 /**
1337 * Attribute a parse tree.
1338 * @return the attributed parse tree
1339 */
1340 public Env<AttrContext> attribute(Env<AttrContext> env) {
1341 if (compileStates.isDone(env, CompileState.ATTR))
1342 return env;
1343
1344 if (verboseCompilePolicy)
1345 printNote("[attribute " + env.enclClass.sym + "]");
1346 if (verbose)
1347 log.printVerbose("checking.attribution", env.enclClass.sym);
1348
1349 if (!taskListener.isEmpty()) {
1350 TaskEvent e = newAnalyzeTaskEvent(env);
1351 taskListener.started(e);
1352 }
1353
1354 JavaFileObject prev = log.useSource(
1355 env.enclClass.sym.sourcefile != null ?
1356 env.enclClass.sym.sourcefile :
1357 env.toplevel.sourcefile);
1358 try {
1359 attr.attrib(env);
1360 if (errorCount() > 0 && !shouldStop(CompileState.ATTR)) {
1361 //if in fail-over mode, ensure that AST expression nodes
1362 //are correctly initialized (e.g. they have a type/symbol)
1363 attr.postAttr(env.tree);
1364 }
1365 compileStates.put(env, CompileState.ATTR);
1366 }
1367 finally {
1368 log.useSource(prev);
1369 }
1370
1371 return env;
1372 }
1373
1374 /**
1375 * Perform dataflow checks on attributed parse trees.
1376 * These include checks for definite assignment and unreachable statements.
1377 * If any errors occur, an empty list will be returned.
1378 * @return the list of attributed parse trees
1379 */
1380 public Queue<Env<AttrContext>> flow(Queue<Env<AttrContext>> envs) {
1381 ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1382 for (Env<AttrContext> env: envs) {
1383 flow(env, results);
1384 }
1385 return stopIfError(CompileState.FLOW, results);
1386 }
1387
1388 /**
1389 * Perform dataflow checks on an attributed parse tree.
1390 */
1391 public Queue<Env<AttrContext>> flow(Env<AttrContext> env) {
1392 ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1393 flow(env, results);
1394 return stopIfError(CompileState.FLOW, results);
1395 }
1396
1397 /**
1398 * Perform dataflow checks on an attributed parse tree.
1399 */
1400 protected void flow(Env<AttrContext> env, Queue<Env<AttrContext>> results) {
1401 if (compileStates.isDone(env, CompileState.FLOW)) {
1402 results.add(env);
1403 return;
1404 }
1405
1406 try {
1407 if (shouldStop(CompileState.FLOW))
1408 return;
1409
1410 if (verboseCompilePolicy)
1411 printNote("[flow " + env.enclClass.sym + "]");
1412 JavaFileObject prev = log.useSource(
1413 env.enclClass.sym.sourcefile != null ?
1414 env.enclClass.sym.sourcefile :
1415 env.toplevel.sourcefile);
1416 try {
1417 make.at(Position.FIRSTPOS);
1418 TreeMaker localMake = make.forToplevel(env.toplevel);
1419 flow.analyzeTree(env, localMake);
1420 compileStates.put(env, CompileState.FLOW);
1421
1422 if (shouldStop(CompileState.FLOW))
1423 return;
1424
1425 analyzer.flush(env);
1426
1427 results.add(env);
1428 }
1429 finally {
1430 log.useSource(prev);
1431 }
1432 }
1433 finally {
1434 if (!taskListener.isEmpty()) {
1435 TaskEvent e = newAnalyzeTaskEvent(env);
1436 taskListener.finished(e);
1437 }
1438 }
1439 }
1440
1441 /**
1442 * Check for various things to warn about.
1443 *
1444 * @return the list of attributed parse trees
1445 */
1446 public Queue<Env<AttrContext>> warn(Queue<Env<AttrContext>> envs) {
1447 ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1448 for (Env<AttrContext> env: envs) {
1449 warn(env, results);
1450 }
1451 return stopIfError(CompileState.WARN, results);
1452 }
1453
1454 /**
1455 * Check for various things to warn about in an attributed parse tree.
1456 */
1457 public Queue<Env<AttrContext>> warn(Env<AttrContext> env) {
1458 ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1459 warn(env, results);
1460 return stopIfError(CompileState.WARN, results);
1461 }
1462
1463 /**
1464 * Check for various things to warn about in an attributed parse tree.
1465 */
1466 protected void warn(Env<AttrContext> env, Queue<Env<AttrContext>> results) {
1467 if (compileStates.isDone(env, CompileState.WARN)) {
1468 results.add(env);
1469 return;
1470 }
1471
1472 if (shouldStop(CompileState.WARN))
1473 return;
1474
1475 if (verboseCompilePolicy)
1476 printNote("[warn " + env.enclClass.sym + "]");
1477 JavaFileObject prev = log.useSource(
1478 env.enclClass.sym.sourcefile != null ?
1479 env.enclClass.sym.sourcefile :
1480 env.toplevel.sourcefile);
1481 try {
1482 warningAnalyzer.analyzeTree(env);
1483 compileStates.put(env, CompileState.WARN);
1484 results.add(env);
1485 }
1486 finally {
1487 log.useSource(prev);
1488 }
1489 }
1490
1491 private TaskEvent newAnalyzeTaskEvent(Env<AttrContext> env) {
1492 JCCompilationUnit toplevel = env.toplevel;
1493 ClassSymbol sym;
1494 if (env.enclClass.sym == syms.predefClass) {
1495 if (TreeInfo.isModuleInfo(toplevel)) {
1496 sym = toplevel.modle.module_info;
1497 } else if (TreeInfo.isPackageInfo(toplevel)) {
1498 sym = toplevel.packge.package_info;
1499 } else {
1500 throw new IllegalStateException("unknown env.toplevel");
1501 }
1502 } else {
1503 sym = env.enclClass.sym;
1504 }
1505
1506 return new TaskEvent(TaskEvent.Kind.ANALYZE, toplevel, sym);
1507 }
1508
1509 /**
1510 * Prepare attributed parse trees, in conjunction with their attribution contexts,
1511 * for source or code generation.
1512 * If any errors occur, an empty list will be returned.
1513 * @return a list containing the classes to be generated
1514 */
1515 public Queue<Pair<Env<AttrContext>, JCClassDecl>> desugar(Queue<Env<AttrContext>> envs) {
1516 ListBuffer<Pair<Env<AttrContext>, JCClassDecl>> results = new ListBuffer<>();
1517 for (Env<AttrContext> env: envs)
1518 desugar(env, results);
1519 return stopIfError(CompileState.FLOW, results);
1520 }
1521
1522 HashMap<Env<AttrContext>, Queue<Pair<Env<AttrContext>, JCClassDecl>>> desugaredEnvs = new HashMap<>();
1523
1524 /**
1525 * Prepare attributed parse trees, in conjunction with their attribution contexts,
1526 * for source or code generation. If the file was not listed on the command line,
1527 * the current implicitSourcePolicy is taken into account.
1528 * The preparation stops as soon as an error is found.
1529 */
1530 protected void desugar(final Env<AttrContext> env, Queue<Pair<Env<AttrContext>, JCClassDecl>> results) {
1531 if (shouldStop(CompileState.TRANSTYPES))
1532 return;
1533
1534 if (implicitSourcePolicy == ImplicitSourcePolicy.NONE
1535 && !inputFiles.contains(env.toplevel.sourcefile)) {
1536 return;
1537 }
1538
1539 if (!modules.multiModuleMode && env.toplevel.modle != modules.getDefaultModule()) {
1540 //can only generate classfiles for a single module:
1541 return;
1542 }
1543
1544 if (compileStates.isDone(env, CompileState.LOWER)) {
1545 results.addAll(desugaredEnvs.get(env));
1546 return;
1547 }
1548
1549 // Ensure the file has reached the WARN state
1550 if (!compileStates.isDone(env, CompileState.WARN))
1551 warn(env);
1552
1553 /**
1554 * Ensure that superclasses of C are desugared before C itself. This is
1555 * required for two reasons: (i) as erasure (TransTypes) destroys
1556 * information needed in flow analysis and (ii) as some checks carried
1557 * out during lowering require that all synthetic fields/methods have
1558 * already been added to C and its superclasses.
1559 */
1560 class ScanNested extends TreeScanner {
1561 Set<Env<AttrContext>> dependencies = new LinkedHashSet<>();
1562 protected boolean hasLambdas;
1563 protected boolean hasPatterns;
1564 @Override
1565 public void visitClassDef(JCClassDecl node) {
1566 Type st = types.supertype(node.sym.type);
1567 boolean envForSuperTypeFound = false;
1568 while (!envForSuperTypeFound && st.hasTag(CLASS)) {
1569 ClassSymbol c = st.tsym.outermostClass();
1570 Env<AttrContext> stEnv = enter.getEnv(c);
1571 if (stEnv != null && env != stEnv) {
1572 if (dependencies.add(stEnv)) {
1573 boolean prevHasLambdas = hasLambdas;
1574 boolean prevHasPatterns = hasPatterns;
1575 try {
1576 scan(stEnv.tree);
1577 } finally {
1578 /*
1579 * ignore any updates to hasLambdas and hasPatterns
1580 * made during the nested scan, this ensures an
1581 * initialized LambdaToMethod or TransPatterns is
1582 * available only to those classes that contain
1583 * lambdas or patterns, respectivelly
1584 */
1585 hasLambdas = prevHasLambdas;
1586 hasPatterns = prevHasPatterns;
1587 }
1588 }
1589 envForSuperTypeFound = true;
1590 }
1591 st = types.supertype(st);
1592 }
1593 super.visitClassDef(node);
1594 }
1595 @Override
1596 public void visitLambda(JCLambda tree) {
1597 hasLambdas = true;
1598 super.visitLambda(tree);
1599 }
1600 @Override
1601 public void visitReference(JCMemberReference tree) {
1602 hasLambdas = true;
1603 super.visitReference(tree);
1604 }
1605 @Override
1606 public void visitBindingPattern(JCBindingPattern tree) {
1607 hasPatterns = true;
1608 super.visitBindingPattern(tree);
1609 }
1610 @Override
1611 public void visitTypeTest(JCInstanceOf tree) {
1612 if (tree.pattern.type.isPrimitive()) {
1613 hasPatterns = true;
1614 }
1615 super.visitTypeTest(tree);
1616 }
1617 @Override
1618 public void visitRecordPattern(JCRecordPattern that) {
1619 hasPatterns = true;
1620 super.visitRecordPattern(that);
1621 }
1622 @Override
1623 public void visitSwitch(JCSwitch tree) {
1624 hasPatterns |= tree.patternSwitch;
1625 super.visitSwitch(tree);
1626 }
1627 @Override
1628 public void visitSwitchExpression(JCSwitchExpression tree) {
1629 hasPatterns |= tree.patternSwitch;
1630 super.visitSwitchExpression(tree);
1631 }
1632 }
1633 ScanNested scanner = new ScanNested();
1634 scanner.scan(env.tree);
1635 for (Env<AttrContext> dep: scanner.dependencies) {
1636 if (!compileStates.isDone(dep, CompileState.WARN))
1637 desugaredEnvs.put(dep, desugar(warn(flow(attribute(dep)))));
1638 }
1639
1640 //We need to check for error another time as more classes might
1641 //have been attributed and analyzed at this stage
1642 if (shouldStop(CompileState.TRANSTYPES))
1643 return;
1644
1645 if (verboseCompilePolicy)
1646 printNote("[desugar " + env.enclClass.sym + "]");
1647
1648 JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ?
1649 env.enclClass.sym.sourcefile :
1650 env.toplevel.sourcefile);
1651 try {
1652 //save tree prior to rewriting
1653 JCTree untranslated = env.tree;
1654
1655 make.at(Position.FIRSTPOS);
1656 TreeMaker localMake = make.forToplevel(env.toplevel);
1657
1658 if (env.tree.hasTag(JCTree.Tag.PACKAGEDEF) || env.tree.hasTag(JCTree.Tag.MODULEDEF)) {
1659 if (!(sourceOutput)) {
1660 if (shouldStop(CompileState.LOWER))
1661 return;
1662 List<JCTree> def = lower.translateTopLevelClass(env, env.tree, localMake);
1663 if (def.head != null) {
1664 Assert.check(def.tail.isEmpty());
1665 results.add(new Pair<>(env, (JCClassDecl)def.head));
1666 }
1667 }
1668 return;
1669 }
1670
1671 if (shouldStop(CompileState.TRANSTYPES))
1672 return;
1673
1674 if (Feature.REFLECT_METHODS.allowedInSource(source)) {
1675 Optional<CodeReflectionTransformer> reflectMethods = reflectMethods();
1676 if (reflectMethods.isPresent()) {
1677 env.tree = reflectMethods.get().translateTopLevelClass(context, env.tree, localMake);
1678 }
1679 }
1680
1681 env.tree = transTypes.translateTopLevelClass(env.tree, localMake);
1682 compileStates.put(env, CompileState.TRANSTYPES);
1683
1684 if (shouldStop(CompileState.TRANSPATTERNS))
1685 return;
1686
1687 if (scanner.hasPatterns) {
1688 env.tree = TransPatterns.instance(context)
1689 .translateTopLevelClass(env, env.tree, localMake);
1690 }
1691
1692 compileStates.put(env, CompileState.TRANSPATTERNS);
1693
1694 if (shouldStop(CompileState.LOWER))
1695 return;
1696
1697 if (sourceOutput) {
1698 //emit standard Java source file, only for compilation
1699 //units enumerated explicitly on the command line
1700 JCClassDecl cdef = (JCClassDecl)env.tree;
1701 if (untranslated instanceof JCClassDecl classDecl &&
1702 rootClasses.contains(classDecl)) {
1703 results.add(new Pair<>(env, cdef));
1704 }
1705 return;
1706 }
1707
1708 //translate out inner classes
1709 List<JCTree> cdefs = lower.translateTopLevelClass(env, env.tree, localMake);
1710 compileStates.put(env, CompileState.LOWER);
1711
1712 if (shouldStop(CompileState.LOWER))
1713 return;
1714
1715 if (scanner.hasLambdas) {
1716 if (shouldStop(CompileState.UNLAMBDA))
1717 return;
1718
1719 for (JCTree def : cdefs) {
1720 LambdaToMethod.instance(context).translateTopLevelClass(env, def, localMake);
1721 }
1722 compileStates.put(env, CompileState.UNLAMBDA);
1723 }
1724
1725 //generate code for each class
1726 for (List<JCTree> l = cdefs; l.nonEmpty(); l = l.tail) {
1727 JCClassDecl cdef = (JCClassDecl)l.head;
1728 results.add(new Pair<>(env, cdef));
1729 }
1730 }
1731 finally {
1732 log.useSource(prev);
1733 }
1734
1735 }
1736
1737 Optional<CodeReflectionTransformer> reflectMethods() {
1738 return CodeReflectionSupport.CODE_LAYER != null ?
1739 ServiceLoader.load(CodeReflectionSupport.CODE_LAYER, CodeReflectionTransformer.class).findFirst() :
1740 Optional.empty();
1741 }
1742
1743 public static class CodeReflectionSupport {
1744 public static final ModuleLayer CODE_LAYER;
1745
1746 static {
1747 if (ModuleLayer.boot().findModule("jdk.incubator.code").isPresent()) {
1748 // we are in an exploded build, so just use the boot layer
1749 CODE_LAYER = ModuleLayer.boot();
1750 } else if (java.lang.module.ModuleFinder.ofSystem().find("jdk.incubator.code").isPresent()) {
1751 // the code module is installed, but not in the boot layer, create a new layer which contains it
1752 ModuleLayer parent = ModuleLayer.boot();
1753 Configuration cf = parent.configuration()
1754 .resolve(java.lang.module.ModuleFinder.of(), java.lang.module.ModuleFinder.ofSystem(), Set.of("jdk.incubator.code"));
1755 ClassLoader scl = ClassLoader.getSystemClassLoader();
1756 CODE_LAYER = parent.defineModulesWithOneLoader(cf, scl);
1757 Module codeReflectionModule = CODE_LAYER.findModule("jdk.incubator.code").get();
1758 Module jdkCompilerModule = JavaCompiler.class.getModule();
1759 // We need to add exports all jdk.compiler packages so that the plugin can use them
1760 for (String packageName : jdkCompilerModule.getPackages()) {
1761 jdkCompilerModule.addExports(packageName, codeReflectionModule);
1762 }
1763 // We also need to add exports all java.base packages so that the plugin can use them
1764 // But we need to do so by calling a method in java.base reflectively
1765 try {
1766 Class<?> codeModuleLayerInit = Class.forName("jdk.internal.access.code.CodeModuleLayerInit");
1767 Method initLayerMethod = codeModuleLayerInit.getDeclaredMethod("initCodeModuleLayer", ModuleLayer.class);
1768 initLayerMethod.invoke(null, CODE_LAYER);
1769 } catch (ReflectiveOperationException ex) {
1770 throw new AssertionError(ex);
1771 }
1772 } else {
1773 // if we run in bootstrap mode, there might be no jdk.incubator.code
1774 CODE_LAYER = null;
1775 }
1776 }
1777 }
1778
1779 /** Generates the source or class file for a list of classes.
1780 * The decision to generate a source file or a class file is
1781 * based upon the compiler's options.
1782 * Generation stops if an error occurs while writing files.
1783 */
1784 public void generate(Queue<Pair<Env<AttrContext>, JCClassDecl>> queue) {
1785 generate(queue, null);
1786 }
1787
1788 public void generate(Queue<Pair<Env<AttrContext>, JCClassDecl>> queue, Queue<JavaFileObject> results) {
1789 if (shouldStop(CompileState.GENERATE))
1790 return;
1791
1792 for (Pair<Env<AttrContext>, JCClassDecl> x: queue) {
1793 Env<AttrContext> env = x.fst;
1794 JCClassDecl cdef = x.snd;
1795
1796 if (verboseCompilePolicy) {
1797 printNote("[generate " + (sourceOutput ? " source" : "code") + " " + cdef.sym + "]");
1798 }
1799
1800 if (!taskListener.isEmpty()) {
1801 TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
1802 taskListener.started(e);
1803 }
1804
1805 JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ?
1806 env.enclClass.sym.sourcefile :
1807 env.toplevel.sourcefile);
1808 try {
1809 JavaFileObject file;
1810 if (sourceOutput) {
1811 file = printSource(env, cdef);
1812 } else {
1813 if (fileManager.hasLocation(StandardLocation.NATIVE_HEADER_OUTPUT)
1814 && jniWriter.needsHeader(cdef.sym)) {
1815 jniWriter.write(cdef.sym);
1816 }
1817 file = genCode(env, cdef);
1818 }
1819 if (results != null && file != null)
1820 results.add(file);
1821 } catch (IOException
1822 | UncheckedIOException
1823 | FileSystemNotFoundException
1824 | InvalidPathException
1825 | ReadOnlyFileSystemException ex) {
1826 log.error(cdef.pos(),
1827 Errors.ClassCantWrite(cdef.sym, ex.getMessage()));
1828 return;
1829 } finally {
1830 log.useSource(prev);
1831 }
1832
1833 if (!taskListener.isEmpty()) {
1834 TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
1835 taskListener.finished(e);
1836 }
1837 }
1838 }
1839
1840 // where
1841 Map<JCCompilationUnit, Queue<Env<AttrContext>>> groupByFile(Queue<Env<AttrContext>> envs) {
1842 // use a LinkedHashMap to preserve the order of the original list as much as possible
1843 Map<JCCompilationUnit, Queue<Env<AttrContext>>> map = new LinkedHashMap<>();
1844 for (Env<AttrContext> env: envs) {
1845 Queue<Env<AttrContext>> sublist = map.get(env.toplevel);
1846 if (sublist == null) {
1847 sublist = new ListBuffer<>();
1848 map.put(env.toplevel, sublist);
1849 }
1850 sublist.add(env);
1851 }
1852 return map;
1853 }
1854
1855 JCClassDecl removeMethodBodies(JCClassDecl cdef) {
1856 final boolean isInterface = (cdef.mods.flags & Flags.INTERFACE) != 0;
1857 class MethodBodyRemover extends TreeTranslator {
1858 @Override
1859 public void visitMethodDef(JCMethodDecl tree) {
1860 tree.mods.flags &= ~Flags.SYNCHRONIZED;
1861 for (JCVariableDecl vd : tree.params)
1862 vd.mods.flags &= ~Flags.FINAL;
1863 tree.body = null;
1864 super.visitMethodDef(tree);
1865 }
1866 @Override
1867 public void visitVarDef(JCVariableDecl tree) {
1868 if (tree.init != null && tree.init.type.constValue() == null)
1869 tree.init = null;
1870 super.visitVarDef(tree);
1871 }
1872 @Override
1873 public void visitClassDef(JCClassDecl tree) {
1874 ListBuffer<JCTree> newdefs = new ListBuffer<>();
1875 for (List<JCTree> it = tree.defs; it.tail != null; it = it.tail) {
1876 JCTree t = it.head;
1877 switch (t.getTag()) {
1878 case CLASSDEF:
1879 if (isInterface ||
1880 (((JCClassDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1881 (((JCClassDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCClassDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1882 newdefs.append(t);
1883 break;
1884 case METHODDEF:
1885 if (isInterface ||
1886 (((JCMethodDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1887 ((JCMethodDecl) t).sym.name == names.init ||
1888 (((JCMethodDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCMethodDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1889 newdefs.append(t);
1890 break;
1891 case VARDEF:
1892 if (isInterface || (((JCVariableDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1893 (((JCVariableDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCVariableDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1894 newdefs.append(t);
1895 break;
1896 default:
1897 break;
1898 }
1899 }
1900 tree.defs = newdefs.toList();
1901 super.visitClassDef(tree);
1902 }
1903 }
1904 MethodBodyRemover r = new MethodBodyRemover();
1905 return r.translate(cdef);
1906 }
1907
1908 public void reportDeferredDiagnostics() {
1909 if (errorCount() == 0
1910 && annotationProcessingOccurred
1911 && implicitSourceFilesRead
1912 && implicitSourcePolicy == ImplicitSourcePolicy.UNSET) {
1913 if (explicitAnnotationProcessingRequested())
1914 log.warning(Warnings.ProcUseImplicit);
1915 else
1916 log.warning(Warnings.ProcUseProcOrImplicit);
1917 }
1918 chk.reportDeferredDiagnostics();
1919 preview.reportDeferredDiagnostics();
1920 if (log.compressedOutput) {
1921 log.mandatoryNote(null, Notes.CompressedDiags);
1922 }
1923 }
1924
1925 public void enterDone() {
1926 enterDone = true;
1927 annotate.enterDone();
1928 }
1929
1930 public boolean isEnterDone() {
1931 return enterDone;
1932 }
1933
1934 public boolean hasCodeReflectionModule() {
1935 return hasCodeReflectionModule;
1936 }
1937
1938 private Name readModuleName(JavaFileObject fo) {
1939 return parseAndGetName(fo, t -> {
1940 JCModuleDecl md = t.getModuleDecl();
1941
1942 return md != null ? TreeInfo.fullName(md.getName()) : null;
1943 });
1944 }
1945
1946 private Name findPackageInFile(JavaFileObject fo) {
1947 return parseAndGetName(fo, t -> t.getPackage() != null ?
1948 TreeInfo.fullName(t.getPackage().getPackageName()) : null);
1949 }
1950
1951 private Name parseAndGetName(JavaFileObject fo,
1952 Function<JCTree.JCCompilationUnit, Name> tree2Name) {
1953 DiagnosticHandler dh = log.new DiscardDiagnosticHandler();
1954 JavaFileObject prevSource = log.useSource(fo);
1955 try {
1956 JCTree.JCCompilationUnit t = parse(fo, fo.getCharContent(false), true);
1957 return tree2Name.apply(t);
1958 } catch (IOException e) {
1959 return null;
1960 } finally {
1961 log.popDiagnosticHandler(dh);
1962 log.useSource(prevSource);
1963 }
1964 }
1965
1966 public void reportDeferredDiagnosticAndClearHandler() {
1967 if (deferredDiagnosticHandler != null) {
1968 ToIntFunction<JCDiagnostic> diagValue =
1969 d -> d.isFlagSet(RECOVERABLE) ? 1 : 0;
1970 Comparator<JCDiagnostic> compareDiags =
1971 (d1, d2) -> diagValue.applyAsInt(d1) - diagValue.applyAsInt(d2);
1972 deferredDiagnosticHandler.reportDeferredDiagnostics(compareDiags);
1973 log.popDiagnosticHandler(deferredDiagnosticHandler);
1974 deferredDiagnosticHandler = null;
1975 }
1976 }
1977
1978 /** Close the compiler, flushing the logs
1979 */
1980 public void close() {
1981 rootClasses = null;
1982 finder = null;
1983 reader = null;
1984 make = null;
1985 writer = null;
1986 enter = null;
1987 if (todo != null)
1988 todo.clear();
1989 todo = null;
1990 parserFactory = null;
1991 syms = null;
1992 source = null;
1993 attr = null;
1994 chk = null;
1995 gen = null;
1996 flow = null;
1997 transTypes = null;
1998 lower = null;
1999 annotate = null;
2000 types = null;
2001
2002 log.flush();
2003 try {
2004 fileManager.flush();
2005 } catch (IOException e) {
2006 throw new Abort(e);
2007 } finally {
2008 if (names != null)
2009 names.dispose();
2010 names = null;
2011
2012 FatalError fatalError = null;
2013 for (Closeable c: closeables) {
2014 try {
2015 c.close();
2016 } catch (IOException e) {
2017 if (fatalError == null) {
2018 JCDiagnostic msg = diagFactory.fragment(Fragments.FatalErrCantClose);
2019 fatalError = new FatalError(msg, e);
2020 } else {
2021 fatalError.addSuppressed(e);
2022 }
2023 }
2024 }
2025 if (fatalError != null) {
2026 throw fatalError;
2027 }
2028 closeables = List.nil();
2029 }
2030 }
2031
2032 protected void printNote(String lines) {
2033 log.printRawLines(Log.WriterKind.NOTICE, lines);
2034 }
2035
2036 /** Print numbers of errors and warnings.
2037 */
2038 public void printCount(String kind, int count) {
2039 if (count != 0) {
2040 String key;
2041 if (count == 1)
2042 key = "count." + kind;
2043 else
2044 key = "count." + kind + ".plural";
2045 log.printLines(WriterKind.ERROR, key, String.valueOf(count));
2046 log.flush(Log.WriterKind.ERROR);
2047 }
2048 }
2049
2050 private void printSuppressedCount(int shown, int suppressed, String diagKey) {
2051 if (suppressed > 0) {
2052 int total = shown + suppressed;
2053 log.printLines(WriterKind.ERROR, diagKey,
2054 String.valueOf(shown), String.valueOf(total));
2055 log.flush(Log.WriterKind.ERROR);
2056 }
2057 }
2058
2059 private static long now() {
2060 return System.currentTimeMillis();
2061 }
2062
2063 private static long elapsed(long then) {
2064 return now() - then;
2065 }
2066
2067 public void newRound() {
2068 inputFiles.clear();
2069 todo.clear();
2070 }
2071
2072 public interface InitialFileParserIntf {
2073 public List<JCCompilationUnit> parse(Iterable<JavaFileObject> files);
2074 }
2075
2076 public static class InitialFileParser implements InitialFileParserIntf {
2077
2078 public static final Key<InitialFileParserIntf> initialParserKey = new Key<>();
2079
2080 public static InitialFileParserIntf instance(Context context) {
2081 InitialFileParserIntf instance = context.get(initialParserKey);
2082 if (instance == null)
2083 instance = new InitialFileParser(context);
2084 return instance;
2085 }
2086
2087 private final JavaCompiler compiler;
2088
2089 private InitialFileParser(Context context) {
2090 context.put(initialParserKey, this);
2091 this.compiler = JavaCompiler.instance(context);
2092 }
2093
2094 @Override
2095 public List<JCCompilationUnit> parse(Iterable<JavaFileObject> fileObjects) {
2096 return compiler.parseFiles(fileObjects, false);
2097 }
2098 }
2099 }