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