src/share/classes/com/sun/tools/javac/main/JavaCompiler.java

Thu, 25 Oct 2012 11:09:36 -0700

author
jjg
date
Thu, 25 Oct 2012 11:09:36 -0700
changeset 1374
c002fdee76fd
parent 1358
fc123bdeddb8
child 1380
a65971893c50
permissions
-rw-r--r--

7200915: convert TypeTags from a series of small ints to an enum
Reviewed-by: jjg, mcimadamore
Contributed-by: vicente.romero@oracle.com

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

mercurial