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