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