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