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