0001: /*
0002: * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package com.sun.tools.javac.main;
0027:
0028: import java.io.*;
0029: import java.util.HashSet;
0030: import java.util.LinkedHashMap;
0031: import java.util.Map;
0032: import java.util.MissingResourceException;
0033: import java.util.ResourceBundle;
0034: import java.util.Set;
0035: import java.util.logging.Handler;
0036: import java.util.logging.Level;
0037: import java.util.logging.Logger;
0038:
0039: import javax.tools.JavaFileManager;
0040: import javax.tools.JavaFileObject;
0041: import javax.tools.DiagnosticListener;
0042:
0043: import com.sun.source.util.TaskEvent;
0044: import com.sun.source.util.TaskListener;
0045:
0046: import com.sun.tools.javac.util.*;
0047: import com.sun.tools.javac.code.*;
0048: import com.sun.tools.javac.tree.*;
0049: import com.sun.tools.javac.parser.*;
0050: import com.sun.tools.javac.comp.*;
0051: import com.sun.tools.javac.jvm.*;
0052:
0053: import com.sun.tools.javac.code.Symbol.*;
0054: import com.sun.tools.javac.tree.JCTree.*;
0055:
0056: import com.sun.tools.javac.processing.*;
0057: import javax.annotation.processing.Processor;
0058:
0059: import static javax.tools.StandardLocation.CLASS_OUTPUT;
0060: import static com.sun.tools.javac.util.ListBuffer.lb;
0061:
0062: // TEMP, until we have a more efficient way to save doc comment info
0063: import com.sun.tools.javac.parser.DocCommentScanner;
0064:
0065: import javax.lang.model.SourceVersion;
0066:
0067: /** This class could be the main entry point for GJC when GJC is used as a
0068: * component in a larger software system. It provides operations to
0069: * construct a new compiler, and to run a new compiler on a set of source
0070: * files.
0071: *
0072: * <p><b>This is NOT part of any API supported by Sun Microsystems. If
0073: * you write code that depends on this, you do so at your own risk.
0074: * This code and its internal interfaces are subject to change or
0075: * deletion without notice.</b>
0076: */
0077: @Version("@(#)JavaCompiler.java 1.117 07/06/14")
0078: public class JavaCompiler implements ClassReader.SourceCompleter {
0079: /** The context key for the compiler. */
0080: protected static final Context.Key<JavaCompiler> compilerKey = new Context.Key<JavaCompiler>();
0081:
0082: /** Get the JavaCompiler instance for this context. */
0083: public static JavaCompiler instance(Context context) {
0084: JavaCompiler instance = context.get(compilerKey);
0085: if (instance == null)
0086: instance = new JavaCompiler(context);
0087: return instance;
0088: }
0089:
0090: /** The current version number as a string.
0091: */
0092: public static String version() {
0093: return version("release"); // mm.nn.oo[-milestone]
0094: }
0095:
0096: /** The current full version number as a string.
0097: */
0098: public static String fullVersion() {
0099: return version("full"); // mm.mm.oo[-milestone]-build
0100: }
0101:
0102: private static final String versionRBName = "com.sun.tools.javac.resources.version";
0103: private static ResourceBundle versionRB;
0104:
0105: private static String version(String key) {
0106: if (versionRB == null) {
0107: try {
0108: versionRB = ResourceBundle.getBundle(versionRBName);
0109: } catch (MissingResourceException e) {
0110: return Log.getLocalizedString(
0111: "version.resource.missing", System
0112: .getProperty("java.version"));
0113: }
0114: }
0115: try {
0116: return versionRB.getString(key);
0117: } catch (MissingResourceException e) {
0118: return Log.getLocalizedString("version.unknown", System
0119: .getProperty("java.version"));
0120: }
0121: }
0122:
0123: private static enum CompilePolicy {
0124: /*
0125: * Just attribute the parse trees
0126: */
0127: ATTR_ONLY,
0128:
0129: /*
0130: * Just attribute and do flow analysis on the parse trees.
0131: * This should catch most user errors.
0132: */
0133: CHECK_ONLY,
0134:
0135: /*
0136: * Attribute everything, then do flow analysis for everything,
0137: * then desugar everything, and only then generate output.
0138: * Means nothing is generated if there are any errors in any classes.
0139: */
0140: SIMPLE,
0141:
0142: /*
0143: * After attributing everything and doing flow analysis,
0144: * group the work by compilation unit.
0145: * Then, process the work for each compilation unit together.
0146: * Means nothing is generated for a compilation unit if the are any errors
0147: * in the compilation unit (or in any preceding compilation unit.)
0148: */
0149: BY_FILE,
0150:
0151: /*
0152: * Completely process each entry on the todo list in turn.
0153: * -- this is the same for 1.5.
0154: * Means output might be generated for some classes in a compilation unit
0155: * and not others.
0156: */
0157: BY_TODO;
0158:
0159: static CompilePolicy decode(String option) {
0160: if (option == null)
0161: return DEFAULT_COMPILE_POLICY;
0162: else if (option.equals("attr"))
0163: return ATTR_ONLY;
0164: else if (option.equals("check"))
0165: return CHECK_ONLY;
0166: else if (option.equals("simple"))
0167: return SIMPLE;
0168: else if (option.equals("byfile"))
0169: return BY_FILE;
0170: else if (option.equals("bytodo"))
0171: return BY_TODO;
0172: else
0173: return DEFAULT_COMPILE_POLICY;
0174: }
0175: }
0176:
0177: private static CompilePolicy DEFAULT_COMPILE_POLICY = CompilePolicy.BY_TODO;
0178:
0179: private static enum ImplicitSourcePolicy {
0180: /** Don't generate or process implicitly read source files. */
0181: NONE,
0182: /** Generate classes for implicitly read source files. */
0183: CLASS,
0184: /** Like CLASS, but generate warnings if annotation processing occurs */
0185: UNSET;
0186:
0187: static ImplicitSourcePolicy decode(String option) {
0188: if (option == null)
0189: return UNSET;
0190: else if (option.equals("none"))
0191: return NONE;
0192: else if (option.equals("class"))
0193: return CLASS;
0194: else
0195: return UNSET;
0196: }
0197: }
0198:
0199: /** The log to be used for error reporting.
0200: */
0201: public Log log;
0202:
0203: /** The tree factory module.
0204: */
0205: protected TreeMaker make;
0206:
0207: /** The class reader.
0208: */
0209: protected ClassReader reader;
0210:
0211: /** The class writer.
0212: */
0213: protected ClassWriter writer;
0214:
0215: /** The module for the symbol table entry phases.
0216: */
0217: protected Enter enter;
0218:
0219: /** The symbol table.
0220: */
0221: protected Symtab syms;
0222:
0223: /** The language version.
0224: */
0225: protected Source source;
0226:
0227: /** The module for code generation.
0228: */
0229: protected Gen gen;
0230:
0231: /** The name table.
0232: */
0233: protected Name.Table names;
0234:
0235: /** The attributor.
0236: */
0237: protected Attr attr;
0238:
0239: /** The attributor.
0240: */
0241: protected Check chk;
0242:
0243: /** The flow analyzer.
0244: */
0245: protected Flow flow;
0246:
0247: /** The type eraser.
0248: */
0249: TransTypes transTypes;
0250:
0251: /** The syntactic sugar desweetener.
0252: */
0253: Lower lower;
0254:
0255: /** The annotation annotator.
0256: */
0257: protected Annotate annotate;
0258:
0259: /** Force a completion failure on this name
0260: */
0261: protected final Name completionFailureName;
0262:
0263: /** Type utilities.
0264: */
0265: protected Types types;
0266:
0267: /** Access to file objects.
0268: */
0269: protected JavaFileManager fileManager;
0270:
0271: /** Factory for parsers.
0272: */
0273: protected Parser.Factory parserFactory;
0274:
0275: /** Optional listener for progress events
0276: */
0277: protected TaskListener taskListener;
0278:
0279: /**
0280: * Annotation processing may require and provide a new instance
0281: * of the compiler to be used for the analyze and generate phases.
0282: */
0283: protected JavaCompiler delegateCompiler;
0284:
0285: /**
0286: * Flag set if any annotation processing occurred.
0287: **/
0288: protected boolean annotationProcessingOccurred;
0289:
0290: /**
0291: * Flag set if any implicit source files read.
0292: **/
0293: protected boolean implicitSourceFilesRead;
0294:
0295: protected Context context;
0296:
0297: /** Construct a new compiler using a shared context.
0298: */
0299: public JavaCompiler(final Context context) {
0300: this .context = context;
0301: context.put(compilerKey, this );
0302:
0303: // if fileManager not already set, register the JavacFileManager to be used
0304: if (context.get(JavaFileManager.class) == null)
0305: JavacFileManager.preRegister(context);
0306:
0307: names = Name.Table.instance(context);
0308: log = Log.instance(context);
0309: reader = ClassReader.instance(context);
0310: make = TreeMaker.instance(context);
0311: writer = ClassWriter.instance(context);
0312: enter = Enter.instance(context);
0313: todo = Todo.instance(context);
0314:
0315: fileManager = context.get(JavaFileManager.class);
0316: parserFactory = Parser.Factory.instance(context);
0317:
0318: try {
0319: // catch completion problems with predefineds
0320: syms = Symtab.instance(context);
0321: } catch (CompletionFailure ex) {
0322: // inlined Check.completionError as it is not initialized yet
0323: log.error("cant.access", ex.sym, ex.errmsg);
0324: if (ex instanceof ClassReader.BadClassFile)
0325: throw new Abort();
0326: }
0327: source = Source.instance(context);
0328: attr = Attr.instance(context);
0329: chk = Check.instance(context);
0330: gen = Gen.instance(context);
0331: flow = Flow.instance(context);
0332: transTypes = TransTypes.instance(context);
0333: lower = Lower.instance(context);
0334: annotate = Annotate.instance(context);
0335: types = Types.instance(context);
0336: taskListener = context.get(TaskListener.class);
0337:
0338: reader.sourceCompleter = this ;
0339:
0340: Options options = Options.instance(context);
0341:
0342: verbose = options.get("-verbose") != null;
0343: sourceOutput = options.get("-printsource") != null; // used to be -s
0344: stubOutput = options.get("-stubs") != null;
0345: relax = options.get("-relax") != null;
0346: printFlat = options.get("-printflat") != null;
0347: attrParseOnly = options.get("-attrparseonly") != null;
0348: encoding = options.get("-encoding");
0349: lineDebugInfo = options.get("-g:") == null
0350: || options.get("-g:lines") != null;
0351: genEndPos = options.get("-Xjcov") != null
0352: || context.get(DiagnosticListener.class) != null;
0353: devVerbose = options.get("dev") != null;
0354: processPcks = options.get("process.packages") != null;
0355:
0356: verboseCompilePolicy = options.get("verboseCompilePolicy") != null;
0357:
0358: if (attrParseOnly)
0359: compilePolicy = CompilePolicy.ATTR_ONLY;
0360: else
0361: compilePolicy = CompilePolicy.decode(options
0362: .get("compilePolicy"));
0363:
0364: implicitSourcePolicy = ImplicitSourcePolicy.decode(options
0365: .get("-implicit"));
0366:
0367: completionFailureName = (options.get("failcomplete") != null) ? names
0368: .fromString(options.get("failcomplete"))
0369: : null;
0370: }
0371:
0372: /* Switches:
0373: */
0374:
0375: /** Verbose output.
0376: */
0377: public boolean verbose;
0378:
0379: /** Emit plain Java source files rather than class files.
0380: */
0381: public boolean sourceOutput;
0382:
0383: /** Emit stub source files rather than class files.
0384: */
0385: public boolean stubOutput;
0386:
0387: /** Generate attributed parse tree only.
0388: */
0389: public boolean attrParseOnly;
0390:
0391: /** Switch: relax some constraints for producing the jsr14 prototype.
0392: */
0393: boolean relax;
0394:
0395: /** Debug switch: Emit Java sources after inner class flattening.
0396: */
0397: public boolean printFlat;
0398:
0399: /** The encoding to be used for source input.
0400: */
0401: public String encoding;
0402:
0403: /** Generate code with the LineNumberTable attribute for debugging
0404: */
0405: public boolean lineDebugInfo;
0406:
0407: /** Switch: should we store the ending positions?
0408: */
0409: public boolean genEndPos;
0410:
0411: /** Switch: should we debug ignored exceptions
0412: */
0413: protected boolean devVerbose;
0414:
0415: /** Switch: should we (annotation) process packages as well
0416: */
0417: protected boolean processPcks;
0418:
0419: /** Switch: is annotation processing requested explitly via
0420: * CompilationTask.setProcessors?
0421: */
0422: protected boolean explicitAnnotationProcessingRequested = false;
0423:
0424: /**
0425: * The policy for the order in which to perform the compilation
0426: */
0427: protected CompilePolicy compilePolicy;
0428:
0429: /**
0430: * The policy for what to do with implicitly read source files
0431: */
0432: protected ImplicitSourcePolicy implicitSourcePolicy;
0433:
0434: /**
0435: * Report activity related to compilePolicy
0436: */
0437: public boolean verboseCompilePolicy;
0438:
0439: /** A queue of all as yet unattributed classes.
0440: */
0441: public Todo todo;
0442:
0443: private Set<Env<AttrContext>> deferredSugar = new HashSet<Env<AttrContext>>();
0444:
0445: /** The set of currently compiled inputfiles, needed to ensure
0446: * we don't accidentally overwrite an input file when -s is set.
0447: * initialized by `compile'.
0448: */
0449: protected Set<JavaFileObject> inputFiles = new HashSet<JavaFileObject>();
0450:
0451: /** The number of errors reported so far.
0452: */
0453: public int errorCount() {
0454: if (delegateCompiler != null && delegateCompiler != this )
0455: return delegateCompiler.errorCount();
0456: else
0457: return log.nerrors;
0458: }
0459:
0460: protected final <T> List<T> stopIfError(ListBuffer<T> listBuffer) {
0461: if (errorCount() == 0)
0462: return listBuffer.toList();
0463: else
0464: return List.nil();
0465: }
0466:
0467: protected final <T> List<T> stopIfError(List<T> list) {
0468: if (errorCount() == 0)
0469: return list;
0470: else
0471: return List.nil();
0472: }
0473:
0474: /** The number of warnings reported so far.
0475: */
0476: public int warningCount() {
0477: if (delegateCompiler != null && delegateCompiler != this )
0478: return delegateCompiler.warningCount();
0479: else
0480: return log.nwarnings;
0481: }
0482:
0483: /** Whether or not any parse errors have occurred.
0484: */
0485: public boolean parseErrors() {
0486: return parseErrors;
0487: }
0488:
0489: protected Scanner.Factory getScannerFactory() {
0490: return Scanner.Factory.instance(context);
0491: }
0492:
0493: /** Try to open input stream with given name.
0494: * Report an error if this fails.
0495: * @param filename The file name of the input stream to be opened.
0496: */
0497: public CharSequence readSource(JavaFileObject filename) {
0498: try {
0499: inputFiles.add(filename);
0500: return filename.getCharContent(false);
0501: } catch (IOException e) {
0502: log.error("error.reading.file", filename, e
0503: .getLocalizedMessage());
0504: return null;
0505: }
0506: }
0507:
0508: /** Parse contents of input stream.
0509: * @param filename The name of the file from which input stream comes.
0510: * @param input The input stream to be parsed.
0511: */
0512: protected JCCompilationUnit parse(JavaFileObject filename,
0513: CharSequence content) {
0514: long msec = now();
0515: JCCompilationUnit tree = make
0516: .TopLevel(List.<JCTree.JCAnnotation> nil(), null, List
0517: .<JCTree> nil());
0518: if (content != null) {
0519: if (verbose) {
0520: printVerbose("parsing.started", filename);
0521: }
0522: if (taskListener != null) {
0523: TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE,
0524: filename);
0525: taskListener.started(e);
0526: }
0527: int initialErrorCount = log.nerrors;
0528: Scanner scanner = getScannerFactory().newScanner(content);
0529: Parser parser = parserFactory.newParser(scanner,
0530: keepComments(), genEndPos);
0531: tree = parser.compilationUnit();
0532: parseErrors |= (log.nerrors > initialErrorCount);
0533: if (lineDebugInfo) {
0534: tree.lineMap = scanner.getLineMap();
0535: }
0536: if (verbose) {
0537: printVerbose("parsing.done", Long
0538: .toString(elapsed(msec)));
0539: }
0540: }
0541:
0542: tree.sourcefile = filename;
0543:
0544: if (content != null && taskListener != null) {
0545: TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree);
0546: taskListener.finished(e);
0547: }
0548:
0549: return tree;
0550: }
0551:
0552: // where
0553: public boolean keepComments = false;
0554:
0555: protected boolean keepComments() {
0556: return keepComments || sourceOutput || stubOutput;
0557: }
0558:
0559: /** Parse contents of file.
0560: * @param filename The name of the file to be parsed.
0561: */
0562: @Deprecated
0563: public JCTree.JCCompilationUnit parse(String filename)
0564: throws IOException {
0565: JavacFileManager fm = (JavacFileManager) fileManager;
0566: return parse(fm
0567: .getJavaFileObjectsFromStrings(List.of(filename))
0568: .iterator().next());
0569: }
0570:
0571: /** Parse contents of file.
0572: * @param filename The name of the file to be parsed.
0573: */
0574: public JCTree.JCCompilationUnit parse(JavaFileObject filename) {
0575: JavaFileObject prev = log.useSource(filename);
0576: try {
0577: JCTree.JCCompilationUnit t = parse(filename,
0578: readSource(filename));
0579: if (t.endPositions != null)
0580: log.setEndPosTable(filename, t.endPositions);
0581: return t;
0582: } finally {
0583: log.useSource(prev);
0584: }
0585: }
0586:
0587: /** Resolve an identifier.
0588: * @param name The identifier to resolve
0589: */
0590: public Symbol resolveIdent(String name) {
0591: if (name.equals(""))
0592: return syms.errSymbol;
0593: JavaFileObject prev = log.useSource(null);
0594: try {
0595: JCExpression tree = null;
0596: for (String s : name.split("\\.", -1)) {
0597: if (!SourceVersion.isIdentifier(s)) // TODO: check for keywords
0598: return syms.errSymbol;
0599: tree = (tree == null) ? make.Ident(names.fromString(s))
0600: : make.Select(tree, names.fromString(s));
0601: }
0602: JCCompilationUnit toplevel = make.TopLevel(List
0603: .<JCTree.JCAnnotation> nil(), null, List
0604: .<JCTree> nil());
0605: toplevel.packge = syms.unnamedPackage;
0606: return attr.attribIdent(tree, toplevel);
0607: } finally {
0608: log.useSource(prev);
0609: }
0610: }
0611:
0612: /** Emit plain Java source for a class.
0613: * @param env The attribution environment of the outermost class
0614: * containing this class.
0615: * @param cdef The class definition to be printed.
0616: */
0617: JavaFileObject printSource(Env<AttrContext> env, JCClassDecl cdef)
0618: throws IOException {
0619: JavaFileObject outFile = fileManager.getJavaFileForOutput(
0620: CLASS_OUTPUT, cdef.sym.flatname.toString(),
0621: JavaFileObject.Kind.SOURCE, null);
0622: if (inputFiles.contains(outFile)) {
0623: log.error(cdef.pos(), "source.cant.overwrite.input.file",
0624: outFile);
0625: return null;
0626: } else {
0627: BufferedWriter out = new BufferedWriter(outFile
0628: .openWriter());
0629: try {
0630: new Pretty(out, true).printUnit(env.toplevel, cdef);
0631: if (verbose)
0632: printVerbose("wrote.file", outFile);
0633: } finally {
0634: out.close();
0635: }
0636: return outFile;
0637: }
0638: }
0639:
0640: /** Generate code and emit a class file for a given class
0641: * @param env The attribution environment of the outermost class
0642: * containing this class.
0643: * @param cdef The class definition from which code is generated.
0644: */
0645: JavaFileObject genCode(Env<AttrContext> env, JCClassDecl cdef)
0646: throws IOException {
0647: try {
0648: if (gen.genClass(env, cdef))
0649: return writer.writeClass(cdef.sym);
0650: } catch (ClassWriter.PoolOverflow ex) {
0651: log.error(cdef.pos(), "limit.pool");
0652: } catch (ClassWriter.StringOverflow ex) {
0653: log.error(cdef.pos(), "limit.string.overflow", ex.value
0654: .substring(0, 20));
0655: } catch (CompletionFailure ex) {
0656: chk.completionError(cdef.pos(), ex);
0657: }
0658: return null;
0659: }
0660:
0661: /** Complete compiling a source file that has been accessed
0662: * by the class file reader.
0663: * @param c The class the source file of which needs to be compiled.
0664: * @param filename The name of the source file.
0665: * @param f An input stream that reads the source file.
0666: */
0667: public void complete(ClassSymbol c) throws CompletionFailure {
0668: // System.err.println("completing " + c);//DEBUG
0669: if (completionFailureName == c.fullname) {
0670: throw new CompletionFailure(c,
0671: "user-selected completion failure by class name");
0672: }
0673: JCCompilationUnit tree;
0674: JavaFileObject filename = c.classfile;
0675: JavaFileObject prev = log.useSource(filename);
0676:
0677: try {
0678: tree = parse(filename, filename.getCharContent(false));
0679: } catch (IOException e) {
0680: log.error("error.reading.file", filename, e);
0681: tree = make.TopLevel(List.<JCTree.JCAnnotation> nil(),
0682: null, List.<JCTree> nil());
0683: } finally {
0684: log.useSource(prev);
0685: }
0686:
0687: if (taskListener != null) {
0688: TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
0689: taskListener.started(e);
0690: }
0691:
0692: enter.complete(List.of(tree), c);
0693:
0694: if (taskListener != null) {
0695: TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
0696: taskListener.finished(e);
0697: }
0698:
0699: if (enter.getEnv(c) == null) {
0700: boolean isPkgInfo = tree.sourcefile.isNameCompatible(
0701: "package-info", JavaFileObject.Kind.SOURCE);
0702: if (isPkgInfo) {
0703: if (enter.getEnv(tree.packge) == null) {
0704: String msg = log.getLocalizedString(
0705: "file.does.not.contain.package", c
0706: .location());
0707: throw new ClassReader.BadClassFile(c, filename, msg);
0708: }
0709: } else {
0710: throw new ClassReader.BadClassFile(c, filename,
0711: log
0712: .getLocalizedString(
0713: "file.doesnt.contain.class",
0714: c.fullname));
0715: }
0716: }
0717:
0718: implicitSourceFilesRead = true;
0719: }
0720:
0721: /** Track when the JavaCompiler has been used to compile something. */
0722: private boolean hasBeenUsed = false;
0723: private long start_msec = 0;
0724: public long elapsed_msec = 0;
0725:
0726: /** Track whether any errors occurred while parsing source text. */
0727: private boolean parseErrors = false;
0728:
0729: public void compile(List<JavaFileObject> sourceFileObject)
0730: throws Throwable {
0731: compile(sourceFileObject, List.<String> nil(), null);
0732: }
0733:
0734: /**
0735: * Main method: compile a list of files, return all compiled classes
0736: *
0737: * @param sourceFileObjects file objects to be compiled
0738: * @param classnames class names to process for annotations
0739: * @param processors user provided annotation processors to bypass
0740: * discovery, {@code null} means that no processors were provided
0741: */
0742: public void compile(List<JavaFileObject> sourceFileObjects,
0743: List<String> classnames,
0744: Iterable<? extends Processor> processors)
0745: throws IOException // TODO: temp, from JavacProcessingEnvironment
0746: {
0747: if (processors != null && processors.iterator().hasNext())
0748: explicitAnnotationProcessingRequested = true;
0749: // as a JavaCompiler can only be used once, throw an exception if
0750: // it has been used before.
0751: if (hasBeenUsed)
0752: throw new AssertionError("attempt to reuse JavaCompiler");
0753: hasBeenUsed = true;
0754:
0755: start_msec = now();
0756: try {
0757: initProcessAnnotations(processors);
0758:
0759: // These method calls must be chained to avoid memory leaks
0760: delegateCompiler = processAnnotations(
0761: enterTrees(stopIfError(parseFiles(sourceFileObjects))),
0762: classnames);
0763:
0764: delegateCompiler.compile2();
0765: delegateCompiler.close();
0766: elapsed_msec = delegateCompiler.elapsed_msec;
0767: } catch (Abort ex) {
0768: if (devVerbose)
0769: ex.printStackTrace();
0770: }
0771: }
0772:
0773: /**
0774: * The phases following annotation processing: attribution,
0775: * desugar, and finally code generation.
0776: */
0777: private void compile2() {
0778: try {
0779: switch (compilePolicy) {
0780: case ATTR_ONLY:
0781: attribute(todo);
0782: break;
0783:
0784: case CHECK_ONLY:
0785: flow(attribute(todo));
0786: break;
0787:
0788: case SIMPLE:
0789: generate(desugar(flow(attribute(todo))));
0790: break;
0791:
0792: case BY_FILE:
0793: for (List<Env<AttrContext>> list : groupByFile(
0794: flow(attribute(todo))).values())
0795: generate(desugar(list));
0796: break;
0797:
0798: case BY_TODO:
0799: while (todo.nonEmpty())
0800: generate(desugar(flow(attribute(todo.next()))));
0801: break;
0802:
0803: default:
0804: assert false : "unknown compile policy";
0805: }
0806: } catch (Abort ex) {
0807: if (devVerbose)
0808: ex.printStackTrace();
0809: }
0810:
0811: if (verbose) {
0812: elapsed_msec = elapsed(start_msec);
0813: ;
0814: printVerbose("total", Long.toString(elapsed_msec));
0815: }
0816:
0817: reportDeferredDiagnostics();
0818:
0819: if (!log.hasDiagnosticListener()) {
0820: printCount("error", errorCount());
0821: printCount("warn", warningCount());
0822: }
0823: }
0824:
0825: private List<JCClassDecl> rootClasses;
0826:
0827: /**
0828: * Parses a list of files.
0829: */
0830: public List<JCCompilationUnit> parseFiles(
0831: List<JavaFileObject> fileObjects) throws IOException {
0832: if (errorCount() > 0)
0833: return List.nil();
0834:
0835: //parse all files
0836: ListBuffer<JCCompilationUnit> trees = lb();
0837: for (JavaFileObject fileObject : fileObjects)
0838: trees.append(parse(fileObject));
0839: return trees.toList();
0840: }
0841:
0842: /**
0843: * Enter the symbols found in a list of parse trees.
0844: * As a side-effect, this puts elements on the "todo" list.
0845: * Also stores a list of all top level classes in rootClasses.
0846: */
0847: public List<JCCompilationUnit> enterTrees(
0848: List<JCCompilationUnit> roots) {
0849: //enter symbols for all files
0850: if (taskListener != null) {
0851: for (JCCompilationUnit unit : roots) {
0852: TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
0853: taskListener.started(e);
0854: }
0855: }
0856:
0857: enter.main(roots);
0858:
0859: if (taskListener != null) {
0860: for (JCCompilationUnit unit : roots) {
0861: TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
0862: taskListener.finished(e);
0863: }
0864: }
0865:
0866: //If generating source, remember the classes declared in
0867: //the original compilation units listed on the command line.
0868: if (sourceOutput || stubOutput) {
0869: ListBuffer<JCClassDecl> cdefs = lb();
0870: for (JCCompilationUnit unit : roots) {
0871: for (List<JCTree> defs = unit.defs; defs.nonEmpty(); defs = defs.tail) {
0872: if (defs.head instanceof JCClassDecl)
0873: cdefs.append((JCClassDecl) defs.head);
0874: }
0875: }
0876: rootClasses = cdefs.toList();
0877: }
0878: return roots;
0879: }
0880:
0881: /**
0882: * Set to true to enable skeleton annotation processing code.
0883: * Currently, we assume this variable will be replaced more
0884: * advanced logic to figure out if annotation processing is
0885: * needed.
0886: */
0887: boolean processAnnotations = false;
0888:
0889: /**
0890: * Object to handle annotation processing.
0891: */
0892: JavacProcessingEnvironment procEnvImpl = null;
0893:
0894: /**
0895: * Check if we should process annotations.
0896: * If so, and if no scanner is yet registered, then set up the DocCommentScanner
0897: * to catch doc comments, and set keepComments so the parser records them in
0898: * the compilation unit.
0899: *
0900: * @param processors user provided annotation processors to bypass
0901: * discovery, {@code null} means that no processors were provided
0902: */
0903: public void initProcessAnnotations(
0904: Iterable<? extends Processor> processors) {
0905: // Process annotations if processing is not disabled and there
0906: // is at least one Processor available.
0907: Options options = Options.instance(context);
0908: if (options.get("-proc:none") != null) {
0909: processAnnotations = false;
0910: } else if (procEnvImpl == null) {
0911: procEnvImpl = new JavacProcessingEnvironment(context,
0912: processors);
0913: processAnnotations = procEnvImpl.atLeastOneProcessor();
0914:
0915: if (processAnnotations) {
0916: if (context.get(Scanner.Factory.scannerFactoryKey) == null)
0917: DocCommentScanner.Factory.preRegister(context);
0918: options.put("save-parameter-names",
0919: "save-parameter-names");
0920: reader.saveParameterNames = true;
0921: keepComments = true;
0922: if (taskListener != null)
0923: taskListener.started(new TaskEvent(
0924: TaskEvent.Kind.ANNOTATION_PROCESSING));
0925:
0926: } else { // free resources
0927: procEnvImpl.close();
0928: }
0929: }
0930: }
0931:
0932: // TODO: called by JavacTaskImpl
0933: public JavaCompiler processAnnotations(List<JCCompilationUnit> roots)
0934: throws IOException {
0935: return processAnnotations(roots, List.<String> nil());
0936: }
0937:
0938: /**
0939: * Process any anotations found in the specifed compilation units.
0940: * @param roots a list of compilation units
0941: * @return an instance of the compiler in which to complete the compilation
0942: */
0943: public JavaCompiler processAnnotations(
0944: List<JCCompilationUnit> roots, List<String> classnames)
0945: throws IOException { // TODO: see TEMP note in JavacProcessingEnvironment
0946: if (errorCount() != 0) {
0947: // Errors were encountered. If todo is empty, then the
0948: // encountered errors were parse errors. Otherwise, the
0949: // errors were found during the enter phase which should
0950: // be ignored when processing annotations.
0951:
0952: if (todo.isEmpty())
0953: return this ;
0954: }
0955:
0956: // ASSERT: processAnnotations and procEnvImpl should have been set up by
0957: // by initProcessAnnotations
0958:
0959: // NOTE: The !classnames.isEmpty() checks should be refactored to Main.
0960:
0961: if (!processAnnotations) {
0962: // If there are no annotation processors present, and
0963: // annotation processing is to occur with compilation,
0964: // emit a warning.
0965: Options options = Options.instance(context);
0966: if (options.get("-proc:only") != null) {
0967: log.warning("proc.proc-only.requested.no.procs");
0968: todo.clear();
0969: }
0970: // If not processing annotations, classnames must be empty
0971: if (!classnames.isEmpty()) {
0972: log
0973: .error(
0974: "proc.no.explicit.annotation.processing.requested",
0975: classnames);
0976: }
0977: return this ; // continue regular compilation
0978: }
0979:
0980: try {
0981: List<ClassSymbol> classSymbols = List.nil();
0982: List<PackageSymbol> pckSymbols = List.nil();
0983: if (!classnames.isEmpty()) {
0984: // Check for explicit request for annotation
0985: // processing
0986: if (!explicitAnnotationProcessingRequested()) {
0987: log
0988: .error(
0989: "proc.no.explicit.annotation.processing.requested",
0990: classnames);
0991: return this ; // TODO: Will this halt compilation?
0992: } else {
0993: boolean errors = false;
0994: for (String nameStr : classnames) {
0995: Symbol sym = resolveIdent(nameStr);
0996: if (sym == null
0997: || (sym.kind == Kinds.PCK && !processPcks)) {
0998: log.error("proc.cant.find.class", nameStr);
0999: errors = true;
1000: continue;
1001: }
1002: try {
1003: if (sym.kind == Kinds.PCK)
1004: sym.complete();
1005: if (sym.exists()) {
1006: Name name = names.fromString(nameStr);
1007: if (sym.kind == Kinds.PCK)
1008: pckSymbols = pckSymbols
1009: .prepend((PackageSymbol) sym);
1010: else
1011: classSymbols = classSymbols
1012: .prepend((ClassSymbol) sym);
1013: continue;
1014: }
1015: assert sym.kind == Kinds.PCK;
1016: log.warning("proc.package.does.not.exist",
1017: nameStr);
1018: pckSymbols = pckSymbols
1019: .prepend((PackageSymbol) sym);
1020: } catch (CompletionFailure e) {
1021: log.error("proc.cant.find.class", nameStr);
1022: errors = true;
1023: continue;
1024: }
1025: }
1026: if (errors)
1027: return this ;
1028: }
1029: }
1030: JavaCompiler c = procEnvImpl.doProcessing(context, roots,
1031: classSymbols, pckSymbols);
1032: if (c != this )
1033: annotationProcessingOccurred = c.annotationProcessingOccurred = true;
1034: return c;
1035: } catch (CompletionFailure ex) {
1036: log.error("cant.access", ex.sym, ex.errmsg);
1037: return this ;
1038:
1039: }
1040: }
1041:
1042: boolean explicitAnnotationProcessingRequested() {
1043: Options options = Options.instance(context);
1044: return explicitAnnotationProcessingRequested
1045: || options.get("-processor") != null
1046: || options.get("-processorpath") != null
1047: || options.get("-proc:only") != null
1048: || options.get("-Xprint") != null;
1049: }
1050:
1051: /**
1052: * Attribute a list of parse trees, such as found on the "todo" list.
1053: * Note that attributing classes may cause additional files to be
1054: * parsed and entered via the SourceCompleter.
1055: * Attribution of the entries in the list does not stop if any errors occur.
1056: * @returns a list of environments for attributd classes.
1057: */
1058: public List<Env<AttrContext>> attribute(
1059: ListBuffer<Env<AttrContext>> envs) {
1060: ListBuffer<Env<AttrContext>> results = lb();
1061: while (envs.nonEmpty())
1062: results.append(attribute(envs.next()));
1063: return results.toList();
1064: }
1065:
1066: /**
1067: * Attribute a parse tree.
1068: * @returns the attributed parse tree
1069: */
1070: public Env<AttrContext> attribute(Env<AttrContext> env) {
1071: if (verboseCompilePolicy)
1072: log.printLines(log.noticeWriter, "[attribute "
1073: + env.enclClass.sym + "]");
1074: if (verbose)
1075: printVerbose("checking.attribution", env.enclClass.sym);
1076:
1077: if (taskListener != null) {
1078: TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE,
1079: env.toplevel, env.enclClass.sym);
1080: taskListener.started(e);
1081: }
1082:
1083: JavaFileObject prev = log
1084: .useSource(env.enclClass.sym.sourcefile != null ? env.enclClass.sym.sourcefile
1085: : env.toplevel.sourcefile);
1086: try {
1087: attr.attribClass(env.tree.pos(), env.enclClass.sym);
1088: } finally {
1089: log.useSource(prev);
1090: }
1091:
1092: return env;
1093: }
1094:
1095: /**
1096: * Perform dataflow checks on attributed parse trees.
1097: * These include checks for definite assignment and unreachable statements.
1098: * If any errors occur, an empty list will be returned.
1099: * @returns the list of attributed parse trees
1100: */
1101: public List<Env<AttrContext>> flow(List<Env<AttrContext>> envs) {
1102: ListBuffer<Env<AttrContext>> results = lb();
1103: for (List<Env<AttrContext>> l = envs; l.nonEmpty(); l = l.tail) {
1104: flow(l.head, results);
1105: }
1106: return stopIfError(results);
1107: }
1108:
1109: /**
1110: * Perform dataflow checks on an attributed parse tree.
1111: */
1112: public List<Env<AttrContext>> flow(Env<AttrContext> env) {
1113: ListBuffer<Env<AttrContext>> results = lb();
1114: flow(env, results);
1115: return stopIfError(results);
1116: }
1117:
1118: /**
1119: * Perform dataflow checks on an attributed parse tree.
1120: */
1121: protected void flow(Env<AttrContext> env,
1122: ListBuffer<Env<AttrContext>> results) {
1123: try {
1124: if (errorCount() > 0)
1125: return;
1126:
1127: if (relax || deferredSugar.contains(env)) {
1128: results.append(env);
1129: return;
1130: }
1131:
1132: if (verboseCompilePolicy)
1133: log.printLines(log.noticeWriter, "[flow "
1134: + env.enclClass.sym + "]");
1135: JavaFileObject prev = log
1136: .useSource(env.enclClass.sym.sourcefile != null ? env.enclClass.sym.sourcefile
1137: : env.toplevel.sourcefile);
1138: try {
1139: make.at(Position.FIRSTPOS);
1140: TreeMaker localMake = make.forToplevel(env.toplevel);
1141: flow.analyzeTree(env.tree, localMake);
1142:
1143: if (errorCount() > 0)
1144: return;
1145:
1146: results.append(env);
1147: } finally {
1148: log.useSource(prev);
1149: }
1150: } finally {
1151: if (taskListener != null) {
1152: TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE,
1153: env.toplevel, env.enclClass.sym);
1154: taskListener.finished(e);
1155: }
1156: }
1157: }
1158:
1159: /**
1160: * Prepare attributed parse trees, in conjunction with their attribution contexts,
1161: * for source or code generation.
1162: * If any errors occur, an empty list will be returned.
1163: * @returns a list containing the classes to be generated
1164: */
1165: public List<Pair<Env<AttrContext>, JCClassDecl>> desugar(
1166: List<Env<AttrContext>> envs) {
1167: ListBuffer<Pair<Env<AttrContext>, JCClassDecl>> results = lb();
1168: for (List<Env<AttrContext>> l = envs; l.nonEmpty(); l = l.tail)
1169: desugar(l.head, results);
1170: return stopIfError(results);
1171: }
1172:
1173: /**
1174: * Prepare attributed parse trees, in conjunction with their attribution contexts,
1175: * for source or code generation. If the file was not listed on the command line,
1176: * the current implicitSourcePolicy is taken into account.
1177: * The preparation stops as soon as an error is found.
1178: */
1179: protected void desugar(Env<AttrContext> env,
1180: ListBuffer<Pair<Env<AttrContext>, JCClassDecl>> results) {
1181: if (errorCount() > 0)
1182: return;
1183:
1184: if (implicitSourcePolicy == ImplicitSourcePolicy.NONE
1185: && !inputFiles.contains(env.toplevel.sourcefile)) {
1186: return;
1187: }
1188:
1189: if (desugarLater(env)) {
1190: if (verboseCompilePolicy)
1191: log.printLines(log.noticeWriter, "[defer "
1192: + env.enclClass.sym + "]");
1193: todo.append(env);
1194: return;
1195: }
1196: deferredSugar.remove(env);
1197:
1198: if (verboseCompilePolicy)
1199: log.printLines(log.noticeWriter, "[desugar "
1200: + env.enclClass.sym + "]");
1201:
1202: JavaFileObject prev = log
1203: .useSource(env.enclClass.sym.sourcefile != null ? env.enclClass.sym.sourcefile
1204: : env.toplevel.sourcefile);
1205: try {
1206: //save tree prior to rewriting
1207: JCTree untranslated = env.tree;
1208:
1209: make.at(Position.FIRSTPOS);
1210: TreeMaker localMake = make.forToplevel(env.toplevel);
1211:
1212: if (env.tree instanceof JCCompilationUnit) {
1213: if (!(stubOutput || sourceOutput || printFlat)) {
1214: List<JCTree> pdef = lower.translateTopLevelClass(
1215: env, env.tree, localMake);
1216: if (pdef.head != null) {
1217: assert pdef.tail.isEmpty();
1218: results
1219: .append(new Pair<Env<AttrContext>, JCClassDecl>(
1220: env, (JCClassDecl) pdef.head));
1221: }
1222: }
1223: return;
1224: }
1225:
1226: if (stubOutput) {
1227: //emit stub Java source file, only for compilation
1228: //units enumerated explicitly on the command line
1229: JCClassDecl cdef = (JCClassDecl) env.tree;
1230: if (untranslated instanceof JCClassDecl
1231: && rootClasses
1232: .contains((JCClassDecl) untranslated)
1233: && ((cdef.mods.flags & (Flags.PROTECTED | Flags.PUBLIC)) != 0 || cdef.sym
1234: .packge().getQualifiedName() == names.java_lang)) {
1235: results
1236: .append(new Pair<Env<AttrContext>, JCClassDecl>(
1237: env, removeMethodBodies(cdef)));
1238: }
1239: return;
1240: }
1241:
1242: env.tree = transTypes.translateTopLevelClass(env.tree,
1243: localMake);
1244:
1245: if (errorCount() != 0)
1246: return;
1247:
1248: if (sourceOutput) {
1249: //emit standard Java source file, only for compilation
1250: //units enumerated explicitly on the command line
1251: JCClassDecl cdef = (JCClassDecl) env.tree;
1252: if (untranslated instanceof JCClassDecl
1253: && rootClasses
1254: .contains((JCClassDecl) untranslated)) {
1255: results
1256: .append(new Pair<Env<AttrContext>, JCClassDecl>(
1257: env, cdef));
1258: }
1259: return;
1260: }
1261:
1262: //translate out inner classes
1263: List<JCTree> cdefs = lower.translateTopLevelClass(env,
1264: env.tree, localMake);
1265:
1266: if (errorCount() != 0)
1267: return;
1268:
1269: //generate code for each class
1270: for (List<JCTree> l = cdefs; l.nonEmpty(); l = l.tail) {
1271: JCClassDecl cdef = (JCClassDecl) l.head;
1272: results.append(new Pair<Env<AttrContext>, JCClassDecl>(
1273: env, cdef));
1274: }
1275: } finally {
1276: log.useSource(prev);
1277: }
1278:
1279: }
1280:
1281: /**
1282: * Determine if a class needs to be desugared later. As erasure
1283: * (TransTypes) destroys information needed in flow analysis, we
1284: * need to ensure that supertypes are translated before derived
1285: * types are translated.
1286: */
1287: public boolean desugarLater(final Env<AttrContext> env) {
1288: if (compilePolicy == CompilePolicy.BY_FILE)
1289: return false;
1290: if (!devVerbose && deferredSugar.contains(env))
1291: // guarantee that compiler terminates
1292: return false;
1293: class ScanNested extends TreeScanner {
1294: Set<Symbol> externalSupers = new HashSet<Symbol>();
1295:
1296: public void visitClassDef(JCClassDecl node) {
1297: Type st = types.super type(node.sym.type);
1298: if (st.tag == TypeTags.CLASS) {
1299: ClassSymbol c = st.tsym.outermostClass();
1300: Env<AttrContext> stEnv = enter.getEnv(c);
1301: if (stEnv != null && env != stEnv)
1302: externalSupers.add(st.tsym);
1303: }
1304: super .visitClassDef(node);
1305: }
1306: }
1307: ScanNested scanner = new ScanNested();
1308: scanner.scan(env.tree);
1309: if (scanner.externalSupers.isEmpty())
1310: return false;
1311: if (!deferredSugar.add(env) && devVerbose) {
1312: throw new AssertionError(env.enclClass.sym
1313: + " was deferred, "
1314: + "second time has these external super types "
1315: + scanner.externalSupers);
1316: }
1317: return true;
1318: }
1319:
1320: /** Generates the source or class file for a list of classes.
1321: * The decision to generate a source file or a class file is
1322: * based upon the compiler's options.
1323: * Generation stops if an error occurs while writing files.
1324: */
1325: public void generate(List<Pair<Env<AttrContext>, JCClassDecl>> list) {
1326: generate(list, null);
1327: }
1328:
1329: public void generate(
1330: List<Pair<Env<AttrContext>, JCClassDecl>> list,
1331: ListBuffer<JavaFileObject> results) {
1332: boolean usePrintSource = (stubOutput || sourceOutput || printFlat);
1333:
1334: for (List<Pair<Env<AttrContext>, JCClassDecl>> l = list; l
1335: .nonEmpty(); l = l.tail) {
1336: Pair<Env<AttrContext>, JCClassDecl> x = l.head;
1337: Env<AttrContext> env = x.fst;
1338: JCClassDecl cdef = x.snd;
1339:
1340: if (verboseCompilePolicy) {
1341: log.printLines(log.noticeWriter, "[generate "
1342: + (usePrintSource ? " source" : "code") + " "
1343: + env.enclClass.sym + "]");
1344: }
1345:
1346: if (taskListener != null) {
1347: TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE,
1348: env.toplevel, cdef.sym);
1349: taskListener.started(e);
1350: }
1351:
1352: JavaFileObject prev = log
1353: .useSource(env.enclClass.sym.sourcefile != null ? env.enclClass.sym.sourcefile
1354: : env.toplevel.sourcefile);
1355: try {
1356: JavaFileObject file;
1357: if (usePrintSource)
1358: file = printSource(env, cdef);
1359: else
1360: file = genCode(env, cdef);
1361: if (results != null && file != null)
1362: results.append(file);
1363: } catch (IOException ex) {
1364: log.error(cdef.pos(), "class.cant.write", cdef.sym, ex
1365: .getMessage());
1366: return;
1367: } finally {
1368: log.useSource(prev);
1369: }
1370:
1371: if (taskListener != null) {
1372: TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE,
1373: env.toplevel, cdef.sym);
1374: taskListener.finished(e);
1375: }
1376: }
1377: }
1378:
1379: // where
1380: Map<JCCompilationUnit, List<Env<AttrContext>>> groupByFile(
1381: List<Env<AttrContext>> list) {
1382: // use a LinkedHashMap to preserve the order of the original list as much as possible
1383: Map<JCCompilationUnit, List<Env<AttrContext>>> map = new LinkedHashMap<JCCompilationUnit, List<Env<AttrContext>>>();
1384: Set<JCCompilationUnit> fixupSet = new HashSet<JCTree.JCCompilationUnit>();
1385: for (List<Env<AttrContext>> l = list; l.nonEmpty(); l = l.tail) {
1386: Env<AttrContext> env = l.head;
1387: List<Env<AttrContext>> sublist = map.get(env.toplevel);
1388: if (sublist == null)
1389: sublist = List.of(env);
1390: else {
1391: // this builds the list for the file in reverse order, so make a note
1392: // to reverse the list before returning.
1393: sublist = sublist.prepend(env);
1394: fixupSet.add(env.toplevel);
1395: }
1396: map.put(env.toplevel, sublist);
1397: }
1398: // fixup any lists that need reversing back to the correct order
1399: for (JCTree.JCCompilationUnit tree : fixupSet)
1400: map.put(tree, map.get(tree).reverse());
1401: return map;
1402: }
1403:
1404: JCClassDecl removeMethodBodies(JCClassDecl cdef) {
1405: final boolean isInterface = (cdef.mods.flags & Flags.INTERFACE) != 0;
1406: class MethodBodyRemover extends TreeTranslator {
1407: public void visitMethodDef(JCMethodDecl tree) {
1408: tree.mods.flags &= ~Flags.SYNCHRONIZED;
1409: for (JCVariableDecl vd : tree.params)
1410: vd.mods.flags &= ~Flags.FINAL;
1411: tree.body = null;
1412: super .visitMethodDef(tree);
1413: }
1414:
1415: public void visitVarDef(JCVariableDecl tree) {
1416: if (tree.init != null
1417: && tree.init.type.constValue() == null)
1418: tree.init = null;
1419: super .visitVarDef(tree);
1420: }
1421:
1422: public void visitClassDef(JCClassDecl tree) {
1423: ListBuffer<JCTree> newdefs = lb();
1424: for (List<JCTree> it = tree.defs; it.tail != null; it = it.tail) {
1425: JCTree t = it.head;
1426: switch (t.getTag()) {
1427: case JCTree.CLASSDEF:
1428: if (isInterface
1429: || (((JCClassDecl) t).mods.flags & (Flags.PROTECTED | Flags.PUBLIC)) != 0
1430: || (((JCClassDecl) t).mods.flags & (Flags.PRIVATE)) == 0
1431: && ((JCClassDecl) t).sym.packge()
1432: .getQualifiedName() == names.java_lang)
1433: newdefs.append(t);
1434: break;
1435: case JCTree.METHODDEF:
1436: if (isInterface
1437: || (((JCMethodDecl) t).mods.flags & (Flags.PROTECTED | Flags.PUBLIC)) != 0
1438: || ((JCMethodDecl) t).sym.name == names.init
1439: || (((JCMethodDecl) t).mods.flags & (Flags.PRIVATE)) == 0
1440: && ((JCMethodDecl) t).sym.packge()
1441: .getQualifiedName() == names.java_lang)
1442: newdefs.append(t);
1443: break;
1444: case JCTree.VARDEF:
1445: if (isInterface
1446: || (((JCVariableDecl) t).mods.flags & (Flags.PROTECTED | Flags.PUBLIC)) != 0
1447: || (((JCVariableDecl) t).mods.flags & (Flags.PRIVATE)) == 0
1448: && ((JCVariableDecl) t).sym.packge()
1449: .getQualifiedName() == names.java_lang)
1450: newdefs.append(t);
1451: break;
1452: default:
1453: break;
1454: }
1455: }
1456: tree.defs = newdefs.toList();
1457: super .visitClassDef(tree);
1458: }
1459: }
1460: MethodBodyRemover r = new MethodBodyRemover();
1461: return r.translate(cdef);
1462: }
1463:
1464: public void reportDeferredDiagnostics() {
1465: if (annotationProcessingOccurred && implicitSourceFilesRead
1466: && implicitSourcePolicy == ImplicitSourcePolicy.UNSET) {
1467: if (explicitAnnotationProcessingRequested())
1468: log.warning("proc.use.implicit");
1469: else
1470: log.warning("proc.use.proc.or.implicit");
1471: }
1472: chk.reportDeferredDiagnostics();
1473: }
1474:
1475: /** Close the compiler, flushing the logs
1476: */
1477: public void close() {
1478: close(true);
1479: }
1480:
1481: private void close(boolean disposeNames) {
1482: rootClasses = null;
1483: reader = null;
1484: make = null;
1485: writer = null;
1486: enter = null;
1487: if (todo != null)
1488: todo.clear();
1489: todo = null;
1490: parserFactory = null;
1491: syms = null;
1492: source = null;
1493: attr = null;
1494: chk = null;
1495: gen = null;
1496: flow = null;
1497: transTypes = null;
1498: lower = null;
1499: annotate = null;
1500: types = null;
1501:
1502: log.flush();
1503: try {
1504: fileManager.flush();
1505: } catch (IOException e) {
1506: throw new Abort(e);
1507: } finally {
1508: if (names != null && disposeNames)
1509: names.dispose();
1510: names = null;
1511: }
1512: }
1513:
1514: /** Output for "-verbose" option.
1515: * @param key The key to look up the correct internationalized string.
1516: * @param arg An argument for substitution into the output string.
1517: */
1518: protected void printVerbose(String key, Object arg) {
1519: Log.printLines(log.noticeWriter, log.getLocalizedString(
1520: "verbose." + key, arg));
1521: }
1522:
1523: /** Print numbers of errors and warnings.
1524: */
1525: protected void printCount(String kind, int count) {
1526: if (count != 0) {
1527: String text;
1528: if (count == 1)
1529: text = log.getLocalizedString("count." + kind, String
1530: .valueOf(count));
1531: else
1532: text = log.getLocalizedString("count." + kind
1533: + ".plural", String.valueOf(count));
1534: Log.printLines(log.errWriter, text);
1535: log.errWriter.flush();
1536: }
1537: }
1538:
1539: private static long now() {
1540: return System.currentTimeMillis();
1541: }
1542:
1543: private static long elapsed(long then) {
1544: return now() - then;
1545: }
1546:
1547: public void initRound(JavaCompiler prev) {
1548: keepComments = prev.keepComments;
1549: start_msec = prev.start_msec;
1550: hasBeenUsed = true;
1551: }
1552:
1553: public static void enableLogging() {
1554: Logger logger = Logger.getLogger(com.sun.tools.javac.Main.class
1555: .getPackage().getName());
1556: logger.setLevel(Level.ALL);
1557: for (Handler h : logger.getParent().getHandlers()) {
1558: h.setLevel(Level.ALL);
1559: }
1560:
1561: }
1562: }
|