001 /*
002 * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package com.sun.tools.javac.main;
027
028 import java.io.*;
029 import java.util.HashSet;
030 import java.util.LinkedHashSet;
031 import java.util.LinkedHashMap;
032 import java.util.Map;
033 import java.util.MissingResourceException;
034 import java.util.ResourceBundle;
035 import java.util.Set;
036 import java.util.logging.Handler;
037 import java.util.logging.Level;
038 import java.util.logging.Logger;
039
040 import javax.tools.JavaFileManager;
041 import javax.tools.JavaFileObject;
042 import javax.tools.DiagnosticListener;
043
044 import com.sun.tools.javac.file.JavacFileManager;
045 import com.sun.source.util.TaskEvent;
046 import com.sun.source.util.TaskListener;
047
048 import com.sun.tools.javac.util.*;
049 import com.sun.tools.javac.code.*;
050 import com.sun.tools.javac.tree.*;
051 import com.sun.tools.javac.parser.*;
052 import com.sun.tools.javac.comp.*;
053 import com.sun.tools.javac.jvm.*;
054
055 import com.sun.tools.javac.code.Symbol.*;
056 import com.sun.tools.javac.tree.JCTree.*;
057
058 import com.sun.tools.javac.processing.*;
059 import javax.annotation.processing.Processor;
060
061 import static javax.tools.StandardLocation.CLASS_OUTPUT;
062 import static com.sun.tools.javac.util.ListBuffer.lb;
063
064 // TEMP, until we have a more efficient way to save doc comment info
065 import com.sun.tools.javac.parser.DocCommentScanner;
066
067 import edu.rice.cs.mint.comp.TransStaging;
068
069 import java.util.HashMap;
070 import java.util.Queue;
071 import javax.lang.model.SourceVersion;
072
073 /** This class could be the main entry point for GJC when GJC is used as a
074 * component in a larger software system. It provides operations to
075 * construct a new compiler, and to run a new compiler on a set of source
076 * files.
077 *
078 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
079 * you write code that depends on this, you do so at your own risk.
080 * This code and its internal interfaces are subject to change or
081 * deletion without notice.</b>
082 */
083 public class JavaCompiler implements ClassReader.SourceCompleter {
084 /** The context key for the compiler. */
085 protected static final Context.Key<JavaCompiler> compilerKey =
086 new Context.Key<JavaCompiler>();
087
088 /** Get the JavaCompiler instance for this context. */
089 public static JavaCompiler instance(Context context) {
090 JavaCompiler instance = context.get(compilerKey);
091 if (instance == null)
092 instance = new JavaCompiler(context);
093 return instance;
094 }
095
096 /** The current version number as a string.
097 */
098 public static String version() {
099 return version("release"); // mm.nn.oo[-milestone]
100 }
101
102 /** The current full version number as a string.
103 */
104 public static String fullVersion() {
105 return version("full"); // mm.mm.oo[-milestone]-build
106 }
107
108 private static final String versionRBName = "com.sun.tools.javac.resources.version";
109 private static ResourceBundle versionRB;
110
111 private static String version(String key) {
112 if (versionRB == null) {
113 try {
114 versionRB = ResourceBundle.getBundle(versionRBName);
115 } catch (MissingResourceException e) {
116 return Log.getLocalizedString("version.resource.missing", System.getProperty("java.version"));
117 }
118 }
119 try {
120 return versionRB.getString(key);
121 }
122 catch (MissingResourceException e) {
123 return Log.getLocalizedString("version.unknown", System.getProperty("java.version"));
124 }
125 }
126
127 /**
128 * Control how the compiler's latter phases (attr, flow, desugar, generate)
129 * are connected. Each individual file is processed by each phase in turn,
130 * but with different compile policies, you can control the order in which
131 * each class is processed through its next phase.
132 *
133 * <p>Generally speaking, the compiler will "fail fast" in the face of
134 * errors, although not aggressively so. flow, desugar, etc become no-ops
135 * once any errors have occurred. No attempt is currently made to determine
136 * if it might be safe to process a class through its next phase because
137 * it does not depend on any unrelated errors that might have occurred.
138 */
139 protected static enum CompilePolicy {
140 /**
141 * Just attribute the parse trees.
142 */
143 ATTR_ONLY,
144
145 /**
146 * Just attribute and do flow analysis on the parse trees.
147 * This should catch most user errors.
148 */
149 CHECK_ONLY,
150
151 /**
152 * Attribute everything, then do flow analysis for everything,
153 * then desugar everything, and only then generate output.
154 * This means no output will be generated if there are any
155 * errors in any classes.
156 */
157 SIMPLE,
158
159 /**
160 * Groups the classes for each source file together, then process
161 * each group in a manner equivalent to the {@code SIMPLE} policy.
162 * This means no output will be generated if there are any
163 * errors in any of the classes in a source file.
164 */
165 BY_FILE,
166
167 /**
168 * Completely process each entry on the todo list in turn.
169 * -- this is the same for 1.5.
170 * Means output might be generated for some classes in a compilation unit
171 * and not others.
172 */
173 BY_TODO;
174
175 static CompilePolicy decode(String option) {
176 if (option == null)
177 return DEFAULT_COMPILE_POLICY;
178 else if (option.equals("attr"))
179 return ATTR_ONLY;
180 else if (option.equals("check"))
181 return CHECK_ONLY;
182 else if (option.equals("simple"))
183 return SIMPLE;
184 else if (option.equals("byfile"))
185 return BY_FILE;
186 else if (option.equals("bytodo"))
187 return BY_TODO;
188 else
189 return DEFAULT_COMPILE_POLICY;
190 }
191 }
192
193 private static CompilePolicy DEFAULT_COMPILE_POLICY = CompilePolicy.BY_TODO;
194
195 protected static enum ImplicitSourcePolicy {
196 /** Don't generate or process implicitly read source files. */
197 NONE,
198 /** Generate classes for implicitly read source files. */
199 CLASS,
200 /** Like CLASS, but generate warnings if annotation processing occurs */
201 UNSET;
202
203 static ImplicitSourcePolicy decode(String option) {
204 if (option == null)
205 return UNSET;
206 else if (option.equals("none"))
207 return NONE;
208 else if (option.equals("class"))
209 return CLASS;
210 else
211 return UNSET;
212 }
213 }
214
215 /** The log to be used for error reporting.
216 */
217 public Log log;
218
219 /** Factory for creating diagnostic objects
220 */
221 JCDiagnostic.Factory diagFactory;
222
223 /** The tree factory module.
224 */
225 protected TreeMaker make;
226
227 /** The class reader.
228 */
229 protected ClassReader reader;
230
231 /** The class writer.
232 */
233 protected ClassWriter writer;
234
235 /** The module for the symbol table entry phases.
236 */
237 protected Enter enter;
238
239 /** The symbol table.
240 */
241 protected Symtab syms;
242
243 /** The language version.
244 */
245 protected Source source;
246
247 /** The module for code generation.
248 */
249 protected Gen gen;
250
251 /** The name table.
252 */
253 protected Names names;
254
255 /** The attributor.
256 */
257 protected Attr attr;
258
259 /** The attributor.
260 */
261 protected Check chk;
262
263 /** The flow analyzer.
264 */
265 protected Flow flow;
266
267 /** The type eraser.
268 */
269 protected TransTypes transTypes;
270
271 /** The staging eraser.
272 */
273 protected TransStaging transStaging;
274
275 /** The syntactic sugar desweetener.
276 */
277 protected Lower lower;
278
279 /** The annotation annotator.
280 */
281 protected Annotate annotate;
282
283 /** Force a completion failure on this name
284 */
285 protected final Name completionFailureName;
286
287 /** Type utilities.
288 */
289 protected Types types;
290
291 /** Access to file objects.
292 */
293 protected JavaFileManager fileManager;
294
295 /** Factory for parsers.
296 */
297 protected ParserFactory parserFactory;
298
299 /** Optional listener for progress events
300 */
301 protected TaskListener taskListener;
302
303 /**
304 * Annotation processing may require and provide a new instance
305 * of the compiler to be used for the analyze and generate phases.
306 */
307 protected JavaCompiler delegateCompiler;
308
309 /**
310 * Flag set if any annotation processing occurred.
311 **/
312 protected boolean annotationProcessingOccurred;
313
314 /**
315 * Flag set if any implicit source files read.
316 **/
317 protected boolean implicitSourceFilesRead;
318
319 protected Context context;
320
321 /** Construct a new compiler using a shared context.
322 */
323 public JavaCompiler(final Context context) {
324 this.context = context;
325 context.put(compilerKey, this);
326
327 // if fileManager not already set, register the JavacFileManager to be used
328 if (context.get(JavaFileManager.class) == null)
329 JavacFileManager.preRegister(context);
330
331 names = Names.instance(context);
332 log = Log.instance(context);
333 diagFactory = JCDiagnostic.Factory.instance(context);
334 reader = ClassReader.instance(context);
335 make = TreeMaker.instance(context);
336 writer = ClassWriter.instance(context);
337 enter = Enter.instance(context);
338 todo = Todo.instance(context);
339
340 fileManager = context.get(JavaFileManager.class);
341 parserFactory = ParserFactory.instance(context);
342
343 try {
344 // catch completion problems with predefineds
345 syms = Symtab.instance(context);
346 } catch (CompletionFailure ex) {
347 // inlined Check.completionError as it is not initialized yet
348 log.error("cant.access", ex.sym, ex.getDetailValue());
349 if (ex instanceof ClassReader.BadClassFile)
350 throw new Abort();
351 }
352 source = Source.instance(context);
353 attr = Attr.instance(context);
354 chk = Check.instance(context);
355 gen = Gen.instance(context);
356 flow = Flow.instance(context);
357 transTypes = TransTypes.instance(context);
358 transStaging = TransStaging.instance(context);
359 lower = Lower.instance(context);
360 annotate = Annotate.instance(context);
361 types = Types.instance(context);
362 taskListener = context.get(TaskListener.class);
363
364 reader.sourceCompleter = this;
365
366 Options options = Options.instance(context);
367
368 verbose = options.get("-verbose") != null;
369 sourceOutput = options.get("-printsource") != null; // used to be -s
370 stubOutput = options.get("-stubs") != null;
371 relax = options.get("-relax") != null;
372 printFlat = options.get("-printflat") != null;
373 attrParseOnly = options.get("-attrparseonly") != null;
374 encoding = options.get("-encoding");
375 lineDebugInfo = options.get("-g:") == null ||
376 options.get("-g:lines") != null;
377 genEndPos = options.get("-Xjcov") != null ||
378 context.get(DiagnosticListener.class) != null;
379 devVerbose = options.get("dev") != null;
380 processPcks = options.get("process.packages") != null;
381
382 verboseCompilePolicy = options.get("verboseCompilePolicy") != null;
383
384 if (attrParseOnly)
385 compilePolicy = CompilePolicy.ATTR_ONLY;
386 else
387 compilePolicy = CompilePolicy.decode(options.get("compilePolicy"));
388
389 implicitSourcePolicy = ImplicitSourcePolicy.decode(options.get("-implicit"));
390
391 completionFailureName =
392 (options.get("failcomplete") != null)
393 ? names.fromString(options.get("failcomplete"))
394 : null;
395 }
396
397 /* Switches:
398 */
399
400 /** Verbose output.
401 */
402 public boolean verbose;
403
404 /** Emit plain Java source files rather than class files.
405 */
406 public boolean sourceOutput;
407
408 /** Emit stub source files rather than class files.
409 */
410 public boolean stubOutput;
411
412 /** Generate attributed parse tree only.
413 */
414 public boolean attrParseOnly;
415
416 /** Switch: relax some constraints for producing the jsr14 prototype.
417 */
418 boolean relax;
419
420 /** Debug switch: Emit Java sources after inner class flattening.
421 */
422 public boolean printFlat;
423
424 /** The encoding to be used for source input.
425 */
426 public String encoding;
427
428 /** Generate code with the LineNumberTable attribute for debugging
429 */
430 public boolean lineDebugInfo;
431
432 /** Switch: should we store the ending positions?
433 */
434 public boolean genEndPos;
435
436 /** Switch: should we debug ignored exceptions
437 */
438 protected boolean devVerbose;
439
440 /** Switch: should we (annotation) process packages as well
441 */
442 protected boolean processPcks;
443
444 /** Switch: is annotation processing requested explitly via
445 * CompilationTask.setProcessors?
446 */
447 protected boolean explicitAnnotationProcessingRequested = false;
448
449 /**
450 * The policy for the order in which to perform the compilation
451 */
452 protected CompilePolicy compilePolicy;
453
454 /**
455 * The policy for what to do with implicitly read source files
456 */
457 protected ImplicitSourcePolicy implicitSourcePolicy;
458
459 /**
460 * Report activity related to compilePolicy
461 */
462 public boolean verboseCompilePolicy;
463
464 /** A queue of all as yet unattributed classes.
465 */
466 public Todo todo;
467
468 protected enum CompileState {
469 TODO(0),
470 ATTR(1),
471 FLOW(2);
472 CompileState(int value) {
473 this.value = value;
474 }
475 boolean isDone(CompileState other) {
476 return value >= other.value;
477 }
478 private int value;
479 };
480 protected class CompileStates extends HashMap<Env<AttrContext>,CompileState> {
481 private static final long serialVersionUID = 1812267524140424433L;
482 boolean isDone(Env<AttrContext> env, CompileState cs) {
483 CompileState ecs = get(env);
484 return ecs != null && ecs.isDone(cs);
485 }
486 }
487 private CompileStates compileStates = new CompileStates();
488
489 /** The set of currently compiled inputfiles, needed to ensure
490 * we don't accidentally overwrite an input file when -s is set.
491 * initialized by `compile'.
492 */
493 protected Set<JavaFileObject> inputFiles = new HashSet<JavaFileObject>();
494
495 /** The number of errors reported so far.
496 */
497 public int errorCount() {
498 if (delegateCompiler != null && delegateCompiler != this)
499 return delegateCompiler.errorCount();
500 else
501 return log.nerrors;
502 }
503
504 protected final <T> Queue<T> stopIfError(Queue<T> queue) {
505 if (errorCount() == 0)
506 return queue;
507 else
508 return ListBuffer.lb();
509 }
510
511 protected final <T> List<T> stopIfError(List<T> list) {
512 if (errorCount() == 0)
513 return list;
514 else
515 return List.nil();
516 }
517
518 /** The number of warnings reported so far.
519 */
520 public int warningCount() {
521 if (delegateCompiler != null && delegateCompiler != this)
522 return delegateCompiler.warningCount();
523 else
524 return log.nwarnings;
525 }
526
527 /** Whether or not any parse errors have occurred.
528 */
529 public boolean parseErrors() {
530 return parseErrors;
531 }
532
533 /** Try to open input stream with given name.
534 * Report an error if this fails.
535 * @param filename The file name of the input stream to be opened.
536 */
537 public CharSequence readSource(JavaFileObject filename) {
538 try {
539 inputFiles.add(filename);
540 return filename.getCharContent(false);
541 } catch (IOException e) {
542 log.error("error.reading.file", filename, e.getLocalizedMessage());
543 return null;
544 }
545 }
546
547 /** Parse contents of input stream.
548 * @param filename The name of the file from which input stream comes.
549 * @param input The input stream to be parsed.
550 */
551 protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) {
552 long msec = now();
553 JCCompilationUnit tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(),
554 null, List.<JCTree>nil());
555 if (content != null) {
556 if (verbose) {
557 printVerbose("parsing.started", filename);
558 }
559 if (taskListener != null) {
560 TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, filename);
561 taskListener.started(e);
562 }
563 int initialErrorCount = log.nerrors;
564 Parser parser = parserFactory.newParser(content, keepComments(), genEndPos, lineDebugInfo);
565 tree = parser.parseCompilationUnit();
566 parseErrors |= (log.nerrors > initialErrorCount);
567 if (verbose) {
568 printVerbose("parsing.done", Long.toString(elapsed(msec)));
569 }
570 }
571
572 tree.sourcefile = filename;
573
574 if (content != null && taskListener != null) {
575 TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree);
576 taskListener.finished(e);
577 }
578
579 return tree;
580 }
581 // where
582 public boolean keepComments = false;
583 protected boolean keepComments() {
584 return keepComments || sourceOutput || stubOutput;
585 }
586
587
588 /** Parse contents of file.
589 * @param filename The name of the file to be parsed.
590 */
591 @Deprecated
592 public JCTree.JCCompilationUnit parse(String filename) throws IOException {
593 JavacFileManager fm = (JavacFileManager)fileManager;
594 return parse(fm.getJavaFileObjectsFromStrings(List.of(filename)).iterator().next());
595 }
596
597 /** Parse contents of file.
598 * @param filename The name of the file to be parsed.
599 */
600 public JCTree.JCCompilationUnit parse(JavaFileObject filename) {
601 JavaFileObject prev = log.useSource(filename);
602 try {
603 JCTree.JCCompilationUnit t = parse(filename, readSource(filename));
604 if (t.endPositions != null)
605 log.setEndPosTable(filename, t.endPositions);
606 return t;
607 } finally {
608 log.useSource(prev);
609 }
610 }
611
612 /** Resolve an identifier.
613 * @param name The identifier to resolve
614 */
615 public Symbol resolveIdent(String name) {
616 if (name.equals(""))
617 return syms.errSymbol;
618 JavaFileObject prev = log.useSource(null);
619 try {
620 JCExpression tree = null;
621 for (String s : name.split("\\.", -1)) {
622 if (!SourceVersion.isIdentifier(s)) // TODO: check for keywords
623 return syms.errSymbol;
624 tree = (tree == null) ? make.Ident(names.fromString(s))
625 : make.Select(tree, names.fromString(s));
626 }
627 JCCompilationUnit toplevel =
628 make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil());
629 toplevel.packge = syms.unnamedPackage;
630 return attr.attribIdent(tree, toplevel);
631 } finally {
632 log.useSource(prev);
633 }
634 }
635
636 /** Emit plain Java source for a class.
637 * @param env The attribution environment of the outermost class
638 * containing this class.
639 * @param cdef The class definition to be printed.
640 */
641 JavaFileObject printSource(Env<AttrContext> env, JCClassDecl cdef) throws IOException {
642 JavaFileObject outFile
643 = fileManager.getJavaFileForOutput(CLASS_OUTPUT,
644 cdef.sym.flatname.toString(),
645 JavaFileObject.Kind.SOURCE,
646 null);
647 if (inputFiles.contains(outFile)) {
648 log.error(cdef.pos(), "source.cant.overwrite.input.file", outFile);
649 return null;
650 } else {
651 BufferedWriter out = new BufferedWriter(outFile.openWriter());
652 try {
653 new Pretty(out, true).printUnit(env.toplevel, cdef);
654 if (verbose)
655 printVerbose("wrote.file", outFile);
656 } finally {
657 out.close();
658 }
659 return outFile;
660 }
661 }
662
663 /** Generate code and emit a class file for a given class
664 * @param env The attribution environment of the outermost class
665 * containing this class.
666 * @param cdef The class definition from which code is generated.
667 */
668 JavaFileObject genCode(Env<AttrContext> env, JCClassDecl cdef) throws IOException {
669 try {
670 if (gen.genClass(env, cdef))
671 return writer.writeClass(cdef.sym);
672 } catch (ClassWriter.PoolOverflow ex) {
673 log.error(cdef.pos(), "limit.pool");
674 } catch (ClassWriter.StringOverflow ex) {
675 log.error(cdef.pos(), "limit.string.overflow",
676 ex.value.substring(0, 20));
677 } catch (CompletionFailure ex) {
678 chk.completionError(cdef.pos(), ex);
679 }
680 return null;
681 }
682
683 /** Complete compiling a source file that has been accessed
684 * by the class file reader.
685 * @param c The class the source file of which needs to be compiled.
686 * @param filename The name of the source file.
687 * @param f An input stream that reads the source file.
688 */
689 public void complete(ClassSymbol c) throws CompletionFailure {
690 // System.err.println("completing " + c);//DEBUG
691 if (completionFailureName == c.fullname) {
692 throw new CompletionFailure(c, "user-selected completion failure by class name");
693 }
694 JCCompilationUnit tree;
695 JavaFileObject filename = c.classfile;
696 JavaFileObject prev = log.useSource(filename);
697
698 try {
699 tree = parse(filename, filename.getCharContent(false));
700 } catch (IOException e) {
701 log.error("error.reading.file", filename, e);
702 tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil());
703 } finally {
704 log.useSource(prev);
705 }
706
707 if (taskListener != null) {
708 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
709 taskListener.started(e);
710 }
711
712 enter.complete(List.of(tree), c);
713
714 if (taskListener != null) {
715 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
716 taskListener.finished(e);
717 }
718
719 if (enter.getEnv(c) == null) {
720 boolean isPkgInfo =
721 tree.sourcefile.isNameCompatible("package-info",
722 JavaFileObject.Kind.SOURCE);
723 if (isPkgInfo) {
724 if (enter.getEnv(tree.packge) == null) {
725 JCDiagnostic diag =
726 diagFactory.fragment("file.does.not.contain.package",
727 c.location());
728 throw reader.new BadClassFile(c, filename, diag);
729 }
730 } else {
731 JCDiagnostic diag =
732 diagFactory.fragment("file.doesnt.contain.class",
733 c.getQualifiedName());
734 throw reader.new BadClassFile(c, filename, diag);
735 }
736 }
737
738 implicitSourceFilesRead = true;
739 }
740
741 /** Track when the JavaCompiler has been used to compile something. */
742 private boolean hasBeenUsed = false;
743 private long start_msec = 0;
744 public long elapsed_msec = 0;
745
746 /** Track whether any errors occurred while parsing source text. */
747 private boolean parseErrors = false;
748
749 public void compile(List<JavaFileObject> sourceFileObject)
750 throws Throwable {
751 compile(sourceFileObject, List.<String>nil(), null);
752 }
753
754 /**
755 * Main method: compile a list of files, return all compiled classes
756 *
757 * @param sourceFileObjects file objects to be compiled
758 * @param classnames class names to process for annotations
759 * @param processors user provided annotation processors to bypass
760 * discovery, {@code null} means that no processors were provided
761 */
762 public void compile(List<JavaFileObject> sourceFileObjects,
763 List<String> classnames,
764 Iterable<? extends Processor> processors)
765 throws IOException // TODO: temp, from JavacProcessingEnvironment
766 {
767 if (processors != null && processors.iterator().hasNext())
768 explicitAnnotationProcessingRequested = true;
769 // as a JavaCompiler can only be used once, throw an exception if
770 // it has been used before.
771 if (hasBeenUsed)
772 throw new AssertionError("attempt to reuse JavaCompiler");
773 hasBeenUsed = true;
774
775 start_msec = now();
776 try {
777 initProcessAnnotations(processors);
778
779 // These method calls must be chained to avoid memory leaks
780 delegateCompiler = processAnnotations(enterTrees(stopIfError(parseFiles(sourceFileObjects))),
781 classnames);
782
783 delegateCompiler.compile2();
784 delegateCompiler.close();
785 elapsed_msec = delegateCompiler.elapsed_msec;
786 } catch (Abort ex) {
787 if (devVerbose)
788 ex.printStackTrace();
789 }
790 }
791
792 /**
793 * The phases following annotation processing: attribution,
794 * desugar, and finally code generation.
795 */
796 private void compile2() {
797 try {
798 switch (compilePolicy) {
799 case ATTR_ONLY:
800 attribute(todo);
801 break;
802
803 case CHECK_ONLY:
804 flow(attribute(todo));
805 break;
806
807 case SIMPLE:
808 generate(desugar(flow(attribute(todo))));
809 break;
810
811 case BY_FILE: {
812 Queue<Queue<Env<AttrContext>>> q = todo.groupByFile();
813 while (!q.isEmpty() && errorCount() == 0) {
814 generate(desugar(flow(attribute(q.remove()))));
815 }
816 }
817 break;
818
819 case BY_TODO:
820 while (!todo.isEmpty())
821 generate(desugar(flow(attribute(todo.remove()))));
822 break;
823
824 default:
825 assert false: "unknown compile policy";
826 }
827 } catch (Abort ex) {
828 if (devVerbose)
829 ex.printStackTrace();
830 }
831
832 if (verbose) {
833 elapsed_msec = elapsed(start_msec);
834 printVerbose("total", Long.toString(elapsed_msec));
835 }
836
837 reportDeferredDiagnostics();
838
839 if (!log.hasDiagnosticListener()) {
840 printCount("error", errorCount());
841 printCount("warn", warningCount());
842 }
843 }
844
845 private List<JCClassDecl> rootClasses;
846
847 /**
848 * Parses a list of files.
849 */
850 public List<JCCompilationUnit> parseFiles(List<JavaFileObject> fileObjects) throws IOException {
851 if (errorCount() > 0)
852 return List.nil();
853
854 //parse all files
855 ListBuffer<JCCompilationUnit> trees = lb();
856 for (JavaFileObject fileObject : fileObjects)
857 trees.append(parse(fileObject));
858 return trees.toList();
859 }
860
861 /**
862 * Enter the symbols found in a list of parse trees.
863 * As a side-effect, this puts elements on the "todo" list.
864 * Also stores a list of all top level classes in rootClasses.
865 */
866 public List<JCCompilationUnit> enterTrees(List<JCCompilationUnit> roots) {
867 //enter symbols for all files
868 if (taskListener != null) {
869 for (JCCompilationUnit unit: roots) {
870 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
871 taskListener.started(e);
872 }
873 }
874
875 enter.main(roots);
876
877 if (taskListener != null) {
878 for (JCCompilationUnit unit: roots) {
879 TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
880 taskListener.finished(e);
881 }
882 }
883
884 //If generating source, remember the classes declared in
885 //the original compilation units listed on the command line.
886 if (sourceOutput || stubOutput) {
887 ListBuffer<JCClassDecl> cdefs = lb();
888 for (JCCompilationUnit unit : roots) {
889 for (List<JCTree> defs = unit.defs;
890 defs.nonEmpty();
891 defs = defs.tail) {
892 if (defs.head instanceof JCClassDecl)
893 cdefs.append((JCClassDecl)defs.head);
894 }
895 }
896 rootClasses = cdefs.toList();
897 }
898 return roots;
899 }
900
901 /**
902 * Set to true to enable skeleton annotation processing code.
903 * Currently, we assume this variable will be replaced more
904 * advanced logic to figure out if annotation processing is
905 * needed.
906 */
907 boolean processAnnotations = false;
908
909 /**
910 * Object to handle annotation processing.
911 */
912 JavacProcessingEnvironment procEnvImpl = null;
913
914 /**
915 * Check if we should process annotations.
916 * If so, and if no scanner is yet registered, then set up the DocCommentScanner
917 * to catch doc comments, and set keepComments so the parser records them in
918 * the compilation unit.
919 *
920 * @param processors user provided annotation processors to bypass
921 * discovery, {@code null} means that no processors were provided
922 */
923 public void initProcessAnnotations(Iterable<? extends Processor> processors) {
924 // Process annotations if processing is not disabled and there
925 // is at least one Processor available.
926 Options options = Options.instance(context);
927 if (options.get("-proc:none") != null) {
928 processAnnotations = false;
929 } else if (procEnvImpl == null) {
930 procEnvImpl = new JavacProcessingEnvironment(context, processors);
931 processAnnotations = procEnvImpl.atLeastOneProcessor();
932
933 if (processAnnotations) {
934 if (context.get(Scanner.Factory.scannerFactoryKey) == null)
935 DocCommentScanner.Factory.preRegister(context);
936 options.put("save-parameter-names", "save-parameter-names");
937 reader.saveParameterNames = true;
938 keepComments = true;
939 if (taskListener != null)
940 taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
941
942
943 } else { // free resources
944 procEnvImpl.close();
945 }
946 }
947 }
948
949 // TODO: called by JavacTaskImpl
950 public JavaCompiler processAnnotations(List<JCCompilationUnit> roots) throws IOException {
951 return processAnnotations(roots, List.<String>nil());
952 }
953
954 /**
955 * Process any anotations found in the specifed compilation units.
956 * @param roots a list of compilation units
957 * @return an instance of the compiler in which to complete the compilation
958 */
959 public JavaCompiler processAnnotations(List<JCCompilationUnit> roots,
960 List<String> classnames)
961 throws IOException { // TODO: see TEMP note in JavacProcessingEnvironment
962 if (errorCount() != 0) {
963 // Errors were encountered. If todo is empty, then the
964 // encountered errors were parse errors. Otherwise, the
965 // errors were found during the enter phase which should
966 // be ignored when processing annotations.
967
968 if (todo.isEmpty())
969 return this;
970 }
971
972 // ASSERT: processAnnotations and procEnvImpl should have been set up by
973 // by initProcessAnnotations
974
975 // NOTE: The !classnames.isEmpty() checks should be refactored to Main.
976
977 if (!processAnnotations) {
978 // If there are no annotation processors present, and
979 // annotation processing is to occur with compilation,
980 // emit a warning.
981 Options options = Options.instance(context);
982 if (options.get("-proc:only") != null) {
983 log.warning("proc.proc-only.requested.no.procs");
984 todo.clear();
985 }
986 // If not processing annotations, classnames must be empty
987 if (!classnames.isEmpty()) {
988 log.error("proc.no.explicit.annotation.processing.requested",
989 classnames);
990 }
991 return this; // continue regular compilation
992 }
993
994 try {
995 List<ClassSymbol> classSymbols = List.nil();
996 List<PackageSymbol> pckSymbols = List.nil();
997 if (!classnames.isEmpty()) {
998 // Check for explicit request for annotation
999 // processing
1000 if (!explicitAnnotationProcessingRequested()) {
1001 log.error("proc.no.explicit.annotation.processing.requested",
1002 classnames);
1003 return this; // TODO: Will this halt compilation?
1004 } else {
1005 boolean errors = false;
1006 for (String nameStr : classnames) {
1007 Symbol sym = resolveIdent(nameStr);
1008 if (sym == null || (sym.kind == Kinds.PCK && !processPcks)) {
1009 log.error("proc.cant.find.class", nameStr);
1010 errors = true;
1011 continue;
1012 }
1013 try {
1014 if (sym.kind == Kinds.PCK)
1015 sym.complete();
1016 if (sym.exists()) {
1017 Name name = names.fromString(nameStr);
1018 if (sym.kind == Kinds.PCK)
1019 pckSymbols = pckSymbols.prepend((PackageSymbol)sym);
1020 else
1021 classSymbols = classSymbols.prepend((ClassSymbol)sym);
1022 continue;
1023 }
1024 assert sym.kind == Kinds.PCK;
1025 log.warning("proc.package.does.not.exist", nameStr);
1026 pckSymbols = pckSymbols.prepend((PackageSymbol)sym);
1027 } catch (CompletionFailure e) {
1028 log.error("proc.cant.find.class", nameStr);
1029 errors = true;
1030 continue;
1031 }
1032 }
1033 if (errors)
1034 return this;
1035 }
1036 }
1037 JavaCompiler c = procEnvImpl.doProcessing(context, roots, classSymbols, pckSymbols);
1038 if (c != this)
1039 annotationProcessingOccurred = c.annotationProcessingOccurred = true;
1040 return c;
1041 } catch (CompletionFailure ex) {
1042 log.error("cant.access", ex.sym, ex.getDetailValue());
1043 return this;
1044
1045 }
1046 }
1047
1048 boolean explicitAnnotationProcessingRequested() {
1049 Options options = Options.instance(context);
1050 return
1051 explicitAnnotationProcessingRequested ||
1052 options.get("-processor") != null ||
1053 options.get("-processorpath") != null ||
1054 options.get("-proc:only") != null ||
1055 options.get("-Xprint") != null;
1056 }
1057
1058 /**
1059 * Attribute a list of parse trees, such as found on the "todo" list.
1060 * Note that attributing classes may cause additional files to be
1061 * parsed and entered via the SourceCompleter.
1062 * Attribution of the entries in the list does not stop if any errors occur.
1063 * @returns a list of environments for attributd classes.
1064 */
1065 public Queue<Env<AttrContext>> attribute(Queue<Env<AttrContext>> envs) {
1066 ListBuffer<Env<AttrContext>> results = lb();
1067 while (!envs.isEmpty())
1068 results.append(attribute(envs.remove()));
1069 return results;
1070 }
1071
1072 /**
1073 * Attribute a parse tree.
1074 * @returns the attributed parse tree
1075 */
1076 public Env<AttrContext> attribute(Env<AttrContext> env) {
1077 if (compileStates.isDone(env, CompileState.ATTR))
1078 return env;
1079
1080 if (verboseCompilePolicy)
1081 log.printLines(log.noticeWriter, "[attribute " + env.enclClass.sym + "]");
1082 if (verbose)
1083 printVerbose("checking.attribution", env.enclClass.sym);
1084
1085 if (taskListener != null) {
1086 TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym);
1087 taskListener.started(e);
1088 }
1089
1090 JavaFileObject prev = log.useSource(
1091 env.enclClass.sym.sourcefile != null ?
1092 env.enclClass.sym.sourcefile :
1093 env.toplevel.sourcefile);
1094 try {
1095 attr.attribClass(env.tree.pos(), env.enclClass.sym);
1096 compileStates.put(env, CompileState.ATTR);
1097 }
1098 finally {
1099 log.useSource(prev);
1100 }
1101
1102 return env;
1103 }
1104
1105 /**
1106 * Perform dataflow checks on attributed parse trees.
1107 * These include checks for definite assignment and unreachable statements.
1108 * If any errors occur, an empty list will be returned.
1109 * @returns the list of attributed parse trees
1110 */
1111 public Queue<Env<AttrContext>> flow(Queue<Env<AttrContext>> envs) {
1112 ListBuffer<Env<AttrContext>> results = lb();
1113 for (Env<AttrContext> env: envs) {
1114 flow(env, results);
1115 }
1116 return stopIfError(results);
1117 }
1118
1119 /**
1120 * Perform dataflow checks on an attributed parse tree.
1121 */
1122 public Queue<Env<AttrContext>> flow(Env<AttrContext> env) {
1123 ListBuffer<Env<AttrContext>> results = lb();
1124 flow(env, results);
1125 return stopIfError(results);
1126 }
1127
1128 /**
1129 * Perform dataflow checks on an attributed parse tree.
1130 */
1131 protected void flow(Env<AttrContext> env, Queue<Env<AttrContext>> results) {
1132 try {
1133 if (errorCount() > 0)
1134 return;
1135
1136 if (relax || compileStates.isDone(env, CompileState.FLOW)) {
1137 results.add(env);
1138 return;
1139 }
1140
1141 if (verboseCompilePolicy)
1142 log.printLines(log.noticeWriter, "[flow " + env.enclClass.sym + "]");
1143 JavaFileObject prev = log.useSource(
1144 env.enclClass.sym.sourcefile != null ?
1145 env.enclClass.sym.sourcefile :
1146 env.toplevel.sourcefile);
1147 try {
1148 make.at(Position.FIRSTPOS);
1149 TreeMaker localMake = make.forToplevel(env.toplevel);
1150 flow.analyzeTree(env.tree, localMake);
1151 compileStates.put(env, CompileState.FLOW);
1152
1153 if (errorCount() > 0)
1154 return;
1155
1156 results.add(env);
1157 }
1158 finally {
1159 log.useSource(prev);
1160 }
1161 }
1162 finally {
1163 if (taskListener != null) {
1164 TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym);
1165 taskListener.finished(e);
1166 }
1167 }
1168 }
1169
1170 /**
1171 * Prepare attributed parse trees, in conjunction with their attribution contexts,
1172 * for source or code generation.
1173 * If any errors occur, an empty list will be returned.
1174 * @returns a list containing the classes to be generated
1175 */
1176 public Queue<Pair<Env<AttrContext>, JCClassDecl>> desugar(Queue<Env<AttrContext>> envs) {
1177 ListBuffer<Pair<Env<AttrContext>, JCClassDecl>> results = lb();
1178 for (Env<AttrContext> env: envs)
1179 desugar(env, results);
1180 return stopIfError(results);
1181 }
1182
1183 /**
1184 * Prepare attributed parse trees, in conjunction with their attribution contexts,
1185 * for source or code generation. If the file was not listed on the command line,
1186 * the current implicitSourcePolicy is taken into account.
1187 * The preparation stops as soon as an error is found.
1188 */
1189 protected void desugar(final Env<AttrContext> env, Queue<Pair<Env<AttrContext>, JCClassDecl>> results) {
1190 if (errorCount() > 0)
1191 return;
1192
1193 if (implicitSourcePolicy == ImplicitSourcePolicy.NONE
1194 && !inputFiles.contains(env.toplevel.sourcefile)) {
1195 return;
1196 }
1197
1198 /**
1199 * As erasure (TransTypes) destroys information needed in flow analysis,
1200 * including information in supertypes, we need to ensure that supertypes
1201 * are processed through attribute and flow before subtypes are translated.
1202 */
1203 class ScanNested extends TreeScanner {
1204 Set<Env<AttrContext>> dependencies = new LinkedHashSet<Env<AttrContext>>();
1205 public void visitClassDef(JCClassDecl node) {
1206 Type st = types.supertype(node.sym.type);
1207 if (st.tag == TypeTags.CLASS) {
1208 ClassSymbol c = st.tsym.outermostClass();
1209 Env<AttrContext> stEnv = enter.getEnv(c);
1210 if (stEnv != null && env != stEnv) {
1211 if (dependencies.add(stEnv))
1212 scan(stEnv.tree);
1213 }
1214 }
1215 super.visitClassDef(node);
1216 }
1217 }
1218 ScanNested scanner = new ScanNested();
1219 scanner.scan(env.tree);
1220 for (Env<AttrContext> dep: scanner.dependencies) {
1221 if (!compileStates.isDone(dep, CompileState.FLOW))
1222 flow(attribute(dep));
1223 }
1224
1225 //We need to check for error another time as more classes might
1226 //have been attributed and analyzed at this stage
1227 if (errorCount() > 0)
1228 return;
1229
1230 if (verboseCompilePolicy)
1231 log.printLines(log.noticeWriter, "[desugar " + env.enclClass.sym + "]");
1232
1233 JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ?
1234 env.enclClass.sym.sourcefile :
1235 env.toplevel.sourcefile);
1236 try {
1237 //save tree prior to rewriting
1238 JCTree untranslated = env.tree;
1239
1240 make.at(Position.FIRSTPOS);
1241 TreeMaker localMake = make.forToplevel(env.toplevel);
1242
1243 if (env.tree instanceof JCCompilationUnit) {
1244 if (!(stubOutput || sourceOutput || printFlat)) {
1245 List<JCTree> pdef = lower.translateTopLevelClass(env, env.tree, localMake);
1246 if (pdef.head != null) {
1247 assert pdef.tail.isEmpty();
1248 results.add(new Pair<Env<AttrContext>, JCClassDecl>(env, (JCClassDecl)pdef.head));
1249 }
1250 }
1251 return;
1252 }
1253
1254 if (stubOutput) {
1255 //emit stub Java source file, only for compilation
1256 //units enumerated explicitly on the command line
1257 JCClassDecl cdef = (JCClassDecl)env.tree;
1258 if (untranslated instanceof JCClassDecl &&
1259 rootClasses.contains((JCClassDecl)untranslated) &&
1260 ((cdef.mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1261 cdef.sym.packge().getQualifiedName() == names.java_lang)) {
1262 results.add(new Pair<Env<AttrContext>, JCClassDecl>(env, removeMethodBodies(cdef)));
1263 }
1264 return;
1265 }
1266
1267 // mgr: staging additions
1268 env.tree = transStaging.translateTopLevelClass(env, env.tree, localMake);
1269 env.tree = transTypes.translateTopLevelClass(env.tree, localMake);
1270
1271 if (errorCount() != 0)
1272 return;
1273
1274 if (sourceOutput) {
1275 //emit standard Java source file, only for compilation
1276 //units enumerated explicitly on the command line
1277 JCClassDecl cdef = (JCClassDecl)env.tree;
1278 if (untranslated instanceof JCClassDecl &&
1279 rootClasses.contains((JCClassDecl)untranslated)) {
1280 results.add(new Pair<Env<AttrContext>, JCClassDecl>(env, cdef));
1281 }
1282 return;
1283 }
1284
1285 //translate out inner classes
1286 List<JCTree> cdefs = lower.translateTopLevelClass(env, env.tree, localMake);
1287
1288 if (errorCount() != 0)
1289 return;
1290
1291 //generate code for each class
1292 for (List<JCTree> l = cdefs; l.nonEmpty(); l = l.tail) {
1293 JCClassDecl cdef = (JCClassDecl)l.head;
1294 results.add(new Pair<Env<AttrContext>, JCClassDecl>(env, cdef));
1295 }
1296 }
1297 finally {
1298 log.useSource(prev);
1299 }
1300
1301 }
1302
1303 /** Generates the source or class file for a list of classes.
1304 * The decision to generate a source file or a class file is
1305 * based upon the compiler's options.
1306 * Generation stops if an error occurs while writing files.
1307 */
1308 public void generate(Queue<Pair<Env<AttrContext>, JCClassDecl>> queue) {
1309 generate(queue, null);
1310 }
1311
1312 public void generate(Queue<Pair<Env<AttrContext>, JCClassDecl>> queue, Queue<JavaFileObject> results) {
1313 boolean usePrintSource = (stubOutput || sourceOutput || printFlat);
1314
1315 for (Pair<Env<AttrContext>, JCClassDecl> x: queue) {
1316 Env<AttrContext> env = x.fst;
1317 JCClassDecl cdef = x.snd;
1318
1319 if (verboseCompilePolicy) {
1320 log.printLines(log.noticeWriter, "[generate "
1321 + (usePrintSource ? " source" : "code")
1322 + " " + cdef.sym + "]");
1323 }
1324
1325 if (taskListener != null) {
1326 TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
1327 taskListener.started(e);
1328 }
1329
1330 JavaFileObject prev = log.useSource(env.enclClass.sym.sourcefile != null ?
1331 env.enclClass.sym.sourcefile :
1332 env.toplevel.sourcefile);
1333 try {
1334 JavaFileObject file;
1335 if (usePrintSource)
1336 file = printSource(env, cdef);
1337 else
1338 file = genCode(env, cdef);
1339 if (results != null && file != null)
1340 results.add(file);
1341 } catch (IOException ex) {
1342 log.error(cdef.pos(), "class.cant.write",
1343 cdef.sym, ex.getMessage());
1344 return;
1345 } finally {
1346 log.useSource(prev);
1347 }
1348
1349 if (taskListener != null) {
1350 TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
1351 taskListener.finished(e);
1352 }
1353 }
1354 }
1355
1356 // where
1357 Map<JCCompilationUnit, Queue<Env<AttrContext>>> groupByFile(Queue<Env<AttrContext>> envs) {
1358 // use a LinkedHashMap to preserve the order of the original list as much as possible
1359 Map<JCCompilationUnit, Queue<Env<AttrContext>>> map = new LinkedHashMap<JCCompilationUnit, Queue<Env<AttrContext>>>();
1360 for (Env<AttrContext> env: envs) {
1361 Queue<Env<AttrContext>> sublist = map.get(env.toplevel);
1362 if (sublist == null) {
1363 sublist = new ListBuffer<Env<AttrContext>>();
1364 map.put(env.toplevel, sublist);
1365 }
1366 sublist.add(env);
1367 }
1368 return map;
1369 }
1370
1371 JCClassDecl removeMethodBodies(JCClassDecl cdef) {
1372 final boolean isInterface = (cdef.mods.flags & Flags.INTERFACE) != 0;
1373 class MethodBodyRemover extends TreeTranslator {
1374 public void visitMethodDef(JCMethodDecl tree) {
1375 tree.mods.flags &= ~Flags.SYNCHRONIZED;
1376 for (JCVariableDecl vd : tree.params)
1377 vd.mods.flags &= ~Flags.FINAL;
1378 tree.body = null;
1379 super.visitMethodDef(tree);
1380 }
1381 public void visitVarDef(JCVariableDecl tree) {
1382 if (tree.init != null && tree.init.type.constValue() == null)
1383 tree.init = null;
1384 super.visitVarDef(tree);
1385 }
1386 public void visitClassDef(JCClassDecl tree) {
1387 ListBuffer<JCTree> newdefs = lb();
1388 for (List<JCTree> it = tree.defs; it.tail != null; it = it.tail) {
1389 JCTree t = it.head;
1390 switch (t.getTag()) {
1391 case JCTree.CLASSDEF:
1392 if (isInterface ||
1393 (((JCClassDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1394 (((JCClassDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCClassDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1395 newdefs.append(t);
1396 break;
1397 case JCTree.METHODDEF:
1398 if (isInterface ||
1399 (((JCMethodDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1400 ((JCMethodDecl) t).sym.name == names.init ||
1401 (((JCMethodDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCMethodDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1402 newdefs.append(t);
1403 break;
1404 case JCTree.VARDEF:
1405 if (isInterface || (((JCVariableDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
1406 (((JCVariableDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCVariableDecl) t).sym.packge().getQualifiedName() == names.java_lang)
1407 newdefs.append(t);
1408 break;
1409 default:
1410 break;
1411 }
1412 }
1413 tree.defs = newdefs.toList();
1414 super.visitClassDef(tree);
1415 }
1416 }
1417 MethodBodyRemover r = new MethodBodyRemover();
1418 return r.translate(cdef);
1419 }
1420
1421 public void reportDeferredDiagnostics() {
1422 if (annotationProcessingOccurred
1423 && implicitSourceFilesRead
1424 && implicitSourcePolicy == ImplicitSourcePolicy.UNSET) {
1425 if (explicitAnnotationProcessingRequested())
1426 log.warning("proc.use.implicit");
1427 else
1428 log.warning("proc.use.proc.or.implicit");
1429 }
1430 chk.reportDeferredDiagnostics();
1431 }
1432
1433 /** Close the compiler, flushing the logs
1434 */
1435 public void close() {
1436 close(true);
1437 }
1438
1439 public void close(boolean disposeNames) {
1440 rootClasses = null;
1441 reader = null;
1442 make = null;
1443 writer = null;
1444 enter = null;
1445 if (todo != null)
1446 todo.clear();
1447 todo = null;
1448 parserFactory = null;
1449 syms = null;
1450 source = null;
1451 attr = null;
1452 chk = null;
1453 gen = null;
1454 flow = null;
1455 transTypes = null;
1456 lower = null;
1457 annotate = null;
1458 types = null;
1459
1460 log.flush();
1461 try {
1462 fileManager.flush();
1463 } catch (IOException e) {
1464 throw new Abort(e);
1465 } finally {
1466 if (names != null && disposeNames)
1467 names.dispose();
1468 names = null;
1469 }
1470 }
1471
1472 /** Output for "-verbose" option.
1473 * @param key The key to look up the correct internationalized string.
1474 * @param arg An argument for substitution into the output string.
1475 */
1476 protected void printVerbose(String key, Object arg) {
1477 Log.printLines(log.noticeWriter, log.getLocalizedString("verbose." + key, arg));
1478 }
1479
1480 /** Print numbers of errors and warnings.
1481 */
1482 protected void printCount(String kind, int count) {
1483 if (count != 0) {
1484 String text;
1485 if (count == 1)
1486 text = log.getLocalizedString("count." + kind, String.valueOf(count));
1487 else
1488 text = log.getLocalizedString("count." + kind + ".plural", String.valueOf(count));
1489 Log.printLines(log.errWriter, text);
1490 log.errWriter.flush();
1491 }
1492 }
1493
1494 private static long now() {
1495 return System.currentTimeMillis();
1496 }
1497
1498 private static long elapsed(long then) {
1499 return now() - then;
1500 }
1501
1502 public void initRound(JavaCompiler prev) {
1503 keepComments = prev.keepComments;
1504 start_msec = prev.start_msec;
1505 hasBeenUsed = true;
1506 }
1507
1508 public static void enableLogging() {
1509 Logger logger = Logger.getLogger(com.sun.tools.javac.Main.class.getPackage().getName());
1510 logger.setLevel(Level.ALL);
1511 for (Handler h : logger.getParent().getHandlers()) {
1512 h.setLevel(Level.ALL);
1513 }
1514
1515 }
1516 }