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