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