Wed, 12 Mar 2008 13:06:00 -0700
6668794: javac puts localized text in raw diagnostics
6668796: bad diagnostic "bad class file" given for source files
Summary: Replace internal use of localized text with JCDiagnostic fragments; fix diagnostic for bad source file
Reviewed-by: mcimadamore
1 /*
2 * Copyright 1999-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
26 package com.sun.tools.javac.main;
28 import java.io.*;
29 import java.util.HashSet;
30 import java.util.LinkedHashMap;
31 import java.util.Map;
32 import java.util.MissingResourceException;
33 import java.util.ResourceBundle;
34 import java.util.Set;
35 import java.util.logging.Handler;
36 import java.util.logging.Level;
37 import java.util.logging.Logger;
39 import javax.tools.JavaFileManager;
40 import javax.tools.JavaFileObject;
41 import javax.tools.DiagnosticListener;
43 import com.sun.source.util.TaskEvent;
44 import com.sun.source.util.TaskListener;
46 import com.sun.tools.javac.util.*;
47 import com.sun.tools.javac.code.*;
48 import com.sun.tools.javac.tree.*;
49 import com.sun.tools.javac.parser.*;
50 import com.sun.tools.javac.comp.*;
51 import com.sun.tools.javac.jvm.*;
53 import com.sun.tools.javac.code.Symbol.*;
54 import com.sun.tools.javac.tree.JCTree.*;
56 import com.sun.tools.javac.processing.*;
57 import javax.annotation.processing.Processor;
59 import static javax.tools.StandardLocation.CLASS_OUTPUT;
60 import static com.sun.tools.javac.util.ListBuffer.lb;
62 // TEMP, until we have a more efficient way to save doc comment info
63 import com.sun.tools.javac.parser.DocCommentScanner;
65 import javax.lang.model.SourceVersion;
67 /** This class could be the main entry point for GJC when GJC is used as a
68 * component in a larger software system. It provides operations to
69 * construct a new compiler, and to run a new compiler on a set of source
70 * files.
71 *
72 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
73 * you write code that depends on this, you do so at your own risk.
74 * This code and its internal interfaces are subject to change or
75 * deletion without notice.</b>
76 */
77 public class JavaCompiler implements ClassReader.SourceCompleter {
78 /** The context key for the compiler. */
79 protected static final Context.Key<JavaCompiler> compilerKey =
80 new Context.Key<JavaCompiler>();
82 /** Get the JavaCompiler instance for this context. */
83 public static JavaCompiler instance(Context context) {
84 JavaCompiler instance = context.get(compilerKey);
85 if (instance == null)
86 instance = new JavaCompiler(context);
87 return instance;
88 }
90 /** The current version number as a string.
91 */
92 public static String version() {
93 return version("release"); // mm.nn.oo[-milestone]
94 }
96 /** The current full version number as a string.
97 */
98 public static String fullVersion() {
99 return version("full"); // mm.mm.oo[-milestone]-build
100 }
102 private static final String versionRBName = "com.sun.tools.javac.resources.version";
103 private static ResourceBundle versionRB;
105 private static String version(String key) {
106 if (versionRB == null) {
107 try {
108 versionRB = ResourceBundle.getBundle(versionRBName);
109 } catch (MissingResourceException e) {
110 return Log.getLocalizedString("version.resource.missing", System.getProperty("java.version"));
111 }
112 }
113 try {
114 return versionRB.getString(key);
115 }
116 catch (MissingResourceException e) {
117 return Log.getLocalizedString("version.unknown", System.getProperty("java.version"));
118 }
119 }
121 private static enum CompilePolicy {
122 /*
123 * Just attribute the parse trees
124 */
125 ATTR_ONLY,
127 /*
128 * Just attribute and do flow analysis on the parse trees.
129 * This should catch most user errors.
130 */
131 CHECK_ONLY,
133 /*
134 * Attribute everything, then do flow analysis for everything,
135 * then desugar everything, and only then generate output.
136 * Means nothing is generated if there are any errors in any classes.
137 */
138 SIMPLE,
140 /*
141 * After attributing everything and doing flow analysis,
142 * group the work by compilation unit.
143 * Then, process the work for each compilation unit together.
144 * Means nothing is generated for a compilation unit if the are any errors
145 * in the compilation unit (or in any preceding compilation unit.)
146 */
147 BY_FILE,
149 /*
150 * Completely process each entry on the todo list in turn.
151 * -- this is the same for 1.5.
152 * Means output might be generated for some classes in a compilation unit
153 * and not others.
154 */
155 BY_TODO;
157 static CompilePolicy decode(String option) {
158 if (option == null)
159 return DEFAULT_COMPILE_POLICY;
160 else if (option.equals("attr"))
161 return ATTR_ONLY;
162 else if (option.equals("check"))
163 return CHECK_ONLY;
164 else if (option.equals("simple"))
165 return SIMPLE;
166 else if (option.equals("byfile"))
167 return BY_FILE;
168 else if (option.equals("bytodo"))
169 return BY_TODO;
170 else
171 return DEFAULT_COMPILE_POLICY;
172 }
173 }
175 private static CompilePolicy DEFAULT_COMPILE_POLICY = CompilePolicy.BY_TODO;
177 private static enum ImplicitSourcePolicy {
178 /** Don't generate or process implicitly read source files. */
179 NONE,
180 /** Generate classes for implicitly read source files. */
181 CLASS,
182 /** Like CLASS, but generate warnings if annotation processing occurs */
183 UNSET;
185 static ImplicitSourcePolicy decode(String option) {
186 if (option == null)
187 return UNSET;
188 else if (option.equals("none"))
189 return NONE;
190 else if (option.equals("class"))
191 return CLASS;
192 else
193 return UNSET;
194 }
195 }
197 /** The log to be used for error reporting.
198 */
199 public Log log;
201 /** Factory for creating diagnostic objects
202 */
203 JCDiagnostic.Factory diagFactory;
205 /** The tree factory module.
206 */
207 protected TreeMaker make;
209 /** The class reader.
210 */
211 protected ClassReader reader;
213 /** The class writer.
214 */
215 protected ClassWriter writer;
217 /** The module for the symbol table entry phases.
218 */
219 protected Enter enter;
221 /** The symbol table.
222 */
223 protected Symtab syms;
225 /** The language version.
226 */
227 protected Source source;
229 /** The module for code generation.
230 */
231 protected Gen gen;
233 /** The name table.
234 */
235 protected Name.Table names;
237 /** The attributor.
238 */
239 protected Attr attr;
241 /** The attributor.
242 */
243 protected Check chk;
245 /** The flow analyzer.
246 */
247 protected Flow flow;
249 /** The type eraser.
250 */
251 TransTypes transTypes;
253 /** The syntactic sugar desweetener.
254 */
255 Lower lower;
257 /** The annotation annotator.
258 */
259 protected Annotate annotate;
261 /** Force a completion failure on this name
262 */
263 protected final Name completionFailureName;
265 /** Type utilities.
266 */
267 protected Types types;
269 /** Access to file objects.
270 */
271 protected JavaFileManager fileManager;
273 /** Factory for parsers.
274 */
275 protected Parser.Factory parserFactory;
277 /** Optional listener for progress events
278 */
279 protected TaskListener taskListener;
281 /**
282 * Annotation processing may require and provide a new instance
283 * of the compiler to be used for the analyze and generate phases.
284 */
285 protected JavaCompiler delegateCompiler;
287 /**
288 * Flag set if any annotation processing occurred.
289 **/
290 protected boolean annotationProcessingOccurred;
292 /**
293 * Flag set if any implicit source files read.
294 **/
295 protected boolean implicitSourceFilesRead;
297 protected Context context;
299 /** Construct a new compiler using a shared context.
300 */
301 public JavaCompiler(final Context context) {
302 this.context = context;
303 context.put(compilerKey, this);
305 // if fileManager not already set, register the JavacFileManager to be used
306 if (context.get(JavaFileManager.class) == null)
307 JavacFileManager.preRegister(context);
309 names = Name.Table.instance(context);
310 log = Log.instance(context);
311 diagFactory = JCDiagnostic.Factory.instance(context);
312 reader = ClassReader.instance(context);
313 make = TreeMaker.instance(context);
314 writer = ClassWriter.instance(context);
315 enter = Enter.instance(context);
316 todo = Todo.instance(context);
318 fileManager = context.get(JavaFileManager.class);
319 parserFactory = Parser.Factory.instance(context);
321 try {
322 // catch completion problems with predefineds
323 syms = Symtab.instance(context);
324 } catch (CompletionFailure ex) {
325 // inlined Check.completionError as it is not initialized yet
326 log.error("cant.access", ex.sym, ex.getDetailValue());
327 if (ex instanceof ClassReader.BadClassFile)
328 throw new Abort();
329 }
330 source = Source.instance(context);
331 attr = Attr.instance(context);
332 chk = Check.instance(context);
333 gen = Gen.instance(context);
334 flow = Flow.instance(context);
335 transTypes = TransTypes.instance(context);
336 lower = Lower.instance(context);
337 annotate = Annotate.instance(context);
338 types = Types.instance(context);
339 taskListener = context.get(TaskListener.class);
341 reader.sourceCompleter = this;
343 Options options = Options.instance(context);
345 verbose = options.get("-verbose") != null;
346 sourceOutput = options.get("-printsource") != null; // used to be -s
347 stubOutput = options.get("-stubs") != null;
348 relax = options.get("-relax") != null;
349 printFlat = options.get("-printflat") != null;
350 attrParseOnly = options.get("-attrparseonly") != null;
351 encoding = options.get("-encoding");
352 lineDebugInfo = options.get("-g:") == null ||
353 options.get("-g:lines") != null;
354 genEndPos = options.get("-Xjcov") != null ||
355 context.get(DiagnosticListener.class) != null;
356 devVerbose = options.get("dev") != null;
357 processPcks = options.get("process.packages") != null;
359 verboseCompilePolicy = options.get("verboseCompilePolicy") != null;
361 if (attrParseOnly)
362 compilePolicy = CompilePolicy.ATTR_ONLY;
363 else
364 compilePolicy = CompilePolicy.decode(options.get("compilePolicy"));
366 implicitSourcePolicy = ImplicitSourcePolicy.decode(options.get("-implicit"));
368 completionFailureName =
369 (options.get("failcomplete") != null)
370 ? names.fromString(options.get("failcomplete"))
371 : null;
372 }
374 /* Switches:
375 */
377 /** Verbose output.
378 */
379 public boolean verbose;
381 /** Emit plain Java source files rather than class files.
382 */
383 public boolean sourceOutput;
385 /** Emit stub source files rather than class files.
386 */
387 public boolean stubOutput;
389 /** Generate attributed parse tree only.
390 */
391 public boolean attrParseOnly;
393 /** Switch: relax some constraints for producing the jsr14 prototype.
394 */
395 boolean relax;
397 /** Debug switch: Emit Java sources after inner class flattening.
398 */
399 public boolean printFlat;
401 /** The encoding to be used for source input.
402 */
403 public String encoding;
405 /** Generate code with the LineNumberTable attribute for debugging
406 */
407 public boolean lineDebugInfo;
409 /** Switch: should we store the ending positions?
410 */
411 public boolean genEndPos;
413 /** Switch: should we debug ignored exceptions
414 */
415 protected boolean devVerbose;
417 /** Switch: should we (annotation) process packages as well
418 */
419 protected boolean processPcks;
421 /** Switch: is annotation processing requested explitly via
422 * CompilationTask.setProcessors?
423 */
424 protected boolean explicitAnnotationProcessingRequested = false;
426 /**
427 * The policy for the order in which to perform the compilation
428 */
429 protected CompilePolicy compilePolicy;
431 /**
432 * The policy for what to do with implicitly read source files
433 */
434 protected ImplicitSourcePolicy implicitSourcePolicy;
436 /**
437 * Report activity related to compilePolicy
438 */
439 public boolean verboseCompilePolicy;
441 /** A queue of all as yet unattributed classes.
442 */
443 public Todo todo;
445 private Set<Env<AttrContext>> deferredSugar = new HashSet<Env<AttrContext>>();
447 /** The set of currently compiled inputfiles, needed to ensure
448 * we don't accidentally overwrite an input file when -s is set.
449 * initialized by `compile'.
450 */
451 protected Set<JavaFileObject> inputFiles = new HashSet<JavaFileObject>();
453 /** The number of errors reported so far.
454 */
455 public int errorCount() {
456 if (delegateCompiler != null && delegateCompiler != this)
457 return delegateCompiler.errorCount();
458 else
459 return log.nerrors;
460 }
462 protected final <T> List<T> stopIfError(ListBuffer<T> listBuffer) {
463 if (errorCount() == 0)
464 return listBuffer.toList();
465 else
466 return List.nil();
467 }
469 protected final <T> List<T> stopIfError(List<T> list) {
470 if (errorCount() == 0)
471 return list;
472 else
473 return List.nil();
474 }
476 /** The number of warnings reported so far.
477 */
478 public int warningCount() {
479 if (delegateCompiler != null && delegateCompiler != this)
480 return delegateCompiler.warningCount();
481 else
482 return log.nwarnings;
483 }
485 /** Whether or not any parse errors have occurred.
486 */
487 public boolean parseErrors() {
488 return parseErrors;
489 }
491 protected Scanner.Factory getScannerFactory() {
492 return Scanner.Factory.instance(context);
493 }
495 /** Try to open input stream with given name.
496 * Report an error if this fails.
497 * @param filename The file name of the input stream to be opened.
498 */
499 public CharSequence readSource(JavaFileObject filename) {
500 try {
501 inputFiles.add(filename);
502 return filename.getCharContent(false);
503 } catch (IOException e) {
504 log.error("error.reading.file", filename, e.getLocalizedMessage());
505 return null;
506 }
507 }
509 /** Parse contents of input stream.
510 * @param filename The name of the file from which input stream comes.
511 * @param input The input stream to be parsed.
512 */
513 protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) {
514 long msec = now();
515 JCCompilationUnit tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(),
516 null, List.<JCTree>nil());
517 if (content != null) {
518 if (verbose) {
519 printVerbose("parsing.started", filename);
520 }
521 if (taskListener != null) {
522 TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, filename);
523 taskListener.started(e);
524 }
525 int initialErrorCount = log.nerrors;
526 Scanner scanner = getScannerFactory().newScanner(content);
527 Parser parser = parserFactory.newParser(scanner, keepComments(), genEndPos);
528 tree = parser.compilationUnit();
529 parseErrors |= (log.nerrors > initialErrorCount);
530 if (lineDebugInfo) {
531 tree.lineMap = scanner.getLineMap();
532 }
533 if (verbose) {
534 printVerbose("parsing.done", Long.toString(elapsed(msec)));
535 }
536 }
538 tree.sourcefile = filename;
540 if (content != null && taskListener != null) {
541 TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree);
542 taskListener.finished(e);
543 }
545 return tree;
546 }
547 // where
548 public boolean keepComments = false;
549 protected boolean keepComments() {
550 return keepComments || sourceOutput || stubOutput;
551 }
554 /** Parse contents of file.
555 * @param filename The name of the file to be parsed.
556 */
557 @Deprecated
558 public JCTree.JCCompilationUnit parse(String filename) throws IOException {
559 JavacFileManager fm = (JavacFileManager)fileManager;
560 return parse(fm.getJavaFileObjectsFromStrings(List.of(filename)).iterator().next());
561 }
563 /** Parse contents of file.
564 * @param filename The name of the file to be parsed.
565 */
566 public JCTree.JCCompilationUnit parse(JavaFileObject filename) {
567 JavaFileObject prev = log.useSource(filename);
568 try {
569 JCTree.JCCompilationUnit t = parse(filename, readSource(filename));
570 if (t.endPositions != null)
571 log.setEndPosTable(filename, t.endPositions);
572 return t;
573 } finally {
574 log.useSource(prev);
575 }
576 }
578 /** Resolve an identifier.
579 * @param name The identifier to resolve
580 */
581 public Symbol resolveIdent(String name) {
582 if (name.equals(""))
583 return syms.errSymbol;
584 JavaFileObject prev = log.useSource(null);
585 try {
586 JCExpression tree = null;
587 for (String s : name.split("\\.", -1)) {
588 if (!SourceVersion.isIdentifier(s)) // TODO: check for keywords
589 return syms.errSymbol;
590 tree = (tree == null) ? make.Ident(names.fromString(s))
591 : make.Select(tree, names.fromString(s));
592 }
593 JCCompilationUnit toplevel =
594 make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil());
595 toplevel.packge = syms.unnamedPackage;
596 return attr.attribIdent(tree, toplevel);
597 } finally {
598 log.useSource(prev);
599 }
600 }
602 /** Emit plain Java source for a class.
603 * @param env The attribution environment of the outermost class
604 * containing this class.
605 * @param cdef The class definition to be printed.
606 */
607 JavaFileObject printSource(Env<AttrContext> env, JCClassDecl cdef) throws IOException {
608 JavaFileObject outFile
609 = fileManager.getJavaFileForOutput(CLASS_OUTPUT,
610 cdef.sym.flatname.toString(),
611 JavaFileObject.Kind.SOURCE,
612 null);
613 if (inputFiles.contains(outFile)) {
614 log.error(cdef.pos(), "source.cant.overwrite.input.file", outFile);
615 return null;
616 } else {
617 BufferedWriter out = new BufferedWriter(outFile.openWriter());
618 try {
619 new Pretty(out, true).printUnit(env.toplevel, cdef);
620 if (verbose)
621 printVerbose("wrote.file", outFile);
622 } finally {
623 out.close();
624 }
625 return outFile;
626 }
627 }
629 /** Generate code and emit a class file for a given class
630 * @param env The attribution environment of the outermost class
631 * containing this class.
632 * @param cdef The class definition from which code is generated.
633 */
634 JavaFileObject genCode(Env<AttrContext> env, JCClassDecl cdef) throws IOException {
635 try {
636 if (gen.genClass(env, cdef))
637 return writer.writeClass(cdef.sym);
638 } catch (ClassWriter.PoolOverflow ex) {
639 log.error(cdef.pos(), "limit.pool");
640 } catch (ClassWriter.StringOverflow ex) {
641 log.error(cdef.pos(), "limit.string.overflow",
642 ex.value.substring(0, 20));
643 } catch (CompletionFailure ex) {
644 chk.completionError(cdef.pos(), ex);
645 }
646 return null;
647 }
649 /** Complete compiling a source file that has been accessed
650 * by the class file reader.
651 * @param c The class the source file of which needs to be compiled.
652 * @param filename The name of the source file.
653 * @param f An input stream that reads the source file.
654 */
655 public void complete(ClassSymbol c) throws CompletionFailure {
656 // System.err.println("completing " + c);//DEBUG
657 if (completionFailureName == c.fullname) {
658 throw new CompletionFailure(c, "user-selected completion failure by class name");
659 }
660 JCCompilationUnit tree;
661 JavaFileObject filename = c.classfile;
662 JavaFileObject prev = log.useSource(filename);
664 try {
665 tree = parse(filename, filename.getCharContent(false));
666 } catch (IOException e) {
667 log.error("error.reading.file", filename, e);
668 tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil());
669 } finally {
670 log.useSource(prev);
671 }
673 if (taskListener != null) {
674 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
675 taskListener.started(e);
676 }
678 enter.complete(List.of(tree), c);
680 if (taskListener != null) {
681 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
682 taskListener.finished(e);
683 }
685 if (enter.getEnv(c) == null) {
686 boolean isPkgInfo =
687 tree.sourcefile.isNameCompatible("package-info",
688 JavaFileObject.Kind.SOURCE);
689 if (isPkgInfo) {
690 if (enter.getEnv(tree.packge) == null) {
691 JCDiagnostic diag =
692 diagFactory.fragment("file.does.not.contain.package",
693 c.location());
694 throw reader.new BadClassFile(c, filename, diag);
695 }
696 } else {
697 JCDiagnostic diag =
698 diagFactory.fragment("file.doesnt.contain.class",
699 c.getQualifiedName());
700 throw reader.new BadClassFile(c, filename, diag);
701 }
702 }
704 implicitSourceFilesRead = true;
705 }
707 /** Track when the JavaCompiler has been used to compile something. */
708 private boolean hasBeenUsed = false;
709 private long start_msec = 0;
710 public long elapsed_msec = 0;
712 /** Track whether any errors occurred while parsing source text. */
713 private boolean parseErrors = false;
715 public void compile(List<JavaFileObject> sourceFileObject)
716 throws Throwable {
717 compile(sourceFileObject, List.<String>nil(), null);
718 }
720 /**
721 * Main method: compile a list of files, return all compiled classes
722 *
723 * @param sourceFileObjects file objects to be compiled
724 * @param classnames class names to process for annotations
725 * @param processors user provided annotation processors to bypass
726 * discovery, {@code null} means that no processors were provided
727 */
728 public void compile(List<JavaFileObject> sourceFileObjects,
729 List<String> classnames,
730 Iterable<? extends Processor> processors)
731 throws IOException // TODO: temp, from JavacProcessingEnvironment
732 {
733 if (processors != null && processors.iterator().hasNext())
734 explicitAnnotationProcessingRequested = true;
735 // as a JavaCompiler can only be used once, throw an exception if
736 // it has been used before.
737 if (hasBeenUsed)
738 throw new AssertionError("attempt to reuse JavaCompiler");
739 hasBeenUsed = true;
741 start_msec = now();
742 try {
743 initProcessAnnotations(processors);
745 // These method calls must be chained to avoid memory leaks
746 delegateCompiler = processAnnotations(enterTrees(stopIfError(parseFiles(sourceFileObjects))),
747 classnames);
749 delegateCompiler.compile2();
750 delegateCompiler.close();
751 elapsed_msec = delegateCompiler.elapsed_msec;
752 } catch (Abort ex) {
753 if (devVerbose)
754 ex.printStackTrace();
755 }
756 }
758 /**
759 * The phases following annotation processing: attribution,
760 * desugar, and finally code generation.
761 */
762 private void compile2() {
763 try {
764 switch (compilePolicy) {
765 case ATTR_ONLY:
766 attribute(todo);
767 break;
769 case CHECK_ONLY:
770 flow(attribute(todo));
771 break;
773 case SIMPLE:
774 generate(desugar(flow(attribute(todo))));
775 break;
777 case BY_FILE:
778 for (List<Env<AttrContext>> list : groupByFile(flow(attribute(todo))).values())
779 generate(desugar(list));
780 break;
782 case BY_TODO:
783 while (todo.nonEmpty())
784 generate(desugar(flow(attribute(todo.next()))));
785 break;
787 default:
788 assert false: "unknown compile policy";
789 }
790 } catch (Abort ex) {
791 if (devVerbose)
792 ex.printStackTrace();
793 }
795 if (verbose) {
796 elapsed_msec = elapsed(start_msec);;
797 printVerbose("total", Long.toString(elapsed_msec));
798 }
800 reportDeferredDiagnostics();
802 if (!log.hasDiagnosticListener()) {
803 printCount("error", errorCount());
804 printCount("warn", warningCount());
805 }
806 }
808 private List<JCClassDecl> rootClasses;
810 /**
811 * Parses a list of files.
812 */
813 public List<JCCompilationUnit> parseFiles(List<JavaFileObject> fileObjects) throws IOException {
814 if (errorCount() > 0)
815 return List.nil();
817 //parse all files
818 ListBuffer<JCCompilationUnit> trees = lb();
819 for (JavaFileObject fileObject : fileObjects)
820 trees.append(parse(fileObject));
821 return trees.toList();
822 }
824 /**
825 * Enter the symbols found in a list of parse trees.
826 * As a side-effect, this puts elements on the "todo" list.
827 * Also stores a list of all top level classes in rootClasses.
828 */
829 public List<JCCompilationUnit> enterTrees(List<JCCompilationUnit> roots) {
830 //enter symbols for all files
831 if (taskListener != null) {
832 for (JCCompilationUnit unit: roots) {
833 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
834 taskListener.started(e);
835 }
836 }
838 enter.main(roots);
840 if (taskListener != null) {
841 for (JCCompilationUnit unit: roots) {
842 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
843 taskListener.finished(e);
844 }
845 }
847 //If generating source, remember the classes declared in
848 //the original compilation units listed on the command line.
849 if (sourceOutput || stubOutput) {
850 ListBuffer<JCClassDecl> cdefs = lb();
851 for (JCCompilationUnit unit : roots) {
852 for (List<JCTree> defs = unit.defs;
853 defs.nonEmpty();
854 defs = defs.tail) {
855 if (defs.head instanceof JCClassDecl)
856 cdefs.append((JCClassDecl)defs.head);
857 }
858 }
859 rootClasses = cdefs.toList();
860 }
861 return roots;
862 }
864 /**
865 * Set to true to enable skeleton annotation processing code.
866 * Currently, we assume this variable will be replaced more
867 * advanced logic to figure out if annotation processing is
868 * needed.
869 */
870 boolean processAnnotations = false;
872 /**
873 * Object to handle annotation processing.
874 */
875 JavacProcessingEnvironment procEnvImpl = null;
877 /**
878 * Check if we should process annotations.
879 * If so, and if no scanner is yet registered, then set up the DocCommentScanner
880 * to catch doc comments, and set keepComments so the parser records them in
881 * the compilation unit.
882 *
883 * @param processors user provided annotation processors to bypass
884 * discovery, {@code null} means that no processors were provided
885 */
886 public void initProcessAnnotations(Iterable<? extends Processor> processors) {
887 // Process annotations if processing is not disabled and there
888 // is at least one Processor available.
889 Options options = Options.instance(context);
890 if (options.get("-proc:none") != null) {
891 processAnnotations = false;
892 } else if (procEnvImpl == null) {
893 procEnvImpl = new JavacProcessingEnvironment(context, processors);
894 processAnnotations = procEnvImpl.atLeastOneProcessor();
896 if (processAnnotations) {
897 if (context.get(Scanner.Factory.scannerFactoryKey) == null)
898 DocCommentScanner.Factory.preRegister(context);
899 options.put("save-parameter-names", "save-parameter-names");
900 reader.saveParameterNames = true;
901 keepComments = true;
902 if (taskListener != null)
903 taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
906 } else { // free resources
907 procEnvImpl.close();
908 }
909 }
910 }
912 // TODO: called by JavacTaskImpl
913 public JavaCompiler processAnnotations(List<JCCompilationUnit> roots) throws IOException {
914 return processAnnotations(roots, List.<String>nil());
915 }
917 /**
918 * Process any anotations found in the specifed compilation units.
919 * @param roots a list of compilation units
920 * @return an instance of the compiler in which to complete the compilation
921 */
922 public JavaCompiler processAnnotations(List<JCCompilationUnit> roots,
923 List<String> classnames)
924 throws IOException { // TODO: see TEMP note in JavacProcessingEnvironment
925 if (errorCount() != 0) {
926 // Errors were encountered. If todo is empty, then the
927 // encountered errors were parse errors. Otherwise, the
928 // errors were found during the enter phase which should
929 // be ignored when processing annotations.
931 if (todo.isEmpty())
932 return this;
933 }
935 // ASSERT: processAnnotations and procEnvImpl should have been set up by
936 // by initProcessAnnotations
938 // NOTE: The !classnames.isEmpty() checks should be refactored to Main.
940 if (!processAnnotations) {
941 // If there are no annotation processors present, and
942 // annotation processing is to occur with compilation,
943 // emit a warning.
944 Options options = Options.instance(context);
945 if (options.get("-proc:only") != null) {
946 log.warning("proc.proc-only.requested.no.procs");
947 todo.clear();
948 }
949 // If not processing annotations, classnames must be empty
950 if (!classnames.isEmpty()) {
951 log.error("proc.no.explicit.annotation.processing.requested",
952 classnames);
953 }
954 return this; // continue regular compilation
955 }
957 try {
958 List<ClassSymbol> classSymbols = List.nil();
959 List<PackageSymbol> pckSymbols = List.nil();
960 if (!classnames.isEmpty()) {
961 // Check for explicit request for annotation
962 // processing
963 if (!explicitAnnotationProcessingRequested()) {
964 log.error("proc.no.explicit.annotation.processing.requested",
965 classnames);
966 return this; // TODO: Will this halt compilation?
967 } else {
968 boolean errors = false;
969 for (String nameStr : classnames) {
970 Symbol sym = resolveIdent(nameStr);
971 if (sym == null || (sym.kind == Kinds.PCK && !processPcks)) {
972 log.error("proc.cant.find.class", nameStr);
973 errors = true;
974 continue;
975 }
976 try {
977 if (sym.kind == Kinds.PCK)
978 sym.complete();
979 if (sym.exists()) {
980 Name name = names.fromString(nameStr);
981 if (sym.kind == Kinds.PCK)
982 pckSymbols = pckSymbols.prepend((PackageSymbol)sym);
983 else
984 classSymbols = classSymbols.prepend((ClassSymbol)sym);
985 continue;
986 }
987 assert sym.kind == Kinds.PCK;
988 log.warning("proc.package.does.not.exist", nameStr);
989 pckSymbols = pckSymbols.prepend((PackageSymbol)sym);
990 } catch (CompletionFailure e) {
991 log.error("proc.cant.find.class", nameStr);
992 errors = true;
993 continue;
994 }
995 }
996 if (errors)
997 return this;
998 }
999 }
1000 JavaCompiler c = procEnvImpl.doProcessing(context, roots, classSymbols, pckSymbols);
1001 if (c != this)
1002 annotationProcessingOccurred = c.annotationProcessingOccurred = true;
1003 return c;
1004 } catch (CompletionFailure ex) {
1005 log.error("cant.access", ex.sym, ex.getDetailValue());
1006 return this;
1008 }
1009 }
1011 boolean explicitAnnotationProcessingRequested() {
1012 Options options = Options.instance(context);
1013 return
1014 explicitAnnotationProcessingRequested ||
1015 options.get("-processor") != null ||
1016 options.get("-processorpath") != null ||
1017 options.get("-proc:only") != null ||
1018 options.get("-Xprint") != null;
1019 }
1021 /**
1022 * Attribute a list of parse trees, such as found on the "todo" list.
1023 * Note that attributing classes may cause additional files to be
1024 * parsed and entered via the SourceCompleter.
1025 * Attribution of the entries in the list does not stop if any errors occur.
1026 * @returns a list of environments for attributd classes.
1027 */
1028 public List<Env<AttrContext>> attribute(ListBuffer<Env<AttrContext>> envs) {
1029 ListBuffer<Env<AttrContext>> results = lb();
1030 while (envs.nonEmpty())
1031 results.append(attribute(envs.next()));
1032 return results.toList();
1033 }
1035 /**
1036 * Attribute a parse tree.
1037 * @returns the attributed parse tree
1038 */
1039 public Env<AttrContext> attribute(Env<AttrContext> env) {
1040 if (verboseCompilePolicy)
1041 log.printLines(log.noticeWriter, "[attribute " + env.enclClass.sym + "]");
1042 if (verbose)
1043 printVerbose("checking.attribution", env.enclClass.sym);
1045 if (taskListener != null) {
1046 TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym);
1047 taskListener.started(e);
1048 }
1050 JavaFileObject prev = log.useSource(
1051 env.enclClass.sym.sourcefile != null ?
1052 env.enclClass.sym.sourcefile :
1053 env.toplevel.sourcefile);
1054 try {
1055 attr.attribClass(env.tree.pos(), env.enclClass.sym);
1056 }
1057 finally {
1058 log.useSource(prev);
1059 }
1061 return env;
1062 }
1064 /**
1065 * Perform dataflow checks on attributed parse trees.
1066 * These include checks for definite assignment and unreachable statements.
1067 * If any errors occur, an empty list will be returned.
1068 * @returns the list of attributed parse trees
1069 */
1070 public List<Env<AttrContext>> flow(List<Env<AttrContext>> envs) {
1071 ListBuffer<Env<AttrContext>> results = lb();
1072 for (List<Env<AttrContext>> l = envs; l.nonEmpty(); l = l.tail) {
1073 flow(l.head, results);
1074 }
1075 return stopIfError(results);
1076 }
1078 /**
1079 * Perform dataflow checks on an attributed parse tree.
1080 */
1081 public List<Env<AttrContext>> flow(Env<AttrContext> env) {
1082 ListBuffer<Env<AttrContext>> results = lb();
1083 flow(env, results);
1084 return stopIfError(results);
1085 }
1087 /**
1088 * Perform dataflow checks on an attributed parse tree.
1089 */
1090 protected void flow(Env<AttrContext> env, ListBuffer<Env<AttrContext>> results) {
1091 try {
1092 if (errorCount() > 0)
1093 return;
1095 if (relax || deferredSugar.contains(env)) {
1096 results.append(env);
1097 return;
1098 }
1100 if (verboseCompilePolicy)
1101 log.printLines(log.noticeWriter, "[flow " + env.enclClass.sym + "]");
1102 JavaFileObject prev = log.useSource(
1103 env.enclClass.sym.sourcefile != null ?
1104 env.enclClass.sym.sourcefile :
1105 env.toplevel.sourcefile);
1106 try {
1107 make.at(Position.FIRSTPOS);
1108 TreeMaker localMake = make.forToplevel(env.toplevel);
1109 flow.analyzeTree(env.tree, localMake);
1111 if (errorCount() > 0)
1112 return;
1114 results.append(env);
1115 }
1116 finally {
1117 log.useSource(prev);
1118 }
1119 }
1120 finally {
1121 if (taskListener != null) {
1122 TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym);
1123 taskListener.finished(e);
1124 }
1125 }
1126 }
1128 /**
1129 * Prepare attributed parse trees, in conjunction with their attribution contexts,
1130 * for source or code generation.
1131 * If any errors occur, an empty list will be returned.
1132 * @returns a list containing the classes to be generated
1133 */
1134 public List<Pair<Env<AttrContext>, JCClassDecl>> desugar(List<Env<AttrContext>> envs) {
1135 ListBuffer<Pair<Env<AttrContext>, JCClassDecl>> results = lb();
1136 for (List<Env<AttrContext>> l = envs; l.nonEmpty(); l = l.tail)
1137 desugar(l.head, results);
1138 return stopIfError(results);
1139 }
1141 /**
1142 * Prepare attributed parse trees, in conjunction with their attribution contexts,
1143 * for source or code generation. If the file was not listed on the command line,
1144 * the current implicitSourcePolicy is taken into account.
1145 * The preparation stops as soon as an error is found.
1146 */
1147 protected void desugar(Env<AttrContext> env, ListBuffer<Pair<Env<AttrContext>, JCClassDecl>> results) {
1148 if (errorCount() > 0)
1149 return;
1151 if (implicitSourcePolicy == ImplicitSourcePolicy.NONE
1152 && !inputFiles.contains(env.toplevel.sourcefile)) {
1153 return;
1154 }
1156 if (desugarLater(env)) {
1157 if (verboseCompilePolicy)
1158 log.printLines(log.noticeWriter, "[defer " + env.enclClass.sym + "]");
1159 todo.append(env);
1160 return;
1161 }
1162 deferredSugar.remove(env);
1164 if (verboseCompilePolicy)
1165 log.printLines(log.noticeWriter, "[desugar " + env.enclClass.sym + "]");
1167 JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ?
1168 env.enclClass.sym.sourcefile :
1169 env.toplevel.sourcefile);
1170 try {
1171 //save tree prior to rewriting
1172 JCTree untranslated = env.tree;
1174 make.at(Position.FIRSTPOS);
1175 TreeMaker localMake = make.forToplevel(env.toplevel);
1177 if (env.tree instanceof JCCompilationUnit) {
1178 if (!(stubOutput || sourceOutput || printFlat)) {
1179 List<JCTree> pdef = lower.translateTopLevelClass(env, env.tree, localMake);
1180 if (pdef.head != null) {
1181 assert pdef.tail.isEmpty();
1182 results.append(new Pair<Env<AttrContext>, JCClassDecl>(env, (JCClassDecl)pdef.head));
1183 }
1184 }
1185 return;
1186 }
1188 if (stubOutput) {
1189 //emit stub Java source file, only for compilation
1190 //units enumerated explicitly on the command line
1191 JCClassDecl cdef = (JCClassDecl)env.tree;
1192 if (untranslated instanceof JCClassDecl &&
1193 rootClasses.contains((JCClassDecl)untranslated) &&
1194 ((cdef.mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1195 cdef.sym.packge().getQualifiedName() == names.java_lang)) {
1196 results.append(new Pair<Env<AttrContext>, JCClassDecl>(env, removeMethodBodies(cdef)));
1197 }
1198 return;
1199 }
1201 env.tree = transTypes.translateTopLevelClass(env.tree, localMake);
1203 if (errorCount() != 0)
1204 return;
1206 if (sourceOutput) {
1207 //emit standard Java source file, only for compilation
1208 //units enumerated explicitly on the command line
1209 JCClassDecl cdef = (JCClassDecl)env.tree;
1210 if (untranslated instanceof JCClassDecl &&
1211 rootClasses.contains((JCClassDecl)untranslated)) {
1212 results.append(new Pair<Env<AttrContext>, JCClassDecl>(env, cdef));
1213 }
1214 return;
1215 }
1217 //translate out inner classes
1218 List<JCTree> cdefs = lower.translateTopLevelClass(env, env.tree, localMake);
1220 if (errorCount() != 0)
1221 return;
1223 //generate code for each class
1224 for (List<JCTree> l = cdefs; l.nonEmpty(); l = l.tail) {
1225 JCClassDecl cdef = (JCClassDecl)l.head;
1226 results.append(new Pair<Env<AttrContext>, JCClassDecl>(env, cdef));
1227 }
1228 }
1229 finally {
1230 log.useSource(prev);
1231 }
1233 }
1235 /**
1236 * Determine if a class needs to be desugared later. As erasure
1237 * (TransTypes) destroys information needed in flow analysis, we
1238 * need to ensure that supertypes are translated before derived
1239 * types are translated.
1240 */
1241 public boolean desugarLater(final Env<AttrContext> env) {
1242 if (compilePolicy == CompilePolicy.BY_FILE)
1243 return false;
1244 if (!devVerbose && deferredSugar.contains(env))
1245 // guarantee that compiler terminates
1246 return false;
1247 class ScanNested extends TreeScanner {
1248 Set<Symbol> externalSupers = new HashSet<Symbol>();
1249 public void visitClassDef(JCClassDecl node) {
1250 Type st = types.supertype(node.sym.type);
1251 if (st.tag == TypeTags.CLASS) {
1252 ClassSymbol c = st.tsym.outermostClass();
1253 Env<AttrContext> stEnv = enter.getEnv(c);
1254 if (stEnv != null && env != stEnv)
1255 externalSupers.add(st.tsym);
1256 }
1257 super.visitClassDef(node);
1258 }
1259 }
1260 ScanNested scanner = new ScanNested();
1261 scanner.scan(env.tree);
1262 if (scanner.externalSupers.isEmpty())
1263 return false;
1264 if (!deferredSugar.add(env) && devVerbose) {
1265 throw new AssertionError(env.enclClass.sym + " was deferred, " +
1266 "second time has these external super types " +
1267 scanner.externalSupers);
1268 }
1269 return true;
1270 }
1272 /** Generates the source or class file for a list of classes.
1273 * The decision to generate a source file or a class file is
1274 * based upon the compiler's options.
1275 * Generation stops if an error occurs while writing files.
1276 */
1277 public void generate(List<Pair<Env<AttrContext>, JCClassDecl>> list) {
1278 generate(list, null);
1279 }
1281 public void generate(List<Pair<Env<AttrContext>, JCClassDecl>> list, ListBuffer<JavaFileObject> results) {
1282 boolean usePrintSource = (stubOutput || sourceOutput || printFlat);
1284 for (List<Pair<Env<AttrContext>, JCClassDecl>> l = list; l.nonEmpty(); l = l.tail) {
1285 Pair<Env<AttrContext>, JCClassDecl> x = l.head;
1286 Env<AttrContext> env = x.fst;
1287 JCClassDecl cdef = x.snd;
1289 if (verboseCompilePolicy) {
1290 log.printLines(log.noticeWriter, "[generate "
1291 + (usePrintSource ? " source" : "code")
1292 + " " + env.enclClass.sym + "]");
1293 }
1295 if (taskListener != null) {
1296 TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
1297 taskListener.started(e);
1298 }
1300 JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ?
1301 env.enclClass.sym.sourcefile :
1302 env.toplevel.sourcefile);
1303 try {
1304 JavaFileObject file;
1305 if (usePrintSource)
1306 file = printSource(env, cdef);
1307 else
1308 file = genCode(env, cdef);
1309 if (results != null && file != null)
1310 results.append(file);
1311 } catch (IOException ex) {
1312 log.error(cdef.pos(), "class.cant.write",
1313 cdef.sym, ex.getMessage());
1314 return;
1315 } finally {
1316 log.useSource(prev);
1317 }
1319 if (taskListener != null) {
1320 TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
1321 taskListener.finished(e);
1322 }
1323 }
1324 }
1326 // where
1327 Map<JCCompilationUnit, List<Env<AttrContext>>> groupByFile(List<Env<AttrContext>> list) {
1328 // use a LinkedHashMap to preserve the order of the original list as much as possible
1329 Map<JCCompilationUnit, List<Env<AttrContext>>> map = new LinkedHashMap<JCCompilationUnit, List<Env<AttrContext>>>();
1330 Set<JCCompilationUnit> fixupSet = new HashSet<JCTree.JCCompilationUnit>();
1331 for (List<Env<AttrContext>> l = list; l.nonEmpty(); l = l.tail) {
1332 Env<AttrContext> env = l.head;
1333 List<Env<AttrContext>> sublist = map.get(env.toplevel);
1334 if (sublist == null)
1335 sublist = List.of(env);
1336 else {
1337 // this builds the list for the file in reverse order, so make a note
1338 // to reverse the list before returning.
1339 sublist = sublist.prepend(env);
1340 fixupSet.add(env.toplevel);
1341 }
1342 map.put(env.toplevel, sublist);
1343 }
1344 // fixup any lists that need reversing back to the correct order
1345 for (JCTree.JCCompilationUnit tree: fixupSet)
1346 map.put(tree, map.get(tree).reverse());
1347 return map;
1348 }
1350 JCClassDecl removeMethodBodies(JCClassDecl cdef) {
1351 final boolean isInterface = (cdef.mods.flags & Flags.INTERFACE) != 0;
1352 class MethodBodyRemover extends TreeTranslator {
1353 public void visitMethodDef(JCMethodDecl tree) {
1354 tree.mods.flags &= ~Flags.SYNCHRONIZED;
1355 for (JCVariableDecl vd : tree.params)
1356 vd.mods.flags &= ~Flags.FINAL;
1357 tree.body = null;
1358 super.visitMethodDef(tree);
1359 }
1360 public void visitVarDef(JCVariableDecl tree) {
1361 if (tree.init != null && tree.init.type.constValue() == null)
1362 tree.init = null;
1363 super.visitVarDef(tree);
1364 }
1365 public void visitClassDef(JCClassDecl tree) {
1366 ListBuffer<JCTree> newdefs = lb();
1367 for (List<JCTree> it = tree.defs; it.tail != null; it = it.tail) {
1368 JCTree t = it.head;
1369 switch (t.getTag()) {
1370 case JCTree.CLASSDEF:
1371 if (isInterface ||
1372 (((JCClassDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1373 (((JCClassDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCClassDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1374 newdefs.append(t);
1375 break;
1376 case JCTree.METHODDEF:
1377 if (isInterface ||
1378 (((JCMethodDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1379 ((JCMethodDecl) t).sym.name == names.init ||
1380 (((JCMethodDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCMethodDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1381 newdefs.append(t);
1382 break;
1383 case JCTree.VARDEF:
1384 if (isInterface || (((JCVariableDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1385 (((JCVariableDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCVariableDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1386 newdefs.append(t);
1387 break;
1388 default:
1389 break;
1390 }
1391 }
1392 tree.defs = newdefs.toList();
1393 super.visitClassDef(tree);
1394 }
1395 }
1396 MethodBodyRemover r = new MethodBodyRemover();
1397 return r.translate(cdef);
1398 }
1400 public void reportDeferredDiagnostics() {
1401 if (annotationProcessingOccurred
1402 && implicitSourceFilesRead
1403 && implicitSourcePolicy == ImplicitSourcePolicy.UNSET) {
1404 if (explicitAnnotationProcessingRequested())
1405 log.warning("proc.use.implicit");
1406 else
1407 log.warning("proc.use.proc.or.implicit");
1408 }
1409 chk.reportDeferredDiagnostics();
1410 }
1412 /** Close the compiler, flushing the logs
1413 */
1414 public void close() {
1415 close(true);
1416 }
1418 private void close(boolean disposeNames) {
1419 rootClasses = null;
1420 reader = null;
1421 make = null;
1422 writer = null;
1423 enter = null;
1424 if (todo != null)
1425 todo.clear();
1426 todo = null;
1427 parserFactory = null;
1428 syms = null;
1429 source = null;
1430 attr = null;
1431 chk = null;
1432 gen = null;
1433 flow = null;
1434 transTypes = null;
1435 lower = null;
1436 annotate = null;
1437 types = null;
1439 log.flush();
1440 try {
1441 fileManager.flush();
1442 } catch (IOException e) {
1443 throw new Abort(e);
1444 } finally {
1445 if (names != null && disposeNames)
1446 names.dispose();
1447 names = null;
1448 }
1449 }
1451 /** Output for "-verbose" option.
1452 * @param key The key to look up the correct internationalized string.
1453 * @param arg An argument for substitution into the output string.
1454 */
1455 protected void printVerbose(String key, Object arg) {
1456 Log.printLines(log.noticeWriter, log.getLocalizedString("verbose." + key, arg));
1457 }
1459 /** Print numbers of errors and warnings.
1460 */
1461 protected void printCount(String kind, int count) {
1462 if (count != 0) {
1463 String text;
1464 if (count == 1)
1465 text = log.getLocalizedString("count." + kind, String.valueOf(count));
1466 else
1467 text = log.getLocalizedString("count." + kind + ".plural", String.valueOf(count));
1468 Log.printLines(log.errWriter, text);
1469 log.errWriter.flush();
1470 }
1471 }
1473 private static long now() {
1474 return System.currentTimeMillis();
1475 }
1477 private static long elapsed(long then) {
1478 return now() - then;
1479 }
1481 public void initRound(JavaCompiler prev) {
1482 keepComments = prev.keepComments;
1483 start_msec = prev.start_msec;
1484 hasBeenUsed = true;
1485 }
1487 public static void enableLogging() {
1488 Logger logger = Logger.getLogger(com.sun.tools.javac.Main.class.getPackage().getName());
1489 logger.setLevel(Level.ALL);
1490 for (Handler h : logger.getParent().getHandlers()) {
1491 h.setLevel(Level.ALL);
1492 }
1494 }
1495 }