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