1 /* 2 * Copyright (c) 2005, 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.processing; 27 28 import java.io.Closeable; 29 import java.io.IOException; 30 import java.io.PrintWriter; 31 import java.io.StringWriter; 32 import java.lang.reflect.Method; 33 import java.util.*; 34 import java.util.Map.Entry; 35 import java.util.function.Predicate; 36 import java.util.regex.*; 37 38 import javax.annotation.processing.*; 39 import javax.lang.model.SourceVersion; 40 import javax.lang.model.element.*; 41 import javax.lang.model.util.*; 42 import javax.tools.Diagnostic; 43 import javax.tools.JavaFileManager; 44 import javax.tools.JavaFileObject; 45 import javax.tools.JavaFileObject.Kind; 46 47 import static javax.tools.StandardLocation.*; 48 49 import com.sun.source.util.TaskEvent; 50 import com.sun.tools.javac.api.MultiTaskListener; 51 import com.sun.tools.javac.code.*; 52 import com.sun.tools.javac.code.DeferredCompletionFailureHandler.Handler; 53 import com.sun.tools.javac.code.Scope.WriteableScope; 54 import com.sun.tools.javac.code.Source.Feature; 55 import com.sun.tools.javac.code.Symbol.*; 56 import com.sun.tools.javac.code.Type.ClassType; 57 import com.sun.tools.javac.code.Types; 58 import com.sun.tools.javac.comp.AttrContext; 59 import com.sun.tools.javac.comp.Check; 60 import com.sun.tools.javac.comp.Enter; 61 import com.sun.tools.javac.comp.Env; 62 import com.sun.tools.javac.comp.Modules; 63 import com.sun.tools.javac.main.JavaCompiler; 64 import com.sun.tools.javac.main.Option; 65 import com.sun.tools.javac.model.JavacElements; 66 import com.sun.tools.javac.model.JavacTypes; 67 import com.sun.tools.javac.platform.PlatformDescription; 68 import com.sun.tools.javac.platform.PlatformDescription.PluginInfo; 69 import com.sun.tools.javac.resources.CompilerProperties.Errors; 70 import com.sun.tools.javac.resources.CompilerProperties.LintWarnings; 71 import com.sun.tools.javac.resources.CompilerProperties.Warnings; 72 import com.sun.tools.javac.tree.*; 73 import com.sun.tools.javac.tree.JCTree.*; 74 import com.sun.tools.javac.util.Abort; 75 import com.sun.tools.javac.util.Assert; 76 import com.sun.tools.javac.util.ClientCodeException; 77 import com.sun.tools.javac.util.Context; 78 import com.sun.tools.javac.util.Convert; 79 import com.sun.tools.javac.util.DefinedBy; 80 import com.sun.tools.javac.util.DefinedBy.Api; 81 import com.sun.tools.javac.util.Iterators; 82 import com.sun.tools.javac.util.JCDiagnostic; 83 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; 84 import com.sun.tools.javac.util.JavacMessages; 85 import com.sun.tools.javac.util.List; 86 import com.sun.tools.javac.util.Log; 87 import com.sun.tools.javac.util.MatchingUtils; 88 import com.sun.tools.javac.util.ModuleHelper; 89 import com.sun.tools.javac.util.Name; 90 import com.sun.tools.javac.util.Names; 91 import com.sun.tools.javac.util.Options; 92 93 import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING; 94 import static com.sun.tools.javac.code.Kinds.Kind.*; 95 import com.sun.tools.javac.comp.Annotate; 96 import static com.sun.tools.javac.comp.CompileStates.CompileState; 97 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*; 98 99 /** 100 * Objects of this class hold and manage the state needed to support 101 * annotation processing. 102 * 103 * <p><b>This is NOT part of any supported API. 104 * If you write code that depends on this, you do so at your own risk. 105 * This code and its internal interfaces are subject to change or 106 * deletion without notice.</b> 107 */ 108 public class JavacProcessingEnvironment implements ProcessingEnvironment, Closeable { 109 private final Options options; 110 111 private final boolean printProcessorInfo; 112 private final boolean printRounds; 113 private final boolean verbose; 114 private final boolean fatalErrors; 115 private final boolean werror; 116 private final boolean showResolveErrors; 117 118 private final JavacFiler filer; 119 private final JavacMessager messager; 120 private final JavacElements elementUtils; 121 private final JavacTypes typeUtils; 122 private final JavaCompiler compiler; 123 private final Modules modules; 124 private final Types types; 125 private final Annotate annotate; 126 private final Lint lint; 127 128 /** 129 * Holds relevant state history of which processors have been 130 * used. 131 */ 132 private DiscoveredProcessors discoveredProcs; 133 134 /** 135 * Map of processor-specific options. 136 */ 137 private final Map<String, String> processorOptions; 138 139 /** 140 */ 141 private final Set<String> unmatchedProcessorOptions; 142 143 /** 144 * Annotations implicitly processed and claimed by javac. 145 */ 146 private final Set<String> platformAnnotations; 147 148 /** 149 * Set of packages given on command line. 150 */ 151 private Set<PackageSymbol> specifiedPackages = Collections.emptySet(); 152 153 /** The log to be used for error reporting. 154 */ 155 final Log log; 156 157 /** Diagnostic factory. 158 */ 159 JCDiagnostic.Factory diags; 160 161 /** 162 * Source level of the compile. 163 */ 164 Source source; 165 166 private ClassLoader processorClassLoader; 167 private ServiceLoader<Processor> serviceLoader; 168 169 private final JavaFileManager fileManager; 170 171 /** 172 * JavacMessages object used for localization 173 */ 174 private JavacMessages messages; 175 176 private MultiTaskListener taskListener; 177 private final Symtab symtab; 178 private final DeferredCompletionFailureHandler dcfh; 179 private final Names names; 180 private final Enter enter; 181 private final Completer initialCompleter; 182 private final Check chk; 183 184 private final Context context; 185 186 /** 187 * Support for preview language features. 188 */ 189 private final Preview preview; 190 191 /** Get the JavacProcessingEnvironment instance for this context. */ 192 public static JavacProcessingEnvironment instance(Context context) { 193 JavacProcessingEnvironment instance = context.get(JavacProcessingEnvironment.class); 194 if (instance == null) 195 instance = new JavacProcessingEnvironment(context); 196 return instance; 197 } 198 199 protected JavacProcessingEnvironment(Context context) { 200 this.context = context; 201 context.put(JavacProcessingEnvironment.class, this); 202 log = Log.instance(context); 203 source = Source.instance(context); 204 diags = JCDiagnostic.Factory.instance(context); 205 options = Options.instance(context); 206 printProcessorInfo = options.isSet(Option.XPRINTPROCESSORINFO); 207 printRounds = options.isSet(Option.XPRINTROUNDS); 208 verbose = options.isSet(Option.VERBOSE); 209 lint = Lint.instance(context); 210 compiler = JavaCompiler.instance(context); 211 if (options.isSet(Option.PROC, "only") || options.isSet(Option.XPRINT)) { 212 compiler.shouldStopPolicyIfNoError = CompileState.PROCESS; 213 } 214 fatalErrors = options.isSet("fatalEnterError"); 215 showResolveErrors = options.isSet("showResolveErrors"); 216 werror = options.isSet(Option.WERROR); 217 fileManager = context.get(JavaFileManager.class); 218 platformAnnotations = initPlatformAnnotations(); 219 220 // Initialize services before any processors are initialized 221 // in case processors use them. 222 filer = new JavacFiler(context); 223 messager = new JavacMessager(context, this); 224 elementUtils = JavacElements.instance(context); 225 typeUtils = JavacTypes.instance(context); 226 modules = Modules.instance(context); 227 types = Types.instance(context); 228 annotate = Annotate.instance(context); 229 processorOptions = initProcessorOptions(); 230 unmatchedProcessorOptions = initUnmatchedProcessorOptions(); 231 messages = JavacMessages.instance(context); 232 taskListener = MultiTaskListener.instance(context); 233 symtab = Symtab.instance(context); 234 dcfh = DeferredCompletionFailureHandler.instance(context); 235 names = Names.instance(context); 236 enter = Enter.instance(context); 237 initialCompleter = ClassFinder.instance(context).getCompleter(); 238 chk = Check.instance(context); 239 preview = Preview.instance(context); 240 initProcessorLoader(); 241 } 242 243 public void setProcessors(Iterable<? extends Processor> processors) { 244 Assert.checkNull(discoveredProcs); 245 initProcessorIterator(processors); 246 } 247 248 private Set<String> initPlatformAnnotations() { 249 final String module_prefix = 250 Feature.MODULES.allowedInSource(source) ? "java.base/" : ""; 251 return Set.of(module_prefix + "java.lang.Deprecated", 252 module_prefix + "java.lang.FunctionalInterface", 253 module_prefix + "java.lang.Override", 254 module_prefix + "java.lang.SafeVarargs", 255 module_prefix + "java.lang.SuppressWarnings", 256 257 module_prefix + "java.lang.annotation.Documented", 258 module_prefix + "java.lang.annotation.Inherited", 259 module_prefix + "java.lang.annotation.Native", 260 module_prefix + "java.lang.annotation.Repeatable", 261 module_prefix + "java.lang.annotation.Retention", 262 module_prefix + "java.lang.annotation.Target", 263 264 module_prefix + "java.io.Serial"); 265 } 266 267 private void initProcessorLoader() { 268 if (fileManager.hasLocation(ANNOTATION_PROCESSOR_MODULE_PATH)) { 269 try { 270 serviceLoader = fileManager.getServiceLoader(ANNOTATION_PROCESSOR_MODULE_PATH, Processor.class); 271 } catch (IOException e) { 272 throw new Abort(e); 273 } 274 } else { 275 // If processorpath is not explicitly set, use the classpath. 276 processorClassLoader = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH) 277 ? fileManager.getClassLoader(ANNOTATION_PROCESSOR_PATH) 278 : fileManager.getClassLoader(CLASS_PATH); 279 280 if (options.isSet("accessInternalAPI")) 281 ModuleHelper.addExports(getClass().getModule(), processorClassLoader.getUnnamedModule()); 282 283 if (processorClassLoader != null && processorClassLoader instanceof Closeable closeable) { 284 compiler.closeables = compiler.closeables.prepend(closeable); 285 } 286 } 287 } 288 289 private void initProcessorIterator(Iterable<? extends Processor> processors) { 290 Iterator<? extends Processor> processorIterator; 291 292 if (options.isSet(Option.XPRINT)) { 293 try { 294 processorIterator = List.of(new PrintingProcessor()).iterator(); 295 } catch (Throwable t) { 296 throw new AssertionError("Problem instantiating PrintingProcessor.", t); 297 } 298 } else if (processors != null) { 299 processorIterator = processors.iterator(); 300 } else { 301 /* 302 * If the "-processor" option is used, search the appropriate 303 * path for the named class. Otherwise, use a service 304 * provider mechanism to create the processor iterator. 305 * 306 * Note: if an explicit processor path is not set, 307 * only the class path and _not_ the module path are 308 * searched for processors. 309 */ 310 String processorNames = options.get(Option.PROCESSOR); 311 if (fileManager.hasLocation(ANNOTATION_PROCESSOR_MODULE_PATH)) { 312 processorIterator = (processorNames == null) ? 313 new ServiceIterator(serviceLoader, log) : 314 new NameServiceIterator(serviceLoader, log, processorNames); 315 } else if (processorNames != null) { 316 processorIterator = new NameProcessIterator(processorNames, processorClassLoader, log); 317 } else { 318 processorIterator = new ServiceIterator(processorClassLoader, log); 319 } 320 } 321 PlatformDescription platformProvider = context.get(PlatformDescription.class); 322 java.util.List<Processor> platformProcessors = Collections.emptyList(); 323 if (platformProvider != null) { 324 platformProcessors = platformProvider.getAnnotationProcessors() 325 .stream() 326 .map(PluginInfo::getPlugin) 327 .toList(); 328 } 329 List<Iterator<? extends Processor>> iterators = List.of(processorIterator, 330 platformProcessors.iterator()); 331 Iterator<? extends Processor> compoundIterator = 332 Iterators.createCompoundIterator(iterators, i -> i); 333 discoveredProcs = new DiscoveredProcessors(compoundIterator); 334 } 335 336 public <S> ServiceLoader<S> getServiceLoader(Class<S> service) { 337 if (fileManager.hasLocation(ANNOTATION_PROCESSOR_MODULE_PATH)) { 338 try { 339 return fileManager.getServiceLoader(ANNOTATION_PROCESSOR_MODULE_PATH, service); 340 } catch (IOException e) { 341 throw new Abort(e); 342 } 343 } else { 344 return ServiceLoader.load(service, getProcessorClassLoader()); 345 } 346 } 347 348 /** 349 * Use a service loader appropriate for the platform to provide an 350 * iterator over annotations processors; fails if a loader is 351 * needed but unavailable. 352 */ 353 private class ServiceIterator implements Iterator<Processor> { 354 Iterator<Processor> iterator; 355 Log log; 356 ServiceLoader<Processor> loader; 357 358 ServiceIterator(ClassLoader classLoader, Log log) { 359 this.log = log; 360 try { 361 loader = ServiceLoader.load(Processor.class, classLoader); 362 this.iterator = loader.iterator(); 363 } catch (Throwable t) { 364 log.error(Errors.ProcServiceProblem); 365 throw new Abort(t); 366 } 367 } 368 369 ServiceIterator(ServiceLoader<Processor> loader, Log log) { 370 this.log = log; 371 this.loader = loader; 372 this.iterator = loader.iterator(); 373 } 374 375 @Override 376 public boolean hasNext() { 377 try { 378 return internalHasNext(); 379 } catch(ServiceConfigurationError sce) { 380 log.error(Errors.ProcBadConfigFile(sce.getLocalizedMessage())); 381 throw new Abort(sce); 382 } catch (UnsupportedClassVersionError ucve) { 383 log.error(Errors.ProcCantLoadClass(ucve.getLocalizedMessage())); 384 throw new Abort(ucve); 385 } catch (ClassFormatError cfe) { 386 log.error(Errors.ProcCantLoadClass(cfe.getLocalizedMessage())); 387 throw new Abort(cfe); 388 } catch (Throwable t) { 389 log.error(Errors.ProcBadConfigFile(t.getLocalizedMessage())); 390 throw new Abort(t); 391 } 392 } 393 394 boolean internalHasNext() { 395 return iterator.hasNext(); 396 } 397 398 @Override 399 public Processor next() { 400 try { 401 return internalNext(); 402 } catch (ServiceConfigurationError sce) { 403 log.error(Errors.ProcBadConfigFile(sce.getLocalizedMessage())); 404 throw new Abort(sce); 405 } catch (Throwable t) { 406 log.error(Errors.ProcBadConfigFile(t.getLocalizedMessage())); 407 throw new Abort(t); 408 } 409 } 410 411 Processor internalNext() { 412 return iterator.next(); 413 } 414 415 @Override 416 public void remove() { 417 throw new UnsupportedOperationException(); 418 } 419 420 public void close() { 421 if (loader != null) { 422 try { 423 loader.reload(); 424 } catch(Exception e) { 425 // Ignore problems during a call to reload. 426 } 427 } 428 } 429 } 430 431 private class NameServiceIterator extends ServiceIterator { 432 private Map<String, Processor> namedProcessorsMap = new HashMap<>(); 433 private Iterator<String> processorNames = null; 434 private Processor nextProc = null; 435 436 public NameServiceIterator(ServiceLoader<Processor> loader, Log log, String theNames) { 437 super(loader, log); 438 this.processorNames = Arrays.asList(theNames.split(",")).iterator(); 439 } 440 441 @Override 442 boolean internalHasNext() { 443 if (nextProc != null) { 444 return true; 445 } 446 if (!processorNames.hasNext()) { 447 namedProcessorsMap = null; 448 return false; 449 } 450 String processorName = processorNames.next(); 451 Processor theProcessor = namedProcessorsMap.get(processorName); 452 if (theProcessor != null) { 453 namedProcessorsMap.remove(processorName); 454 nextProc = theProcessor; 455 return true; 456 } else { 457 while (iterator.hasNext()) { 458 theProcessor = iterator.next(); 459 String name = theProcessor.getClass().getName(); 460 if (name.equals(processorName)) { 461 nextProc = theProcessor; 462 return true; 463 } else { 464 namedProcessorsMap.put(name, theProcessor); 465 } 466 } 467 log.error(Errors.ProcProcessorNotFound(processorName)); 468 return false; 469 } 470 } 471 472 @Override 473 Processor internalNext() { 474 if (hasNext()) { 475 Processor p = nextProc; 476 nextProc = null; 477 return p; 478 } else { 479 throw new NoSuchElementException(); 480 } 481 } 482 } 483 484 private static class NameProcessIterator implements Iterator<Processor> { 485 Processor nextProc = null; 486 Iterator<String> names; 487 ClassLoader processorCL; 488 Log log; 489 490 NameProcessIterator(String names, ClassLoader processorCL, Log log) { 491 this.names = Arrays.asList(names.split(",")).iterator(); 492 this.processorCL = processorCL; 493 this.log = log; 494 } 495 496 public boolean hasNext() { 497 if (nextProc != null) 498 return true; 499 else { 500 if (!names.hasNext()) { 501 return false; 502 } else { 503 Processor processor = getNextProcessor(names.next()); 504 if (processor == null) { 505 return false; 506 } else { 507 nextProc = processor; 508 return true; 509 } 510 } 511 } 512 } 513 514 private Processor getNextProcessor(String processorName) { 515 try { 516 try { 517 Class<?> processorClass = processorCL.loadClass(processorName); 518 ensureReadable(processorClass); 519 return (Processor) processorClass.getConstructor().newInstance(); 520 } catch (ClassNotFoundException cnfe) { 521 log.error(Errors.ProcProcessorNotFound(processorName)); 522 return null; 523 } catch (ClassCastException cce) { 524 log.error(Errors.ProcProcessorWrongType(processorName)); 525 return null; 526 } catch (Exception e ) { 527 log.error(Errors.ProcProcessorCantInstantiate(processorName)); 528 return null; 529 } 530 } catch (ClientCodeException e) { 531 throw e; 532 } catch (Throwable t) { 533 throw new AnnotationProcessingError(t); 534 } 535 } 536 537 public Processor next() { 538 if (hasNext()) { 539 Processor p = nextProc; 540 nextProc = null; 541 return p; 542 } else 543 throw new NoSuchElementException(); 544 } 545 546 public void remove () { 547 throw new UnsupportedOperationException(); 548 } 549 550 /** 551 * Ensures that the module of the given class is readable to this 552 * module. 553 */ 554 private void ensureReadable(Class<?> targetClass) { 555 try { 556 Method getModuleMethod = Class.class.getMethod("getModule"); 557 Object thisModule = getModuleMethod.invoke(this.getClass()); 558 Object targetModule = getModuleMethod.invoke(targetClass); 559 560 Class<?> moduleClass = getModuleMethod.getReturnType(); 561 Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass); 562 addReadsMethod.invoke(thisModule, targetModule); 563 } catch (NoSuchMethodException e) { 564 // ignore 565 } catch (Exception e) { 566 throw new InternalError(e); 567 } 568 } 569 } 570 571 public boolean atLeastOneProcessor() { 572 return discoveredProcs.iterator().hasNext(); 573 } 574 575 private Map<String, String> initProcessorOptions() { 576 Set<String> keySet = options.keySet(); 577 Map<String, String> tempOptions = new LinkedHashMap<>(); 578 579 for(String key : keySet) { 580 if (key.startsWith("-A") && key.length() > 2) { 581 int sepIndex = key.indexOf('='); 582 String candidateKey = null; 583 String candidateValue = null; 584 585 if (sepIndex == -1) 586 candidateKey = key.substring(2); 587 else if (sepIndex >= 3) { 588 candidateKey = key.substring(2, sepIndex); 589 candidateValue = (sepIndex < key.length()-1)? 590 key.substring(sepIndex+1) : null; 591 } 592 tempOptions.put(candidateKey, candidateValue); 593 } 594 } 595 596 PlatformDescription platformProvider = context.get(PlatformDescription.class); 597 598 if (platformProvider != null) { 599 for (PluginInfo<Processor> ap : platformProvider.getAnnotationProcessors()) { 600 tempOptions.putAll(ap.getOptions()); 601 } 602 } 603 604 return Collections.unmodifiableMap(tempOptions); 605 } 606 607 private Set<String> initUnmatchedProcessorOptions() { 608 Set<String> unmatchedProcessorOptions = new HashSet<>(); 609 unmatchedProcessorOptions.addAll(processorOptions.keySet()); 610 return unmatchedProcessorOptions; 611 } 612 613 /** 614 * State about how a processor has been used by the tool. If a 615 * processor has been used on a prior round, its process method is 616 * called on all subsequent rounds, perhaps with an empty set of 617 * annotations to process. The {@code annotationSupported} method 618 * caches the supported annotation information from the first (and 619 * only) getSupportedAnnotationTypes call to the processor. 620 */ 621 static class ProcessorState { 622 public Processor processor; 623 public boolean contributed; 624 private Set<String> supportedAnnotationStrings; // Used for warning generation 625 private Set<Pattern> supportedAnnotationPatterns; 626 private Set<String> supportedOptionNames; 627 628 ProcessorState(Processor p, Log log, Source source, DeferredCompletionFailureHandler dcfh, 629 boolean allowModules, ProcessingEnvironment env, Lint lint) { 630 processor = p; 631 contributed = false; 632 633 Handler prevDeferredHandler = dcfh.setHandler(dcfh.userCodeHandler); 634 try { 635 processor.init(env); 636 637 checkSourceVersionCompatibility(source, log); 638 639 640 // Check for direct duplicates in the strings of 641 // supported annotation types. Do not check for 642 // duplicates that would result after stripping of 643 // module prefixes. 644 supportedAnnotationStrings = new LinkedHashSet<>(); 645 supportedAnnotationPatterns = new LinkedHashSet<>(); 646 for (String annotationPattern : processor.getSupportedAnnotationTypes()) { 647 boolean patternAdded = supportedAnnotationStrings.add(annotationPattern); 648 649 supportedAnnotationPatterns. 650 add(importStringToPattern(allowModules, annotationPattern, 651 processor, log, lint)); 652 if (!patternAdded) { 653 lint.logIfEnabled(LintWarnings.ProcDuplicateSupportedAnnotation(annotationPattern, 654 p.getClass().getName())); 655 } 656 } 657 658 // If a processor supports "*", that matches 659 // everything and other entries are redundant. With 660 // more work, it could be checked that the supported 661 // annotation types were otherwise non-overlapping 662 // with each other in other cases, for example "foo.*" 663 // and "foo.bar.*". 664 if (supportedAnnotationPatterns.contains(MatchingUtils.validImportStringToPattern("*")) && 665 supportedAnnotationPatterns.size() > 1) { 666 lint.logIfEnabled(LintWarnings.ProcRedundantTypesWithWildcard(p.getClass().getName())); 667 } 668 669 supportedOptionNames = new LinkedHashSet<>(); 670 for (String optionName : processor.getSupportedOptions() ) { 671 if (checkOptionName(optionName, log)) { 672 boolean optionAdded = supportedOptionNames.add(optionName); 673 if (!optionAdded) { 674 lint.logIfEnabled(LintWarnings.ProcDuplicateOptionName(optionName, 675 p.getClass().getName())); 676 } 677 } 678 } 679 680 } catch (ClientCodeException e) { 681 throw e; 682 } catch (Throwable t) { 683 throw new AnnotationProcessingError(t); 684 } finally { 685 dcfh.setHandler(prevDeferredHandler); 686 } 687 } 688 689 /** 690 * Checks whether or not a processor's source version is 691 * compatible with the compilation source version. The 692 * processor's source version needs to be greater than or 693 * equal to the source version of the compile. 694 */ 695 private void checkSourceVersionCompatibility(Source source, Log log) { 696 SourceVersion procSourceVersion = processor.getSupportedSourceVersion(); 697 if (procSourceVersion.compareTo(Source.toSourceVersion(source)) < 0 ) { 698 log.warning(Warnings.ProcProcessorIncompatibleSourceVersion(procSourceVersion, 699 processor.getClass().getName(), 700 source.name)); 701 } 702 } 703 704 private boolean checkOptionName(String optionName, Log log) { 705 boolean valid = isValidOptionName(optionName); 706 if (!valid) 707 log.error(Errors.ProcProcessorBadOptionName(optionName, 708 processor.getClass().getName())); 709 return valid; 710 } 711 712 public boolean annotationSupported(String annotationName) { 713 for(Pattern p: supportedAnnotationPatterns) { 714 if (p.matcher(annotationName).matches()) 715 return true; 716 } 717 return false; 718 } 719 720 /** 721 * Remove options that are matched by this processor. 722 */ 723 public void removeSupportedOptions(Set<String> unmatchedProcessorOptions) { 724 unmatchedProcessorOptions.removeAll(supportedOptionNames); 725 } 726 } 727 728 // TODO: These two classes can probably be rewritten better... 729 /** 730 * This class holds information about the processors that have 731 * been discovered so far as well as the means to discover more, if 732 * necessary. A single iterator should be used per round of 733 * annotation processing. The iterator first visits already 734 * discovered processors then fails over to the service provider 735 * mechanism if additional queries are made. 736 */ 737 class DiscoveredProcessors implements Iterable<ProcessorState> { 738 739 class ProcessorStateIterator implements Iterator<ProcessorState> { 740 DiscoveredProcessors psi; 741 Iterator<ProcessorState> innerIter; 742 boolean onProcIterator; 743 744 ProcessorStateIterator(DiscoveredProcessors psi) { 745 this.psi = psi; 746 this.innerIter = psi.procStateList.iterator(); 747 this.onProcIterator = false; 748 } 749 750 public ProcessorState next() { 751 if (!onProcIterator) { 752 if (innerIter.hasNext()) 753 return innerIter.next(); 754 else 755 onProcIterator = true; 756 } 757 758 if (psi.processorIterator.hasNext()) { 759 ProcessorState ps = new ProcessorState(psi.processorIterator.next(), 760 log, source, dcfh, 761 Feature.MODULES.allowedInSource(source), 762 JavacProcessingEnvironment.this, 763 lint); 764 psi.procStateList.add(ps); 765 return ps; 766 } else 767 throw new NoSuchElementException(); 768 } 769 770 public boolean hasNext() { 771 if (onProcIterator) 772 return psi.processorIterator.hasNext(); 773 else 774 return innerIter.hasNext() || psi.processorIterator.hasNext(); 775 } 776 777 public void remove () { 778 throw new UnsupportedOperationException(); 779 } 780 781 /** 782 * Run all remaining processors on the procStateList that 783 * have not already run this round with an empty set of 784 * annotations. 785 */ 786 public void runContributingProcs(RoundEnvironment re) { 787 if (!onProcIterator) { 788 Set<TypeElement> emptyTypeElements = Collections.emptySet(); 789 while(innerIter.hasNext()) { 790 ProcessorState ps = innerIter.next(); 791 if (ps.contributed) 792 callProcessor(ps.processor, emptyTypeElements, re); 793 } 794 } 795 } 796 } 797 798 Iterator<? extends Processor> processorIterator; 799 ArrayList<ProcessorState> procStateList; 800 801 public ProcessorStateIterator iterator() { 802 return new ProcessorStateIterator(this); 803 } 804 805 DiscoveredProcessors(Iterator<? extends Processor> processorIterator) { 806 this.processorIterator = processorIterator; 807 this.procStateList = new ArrayList<>(); 808 } 809 810 /** 811 * Free jar files, etc. if using a service loader. 812 */ 813 public void close() { 814 if (processorIterator != null && 815 processorIterator instanceof ServiceIterator serviceIterator) { 816 serviceIterator.close(); 817 } 818 } 819 } 820 821 private void discoverAndRunProcs(Set<TypeElement> annotationsPresent, 822 List<ClassSymbol> topLevelClasses, 823 List<PackageSymbol> packageInfoFiles, 824 List<ModuleSymbol> moduleInfoFiles) { 825 Map<String, TypeElement> unmatchedAnnotations = new HashMap<>(annotationsPresent.size()); 826 827 for(TypeElement a : annotationsPresent) { 828 ModuleElement mod = elementUtils.getModuleOf(a); 829 String moduleSpec = Feature.MODULES.allowedInSource(source) && mod != null ? mod.getQualifiedName() + "/" : ""; 830 unmatchedAnnotations.put(moduleSpec + a.getQualifiedName().toString(), 831 a); 832 } 833 834 // Give "*" processors a chance to match 835 if (unmatchedAnnotations.size() == 0) 836 unmatchedAnnotations.put("", null); 837 838 DiscoveredProcessors.ProcessorStateIterator psi = discoveredProcs.iterator(); 839 // TODO: Create proper argument values; need past round 840 // information to fill in this constructor. Note that the 1 841 // st round of processing could be the last round if there 842 // were parse errors on the initial source files; however, we 843 // are not doing processing in that case. 844 845 Set<Element> rootElements = new LinkedHashSet<>(); 846 rootElements.addAll(topLevelClasses); 847 rootElements.addAll(packageInfoFiles); 848 rootElements.addAll(moduleInfoFiles); 849 rootElements = Collections.unmodifiableSet(rootElements); 850 851 RoundEnvironment renv = new JavacRoundEnvironment(false, 852 false, 853 rootElements, 854 JavacProcessingEnvironment.this); 855 856 while(unmatchedAnnotations.size() > 0 && psi.hasNext() ) { 857 ProcessorState ps = psi.next(); 858 Set<String> matchedNames = new HashSet<>(); 859 Set<TypeElement> typeElements = new LinkedHashSet<>(); 860 861 for (Map.Entry<String, TypeElement> entry: unmatchedAnnotations.entrySet()) { 862 String unmatchedAnnotationName = entry.getKey(); 863 if (ps.annotationSupported(unmatchedAnnotationName) ) { 864 matchedNames.add(unmatchedAnnotationName); 865 TypeElement te = entry.getValue(); 866 if (te != null) 867 typeElements.add(te); 868 } 869 } 870 871 if (matchedNames.size() > 0 || ps.contributed) { 872 boolean processingResult = callProcessor(ps.processor, typeElements, renv); 873 ps.contributed = true; 874 ps.removeSupportedOptions(unmatchedProcessorOptions); 875 876 if (printProcessorInfo || verbose) { 877 log.printLines("x.print.processor.info", 878 ps.processor.getClass().getName(), 879 matchedNames.toString(), 880 processingResult); 881 } 882 883 if (processingResult) { 884 unmatchedAnnotations.keySet().removeAll(matchedNames); 885 } 886 887 } 888 } 889 unmatchedAnnotations.remove(""); 890 891 if (lint.isEnabled(PROCESSING) && unmatchedAnnotations.size() > 0) { 892 // Remove annotations processed by javac 893 unmatchedAnnotations.keySet().removeAll(platformAnnotations); 894 if (unmatchedAnnotations.size() > 0) { 895 log.warning(LintWarnings.ProcAnnotationsWithoutProcessors(unmatchedAnnotations.keySet())); 896 } 897 } 898 899 // Run contributing processors that haven't run yet 900 psi.runContributingProcs(renv); 901 } 902 903 /** 904 * Computes the set of annotations on the symbol in question. 905 * Leave class public for external testing purposes. 906 */ 907 public static class ComputeAnnotationSet extends 908 ElementScanner14<Set<TypeElement>, Set<TypeElement>> { 909 final Elements elements; 910 911 public ComputeAnnotationSet(Elements elements) { 912 super(); 913 this.elements = elements; 914 } 915 916 @Override @DefinedBy(Api.LANGUAGE_MODEL) 917 public Set<TypeElement> visitPackage(PackageElement e, Set<TypeElement> p) { 918 // Don't scan enclosed elements of a package 919 return p; 920 } 921 922 @Override @DefinedBy(Api.LANGUAGE_MODEL) 923 public Set<TypeElement> visitType(TypeElement e, Set<TypeElement> p) { 924 // Type parameters are not considered to be enclosed by a type 925 scan(e.getTypeParameters(), p); 926 return super.visitType(e, p); 927 } 928 929 @Override @DefinedBy(Api.LANGUAGE_MODEL) 930 public Set<TypeElement> visitExecutable(ExecutableElement e, Set<TypeElement> p) { 931 // Type parameters are not considered to be enclosed by an executable 932 scan(e.getTypeParameters(), p); 933 return super.visitExecutable(e, p); 934 } 935 936 void addAnnotations(Element e, Set<TypeElement> p) { 937 for (AnnotationMirror annotationMirror : 938 elements.getAllAnnotationMirrors(e) ) { 939 Element e2 = annotationMirror.getAnnotationType().asElement(); 940 p.add((TypeElement) e2); 941 } 942 } 943 944 @Override @DefinedBy(Api.LANGUAGE_MODEL) 945 public Set<TypeElement> scan(Element e, Set<TypeElement> p) { 946 addAnnotations(e, p); 947 return super.scan(e, p); 948 } 949 } 950 951 private boolean callProcessor(Processor proc, 952 Set<? extends TypeElement> tes, 953 RoundEnvironment renv) { 954 Handler prevDeferredHandler = dcfh.setHandler(dcfh.userCodeHandler); 955 try { 956 return proc.process(tes, renv); 957 } catch (ClassFinder.BadClassFile ex) { 958 log.error(Errors.ProcCantAccess1(ex.sym, ex.getDetailValue())); 959 return false; 960 } catch (CompletionFailure ex) { 961 StringWriter out = new StringWriter(); 962 ex.printStackTrace(new PrintWriter(out)); 963 log.error(Errors.ProcCantAccess(ex.sym, ex.getDetailValue(), out.toString())); 964 return false; 965 } catch (ClientCodeException e) { 966 throw e; 967 } catch (Throwable t) { 968 throw new AnnotationProcessingError(t); 969 } finally { 970 dcfh.setHandler(prevDeferredHandler); 971 } 972 } 973 974 /** 975 * Helper object for a single round of annotation processing. 976 */ 977 class Round { 978 /** The round number. */ 979 final int number; 980 /** The diagnostic handler for the round. */ 981 final Log.DeferredDiagnosticHandler deferredDiagnosticHandler; 982 983 /** The ASTs to be compiled. */ 984 List<JCCompilationUnit> roots; 985 /** The trees that need to be cleaned - includes roots and implicitly parsed trees. */ 986 Set<JCCompilationUnit> treesToClean; 987 /** The classes to be compiler that have were generated. */ 988 Map<ModuleSymbol, Map<String, JavaFileObject>> genClassFiles; 989 990 /** The set of annotations to be processed this round. */ 991 Set<TypeElement> annotationsPresent; 992 /** The set of top level classes to be processed this round. */ 993 List<ClassSymbol> topLevelClasses; 994 /** The set of package-info files to be processed this round. */ 995 List<PackageSymbol> packageInfoFiles; 996 /** The set of module-info files to be processed this round. */ 997 List<ModuleSymbol> moduleInfoFiles; 998 999 /** Create a round (common code). */ 1000 private Round(int number, Set<JCCompilationUnit> treesToClean, 1001 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { 1002 this.number = number; 1003 1004 if (number == 1) { 1005 Assert.checkNonNull(deferredDiagnosticHandler); 1006 this.deferredDiagnosticHandler = deferredDiagnosticHandler; 1007 } else { 1008 this.deferredDiagnosticHandler = log.new DeferredDiagnosticHandler(); 1009 compiler.setDeferredDiagnosticHandler(this.deferredDiagnosticHandler); 1010 } 1011 1012 // the following will be populated as needed 1013 topLevelClasses = List.nil(); 1014 packageInfoFiles = List.nil(); 1015 moduleInfoFiles = List.nil(); 1016 this.treesToClean = treesToClean; 1017 } 1018 1019 /** Create the first round. */ 1020 Round(List<JCCompilationUnit> roots, 1021 List<ClassSymbol> classSymbols, 1022 Set<JCCompilationUnit> treesToClean, 1023 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { 1024 this(1, treesToClean, deferredDiagnosticHandler); 1025 this.roots = roots; 1026 genClassFiles = new HashMap<>(); 1027 1028 // The reverse() in the following line is to maintain behavioural 1029 // compatibility with the previous revision of the code. Strictly speaking, 1030 // it should not be necessary, but a javah golden file test fails without it. 1031 topLevelClasses = 1032 getTopLevelClasses(roots).prependList(classSymbols.reverse()); 1033 1034 packageInfoFiles = getPackageInfoFiles(roots); 1035 1036 moduleInfoFiles = getModuleInfoFiles(roots); 1037 1038 findAnnotationsPresent(); 1039 } 1040 1041 /** Create a new round. */ 1042 private Round(Round prev, 1043 Set<JavaFileObject> newSourceFiles, Map<ModuleSymbol, Map<String,JavaFileObject>> newClassFiles) { 1044 this(prev.number+1, prev.treesToClean, null); 1045 prev.newRound(); 1046 this.genClassFiles = prev.genClassFiles; 1047 1048 //parse the generated files even despite errors reported so far, to eliminate 1049 //recoverable errors related to the type declared in the generated files: 1050 List<JCCompilationUnit> parsedFiles = compiler.parseFiles(newSourceFiles, true); 1051 roots = prev.roots.appendList(parsedFiles); 1052 1053 // Check for errors after parsing 1054 if (unrecoverableError()) { 1055 compiler.initModules(List.nil()); 1056 return; 1057 } 1058 1059 roots = compiler.initModules(roots); 1060 1061 enterClassFiles(genClassFiles); 1062 List<ClassSymbol> newClasses = enterClassFiles(newClassFiles); 1063 for (Entry<ModuleSymbol, Map<String, JavaFileObject>> moduleAndClassFiles : newClassFiles.entrySet()) { 1064 genClassFiles.computeIfAbsent(moduleAndClassFiles.getKey(), m -> new LinkedHashMap<>()).putAll(moduleAndClassFiles.getValue()); 1065 } 1066 enterTrees(roots); 1067 1068 if (unrecoverableError()) 1069 return; 1070 1071 topLevelClasses = join( 1072 getTopLevelClasses(parsedFiles), 1073 getTopLevelClassesFromClasses(newClasses)); 1074 1075 packageInfoFiles = join( 1076 getPackageInfoFiles(parsedFiles), 1077 getPackageInfoFilesFromClasses(newClasses)); 1078 1079 moduleInfoFiles = List.nil(); //module-info cannot be generated 1080 1081 findAnnotationsPresent(); 1082 } 1083 1084 /** Create the next round to be used. */ 1085 Round next(Set<JavaFileObject> newSourceFiles, Map<ModuleSymbol, Map<String, JavaFileObject>> newClassFiles) { 1086 return new Round(this, newSourceFiles, newClassFiles); 1087 } 1088 1089 /** Prepare the compiler for the final compilation. */ 1090 void finalCompiler() { 1091 newRound(); 1092 } 1093 1094 /** Return the number of errors found so far in this round. 1095 * This may include unrecoverable errors, such as parse errors, 1096 * and transient errors, such as missing symbols. */ 1097 int errorCount() { 1098 return compiler.errorCount(); 1099 } 1100 1101 /** Return the number of warnings found so far in this round. */ 1102 int warningCount() { 1103 return compiler.warningCount(); 1104 } 1105 1106 /** Return whether or not an unrecoverable error has occurred. */ 1107 boolean unrecoverableError() { 1108 if (messager.errorRaised()) 1109 return true; 1110 1111 return deferredDiagnosticHandler.getDiagnostics().stream() 1112 .anyMatch(d -> (d.getKind() == Diagnostic.Kind.WARNING && werror) || 1113 (d.getKind() == Diagnostic.Kind.ERROR && (fatalErrors || !d.isFlagSet(RECOVERABLE)))); 1114 } 1115 1116 /** Find the set of annotations present in the set of top level 1117 * classes and package info files to be processed this round. */ 1118 void findAnnotationsPresent() { 1119 ComputeAnnotationSet annotationComputer = new ComputeAnnotationSet(elementUtils); 1120 // Use annotation processing to compute the set of annotations present 1121 annotationsPresent = new LinkedHashSet<>(); 1122 for (ClassSymbol classSym : topLevelClasses) 1123 annotationComputer.scan(classSym, annotationsPresent); 1124 for (PackageSymbol pkgSym : packageInfoFiles) 1125 annotationComputer.scan(pkgSym, annotationsPresent); 1126 for (ModuleSymbol mdlSym : moduleInfoFiles) 1127 annotationComputer.scan(mdlSym, annotationsPresent); 1128 } 1129 1130 /** Enter a set of generated class files. */ 1131 private List<ClassSymbol> enterClassFiles(Map<ModuleSymbol, Map<String, JavaFileObject>> modulesAndClassFiles) { 1132 List<ClassSymbol> list = List.nil(); 1133 1134 for (Entry<ModuleSymbol, Map<String, JavaFileObject>> moduleAndClassFiles : modulesAndClassFiles.entrySet()) { 1135 for (Map.Entry<String,JavaFileObject> entry : moduleAndClassFiles.getValue().entrySet()) { 1136 Name name = names.fromString(entry.getKey()); 1137 JavaFileObject file = entry.getValue(); 1138 if (file.getKind() != JavaFileObject.Kind.CLASS) 1139 throw new AssertionError(file); 1140 ClassSymbol cs; 1141 if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) { 1142 Name packageName = Convert.packagePart(name); 1143 PackageSymbol p = symtab.enterPackage(moduleAndClassFiles.getKey(), packageName); 1144 if (p.package_info == null) 1145 p.package_info = symtab.enterClass(moduleAndClassFiles.getKey(), Convert.shortName(name), p); 1146 cs = p.package_info; 1147 cs.reset(); 1148 if (cs.classfile == null) 1149 cs.classfile = file; 1150 cs.completer = initialCompleter; 1151 } else { 1152 cs = symtab.enterClass(moduleAndClassFiles.getKey(), name); 1153 cs.reset(); 1154 cs.classfile = file; 1155 cs.completer = initialCompleter; 1156 if (cs.owner.kind == PCK) { 1157 cs.owner.members().enter(cs); //XXX - OverwriteBetweenCompilations; syms.getClass is not sufficient anymore 1158 } 1159 } 1160 list = list.prepend(cs); 1161 } 1162 } 1163 return list.reverse(); 1164 } 1165 1166 /** Enter a set of syntax trees. */ 1167 private void enterTrees(List<JCCompilationUnit> roots) { 1168 compiler.enterTrees(roots); 1169 } 1170 1171 /** Run a processing round. */ 1172 void run(boolean lastRound, boolean errorStatus) { 1173 printRoundInfo(lastRound); 1174 1175 if (!taskListener.isEmpty()) 1176 taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND)); 1177 1178 try { 1179 if (lastRound) { 1180 filer.setLastRound(true); 1181 Set<Element> emptyRootElements = Collections.emptySet(); // immutable 1182 RoundEnvironment renv = new JavacRoundEnvironment(true, 1183 errorStatus, 1184 emptyRootElements, 1185 JavacProcessingEnvironment.this); 1186 discoveredProcs.iterator().runContributingProcs(renv); 1187 } else { 1188 discoverAndRunProcs(annotationsPresent, topLevelClasses, packageInfoFiles, moduleInfoFiles); 1189 } 1190 } catch (Throwable t) { 1191 // we're specifically expecting Abort here, but if any Throwable 1192 // comes by, we should flush all deferred diagnostics, rather than 1193 // drop them on the ground. 1194 compiler.reportDeferredDiagnosticAndClearHandler(); 1195 throw t; 1196 } finally { 1197 if (!taskListener.isEmpty()) 1198 taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND)); 1199 } 1200 } 1201 1202 void showDiagnostics(boolean showAll) { 1203 deferredDiagnosticHandler.reportDeferredDiagnostics(showAll ? ACCEPT_ALL 1204 : ACCEPT_NON_RECOVERABLE); 1205 log.popDiagnosticHandler(deferredDiagnosticHandler); 1206 compiler.setDeferredDiagnosticHandler(null); 1207 } 1208 //where: 1209 private final Predicate<JCDiagnostic> ACCEPT_NON_RECOVERABLE = 1210 d -> d.getKind() != JCDiagnostic.Kind.ERROR || 1211 !d.isFlagSet(DiagnosticFlag.RECOVERABLE) || 1212 d.isFlagSet(DiagnosticFlag.API); 1213 private final Predicate<JCDiagnostic> ACCEPT_ALL = d -> true; 1214 1215 /** Print info about this round. */ 1216 private void printRoundInfo(boolean lastRound) { 1217 if (printRounds || verbose) { 1218 List<ClassSymbol> tlc = lastRound ? List.nil() : topLevelClasses; 1219 Set<TypeElement> ap = lastRound ? Collections.emptySet() : annotationsPresent; 1220 log.printLines("x.print.rounds", 1221 number, 1222 "{" + tlc.toString(", ") + "}", 1223 ap, 1224 lastRound); 1225 } 1226 } 1227 1228 /** Prepare for new round of annotation processing. Cleans trees, resets symbols, and 1229 * asks selected services to prepare to a new round of annotation processing. 1230 */ 1231 private void newRound() { 1232 //ensure treesToClean contains all trees, including implicitly parsed ones 1233 for (Env<AttrContext> env : enter.getEnvs()) { 1234 treesToClean.add(env.toplevel); 1235 } 1236 for (JCCompilationUnit node : treesToClean) { 1237 treeCleaner.scan(node); 1238 } 1239 chk.newRound(); 1240 enter.newRound(); 1241 filer.newRound(); 1242 messager.newRound(); 1243 compiler.newRound(); 1244 modules.newRound(); 1245 types.newRound(); 1246 annotate.newRound(); 1247 elementUtils.newRound(); 1248 1249 boolean foundError = false; 1250 1251 for (ClassSymbol cs : symtab.getAllClasses()) { 1252 if (cs.kind == ERR) { 1253 foundError = true; 1254 break; 1255 } 1256 } 1257 1258 if (foundError) { 1259 for (ClassSymbol cs : symtab.getAllClasses()) { 1260 if (cs.classfile != null || cs.kind == ERR) { 1261 Kinds.Kind symKind = cs.kind; 1262 cs.reset(); 1263 if (symKind == ERR) { 1264 cs.type = new ClassType(cs.type.getEnclosingType(), null, cs); 1265 } 1266 if (cs.isCompleted()) { 1267 cs.completer = initialCompleter; 1268 } 1269 } 1270 } 1271 } 1272 } 1273 } 1274 1275 1276 // TODO: internal catch clauses?; catch and rethrow an annotation 1277 // processing error 1278 public boolean doProcessing(List<JCCompilationUnit> roots, 1279 List<ClassSymbol> classSymbols, 1280 Iterable<? extends PackageSymbol> pckSymbols, 1281 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { 1282 final Set<JCCompilationUnit> treesToClean = 1283 Collections.newSetFromMap(new IdentityHashMap<JCCompilationUnit, Boolean>()); 1284 1285 //fill already attributed implicit trees: 1286 for (Env<AttrContext> env : enter.getEnvs()) { 1287 treesToClean.add(env.toplevel); 1288 } 1289 1290 Set<PackageSymbol> specifiedPackages = new LinkedHashSet<>(); 1291 for (PackageSymbol psym : pckSymbols) 1292 specifiedPackages.add(psym); 1293 this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages); 1294 1295 Round round = new Round(roots, classSymbols, treesToClean, deferredDiagnosticHandler); 1296 1297 boolean errorStatus; 1298 boolean moreToDo; 1299 do { 1300 // Run processors for round n 1301 round.run(false, false); 1302 1303 // Processors for round n have run to completion. 1304 // Check for errors and whether there is more work to do. 1305 errorStatus = round.unrecoverableError(); 1306 moreToDo = moreToDo(); 1307 1308 round.showDiagnostics(showResolveErrors); 1309 1310 // Set up next round. 1311 // Copy mutable collections returned from filer. 1312 round = round.next( 1313 new LinkedHashSet<>(filer.getGeneratedSourceFileObjects()), 1314 new LinkedHashMap<>(filer.getGeneratedClasses())); 1315 1316 // Check for errors during setup. 1317 if (round.unrecoverableError()) 1318 errorStatus = true; 1319 1320 } while (moreToDo && !errorStatus); 1321 1322 // run last round 1323 round.run(true, errorStatus); 1324 round.showDiagnostics(true); 1325 1326 filer.warnIfUnclosedFiles(); 1327 warnIfUnmatchedOptions(); 1328 1329 /* 1330 * If an annotation processor raises an error in a round, 1331 * that round runs to completion and one last round occurs. 1332 * The last round may also occur because no more source or 1333 * class files have been generated. Therefore, if an error 1334 * was raised on either of the last *two* rounds, the compile 1335 * should exit with a nonzero exit code. The current value of 1336 * errorStatus holds whether or not an error was raised on the 1337 * second to last round; errorRaised() gives the error status 1338 * of the last round. 1339 */ 1340 if (messager.errorRaised() 1341 || werror && round.warningCount() > 0 && round.errorCount() > 0) 1342 errorStatus = true; 1343 1344 Set<JavaFileObject> newSourceFiles = 1345 new LinkedHashSet<>(filer.getGeneratedSourceFileObjects()); 1346 roots = round.roots; 1347 1348 errorStatus = errorStatus || (compiler.errorCount() > 0); 1349 1350 1351 if (newSourceFiles.size() > 0) 1352 roots = roots.appendList(compiler.parseFiles(newSourceFiles)); 1353 1354 errorStatus = errorStatus || (compiler.errorCount() > 0); 1355 1356 if (errorStatus && compiler.errorCount() == 0) { 1357 compiler.log.nerrors++; 1358 } 1359 1360 if (compiler.continueAfterProcessAnnotations()) { 1361 round.finalCompiler(); 1362 compiler.enterTrees(compiler.initModules(roots)); 1363 } else { 1364 compiler.todo.clear(); 1365 } 1366 1367 // Free resources 1368 this.close(); 1369 1370 if (!taskListener.isEmpty()) 1371 taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING)); 1372 1373 return true; 1374 } 1375 1376 private void warnIfUnmatchedOptions() { 1377 if (!unmatchedProcessorOptions.isEmpty()) { 1378 log.warning(Warnings.ProcUnmatchedProcessorOptions(unmatchedProcessorOptions.toString())); 1379 } 1380 } 1381 1382 /** 1383 * Free resources related to annotation processing. 1384 */ 1385 public void close() { 1386 filer.close(); 1387 if (discoveredProcs != null) // Make calling close idempotent 1388 discoveredProcs.close(); 1389 discoveredProcs = null; 1390 } 1391 1392 private List<ClassSymbol> getTopLevelClasses(List<? extends JCCompilationUnit> units) { 1393 List<ClassSymbol> classes = List.nil(); 1394 for (JCCompilationUnit unit : units) { 1395 for (JCTree node : unit.defs) { 1396 if (node.hasTag(JCTree.Tag.CLASSDEF)) { 1397 ClassSymbol sym = ((JCClassDecl) node).sym; 1398 Assert.checkNonNull(sym); 1399 classes = classes.prepend(sym); 1400 } 1401 } 1402 } 1403 return classes.reverse(); 1404 } 1405 1406 private List<ClassSymbol> getTopLevelClassesFromClasses(List<? extends ClassSymbol> syms) { 1407 List<ClassSymbol> classes = List.nil(); 1408 for (ClassSymbol sym : syms) { 1409 if (!isPkgInfo(sym)) { 1410 classes = classes.prepend(sym); 1411 } 1412 } 1413 return classes.reverse(); 1414 } 1415 1416 private List<PackageSymbol> getPackageInfoFiles(List<? extends JCCompilationUnit> units) { 1417 List<PackageSymbol> packages = List.nil(); 1418 for (JCCompilationUnit unit : units) { 1419 if (isPkgInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE)) { 1420 packages = packages.prepend(unit.packge); 1421 } 1422 } 1423 return packages.reverse(); 1424 } 1425 1426 private List<PackageSymbol> getPackageInfoFilesFromClasses(List<? extends ClassSymbol> syms) { 1427 List<PackageSymbol> packages = List.nil(); 1428 for (ClassSymbol sym : syms) { 1429 if (isPkgInfo(sym)) { 1430 packages = packages.prepend((PackageSymbol) sym.owner); 1431 } 1432 } 1433 return packages.reverse(); 1434 } 1435 1436 private List<ModuleSymbol> getModuleInfoFiles(List<? extends JCCompilationUnit> units) { 1437 List<ModuleSymbol> modules = List.nil(); 1438 for (JCCompilationUnit unit : units) { 1439 if (isModuleInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE) && unit.defs.nonEmpty()) { 1440 for (JCTree tree : unit.defs) { 1441 if (tree.hasTag(Tag.IMPORT)) { 1442 continue; 1443 } 1444 else if (tree.hasTag(Tag.MODULEDEF)) { 1445 modules = modules.prepend(unit.modle); 1446 break; 1447 } 1448 else { 1449 break; 1450 } 1451 } 1452 } 1453 } 1454 return modules.reverse(); 1455 } 1456 1457 // avoid unchecked warning from use of varargs 1458 private static <T> List<T> join(List<T> list1, List<T> list2) { 1459 return list1.appendList(list2); 1460 } 1461 1462 private boolean isPkgInfo(JavaFileObject fo, JavaFileObject.Kind kind) { 1463 return fo.isNameCompatible("package-info", kind); 1464 } 1465 1466 private boolean isPkgInfo(ClassSymbol sym) { 1467 return isPkgInfo(sym.classfile, JavaFileObject.Kind.CLASS) && (sym.packge().package_info == sym); 1468 } 1469 1470 private boolean isModuleInfo(JavaFileObject fo, JavaFileObject.Kind kind) { 1471 return fo.isNameCompatible("module-info", kind); 1472 } 1473 1474 class ImplicitCompleter implements Completer { 1475 1476 private final JCCompilationUnit topLevel; 1477 1478 public ImplicitCompleter(JCCompilationUnit topLevel) { 1479 this.topLevel = topLevel; 1480 } 1481 1482 @Override public void complete(Symbol sym) throws CompletionFailure { 1483 compiler.readSourceFile(topLevel, (ClassSymbol) sym); 1484 } 1485 } 1486 1487 private final TreeScanner treeCleaner = new TreeScanner() { 1488 public void scan(JCTree node) { 1489 super.scan(node); 1490 if (node != null) 1491 node.type = null; 1492 } 1493 JCCompilationUnit topLevel; 1494 public void visitTopLevel(JCCompilationUnit node) { 1495 if (node.packge != null) { 1496 if (isPkgInfo(node.sourcefile, Kind.SOURCE)) { 1497 node.packge.package_info.reset(); 1498 } 1499 node.packge.reset(); 1500 } 1501 if (isModuleInfo(node.sourcefile, Kind.SOURCE)) { 1502 node.modle.reset(); 1503 node.modle.completer = sym -> modules.enter(List.of(node), node.modle.module_info); 1504 node.modle.module_info.reset(); 1505 node.modle.module_info.members_field = WriteableScope.create(node.modle.module_info); 1506 } 1507 node.packge = null; 1508 topLevel = node; 1509 try { 1510 super.visitTopLevel(node); 1511 } finally { 1512 topLevel = null; 1513 } 1514 } 1515 public void visitClassDef(JCClassDecl node) { 1516 super.visitClassDef(node); 1517 // remove generated constructor that may have been added during attribution: 1518 List<JCTree> beforeConstructor = List.nil(); 1519 List<JCTree> defs = node.defs; 1520 while (defs.nonEmpty() && !defs.head.hasTag(Tag.METHODDEF)) { 1521 beforeConstructor = beforeConstructor.prepend(defs.head); 1522 defs = defs.tail; 1523 } 1524 if (defs.nonEmpty() && 1525 (((JCMethodDecl) defs.head).mods.flags & Flags.GENERATEDCONSTR) != 0) { 1526 defs = defs.tail; 1527 while (beforeConstructor.nonEmpty()) { 1528 defs = defs.prepend(beforeConstructor.head); 1529 beforeConstructor = beforeConstructor.tail; 1530 } 1531 node.defs = defs; 1532 } 1533 if (node.sym != null) { 1534 node.sym.completer = new ImplicitCompleter(topLevel); 1535 List<? extends RecordComponent> recordComponents = node.sym.getRecordComponents(); 1536 for (RecordComponent rc : recordComponents) { 1537 List<JCAnnotation> originalAnnos = rc.getOriginalAnnos(); 1538 originalAnnos.forEach(a -> visitAnnotation(a)); 1539 } 1540 // we should empty the list of permitted subclasses for next round 1541 node.sym.clearPermittedSubclasses(); 1542 } 1543 node.sym = null; 1544 } 1545 public void visitMethodDef(JCMethodDecl node) { 1546 // remove super constructor call that may have been added during attribution: 1547 if (TreeInfo.isConstructor(node) && node.sym != null && node.sym.owner.isEnum() && 1548 node.body != null && node.body.stats.nonEmpty() && TreeInfo.isSuperCall(node.body.stats.head) && 1549 node.body.stats.head.pos == node.body.pos) { 1550 node.body.stats = node.body.stats.tail; 1551 } 1552 node.sym = null; 1553 super.visitMethodDef(node); 1554 } 1555 public void visitVarDef(JCVariableDecl node) { 1556 node.sym = null; 1557 super.visitVarDef(node); 1558 } 1559 public void visitNewClass(JCNewClass node) { 1560 node.constructor = null; 1561 super.visitNewClass(node); 1562 } 1563 public void visitAssignop(JCAssignOp node) { 1564 node.operator = null; 1565 super.visitAssignop(node); 1566 } 1567 public void visitUnary(JCUnary node) { 1568 node.operator = null; 1569 super.visitUnary(node); 1570 } 1571 public void visitBinary(JCBinary node) { 1572 node.operator = null; 1573 super.visitBinary(node); 1574 } 1575 public void visitSelect(JCFieldAccess node) { 1576 node.sym = null; 1577 super.visitSelect(node); 1578 } 1579 public void visitIdent(JCIdent node) { 1580 node.sym = null; 1581 super.visitIdent(node); 1582 } 1583 public void visitAnnotation(JCAnnotation node) { 1584 node.attribute = null; 1585 super.visitAnnotation(node); 1586 } 1587 }; 1588 1589 1590 private boolean moreToDo() { 1591 return filer.newFiles(); 1592 } 1593 1594 /** 1595 * {@inheritDoc} 1596 * 1597 * Command line options suitable for presenting to annotation 1598 * processors. 1599 * {@literal "-Afoo=bar"} should be {@literal "-Afoo" => "bar"}. 1600 */ 1601 @DefinedBy(Api.ANNOTATION_PROCESSING) 1602 public Map<String,String> getOptions() { 1603 return processorOptions; 1604 } 1605 1606 @DefinedBy(Api.ANNOTATION_PROCESSING) 1607 public Messager getMessager() { 1608 return messager; 1609 } 1610 1611 @DefinedBy(Api.ANNOTATION_PROCESSING) 1612 public JavacFiler getFiler() { 1613 return filer; 1614 } 1615 1616 @DefinedBy(Api.ANNOTATION_PROCESSING) 1617 public JavacElements getElementUtils() { 1618 return elementUtils; 1619 } 1620 1621 @DefinedBy(Api.ANNOTATION_PROCESSING) 1622 public JavacTypes getTypeUtils() { 1623 return typeUtils; 1624 } 1625 1626 @DefinedBy(Api.ANNOTATION_PROCESSING) 1627 public SourceVersion getSourceVersion() { 1628 return Source.toSourceVersion(source); 1629 } 1630 1631 @DefinedBy(Api.ANNOTATION_PROCESSING) 1632 public Locale getLocale() { 1633 return messages.getCurrentLocale(); 1634 } 1635 1636 @DefinedBy(Api.ANNOTATION_PROCESSING) 1637 public boolean isPreviewEnabled() { 1638 return preview.isEnabled(); 1639 } 1640 1641 public Set<Symbol.PackageSymbol> getSpecifiedPackages() { 1642 return specifiedPackages; 1643 } 1644 1645 public static final Pattern noMatches = Pattern.compile("(\\P{all})+"); 1646 1647 /** 1648 * Convert import-style string for supported annotations into a 1649 * regex matching that string. If the string is not a valid 1650 * import-style string, return a regex that won't match anything. 1651 */ 1652 private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log, Lint lint) { 1653 String module; 1654 String pkg; 1655 int slash = s.indexOf('/'); 1656 if (slash == (-1)) { 1657 if (s.equals("*")) { 1658 return MatchingUtils.validImportStringToPattern(s); 1659 } 1660 module = allowModules ? ".*/" : ""; 1661 pkg = s; 1662 } else { 1663 String moduleName = s.substring(0, slash); 1664 if (!SourceVersion.isName(moduleName)) { 1665 return warnAndNoMatches(s, p, log, lint); 1666 } 1667 module = Pattern.quote(moduleName + "/"); 1668 // And warn if module is specified if modules aren't supported, conditional on -Xlint:proc? 1669 pkg = s.substring(slash + 1); 1670 } 1671 if (MatchingUtils.isValidImportString(pkg)) { 1672 return Pattern.compile(module + MatchingUtils.validImportStringToPatternString(pkg)); 1673 } else { 1674 return warnAndNoMatches(s, p, log, lint); 1675 } 1676 } 1677 1678 private static Pattern warnAndNoMatches(String s, Processor p, Log log, Lint lint) { 1679 lint.logIfEnabled(LintWarnings.ProcMalformedSupportedString(s, p.getClass().getName())); 1680 return noMatches; // won't match any valid identifier 1681 } 1682 1683 /** 1684 * For internal use only. This method may be removed without warning. 1685 */ 1686 public Context getContext() { 1687 return context; 1688 } 1689 1690 /** 1691 * For internal use only. This method may be removed without warning. 1692 */ 1693 public ClassLoader getProcessorClassLoader() { 1694 return processorClassLoader; 1695 } 1696 1697 public String toString() { 1698 return "javac ProcessingEnvironment"; 1699 } 1700 1701 public static boolean isValidOptionName(String optionName) { 1702 for(String s : optionName.split("\\.", -1)) { 1703 if (!SourceVersion.isIdentifier(s)) 1704 return false; 1705 } 1706 return true; 1707 } 1708 }