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