JavaCompiler.java revision 2571:10fc81ac75b4
1169689Skan/*
2169689Skan * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
3169689Skan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4169689Skan *
5169689Skan * This code is free software; you can redistribute it and/or modify it
6169689Skan * under the terms of the GNU General Public License version 2 only, as
7169689Skan * published by the Free Software Foundation.  Oracle designates this
8169689Skan * particular file as subject to the "Classpath" exception as provided
9169689Skan * by Oracle in the LICENSE file that accompanied this code.
10169689Skan *
11169689Skan * This code is distributed in the hope that it will be useful, but WITHOUT
12169689Skan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13169689Skan * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14169689Skan * version 2 for more details (a copy is included in the LICENSE file that
15169689Skan * accompanied this code).
16169689Skan *
17169689Skan * You should have received a copy of the GNU General Public License version
18169689Skan * 2 along with this work; if not, write to the Free Software Foundation,
19169689Skan * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20169689Skan *
21169689Skan * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22169689Skan * or visit www.oracle.com if you need additional information or have any
23169689Skan * questions.
24169689Skan */
25169689Skan
26169689Skanpackage com.sun.tools.javac.main;
27169689Skan
28169689Skanimport java.io.*;
29169689Skanimport java.util.HashMap;
30169689Skanimport java.util.HashSet;
31169689Skanimport java.util.LinkedHashMap;
32169689Skanimport java.util.LinkedHashSet;
33169689Skanimport java.util.Map;
34169689Skanimport java.util.MissingResourceException;
35169689Skanimport java.util.Queue;
36169689Skanimport java.util.ResourceBundle;
37169689Skanimport java.util.Set;
38169689Skan
39169689Skanimport javax.annotation.processing.Processor;
40169689Skanimport javax.lang.model.SourceVersion;
41169689Skanimport javax.tools.DiagnosticListener;
42169689Skanimport javax.tools.JavaFileManager;
43169689Skanimport javax.tools.JavaFileObject;
44169689Skanimport javax.tools.StandardLocation;
45169689Skan
46169689Skanimport static javax.tools.StandardLocation.CLASS_OUTPUT;
47169689Skan
48169689Skanimport com.sun.source.util.TaskEvent;
49169689Skanimport com.sun.tools.javac.api.MultiTaskListener;
50169689Skanimport com.sun.tools.javac.code.*;
51169689Skanimport com.sun.tools.javac.code.Lint.LintCategory;
52169689Skanimport com.sun.tools.javac.code.Symbol.*;
53169689Skanimport com.sun.tools.javac.comp.*;
54169689Skanimport com.sun.tools.javac.comp.CompileStates.CompileState;
55169689Skanimport com.sun.tools.javac.file.JavacFileManager;
56169689Skanimport com.sun.tools.javac.jvm.*;
57169689Skanimport com.sun.tools.javac.parser.*;
58169689Skanimport com.sun.tools.javac.processing.*;
59169689Skanimport com.sun.tools.javac.tree.*;
60169689Skanimport com.sun.tools.javac.tree.JCTree.*;
61169689Skanimport com.sun.tools.javac.util.*;
62169689Skanimport com.sun.tools.javac.util.Log.WriterKind;
63169689Skan
64169689Skanimport static com.sun.tools.javac.code.TypeTag.CLASS;
65169689Skanimport static com.sun.tools.javac.main.Option.*;
66169689Skanimport static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
67169689Skan
68169689Skan
69169689Skan/** This class could be the main entry point for GJC when GJC is used as a
70169689Skan *  component in a larger software system. It provides operations to
71169689Skan *  construct a new compiler, and to run a new compiler on a set of source
72169689Skan *  files.
73169689Skan *
74169689Skan *  <p><b>This is NOT part of any supported API.
75169689Skan *  If you write code that depends on this, you do so at your own risk.
76169689Skan *  This code and its internal interfaces are subject to change or
77169689Skan *  deletion without notice.</b>
78169689Skan */
79169689Skanpublic class JavaCompiler {
80169689Skan    /** The context key for the compiler. */
81169689Skan    protected static final Context.Key<JavaCompiler> compilerKey = new Context.Key<>();
82169689Skan
83169689Skan    /** Get the JavaCompiler instance for this context. */
84169689Skan    public static JavaCompiler instance(Context context) {
85169689Skan        JavaCompiler instance = context.get(compilerKey);
86169689Skan        if (instance == null)
87169689Skan            instance = new JavaCompiler(context);
88169689Skan        return instance;
89169689Skan    }
90169689Skan
91169689Skan    /** The current version number as a string.
92169689Skan     */
93169689Skan    public static String version() {
94169689Skan        return version("release");  // mm.nn.oo[-milestone]
95169689Skan    }
96169689Skan
97169689Skan    /** The current full version number as a string.
98169689Skan     */
99169689Skan    public static String fullVersion() {
100169689Skan        return version("full"); // mm.mm.oo[-milestone]-build
101169689Skan    }
102169689Skan
103169689Skan    private static final String versionRBName = "com.sun.tools.javac.resources.version";
104169689Skan    private static ResourceBundle versionRB;
105169689Skan
106169689Skan    private static String version(String key) {
107169689Skan        if (versionRB == null) {
108169689Skan            try {
109169689Skan                versionRB = ResourceBundle.getBundle(versionRBName);
110169689Skan            } catch (MissingResourceException e) {
111169689Skan                return Log.getLocalizedString("version.not.available");
112169689Skan            }
113169689Skan        }
114169689Skan        try {
115169689Skan            return versionRB.getString(key);
116169689Skan        }
117169689Skan        catch (MissingResourceException e) {
118169689Skan            return Log.getLocalizedString("version.not.available");
119169689Skan        }
120169689Skan    }
121169689Skan
122169689Skan    /**
123169689Skan     * Control how the compiler's latter phases (attr, flow, desugar, generate)
124169689Skan     * are connected. Each individual file is processed by each phase in turn,
125169689Skan     * but with different compile policies, you can control the order in which
126169689Skan     * each class is processed through its next phase.
127169689Skan     *
128169689Skan     * <p>Generally speaking, the compiler will "fail fast" in the face of
129169689Skan     * errors, although not aggressively so. flow, desugar, etc become no-ops
130169689Skan     * once any errors have occurred. No attempt is currently made to determine
131169689Skan     * if it might be safe to process a class through its next phase because
132169689Skan     * it does not depend on any unrelated errors that might have occurred.
133169689Skan     */
134169689Skan    protected static enum CompilePolicy {
135169689Skan        /**
136169689Skan         * Just attribute the parse trees.
137169689Skan         */
138169689Skan        ATTR_ONLY,
139169689Skan
140169689Skan        /**
141169689Skan         * Just attribute and do flow analysis on the parse trees.
142169689Skan         * This should catch most user errors.
143169689Skan         */
144169689Skan        CHECK_ONLY,
145169689Skan
146169689Skan        /**
147169689Skan         * Attribute everything, then do flow analysis for everything,
148169689Skan         * then desugar everything, and only then generate output.
149169689Skan         * This means no output will be generated if there are any
150169689Skan         * errors in any classes.
151169689Skan         */
152169689Skan        SIMPLE,
153169689Skan
154169689Skan        /**
155169689Skan         * Groups the classes for each source file together, then process
156169689Skan         * each group in a manner equivalent to the {@code SIMPLE} policy.
157169689Skan         * This means no output will be generated if there are any
158169689Skan         * errors in any of the classes in a source file.
159169689Skan         */
160169689Skan        BY_FILE,
161169689Skan
162169689Skan        /**
163169689Skan         * Completely process each entry on the todo list in turn.
164169689Skan         * -- this is the same for 1.5.
165169689Skan         * Means output might be generated for some classes in a compilation unit
166169689Skan         * and not others.
167169689Skan         */
168169689Skan        BY_TODO;
169169689Skan
170169689Skan        static CompilePolicy decode(String option) {
171169689Skan            if (option == null)
172169689Skan                return DEFAULT_COMPILE_POLICY;
173169689Skan            else if (option.equals("attr"))
174169689Skan                return ATTR_ONLY;
175169689Skan            else if (option.equals("check"))
176169689Skan                return CHECK_ONLY;
177169689Skan            else if (option.equals("simple"))
178169689Skan                return SIMPLE;
179169689Skan            else if (option.equals("byfile"))
180169689Skan                return BY_FILE;
181169689Skan            else if (option.equals("bytodo"))
182169689Skan                return BY_TODO;
183169689Skan            else
184169689Skan                return DEFAULT_COMPILE_POLICY;
185169689Skan        }
186169689Skan    }
187169689Skan
188169689Skan    private static final CompilePolicy DEFAULT_COMPILE_POLICY = CompilePolicy.BY_TODO;
189169689Skan
190169689Skan    protected static enum ImplicitSourcePolicy {
191169689Skan        /** Don't generate or process implicitly read source files. */
192169689Skan        NONE,
193169689Skan        /** Generate classes for implicitly read source files. */
194169689Skan        CLASS,
195169689Skan        /** Like CLASS, but generate warnings if annotation processing occurs */
196169689Skan        UNSET;
197169689Skan
198169689Skan        static ImplicitSourcePolicy decode(String option) {
199169689Skan            if (option == null)
200169689Skan                return UNSET;
201169689Skan            else if (option.equals("none"))
202169689Skan                return NONE;
203169689Skan            else if (option.equals("class"))
204169689Skan                return CLASS;
205169689Skan            else
206169689Skan                return UNSET;
207169689Skan        }
208169689Skan    }
209169689Skan
210169689Skan    /** The log to be used for error reporting.
211169689Skan     */
212169689Skan    public Log log;
213169689Skan
214169689Skan    /** Factory for creating diagnostic objects
215169689Skan     */
216169689Skan    JCDiagnostic.Factory diagFactory;
217169689Skan
218169689Skan    /** The tree factory module.
219169689Skan     */
220169689Skan    protected TreeMaker make;
221169689Skan
222169689Skan    /** The class finder.
223169689Skan     */
224169689Skan    protected ClassFinder finder;
225169689Skan
226169689Skan    /** The class reader.
227169689Skan     */
228169689Skan    protected ClassReader reader;
229169689Skan
230169689Skan    /** The class writer.
231169689Skan     */
232169689Skan    protected ClassWriter writer;
233169689Skan
234169689Skan    /** The native header writer.
235169689Skan     */
236169689Skan    protected JNIWriter jniWriter;
237169689Skan
238169689Skan    /** The module for the symbol table entry phases.
239169689Skan     */
240169689Skan    protected Enter enter;
241169689Skan
242169689Skan    /** The symbol table.
243169689Skan     */
244169689Skan    protected Symtab syms;
245169689Skan
246169689Skan    /** The language version.
247169689Skan     */
248169689Skan    protected Source source;
249169689Skan
250169689Skan    /** The module for code generation.
251169689Skan     */
252169689Skan    protected Gen gen;
253169689Skan
254169689Skan    /** The name table.
255169689Skan     */
256169689Skan    protected Names names;
257169689Skan
258169689Skan    /** The attributor.
259169689Skan     */
260169689Skan    protected Attr attr;
261169689Skan
262169689Skan    /** The attributor.
263169689Skan     */
264    protected Check chk;
265
266    /** The flow analyzer.
267     */
268    protected Flow flow;
269
270    /** The type eraser.
271     */
272    protected TransTypes transTypes;
273
274    /** The syntactic sugar desweetener.
275     */
276    protected Lower lower;
277
278    /** The annotation annotator.
279     */
280    protected Annotate annotate;
281
282    /** Force a completion failure on this name
283     */
284    protected final Name completionFailureName;
285
286    /** Type utilities.
287     */
288    protected Types types;
289
290    /** Access to file objects.
291     */
292    protected JavaFileManager fileManager;
293
294    /** Factory for parsers.
295     */
296    protected ParserFactory parserFactory;
297
298    /** Broadcasting listener for progress events
299     */
300    protected MultiTaskListener taskListener;
301
302    /**
303     * SourceCompleter that delegates to the readSourceFile method of this class.
304     */
305    protected final Symbol.Completer sourceCompleter =
306            new Symbol.Completer() {
307                @Override
308                public void complete(Symbol sym) throws CompletionFailure {
309                    readSourceFile((ClassSymbol) sym);
310                }
311            };
312
313    /**
314     * Command line options.
315     */
316    protected Options options;
317
318    protected Context context;
319
320    /**
321     * Flag set if any annotation processing occurred.
322     **/
323    protected boolean annotationProcessingOccurred;
324
325    /**
326     * Flag set if any implicit source files read.
327     **/
328    protected boolean implicitSourceFilesRead;
329
330    protected CompileStates compileStates;
331
332    /** Construct a new compiler using a shared context.
333     */
334    public JavaCompiler(Context context) {
335        this.context = context;
336        context.put(compilerKey, this);
337
338        // if fileManager not already set, register the JavacFileManager to be used
339        if (context.get(JavaFileManager.class) == null)
340            JavacFileManager.preRegister(context);
341
342        names = Names.instance(context);
343        log = Log.instance(context);
344        diagFactory = JCDiagnostic.Factory.instance(context);
345        finder = ClassFinder.instance(context);
346        reader = ClassReader.instance(context);
347        make = TreeMaker.instance(context);
348        writer = ClassWriter.instance(context);
349        jniWriter = JNIWriter.instance(context);
350        enter = Enter.instance(context);
351        todo = Todo.instance(context);
352
353        fileManager = context.get(JavaFileManager.class);
354        parserFactory = ParserFactory.instance(context);
355        compileStates = CompileStates.instance(context);
356
357        try {
358            // catch completion problems with predefineds
359            syms = Symtab.instance(context);
360        } catch (CompletionFailure ex) {
361            // inlined Check.completionError as it is not initialized yet
362            log.error("cant.access", ex.sym, ex.getDetailValue());
363            if (ex instanceof ClassFinder.BadClassFile)
364                throw new Abort();
365        }
366        source = Source.instance(context);
367        Target target = Target.instance(context);
368        attr = Attr.instance(context);
369        chk = Check.instance(context);
370        gen = Gen.instance(context);
371        flow = Flow.instance(context);
372        transTypes = TransTypes.instance(context);
373        lower = Lower.instance(context);
374        annotate = Annotate.instance(context);
375        types = Types.instance(context);
376        taskListener = MultiTaskListener.instance(context);
377
378        finder.sourceCompleter = sourceCompleter;
379
380        options = Options.instance(context);
381
382        verbose       = options.isSet(VERBOSE);
383        sourceOutput  = options.isSet(PRINTSOURCE); // used to be -s
384        stubOutput    = options.isSet("-stubs");
385        relax         = options.isSet("-relax");
386        printFlat     = options.isSet("-printflat");
387        attrParseOnly = options.isSet("-attrparseonly");
388        encoding      = options.get(ENCODING);
389        lineDebugInfo = options.isUnset(G_CUSTOM) ||
390                        options.isSet(G_CUSTOM, "lines");
391        genEndPos     = options.isSet(XJCOV) ||
392                        context.get(DiagnosticListener.class) != null;
393        devVerbose    = options.isSet("dev");
394        processPcks   = options.isSet("process.packages");
395        werror        = options.isSet(WERROR);
396
397        // Should this be with other option checking, in Main
398        if (source.compareTo(Source.DEFAULT) < 0) {
399            if (options.isUnset(XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option)) {
400                if (fileManager instanceof BaseFileManager) {
401                    if (((BaseFileManager) fileManager).isDefaultBootClassPath())
402                        log.warning(LintCategory.OPTIONS, "source.no.bootclasspath", source.name);
403                }
404            }
405        }
406
407        // Should this be with other option checking, in Main
408        checkForObsoleteOptions(target);
409
410        verboseCompilePolicy = options.isSet("verboseCompilePolicy");
411
412        if (attrParseOnly)
413            compilePolicy = CompilePolicy.ATTR_ONLY;
414        else
415            compilePolicy = CompilePolicy.decode(options.get("compilePolicy"));
416
417        implicitSourcePolicy = ImplicitSourcePolicy.decode(options.get("-implicit"));
418
419        completionFailureName =
420            options.isSet("failcomplete")
421            ? names.fromString(options.get("failcomplete"))
422            : null;
423
424        shouldStopPolicyIfError =
425            options.isSet("shouldStopPolicy") // backwards compatible
426            ? CompileState.valueOf(options.get("shouldStopPolicy"))
427            : options.isSet("shouldStopPolicyIfError")
428            ? CompileState.valueOf(options.get("shouldStopPolicyIfError"))
429            : CompileState.INIT;
430        shouldStopPolicyIfNoError =
431            options.isSet("shouldStopPolicyIfNoError")
432            ? CompileState.valueOf(options.get("shouldStopPolicyIfNoError"))
433            : CompileState.GENERATE;
434
435        if (options.isUnset("oldDiags"))
436            log.setDiagnosticFormatter(RichDiagnosticFormatter.instance(context));
437    }
438
439    // Should this be with other option checking, in Main
440    private void checkForObsoleteOptions(Target target) {
441        // Unless lint checking on options is disabled, check for
442        // obsolete source and target options.
443        boolean obsoleteOptionFound = false;
444
445        boolean lintOptions =
446            options.isUnset(XLINT_CUSTOM, "-"+LintCategory.OPTIONS.option);
447
448        if (source.compareTo(Source.MIN) < 0) {
449            log.error("option.removed.source", source.name, Source.MIN.name);
450        } else if (source == Source.MIN && lintOptions) {
451            log.warning(LintCategory.OPTIONS, "option.obsolete.source", source.name);
452            obsoleteOptionFound = true;
453        }
454
455        if (target.compareTo(Target.MIN) < 0) {
456            log.error("option.removed.target", target.name, Target.MIN.name);
457        } else if (target == Target.MIN && lintOptions) {
458            log.warning(LintCategory.OPTIONS, "option.obsolete.target", target.name);
459            obsoleteOptionFound = true;
460        }
461
462        if (obsoleteOptionFound)
463            log.warning(LintCategory.OPTIONS, "option.obsolete.suppression");
464    }
465
466    /* Switches:
467     */
468
469    /** Verbose output.
470     */
471    public boolean verbose;
472
473    /** Emit plain Java source files rather than class files.
474     */
475    public boolean sourceOutput;
476
477    /** Emit stub source files rather than class files.
478     */
479    public boolean stubOutput;
480
481    /** Generate attributed parse tree only.
482     */
483    public boolean attrParseOnly;
484
485    /** Switch: relax some constraints for producing the jsr14 prototype.
486     */
487    boolean relax;
488
489    /** Debug switch: Emit Java sources after inner class flattening.
490     */
491    public boolean printFlat;
492
493    /** The encoding to be used for source input.
494     */
495    public String encoding;
496
497    /** Generate code with the LineNumberTable attribute for debugging
498     */
499    public boolean lineDebugInfo;
500
501    /** Switch: should we store the ending positions?
502     */
503    public boolean genEndPos;
504
505    /** Switch: should we debug ignored exceptions
506     */
507    protected boolean devVerbose;
508
509    /** Switch: should we (annotation) process packages as well
510     */
511    protected boolean processPcks;
512
513    /** Switch: treat warnings as errors
514     */
515    protected boolean werror;
516
517    /** Switch: is annotation processing requested explicitly via
518     * CompilationTask.setProcessors?
519     */
520    protected boolean explicitAnnotationProcessingRequested = false;
521
522    /**
523     * The policy for the order in which to perform the compilation
524     */
525    protected CompilePolicy compilePolicy;
526
527    /**
528     * The policy for what to do with implicitly read source files
529     */
530    protected ImplicitSourcePolicy implicitSourcePolicy;
531
532    /**
533     * Report activity related to compilePolicy
534     */
535    public boolean verboseCompilePolicy;
536
537    /**
538     * Policy of how far to continue compilation after errors have occurred.
539     * Set this to minimum CompileState (INIT) to stop as soon as possible
540     * after errors.
541     */
542    public CompileState shouldStopPolicyIfError;
543
544    /**
545     * Policy of how far to continue compilation when no errors have occurred.
546     * Set this to maximum CompileState (GENERATE) to perform full compilation.
547     * Set this lower to perform partial compilation, such as -proc:only.
548     */
549    public CompileState shouldStopPolicyIfNoError;
550
551    /** A queue of all as yet unattributed classes.
552     */
553    public Todo todo;
554
555    /** A list of items to be closed when the compilation is complete.
556     */
557    public List<Closeable> closeables = List.nil();
558
559    /** The set of currently compiled inputfiles, needed to ensure
560     *  we don't accidentally overwrite an input file when -s is set.
561     *  initialized by `compile'.
562     */
563    protected Set<JavaFileObject> inputFiles = new HashSet<>();
564
565    protected boolean shouldStop(CompileState cs) {
566        CompileState shouldStopPolicy = (errorCount() > 0 || unrecoverableError())
567            ? shouldStopPolicyIfError
568            : shouldStopPolicyIfNoError;
569        return cs.isAfter(shouldStopPolicy);
570    }
571
572    /** The number of errors reported so far.
573     */
574    public int errorCount() {
575        if (werror && log.nerrors == 0 && log.nwarnings > 0) {
576            log.error("warnings.and.werror");
577        }
578        return log.nerrors;
579    }
580
581    protected final <T> Queue<T> stopIfError(CompileState cs, Queue<T> queue) {
582        return shouldStop(cs) ? new ListBuffer<T>() : queue;
583    }
584
585    protected final <T> List<T> stopIfError(CompileState cs, List<T> list) {
586        return shouldStop(cs) ? List.<T>nil() : list;
587    }
588
589    /** The number of warnings reported so far.
590     */
591    public int warningCount() {
592        return log.nwarnings;
593    }
594
595    /** Try to open input stream with given name.
596     *  Report an error if this fails.
597     *  @param filename   The file name of the input stream to be opened.
598     */
599    public CharSequence readSource(JavaFileObject filename) {
600        try {
601            inputFiles.add(filename);
602            return filename.getCharContent(false);
603        } catch (IOException e) {
604            log.error("error.reading.file", filename, JavacFileManager.getMessage(e));
605            return null;
606        }
607    }
608
609    /** Parse contents of input stream.
610     *  @param filename     The name of the file from which input stream comes.
611     *  @param content      The characters to be parsed.
612     */
613    protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) {
614        long msec = now();
615        JCCompilationUnit tree = make.TopLevel(List.<JCTree>nil());
616        if (content != null) {
617            if (verbose) {
618                log.printVerbose("parsing.started", filename);
619            }
620            if (!taskListener.isEmpty()) {
621                TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, filename);
622                taskListener.started(e);
623                keepComments = true;
624                genEndPos = true;
625            }
626            Parser parser = parserFactory.newParser(content, keepComments(), genEndPos, lineDebugInfo);
627            tree = parser.parseCompilationUnit();
628            if (verbose) {
629                log.printVerbose("parsing.done", Long.toString(elapsed(msec)));
630            }
631        }
632
633        tree.sourcefile = filename;
634
635        if (content != null && !taskListener.isEmpty()) {
636            TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree);
637            taskListener.finished(e);
638        }
639
640        return tree;
641    }
642    // where
643        public boolean keepComments = false;
644        protected boolean keepComments() {
645            return keepComments || sourceOutput || stubOutput;
646        }
647
648
649    /** Parse contents of file.
650     *  @param filename     The name of the file to be parsed.
651     */
652    @Deprecated
653    public JCTree.JCCompilationUnit parse(String filename) {
654        JavacFileManager fm = (JavacFileManager)fileManager;
655        return parse(fm.getJavaFileObjectsFromStrings(List.of(filename)).iterator().next());
656    }
657
658    /** Parse contents of file.
659     *  @param filename     The name of the file to be parsed.
660     */
661    public JCTree.JCCompilationUnit parse(JavaFileObject filename) {
662        JavaFileObject prev = log.useSource(filename);
663        try {
664            JCTree.JCCompilationUnit t = parse(filename, readSource(filename));
665            if (t.endPositions != null)
666                log.setEndPosTable(filename, t.endPositions);
667            return t;
668        } finally {
669            log.useSource(prev);
670        }
671    }
672
673    /** Resolve an identifier which may be the binary name of a class or
674     * the Java name of a class or package.
675     * @param name      The name to resolve
676     */
677    public Symbol resolveBinaryNameOrIdent(String name) {
678        try {
679            Name flatname = names.fromString(name.replace("/", "."));
680            return finder.loadClass(flatname);
681        } catch (CompletionFailure ignore) {
682            return resolveIdent(name);
683        }
684    }
685
686    /** Resolve an identifier.
687     * @param name      The identifier to resolve
688     */
689    public Symbol resolveIdent(String name) {
690        if (name.equals(""))
691            return syms.errSymbol;
692        JavaFileObject prev = log.useSource(null);
693        try {
694            JCExpression tree = null;
695            for (String s : name.split("\\.", -1)) {
696                if (!SourceVersion.isIdentifier(s)) // TODO: check for keywords
697                    return syms.errSymbol;
698                tree = (tree == null) ? make.Ident(names.fromString(s))
699                                      : make.Select(tree, names.fromString(s));
700            }
701            JCCompilationUnit toplevel =
702                make.TopLevel(List.<JCTree>nil());
703            toplevel.packge = syms.unnamedPackage;
704            return attr.attribIdent(tree, toplevel);
705        } finally {
706            log.useSource(prev);
707        }
708    }
709
710    /** Emit plain Java source for a class.
711     *  @param env    The attribution environment of the outermost class
712     *                containing this class.
713     *  @param cdef   The class definition to be printed.
714     */
715    JavaFileObject printSource(Env<AttrContext> env, JCClassDecl cdef) throws IOException {
716        JavaFileObject outFile
717            = fileManager.getJavaFileForOutput(CLASS_OUTPUT,
718                                               cdef.sym.flatname.toString(),
719                                               JavaFileObject.Kind.SOURCE,
720                                               null);
721        if (inputFiles.contains(outFile)) {
722            log.error(cdef.pos(), "source.cant.overwrite.input.file", outFile);
723            return null;
724        } else {
725            try (BufferedWriter out = new BufferedWriter(outFile.openWriter())) {
726                new Pretty(out, true).printUnit(env.toplevel, cdef);
727                if (verbose)
728                    log.printVerbose("wrote.file", outFile);
729            }
730            return outFile;
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    /** Compile a source file that has been accessed by the class finder.
755     *  @param c          The class the source file of which needs to be compiled.
756     */
757    private void readSourceFile(ClassSymbol c) throws CompletionFailure {
758        readSourceFile(null, c);
759    }
760
761    /** Compile a ClassSymbol from source, optionally using the given compilation unit as
762     *  the source tree.
763     *  @param tree the compilation unit in which the given ClassSymbol resides,
764     *              or null if should be parsed from source
765     *  @param c    the ClassSymbol to complete
766     */
767    public void readSourceFile(JCCompilationUnit tree, ClassSymbol c) throws CompletionFailure {
768        if (completionFailureName == c.fullname) {
769            throw new CompletionFailure(c, "user-selected completion failure by class name");
770        }
771        JavaFileObject filename = c.classfile;
772        JavaFileObject prev = log.useSource(filename);
773
774        if (tree == null) {
775            try {
776                tree = parse(filename, filename.getCharContent(false));
777            } catch (IOException e) {
778                log.error("error.reading.file", filename, JavacFileManager.getMessage(e));
779                tree = make.TopLevel(List.<JCTree>nil());
780            } finally {
781                log.useSource(prev);
782            }
783        }
784
785        if (!taskListener.isEmpty()) {
786            TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
787            taskListener.started(e);
788        }
789
790        enter.complete(List.of(tree), c);
791
792        if (!taskListener.isEmpty()) {
793            TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
794            taskListener.finished(e);
795        }
796
797        if (enter.getEnv(c) == null) {
798            boolean isPkgInfo =
799                tree.sourcefile.isNameCompatible("package-info",
800                                                 JavaFileObject.Kind.SOURCE);
801            if (isPkgInfo) {
802                if (enter.getEnv(tree.packge) == null) {
803                    JCDiagnostic diag =
804                        diagFactory.fragment("file.does.not.contain.package",
805                                                 c.location());
806                    throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory);
807                }
808            } else {
809                JCDiagnostic diag =
810                        diagFactory.fragment("file.doesnt.contain.class",
811                                            c.getQualifiedName());
812                throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory);
813            }
814        }
815
816        implicitSourceFilesRead = true;
817    }
818
819    /** Track when the JavaCompiler has been used to compile something. */
820    private boolean hasBeenUsed = false;
821    private long start_msec = 0;
822    public long elapsed_msec = 0;
823
824    public void compile(List<JavaFileObject> sourceFileObject)
825        throws Throwable {
826        compile(sourceFileObject, List.<String>nil(), null);
827    }
828
829    /**
830     * Main method: compile a list of files, return all compiled classes
831     *
832     * @param sourceFileObjects file objects to be compiled
833     * @param classnames class names to process for annotations
834     * @param processors user provided annotation processors to bypass
835     * discovery, {@code null} means that no processors were provided
836     */
837    public void compile(List<JavaFileObject> sourceFileObjects,
838                        List<String> classnames,
839                        Iterable<? extends Processor> processors)
840    {
841        if (!taskListener.isEmpty()) {
842            taskListener.started(new TaskEvent(TaskEvent.Kind.COMPILATION));
843        }
844
845        if (processors != null && processors.iterator().hasNext())
846            explicitAnnotationProcessingRequested = true;
847        // as a JavaCompiler can only be used once, throw an exception if
848        // it has been used before.
849        if (hasBeenUsed)
850            throw new AssertionError("attempt to reuse JavaCompiler");
851        hasBeenUsed = true;
852
853        // forcibly set the equivalent of -Xlint:-options, so that no further
854        // warnings about command line options are generated from this point on
855        options.put(XLINT_CUSTOM.text + "-" + LintCategory.OPTIONS.option, "true");
856        options.remove(XLINT_CUSTOM.text + LintCategory.OPTIONS.option);
857
858        start_msec = now();
859
860        try {
861            initProcessAnnotations(processors);
862
863            // These method calls must be chained to avoid memory leaks
864            processAnnotations(
865                enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))),
866                classnames);
867
868            // If it's safe to do so, skip attr / flow / gen for implicit classes
869            if (taskListener.isEmpty() &&
870                    implicitSourcePolicy == ImplicitSourcePolicy.NONE) {
871                todo.retainFiles(inputFiles);
872            }
873
874            switch (compilePolicy) {
875            case ATTR_ONLY:
876                attribute(todo);
877                break;
878
879            case CHECK_ONLY:
880                flow(attribute(todo));
881                break;
882
883            case SIMPLE:
884                generate(desugar(flow(attribute(todo))));
885                break;
886
887            case BY_FILE: {
888                    Queue<Queue<Env<AttrContext>>> q = todo.groupByFile();
889                    while (!q.isEmpty() && !shouldStop(CompileState.ATTR)) {
890                        generate(desugar(flow(attribute(q.remove()))));
891                    }
892                }
893                break;
894
895            case BY_TODO:
896                while (!todo.isEmpty())
897                    generate(desugar(flow(attribute(todo.remove()))));
898                break;
899
900            default:
901                Assert.error("unknown compile policy");
902            }
903        } catch (Abort ex) {
904            if (devVerbose)
905                ex.printStackTrace(System.err);
906        } finally {
907            if (verbose) {
908                elapsed_msec = elapsed(start_msec);
909                log.printVerbose("total", Long.toString(elapsed_msec));
910            }
911
912            reportDeferredDiagnostics();
913
914            if (!log.hasDiagnosticListener()) {
915                printCount("error", errorCount());
916                printCount("warn", warningCount());
917            }
918            if (!taskListener.isEmpty()) {
919                taskListener.finished(new TaskEvent(TaskEvent.Kind.COMPILATION));
920            }
921            close();
922            if (procEnvImpl != null)
923                procEnvImpl.close();
924        }
925    }
926
927    /**
928     * Set needRootClasses to true, in JavaCompiler subclass constructor
929     * that want to collect public apis of classes supplied on the command line.
930     */
931    protected boolean needRootClasses = false;
932
933    /**
934     * The list of classes explicitly supplied on the command line for compilation.
935     * Not always populated.
936     */
937    private List<JCClassDecl> rootClasses;
938
939    /**
940     * Parses a list of files.
941     */
942   public List<JCCompilationUnit> parseFiles(Iterable<JavaFileObject> fileObjects) {
943       if (shouldStop(CompileState.PARSE))
944           return List.nil();
945
946        //parse all files
947        ListBuffer<JCCompilationUnit> trees = new ListBuffer<>();
948        Set<JavaFileObject> filesSoFar = new HashSet<>();
949        for (JavaFileObject fileObject : fileObjects) {
950            if (!filesSoFar.contains(fileObject)) {
951                filesSoFar.add(fileObject);
952                trees.append(parse(fileObject));
953            }
954        }
955        return trees.toList();
956    }
957
958    /**
959     * Enter the symbols found in a list of parse trees if the compilation
960     * is expected to proceed beyond anno processing into attr.
961     * As a side-effect, this puts elements on the "todo" list.
962     * Also stores a list of all top level classes in rootClasses.
963     */
964    public List<JCCompilationUnit> enterTreesIfNeeded(List<JCCompilationUnit> roots) {
965       if (shouldStop(CompileState.ATTR))
966           return List.nil();
967        return enterTrees(roots);
968    }
969
970    /**
971     * Enter the symbols found in a list of parse trees.
972     * As a side-effect, this puts elements on the "todo" list.
973     * Also stores a list of all top level classes in rootClasses.
974     */
975    public List<JCCompilationUnit> enterTrees(List<JCCompilationUnit> roots) {
976        //enter symbols for all files
977        if (!taskListener.isEmpty()) {
978            for (JCCompilationUnit unit: roots) {
979                TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
980                taskListener.started(e);
981            }
982        }
983
984        enter.main(roots);
985
986        if (!taskListener.isEmpty()) {
987            for (JCCompilationUnit unit: roots) {
988                TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
989                taskListener.finished(e);
990            }
991        }
992
993        // If generating source, or if tracking public apis,
994        // then remember the classes declared in
995        // the original compilation units listed on the command line.
996        if (needRootClasses || sourceOutput || stubOutput) {
997            ListBuffer<JCClassDecl> cdefs = new ListBuffer<>();
998            for (JCCompilationUnit unit : roots) {
999                for (List<JCTree> defs = unit.defs;
1000                     defs.nonEmpty();
1001                     defs = defs.tail) {
1002                    if (defs.head instanceof JCClassDecl)
1003                        cdefs.append((JCClassDecl)defs.head);
1004                }
1005            }
1006            rootClasses = cdefs.toList();
1007        }
1008
1009        // Ensure the input files have been recorded. Although this is normally
1010        // done by readSource, it may not have been done if the trees were read
1011        // in a prior round of annotation processing, and the trees have been
1012        // cleaned and are being reused.
1013        for (JCCompilationUnit unit : roots) {
1014            inputFiles.add(unit.sourcefile);
1015        }
1016
1017        return roots;
1018    }
1019
1020    /**
1021     * Set to true to enable skeleton annotation processing code.
1022     * Currently, we assume this variable will be replaced more
1023     * advanced logic to figure out if annotation processing is
1024     * needed.
1025     */
1026    boolean processAnnotations = false;
1027
1028    Log.DeferredDiagnosticHandler deferredDiagnosticHandler;
1029
1030    /**
1031     * Object to handle annotation processing.
1032     */
1033    private JavacProcessingEnvironment procEnvImpl = null;
1034
1035    /**
1036     * Check if we should process annotations.
1037     * If so, and if no scanner is yet registered, then set up the DocCommentScanner
1038     * to catch doc comments, and set keepComments so the parser records them in
1039     * the compilation unit.
1040     *
1041     * @param processors user provided annotation processors to bypass
1042     * discovery, {@code null} means that no processors were provided
1043     */
1044    public void initProcessAnnotations(Iterable<? extends Processor> processors) {
1045        // Process annotations if processing is not disabled and there
1046        // is at least one Processor available.
1047        if (options.isSet(PROC, "none")) {
1048            processAnnotations = false;
1049        } else if (procEnvImpl == null) {
1050            procEnvImpl = JavacProcessingEnvironment.instance(context);
1051            procEnvImpl.setProcessors(processors);
1052            processAnnotations = procEnvImpl.atLeastOneProcessor();
1053
1054            if (processAnnotations) {
1055                options.put("save-parameter-names", "save-parameter-names");
1056                reader.saveParameterNames = true;
1057                keepComments = true;
1058                genEndPos = true;
1059                if (!taskListener.isEmpty())
1060                    taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
1061                deferredDiagnosticHandler = new Log.DeferredDiagnosticHandler(log);
1062            } else { // free resources
1063                procEnvImpl.close();
1064            }
1065        }
1066    }
1067
1068    // TODO: called by JavacTaskImpl
1069    public void processAnnotations(List<JCCompilationUnit> roots) {
1070        processAnnotations(roots, List.<String>nil());
1071    }
1072
1073    /**
1074     * Process any annotations found in the specified compilation units.
1075     * @param roots a list of compilation units
1076     * @return an instance of the compiler in which to complete the compilation
1077     */
1078    // Implementation note: when this method is called, log.deferredDiagnostics
1079    // will have been set true by initProcessAnnotations, meaning that any diagnostics
1080    // that are reported will go into the log.deferredDiagnostics queue.
1081    // By the time this method exits, log.deferDiagnostics must be set back to false,
1082    // and all deferredDiagnostics must have been handled: i.e. either reported
1083    // or determined to be transient, and therefore suppressed.
1084    public void processAnnotations(List<JCCompilationUnit> roots,
1085                                   List<String> classnames) {
1086        if (shouldStop(CompileState.PROCESS)) {
1087            // Errors were encountered.
1088            // Unless all the errors are resolve errors, the errors were parse errors
1089            // or other errors during enter which cannot be fixed by running
1090            // any annotation processors.
1091            if (unrecoverableError()) {
1092                deferredDiagnosticHandler.reportDeferredDiagnostics();
1093                log.popDiagnosticHandler(deferredDiagnosticHandler);
1094                return ;
1095            }
1096        }
1097
1098        // ASSERT: processAnnotations and procEnvImpl should have been set up by
1099        // by initProcessAnnotations
1100
1101        // NOTE: The !classnames.isEmpty() checks should be refactored to Main.
1102
1103        if (!processAnnotations) {
1104            // If there are no annotation processors present, and
1105            // annotation processing is to occur with compilation,
1106            // emit a warning.
1107            if (options.isSet(PROC, "only")) {
1108                log.warning("proc.proc-only.requested.no.procs");
1109                todo.clear();
1110            }
1111            // If not processing annotations, classnames must be empty
1112            if (!classnames.isEmpty()) {
1113                log.error("proc.no.explicit.annotation.processing.requested",
1114                          classnames);
1115            }
1116            Assert.checkNull(deferredDiagnosticHandler);
1117            return ; // continue regular compilation
1118        }
1119
1120        Assert.checkNonNull(deferredDiagnosticHandler);
1121
1122        try {
1123            List<ClassSymbol> classSymbols = List.nil();
1124            List<PackageSymbol> pckSymbols = List.nil();
1125            if (!classnames.isEmpty()) {
1126                 // Check for explicit request for annotation
1127                 // processing
1128                if (!explicitAnnotationProcessingRequested()) {
1129                    log.error("proc.no.explicit.annotation.processing.requested",
1130                              classnames);
1131                    deferredDiagnosticHandler.reportDeferredDiagnostics();
1132                    log.popDiagnosticHandler(deferredDiagnosticHandler);
1133                    return ; // TODO: Will this halt compilation?
1134                } else {
1135                    boolean errors = false;
1136                    for (String nameStr : classnames) {
1137                        Symbol sym = resolveBinaryNameOrIdent(nameStr);
1138                        if (sym == null ||
1139                            (sym.kind == Kinds.PCK && !processPcks) ||
1140                            sym.kind == Kinds.ABSENT_TYP) {
1141                            log.error("proc.cant.find.class", nameStr);
1142                            errors = true;
1143                            continue;
1144                        }
1145                        try {
1146                            if (sym.kind == Kinds.PCK)
1147                                sym.complete();
1148                            if (sym.exists()) {
1149                                if (sym.kind == Kinds.PCK)
1150                                    pckSymbols = pckSymbols.prepend((PackageSymbol)sym);
1151                                else
1152                                    classSymbols = classSymbols.prepend((ClassSymbol)sym);
1153                                continue;
1154                            }
1155                            Assert.check(sym.kind == Kinds.PCK);
1156                            log.warning("proc.package.does.not.exist", nameStr);
1157                            pckSymbols = pckSymbols.prepend((PackageSymbol)sym);
1158                        } catch (CompletionFailure e) {
1159                            log.error("proc.cant.find.class", nameStr);
1160                            errors = true;
1161                            continue;
1162                        }
1163                    }
1164                    if (errors) {
1165                        deferredDiagnosticHandler.reportDeferredDiagnostics();
1166                        log.popDiagnosticHandler(deferredDiagnosticHandler);
1167                        return ;
1168                    }
1169                }
1170            }
1171            try {
1172                annotationProcessingOccurred =
1173                        procEnvImpl.doProcessing(roots,
1174                                                 classSymbols,
1175                                                 pckSymbols,
1176                                                 deferredDiagnosticHandler);
1177                // doProcessing will have handled deferred diagnostics
1178            } finally {
1179                procEnvImpl.close();
1180            }
1181        } catch (CompletionFailure ex) {
1182            log.error("cant.access", ex.sym, ex.getDetailValue());
1183            if (deferredDiagnosticHandler != null) {
1184                deferredDiagnosticHandler.reportDeferredDiagnostics();
1185                log.popDiagnosticHandler(deferredDiagnosticHandler);
1186            }
1187        }
1188    }
1189
1190    private boolean unrecoverableError() {
1191        if (deferredDiagnosticHandler != null) {
1192            for (JCDiagnostic d: deferredDiagnosticHandler.getDiagnostics()) {
1193                if (d.getKind() == JCDiagnostic.Kind.ERROR && !d.isFlagSet(RECOVERABLE))
1194                    return true;
1195            }
1196        }
1197        return false;
1198    }
1199
1200    boolean explicitAnnotationProcessingRequested() {
1201        return
1202            explicitAnnotationProcessingRequested ||
1203            explicitAnnotationProcessingRequested(options);
1204    }
1205
1206    static boolean explicitAnnotationProcessingRequested(Options options) {
1207        return
1208            options.isSet(PROCESSOR) ||
1209            options.isSet(PROCESSORPATH) ||
1210            options.isSet(PROC, "only") ||
1211            options.isSet(XPRINT);
1212    }
1213
1214    public void setDeferredDiagnosticHandler(Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
1215        this.deferredDiagnosticHandler = deferredDiagnosticHandler;
1216    }
1217
1218    /**
1219     * Attribute a list of parse trees, such as found on the "todo" list.
1220     * Note that attributing classes may cause additional files to be
1221     * parsed and entered via the SourceCompleter.
1222     * Attribution of the entries in the list does not stop if any errors occur.
1223     * @returns a list of environments for attributd classes.
1224     */
1225    public Queue<Env<AttrContext>> attribute(Queue<Env<AttrContext>> envs) {
1226        ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1227        while (!envs.isEmpty())
1228            results.append(attribute(envs.remove()));
1229        return stopIfError(CompileState.ATTR, results);
1230    }
1231
1232    /**
1233     * Attribute a parse tree.
1234     * @returns the attributed parse tree
1235     */
1236    public Env<AttrContext> attribute(Env<AttrContext> env) {
1237        if (compileStates.isDone(env, CompileState.ATTR))
1238            return env;
1239
1240        if (verboseCompilePolicy)
1241            printNote("[attribute " + env.enclClass.sym + "]");
1242        if (verbose)
1243            log.printVerbose("checking.attribution", env.enclClass.sym);
1244
1245        if (!taskListener.isEmpty()) {
1246            TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym);
1247            taskListener.started(e);
1248        }
1249
1250        JavaFileObject prev = log.useSource(
1251                                  env.enclClass.sym.sourcefile != null ?
1252                                  env.enclClass.sym.sourcefile :
1253                                  env.toplevel.sourcefile);
1254        try {
1255            attr.attrib(env);
1256            if (errorCount() > 0 && !shouldStop(CompileState.ATTR)) {
1257                //if in fail-over mode, ensure that AST expression nodes
1258                //are correctly initialized (e.g. they have a type/symbol)
1259                attr.postAttr(env.tree);
1260            }
1261            compileStates.put(env, CompileState.ATTR);
1262            if (rootClasses != null && rootClasses.contains(env.enclClass)) {
1263                // This was a class that was explicitly supplied for compilation.
1264                // If we want to capture the public api of this class,
1265                // then now is a good time to do it.
1266                reportPublicApi(env.enclClass.sym);
1267            }
1268        }
1269        finally {
1270            log.useSource(prev);
1271        }
1272
1273        return env;
1274    }
1275
1276    /** Report the public api of a class that was supplied explicitly for compilation,
1277     *  for example on the command line to javac.
1278     * @param sym The symbol of the class.
1279     */
1280    public void reportPublicApi(ClassSymbol sym) {
1281       // Override to collect the reported public api.
1282    }
1283
1284    /**
1285     * Perform dataflow checks on attributed parse trees.
1286     * These include checks for definite assignment and unreachable statements.
1287     * If any errors occur, an empty list will be returned.
1288     * @returns the list of attributed parse trees
1289     */
1290    public Queue<Env<AttrContext>> flow(Queue<Env<AttrContext>> envs) {
1291        ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1292        for (Env<AttrContext> env: envs) {
1293            flow(env, results);
1294        }
1295        return stopIfError(CompileState.FLOW, results);
1296    }
1297
1298    /**
1299     * Perform dataflow checks on an attributed parse tree.
1300     */
1301    public Queue<Env<AttrContext>> flow(Env<AttrContext> env) {
1302        ListBuffer<Env<AttrContext>> results = new ListBuffer<>();
1303        flow(env, results);
1304        return stopIfError(CompileState.FLOW, results);
1305    }
1306
1307    /**
1308     * Perform dataflow checks on an attributed parse tree.
1309     */
1310    protected void flow(Env<AttrContext> env, Queue<Env<AttrContext>> results) {
1311        if (compileStates.isDone(env, CompileState.FLOW)) {
1312            results.add(env);
1313            return;
1314        }
1315
1316        try {
1317            if (shouldStop(CompileState.FLOW))
1318                return;
1319
1320            if (relax) {
1321                results.add(env);
1322                return;
1323            }
1324
1325            if (verboseCompilePolicy)
1326                printNote("[flow " + env.enclClass.sym + "]");
1327            JavaFileObject prev = log.useSource(
1328                                                env.enclClass.sym.sourcefile != null ?
1329                                                env.enclClass.sym.sourcefile :
1330                                                env.toplevel.sourcefile);
1331            try {
1332                make.at(Position.FIRSTPOS);
1333                TreeMaker localMake = make.forToplevel(env.toplevel);
1334                flow.analyzeTree(env, localMake);
1335                compileStates.put(env, CompileState.FLOW);
1336
1337                if (shouldStop(CompileState.FLOW))
1338                    return;
1339
1340                results.add(env);
1341            }
1342            finally {
1343                log.useSource(prev);
1344            }
1345        }
1346        finally {
1347            if (!taskListener.isEmpty()) {
1348                TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym);
1349                taskListener.finished(e);
1350            }
1351        }
1352    }
1353
1354    /**
1355     * Prepare attributed parse trees, in conjunction with their attribution contexts,
1356     * for source or code generation.
1357     * If any errors occur, an empty list will be returned.
1358     * @returns a list containing the classes to be generated
1359     */
1360    public Queue<Pair<Env<AttrContext>, JCClassDecl>> desugar(Queue<Env<AttrContext>> envs) {
1361        ListBuffer<Pair<Env<AttrContext>, JCClassDecl>> results = new ListBuffer<>();
1362        for (Env<AttrContext> env: envs)
1363            desugar(env, results);
1364        return stopIfError(CompileState.FLOW, results);
1365    }
1366
1367    HashMap<Env<AttrContext>, Queue<Pair<Env<AttrContext>, JCClassDecl>>> desugaredEnvs = new HashMap<>();
1368
1369    /**
1370     * Prepare attributed parse trees, in conjunction with their attribution contexts,
1371     * for source or code generation. If the file was not listed on the command line,
1372     * the current implicitSourcePolicy is taken into account.
1373     * The preparation stops as soon as an error is found.
1374     */
1375    protected void desugar(final Env<AttrContext> env, Queue<Pair<Env<AttrContext>, JCClassDecl>> results) {
1376        if (shouldStop(CompileState.TRANSTYPES))
1377            return;
1378
1379        if (implicitSourcePolicy == ImplicitSourcePolicy.NONE
1380                && !inputFiles.contains(env.toplevel.sourcefile)) {
1381            return;
1382        }
1383
1384        if (compileStates.isDone(env, CompileState.LOWER)) {
1385            results.addAll(desugaredEnvs.get(env));
1386            return;
1387        }
1388
1389        /**
1390         * Ensure that superclasses of C are desugared before C itself. This is
1391         * required for two reasons: (i) as erasure (TransTypes) destroys
1392         * information needed in flow analysis and (ii) as some checks carried
1393         * out during lowering require that all synthetic fields/methods have
1394         * already been added to C and its superclasses.
1395         */
1396        class ScanNested extends TreeScanner {
1397            Set<Env<AttrContext>> dependencies = new LinkedHashSet<>();
1398            protected boolean hasLambdas;
1399            @Override
1400            public void visitClassDef(JCClassDecl node) {
1401                Type st = types.supertype(node.sym.type);
1402                boolean envForSuperTypeFound = false;
1403                while (!envForSuperTypeFound && st.hasTag(CLASS)) {
1404                    ClassSymbol c = st.tsym.outermostClass();
1405                    Env<AttrContext> stEnv = enter.getEnv(c);
1406                    if (stEnv != null && env != stEnv) {
1407                        if (dependencies.add(stEnv)) {
1408                            boolean prevHasLambdas = hasLambdas;
1409                            try {
1410                                scan(stEnv.tree);
1411                            } finally {
1412                                /*
1413                                 * ignore any updates to hasLambdas made during
1414                                 * the nested scan, this ensures an initalized
1415                                 * LambdaToMethod is available only to those
1416                                 * classes that contain lambdas
1417                                 */
1418                                hasLambdas = prevHasLambdas;
1419                            }
1420                        }
1421                        envForSuperTypeFound = true;
1422                    }
1423                    st = types.supertype(st);
1424                }
1425                super.visitClassDef(node);
1426            }
1427            @Override
1428            public void visitLambda(JCLambda tree) {
1429                hasLambdas = true;
1430                super.visitLambda(tree);
1431            }
1432            @Override
1433            public void visitReference(JCMemberReference tree) {
1434                hasLambdas = true;
1435                super.visitReference(tree);
1436            }
1437        }
1438        ScanNested scanner = new ScanNested();
1439        scanner.scan(env.tree);
1440        for (Env<AttrContext> dep: scanner.dependencies) {
1441        if (!compileStates.isDone(dep, CompileState.FLOW))
1442            desugaredEnvs.put(dep, desugar(flow(attribute(dep))));
1443        }
1444
1445        //We need to check for error another time as more classes might
1446        //have been attributed and analyzed at this stage
1447        if (shouldStop(CompileState.TRANSTYPES))
1448            return;
1449
1450        if (verboseCompilePolicy)
1451            printNote("[desugar " + env.enclClass.sym + "]");
1452
1453        JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ?
1454                                  env.enclClass.sym.sourcefile :
1455                                  env.toplevel.sourcefile);
1456        try {
1457            //save tree prior to rewriting
1458            JCTree untranslated = env.tree;
1459
1460            make.at(Position.FIRSTPOS);
1461            TreeMaker localMake = make.forToplevel(env.toplevel);
1462
1463            if (env.tree.hasTag(JCTree.Tag.PACKAGEDEF)) {
1464                if (!(stubOutput || sourceOutput || printFlat)) {
1465                    if (shouldStop(CompileState.LOWER))
1466                        return;
1467                    List<JCTree> pdef = lower.translateTopLevelClass(env, env.tree, localMake);
1468                    if (pdef.head != null) {
1469                        Assert.check(pdef.tail.isEmpty());
1470                        results.add(new Pair<>(env, (JCClassDecl)pdef.head));
1471                    }
1472                }
1473                return;
1474            }
1475
1476            if (stubOutput) {
1477                //emit stub Java source file, only for compilation
1478                //units enumerated explicitly on the command line
1479                JCClassDecl cdef = (JCClassDecl)env.tree;
1480                if (untranslated instanceof JCClassDecl &&
1481                    rootClasses.contains((JCClassDecl)untranslated) &&
1482                    ((cdef.mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1483                     cdef.sym.packge().getQualifiedName() == names.java_lang)) {
1484                    results.add(new Pair<>(env, removeMethodBodies(cdef)));
1485                }
1486                return;
1487            }
1488
1489            if (shouldStop(CompileState.TRANSTYPES))
1490                return;
1491
1492            env.tree = transTypes.translateTopLevelClass(env.tree, localMake);
1493            compileStates.put(env, CompileState.TRANSTYPES);
1494
1495            if (source.allowLambda() && scanner.hasLambdas) {
1496                if (shouldStop(CompileState.UNLAMBDA))
1497                    return;
1498
1499                env.tree = LambdaToMethod.instance(context).translateTopLevelClass(env, env.tree, localMake);
1500                compileStates.put(env, CompileState.UNLAMBDA);
1501            }
1502
1503            if (shouldStop(CompileState.LOWER))
1504                return;
1505
1506            if (sourceOutput) {
1507                //emit standard Java source file, only for compilation
1508                //units enumerated explicitly on the command line
1509                JCClassDecl cdef = (JCClassDecl)env.tree;
1510                if (untranslated instanceof JCClassDecl &&
1511                    rootClasses.contains((JCClassDecl)untranslated)) {
1512                    results.add(new Pair<>(env, cdef));
1513                }
1514                return;
1515            }
1516
1517            //translate out inner classes
1518            List<JCTree> cdefs = lower.translateTopLevelClass(env, env.tree, localMake);
1519            compileStates.put(env, CompileState.LOWER);
1520
1521            if (shouldStop(CompileState.LOWER))
1522                return;
1523
1524            //generate code for each class
1525            for (List<JCTree> l = cdefs; l.nonEmpty(); l = l.tail) {
1526                JCClassDecl cdef = (JCClassDecl)l.head;
1527                results.add(new Pair<>(env, cdef));
1528            }
1529        }
1530        finally {
1531            log.useSource(prev);
1532        }
1533
1534    }
1535
1536    /** Generates the source or class file for a list of classes.
1537     * The decision to generate a source file or a class file is
1538     * based upon the compiler's options.
1539     * Generation stops if an error occurs while writing files.
1540     */
1541    public void generate(Queue<Pair<Env<AttrContext>, JCClassDecl>> queue) {
1542        generate(queue, null);
1543    }
1544
1545    public void generate(Queue<Pair<Env<AttrContext>, JCClassDecl>> queue, Queue<JavaFileObject> results) {
1546        if (shouldStop(CompileState.GENERATE))
1547            return;
1548
1549        boolean usePrintSource = (stubOutput || sourceOutput || printFlat);
1550
1551        for (Pair<Env<AttrContext>, JCClassDecl> x: queue) {
1552            Env<AttrContext> env = x.fst;
1553            JCClassDecl cdef = x.snd;
1554
1555            if (verboseCompilePolicy) {
1556                printNote("[generate "
1557                               + (usePrintSource ? " source" : "code")
1558                               + " " + cdef.sym + "]");
1559            }
1560
1561            if (!taskListener.isEmpty()) {
1562                TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
1563                taskListener.started(e);
1564            }
1565
1566            JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ?
1567                                      env.enclClass.sym.sourcefile :
1568                                      env.toplevel.sourcefile);
1569            try {
1570                JavaFileObject file;
1571                if (usePrintSource)
1572                    file = printSource(env, cdef);
1573                else {
1574                    if (fileManager.hasLocation(StandardLocation.NATIVE_HEADER_OUTPUT)
1575                            && jniWriter.needsHeader(cdef.sym)) {
1576                        jniWriter.write(cdef.sym);
1577                    }
1578                    file = genCode(env, cdef);
1579                }
1580                if (results != null && file != null)
1581                    results.add(file);
1582            } catch (IOException ex) {
1583                log.error(cdef.pos(), "class.cant.write",
1584                          cdef.sym, ex.getMessage());
1585                return;
1586            } finally {
1587                log.useSource(prev);
1588            }
1589
1590            if (!taskListener.isEmpty()) {
1591                TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
1592                taskListener.finished(e);
1593            }
1594        }
1595    }
1596
1597        // where
1598        Map<JCCompilationUnit, Queue<Env<AttrContext>>> groupByFile(Queue<Env<AttrContext>> envs) {
1599            // use a LinkedHashMap to preserve the order of the original list as much as possible
1600            Map<JCCompilationUnit, Queue<Env<AttrContext>>> map = new LinkedHashMap<>();
1601            for (Env<AttrContext> env: envs) {
1602                Queue<Env<AttrContext>> sublist = map.get(env.toplevel);
1603                if (sublist == null) {
1604                    sublist = new ListBuffer<>();
1605                    map.put(env.toplevel, sublist);
1606                }
1607                sublist.add(env);
1608            }
1609            return map;
1610        }
1611
1612        JCClassDecl removeMethodBodies(JCClassDecl cdef) {
1613            final boolean isInterface = (cdef.mods.flags & Flags.INTERFACE) != 0;
1614            class MethodBodyRemover extends TreeTranslator {
1615                @Override
1616                public void visitMethodDef(JCMethodDecl tree) {
1617                    tree.mods.flags &= ~Flags.SYNCHRONIZED;
1618                    for (JCVariableDecl vd : tree.params)
1619                        vd.mods.flags &= ~Flags.FINAL;
1620                    tree.body = null;
1621                    super.visitMethodDef(tree);
1622                }
1623                @Override
1624                public void visitVarDef(JCVariableDecl tree) {
1625                    if (tree.init != null && tree.init.type.constValue() == null)
1626                        tree.init = null;
1627                    super.visitVarDef(tree);
1628                }
1629                @Override
1630                public void visitClassDef(JCClassDecl tree) {
1631                    ListBuffer<JCTree> newdefs = new ListBuffer<>();
1632                    for (List<JCTree> it = tree.defs; it.tail != null; it = it.tail) {
1633                        JCTree t = it.head;
1634                        switch (t.getTag()) {
1635                        case CLASSDEF:
1636                            if (isInterface ||
1637                                (((JCClassDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1638                                (((JCClassDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCClassDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1639                                newdefs.append(t);
1640                            break;
1641                        case METHODDEF:
1642                            if (isInterface ||
1643                                (((JCMethodDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1644                                ((JCMethodDecl) t).sym.name == names.init ||
1645                                (((JCMethodDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCMethodDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1646                                newdefs.append(t);
1647                            break;
1648                        case VARDEF:
1649                            if (isInterface || (((JCVariableDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1650                                (((JCVariableDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCVariableDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1651                                newdefs.append(t);
1652                            break;
1653                        default:
1654                            break;
1655                        }
1656                    }
1657                    tree.defs = newdefs.toList();
1658                    super.visitClassDef(tree);
1659                }
1660            }
1661            MethodBodyRemover r = new MethodBodyRemover();
1662            return r.translate(cdef);
1663        }
1664
1665    public void reportDeferredDiagnostics() {
1666        if (errorCount() == 0
1667                && annotationProcessingOccurred
1668                && implicitSourceFilesRead
1669                && implicitSourcePolicy == ImplicitSourcePolicy.UNSET) {
1670            if (explicitAnnotationProcessingRequested())
1671                log.warning("proc.use.implicit");
1672            else
1673                log.warning("proc.use.proc.or.implicit");
1674        }
1675        chk.reportDeferredDiagnostics();
1676        if (log.compressedOutput) {
1677            log.mandatoryNote(null, "compressed.diags");
1678        }
1679    }
1680
1681    /** Close the compiler, flushing the logs
1682     */
1683    public void close() {
1684        rootClasses = null;
1685        finder = null;
1686        reader = null;
1687        make = null;
1688        writer = null;
1689        enter = null;
1690        if (todo != null)
1691            todo.clear();
1692        todo = null;
1693        parserFactory = null;
1694        syms = null;
1695        source = null;
1696        attr = null;
1697        chk = null;
1698        gen = null;
1699        flow = null;
1700        transTypes = null;
1701        lower = null;
1702        annotate = null;
1703        types = null;
1704
1705        log.flush();
1706        try {
1707            fileManager.flush();
1708        } catch (IOException e) {
1709            throw new Abort(e);
1710        } finally {
1711            if (names != null)
1712                names.dispose();
1713            names = null;
1714
1715            for (Closeable c: closeables) {
1716                try {
1717                    c.close();
1718                } catch (IOException e) {
1719                    // When javac uses JDK 7 as a baseline, this code would be
1720                    // better written to set any/all exceptions from all the
1721                    // Closeables as suppressed exceptions on the FatalError
1722                    // that is thrown.
1723                    JCDiagnostic msg = diagFactory.fragment("fatal.err.cant.close");
1724                    throw new FatalError(msg, e);
1725                }
1726            }
1727            closeables = List.nil();
1728        }
1729    }
1730
1731    protected void printNote(String lines) {
1732        log.printRawLines(Log.WriterKind.NOTICE, lines);
1733    }
1734
1735    /** Print numbers of errors and warnings.
1736     */
1737    public void printCount(String kind, int count) {
1738        if (count != 0) {
1739            String key;
1740            if (count == 1)
1741                key = "count." + kind;
1742            else
1743                key = "count." + kind + ".plural";
1744            log.printLines(WriterKind.ERROR, key, String.valueOf(count));
1745            log.flush(Log.WriterKind.ERROR);
1746        }
1747    }
1748
1749    private static long now() {
1750        return System.currentTimeMillis();
1751    }
1752
1753    private static long elapsed(long then) {
1754        return now() - then;
1755    }
1756
1757    public void newRound() {
1758        inputFiles.clear();
1759        todo.clear();
1760    }
1761}
1762