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