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