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