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