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