JavacProcessingEnvironment.java revision 3513:ea4eea2997b9
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 26package com.sun.tools.javac.processing; 27 28import java.io.Closeable; 29import java.io.File; 30import java.io.IOException; 31import java.io.PrintWriter; 32import java.io.StringWriter; 33import java.lang.reflect.Method; 34import java.lang.reflect.Constructor; 35import java.net.MalformedURLException; 36import java.net.URL; 37import java.nio.file.Path; 38import java.util.*; 39import java.util.regex.*; 40import java.util.stream.Collectors; 41 42import javax.annotation.processing.*; 43import javax.lang.model.SourceVersion; 44import javax.lang.model.element.*; 45import javax.lang.model.util.*; 46import javax.tools.JavaFileManager; 47import javax.tools.JavaFileObject; 48import javax.tools.JavaFileObject.Kind; 49import javax.tools.StandardJavaFileManager; 50 51import static javax.tools.StandardLocation.*; 52 53import com.sun.source.util.TaskEvent; 54import com.sun.tools.javac.api.MultiTaskListener; 55import com.sun.tools.javac.code.*; 56import com.sun.tools.javac.code.Scope.WriteableScope; 57import com.sun.tools.javac.code.Symbol.*; 58import com.sun.tools.javac.code.Type.ClassType; 59import com.sun.tools.javac.code.Types; 60import com.sun.tools.javac.comp.AttrContext; 61import com.sun.tools.javac.comp.Check; 62import com.sun.tools.javac.comp.Enter; 63import com.sun.tools.javac.comp.Env; 64import com.sun.tools.javac.comp.Modules; 65import com.sun.tools.javac.file.JavacFileManager; 66import com.sun.tools.javac.main.JavaCompiler; 67import com.sun.tools.javac.model.JavacElements; 68import com.sun.tools.javac.model.JavacTypes; 69import com.sun.tools.javac.platform.PlatformDescription; 70import com.sun.tools.javac.platform.PlatformDescription.PluginInfo; 71import com.sun.tools.javac.resources.CompilerProperties.Errors; 72import com.sun.tools.javac.tree.*; 73import com.sun.tools.javac.tree.JCTree.*; 74import com.sun.tools.javac.util.Abort; 75import com.sun.tools.javac.util.Assert; 76import com.sun.tools.javac.util.ClientCodeException; 77import com.sun.tools.javac.util.Context; 78import com.sun.tools.javac.util.Convert; 79import com.sun.tools.javac.util.DefinedBy; 80import com.sun.tools.javac.util.DefinedBy.Api; 81import com.sun.tools.javac.util.Iterators; 82import com.sun.tools.javac.util.JCDiagnostic; 83import com.sun.tools.javac.util.JavacMessages; 84import com.sun.tools.javac.util.List; 85import com.sun.tools.javac.util.Log; 86import com.sun.tools.javac.util.MatchingUtils; 87import com.sun.tools.javac.util.ModuleHelper; 88import com.sun.tools.javac.util.Name; 89import com.sun.tools.javac.util.Names; 90import com.sun.tools.javac.util.Options; 91 92import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING; 93import static com.sun.tools.javac.code.Kinds.Kind.*; 94import static com.sun.tools.javac.main.Option.*; 95import static com.sun.tools.javac.comp.CompileStates.CompileState; 96import 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 */ 107public 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 Processor getNextProcessor(String processorName) { 557 try { 558 try { 559 Class<?> processorClass = processorCL.loadClass(processorName); 560 ensureReadable(processorClass); 561 return (Processor) processorClass.getConstructor().newInstance(); 562 } catch (ClassNotFoundException cnfe) { 563 log.error("proc.processor.not.found", processorName); 564 return null; 565 } catch (ClassCastException cce) { 566 log.error("proc.processor.wrong.type", processorName); 567 return null; 568 } catch (Exception e ) { 569 log.error("proc.processor.cant.instantiate", processorName); 570 return null; 571 } 572 } catch (ClientCodeException e) { 573 throw e; 574 } catch (Throwable t) { 575 throw new AnnotationProcessingError(t); 576 } 577 } 578 579 public Processor next() { 580 if (hasNext()) { 581 Processor p = nextProc; 582 nextProc = null; 583 return p; 584 } else 585 throw new NoSuchElementException(); 586 } 587 588 public void remove () { 589 throw new UnsupportedOperationException(); 590 } 591 592 /** 593 * Ensures that the module of the given class is readable to this 594 * module. 595 */ 596 private void ensureReadable(Class<?> targetClass) { 597 try { 598 Method getModuleMethod = Class.class.getMethod("getModule"); 599 Object thisModule = getModuleMethod.invoke(this.getClass()); 600 Object targetModule = getModuleMethod.invoke(targetClass); 601 602 Class<?> moduleClass = getModuleMethod.getReturnType(); 603 Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass); 604 addReadsMethod.invoke(thisModule, targetModule); 605 } catch (NoSuchMethodException e) { 606 // ignore 607 } catch (Exception e) { 608 throw new InternalError(e); 609 } 610 } 611 } 612 613 public boolean atLeastOneProcessor() { 614 return discoveredProcs.iterator().hasNext(); 615 } 616 617 private Map<String, String> initProcessorOptions() { 618 Set<String> keySet = options.keySet(); 619 Map<String, String> tempOptions = new LinkedHashMap<>(); 620 621 for(String key : keySet) { 622 if (key.startsWith("-A") && key.length() > 2) { 623 int sepIndex = key.indexOf('='); 624 String candidateKey = null; 625 String candidateValue = null; 626 627 if (sepIndex == -1) 628 candidateKey = key.substring(2); 629 else if (sepIndex >= 3) { 630 candidateKey = key.substring(2, sepIndex); 631 candidateValue = (sepIndex < key.length()-1)? 632 key.substring(sepIndex+1) : null; 633 } 634 tempOptions.put(candidateKey, candidateValue); 635 } 636 } 637 638 PlatformDescription platformProvider = context.get(PlatformDescription.class); 639 640 if (platformProvider != null) { 641 for (PluginInfo<Processor> ap : platformProvider.getAnnotationProcessors()) { 642 tempOptions.putAll(ap.getOptions()); 643 } 644 } 645 646 return Collections.unmodifiableMap(tempOptions); 647 } 648 649 private Set<String> initUnmatchedProcessorOptions() { 650 Set<String> unmatchedProcessorOptions = new HashSet<>(); 651 unmatchedProcessorOptions.addAll(processorOptions.keySet()); 652 return unmatchedProcessorOptions; 653 } 654 655 /** 656 * State about how a processor has been used by the tool. If a 657 * processor has been used on a prior round, its process method is 658 * called on all subsequent rounds, perhaps with an empty set of 659 * annotations to process. The {@code annotationSupported} method 660 * caches the supported annotation information from the first (and 661 * only) getSupportedAnnotationTypes call to the processor. 662 */ 663 static class ProcessorState { 664 public Processor processor; 665 public boolean contributed; 666 private ArrayList<Pattern> supportedAnnotationPatterns; 667 private ArrayList<String> supportedOptionNames; 668 669 ProcessorState(Processor p, Log log, Source source, ProcessingEnvironment env) { 670 processor = p; 671 contributed = false; 672 673 try { 674 processor.init(env); 675 676 checkSourceVersionCompatibility(source, log); 677 678 supportedAnnotationPatterns = new ArrayList<>(); 679 for (String importString : processor.getSupportedAnnotationTypes()) { 680 supportedAnnotationPatterns.add(importStringToPattern(importString, 681 processor, 682 log)); 683 } 684 685 supportedOptionNames = new ArrayList<>(); 686 for (String optionName : processor.getSupportedOptions() ) { 687 if (checkOptionName(optionName, log)) 688 supportedOptionNames.add(optionName); 689 } 690 691 } catch (ClientCodeException e) { 692 throw e; 693 } catch (Throwable t) { 694 throw new AnnotationProcessingError(t); 695 } 696 } 697 698 /** 699 * Checks whether or not a processor's source version is 700 * compatible with the compilation source version. The 701 * processor's source version needs to be greater than or 702 * equal to the source version of the compile. 703 */ 704 private void checkSourceVersionCompatibility(Source source, Log log) { 705 SourceVersion procSourceVersion = processor.getSupportedSourceVersion(); 706 707 if (procSourceVersion.compareTo(Source.toSourceVersion(source)) < 0 ) { 708 log.warning("proc.processor.incompatible.source.version", 709 procSourceVersion, 710 processor.getClass().getName(), 711 source.name); 712 } 713 } 714 715 private boolean checkOptionName(String optionName, Log log) { 716 boolean valid = isValidOptionName(optionName); 717 if (!valid) 718 log.error("proc.processor.bad.option.name", 719 optionName, 720 processor.getClass().getName()); 721 return valid; 722 } 723 724 public boolean annotationSupported(String annotationName) { 725 for(Pattern p: supportedAnnotationPatterns) { 726 if (p.matcher(annotationName).matches()) 727 return true; 728 } 729 return false; 730 } 731 732 /** 733 * Remove options that are matched by this processor. 734 */ 735 public void removeSupportedOptions(Set<String> unmatchedProcessorOptions) { 736 unmatchedProcessorOptions.removeAll(supportedOptionNames); 737 } 738 } 739 740 // TODO: These two classes can probably be rewritten better... 741 /** 742 * This class holds information about the processors that have 743 * been discovered so far as well as the means to discover more, if 744 * necessary. A single iterator should be used per round of 745 * annotation processing. The iterator first visits already 746 * discovered processors then fails over to the service provider 747 * mechanism if additional queries are made. 748 */ 749 class DiscoveredProcessors implements Iterable<ProcessorState> { 750 751 class ProcessorStateIterator implements Iterator<ProcessorState> { 752 DiscoveredProcessors psi; 753 Iterator<ProcessorState> innerIter; 754 boolean onProcInterator; 755 756 ProcessorStateIterator(DiscoveredProcessors psi) { 757 this.psi = psi; 758 this.innerIter = psi.procStateList.iterator(); 759 this.onProcInterator = false; 760 } 761 762 public ProcessorState next() { 763 if (!onProcInterator) { 764 if (innerIter.hasNext()) 765 return innerIter.next(); 766 else 767 onProcInterator = true; 768 } 769 770 if (psi.processorIterator.hasNext()) { 771 ProcessorState ps = new ProcessorState(psi.processorIterator.next(), 772 log, source, JavacProcessingEnvironment.this); 773 psi.procStateList.add(ps); 774 return ps; 775 } else 776 throw new NoSuchElementException(); 777 } 778 779 public boolean hasNext() { 780 if (onProcInterator) 781 return psi.processorIterator.hasNext(); 782 else 783 return innerIter.hasNext() || psi.processorIterator.hasNext(); 784 } 785 786 public void remove () { 787 throw new UnsupportedOperationException(); 788 } 789 790 /** 791 * Run all remaining processors on the procStateList that 792 * have not already run this round with an empty set of 793 * annotations. 794 */ 795 public void runContributingProcs(RoundEnvironment re) { 796 if (!onProcInterator) { 797 Set<TypeElement> emptyTypeElements = Collections.emptySet(); 798 while(innerIter.hasNext()) { 799 ProcessorState ps = innerIter.next(); 800 if (ps.contributed) 801 callProcessor(ps.processor, emptyTypeElements, re); 802 } 803 } 804 } 805 } 806 807 Iterator<? extends Processor> processorIterator; 808 ArrayList<ProcessorState> procStateList; 809 810 public ProcessorStateIterator iterator() { 811 return new ProcessorStateIterator(this); 812 } 813 814 DiscoveredProcessors(Iterator<? extends Processor> processorIterator) { 815 this.processorIterator = processorIterator; 816 this.procStateList = new ArrayList<>(); 817 } 818 819 /** 820 * Free jar files, etc. if using a service loader. 821 */ 822 public void close() { 823 if (processorIterator != null && 824 processorIterator instanceof ServiceIterator) { 825 ((ServiceIterator) processorIterator).close(); 826 } 827 } 828 } 829 830 private void discoverAndRunProcs(Set<TypeElement> annotationsPresent, 831 List<ClassSymbol> topLevelClasses, 832 List<PackageSymbol> packageInfoFiles) { 833 Map<String, TypeElement> unmatchedAnnotations = new HashMap<>(annotationsPresent.size()); 834 835 for(TypeElement a : annotationsPresent) { 836 unmatchedAnnotations.put(a.getQualifiedName().toString(), 837 a); 838 } 839 840 // Give "*" processors a chance to match 841 if (unmatchedAnnotations.size() == 0) 842 unmatchedAnnotations.put("", null); 843 844 DiscoveredProcessors.ProcessorStateIterator psi = discoveredProcs.iterator(); 845 // TODO: Create proper argument values; need past round 846 // information to fill in this constructor. Note that the 1 847 // st round of processing could be the last round if there 848 // were parse errors on the initial source files; however, we 849 // are not doing processing in that case. 850 851 Set<Element> rootElements = new LinkedHashSet<>(); 852 rootElements.addAll(topLevelClasses); 853 rootElements.addAll(packageInfoFiles); 854 rootElements = Collections.unmodifiableSet(rootElements); 855 856 RoundEnvironment renv = new JavacRoundEnvironment(false, 857 false, 858 rootElements, 859 JavacProcessingEnvironment.this); 860 861 while(unmatchedAnnotations.size() > 0 && psi.hasNext() ) { 862 ProcessorState ps = psi.next(); 863 Set<String> matchedNames = new HashSet<>(); 864 Set<TypeElement> typeElements = new LinkedHashSet<>(); 865 866 for (Map.Entry<String, TypeElement> entry: unmatchedAnnotations.entrySet()) { 867 String unmatchedAnnotationName = entry.getKey(); 868 if (ps.annotationSupported(unmatchedAnnotationName) ) { 869 matchedNames.add(unmatchedAnnotationName); 870 TypeElement te = entry.getValue(); 871 if (te != null) 872 typeElements.add(te); 873 } 874 } 875 876 if (matchedNames.size() > 0 || ps.contributed) { 877 boolean processingResult = callProcessor(ps.processor, typeElements, renv); 878 ps.contributed = true; 879 ps.removeSupportedOptions(unmatchedProcessorOptions); 880 881 if (printProcessorInfo || verbose) { 882 log.printLines("x.print.processor.info", 883 ps.processor.getClass().getName(), 884 matchedNames.toString(), 885 processingResult); 886 } 887 888 if (processingResult) { 889 unmatchedAnnotations.keySet().removeAll(matchedNames); 890 } 891 892 } 893 } 894 unmatchedAnnotations.remove(""); 895 896 if (lint && unmatchedAnnotations.size() > 0) { 897 // Remove annotations processed by javac 898 unmatchedAnnotations.keySet().removeAll(platformAnnotations); 899 if (unmatchedAnnotations.size() > 0) { 900 log.warning("proc.annotations.without.processors", 901 unmatchedAnnotations.keySet()); 902 } 903 } 904 905 // Run contributing processors that haven't run yet 906 psi.runContributingProcs(renv); 907 } 908 909 /** 910 * Computes the set of annotations on the symbol in question. 911 * Leave class public for external testing purposes. 912 */ 913 public static class ComputeAnnotationSet extends 914 ElementScanner9<Set<TypeElement>, Set<TypeElement>> { 915 final Elements elements; 916 917 public ComputeAnnotationSet(Elements elements) { 918 super(); 919 this.elements = elements; 920 } 921 922 @Override @DefinedBy(Api.LANGUAGE_MODEL) 923 public Set<TypeElement> visitPackage(PackageElement e, Set<TypeElement> p) { 924 // Don't scan enclosed elements of a package 925 return p; 926 } 927 928 @Override @DefinedBy(Api.LANGUAGE_MODEL) 929 public Set<TypeElement> visitType(TypeElement e, Set<TypeElement> p) { 930 // Type parameters are not considered to be enclosed by a type 931 scan(e.getTypeParameters(), p); 932 return super.visitType(e, p); 933 } 934 935 @Override @DefinedBy(Api.LANGUAGE_MODEL) 936 public Set<TypeElement> visitExecutable(ExecutableElement e, Set<TypeElement> p) { 937 // Type parameters are not considered to be enclosed by an executable 938 scan(e.getTypeParameters(), p); 939 return super.visitExecutable(e, p); 940 } 941 942 void addAnnotations(Element e, Set<TypeElement> p) { 943 for (AnnotationMirror annotationMirror : 944 elements.getAllAnnotationMirrors(e) ) { 945 Element e2 = annotationMirror.getAnnotationType().asElement(); 946 p.add((TypeElement) e2); 947 } 948 } 949 950 @Override @DefinedBy(Api.LANGUAGE_MODEL) 951 public Set<TypeElement> scan(Element e, Set<TypeElement> p) { 952 addAnnotations(e, p); 953 return super.scan(e, p); 954 } 955 } 956 957 private boolean callProcessor(Processor proc, 958 Set<? extends TypeElement> tes, 959 RoundEnvironment renv) { 960 try { 961 return proc.process(tes, renv); 962 } catch (ClassFinder.BadClassFile ex) { 963 log.error("proc.cant.access.1", ex.sym, ex.getDetailValue()); 964 return false; 965 } catch (CompletionFailure ex) { 966 StringWriter out = new StringWriter(); 967 ex.printStackTrace(new PrintWriter(out)); 968 log.error("proc.cant.access", ex.sym, ex.getDetailValue(), out.toString()); 969 return false; 970 } catch (ClientCodeException e) { 971 throw e; 972 } catch (Throwable t) { 973 throw new AnnotationProcessingError(t); 974 } 975 } 976 977 /** 978 * Helper object for a single round of annotation processing. 979 */ 980 class Round { 981 /** The round number. */ 982 final int number; 983 /** The diagnostic handler for the round. */ 984 final Log.DeferredDiagnosticHandler deferredDiagnosticHandler; 985 986 /** The ASTs to be compiled. */ 987 List<JCCompilationUnit> roots; 988 /** The trees that need to be cleaned - includes roots and implicitly parsed trees. */ 989 Set<JCCompilationUnit> treesToClean; 990 /** The classes to be compiler that have were generated. */ 991 Map<String, JavaFileObject> genClassFiles; 992 993 /** The set of annotations to be processed this round. */ 994 Set<TypeElement> annotationsPresent; 995 /** The set of top level classes to be processed this round. */ 996 List<ClassSymbol> topLevelClasses; 997 /** The set of package-info files to be processed this round. */ 998 List<PackageSymbol> packageInfoFiles; 999 1000 /** Create a round (common code). */ 1001 private Round(int number, Set<JCCompilationUnit> treesToClean, 1002 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { 1003 this.number = number; 1004 1005 if (number == 1) { 1006 Assert.checkNonNull(deferredDiagnosticHandler); 1007 this.deferredDiagnosticHandler = deferredDiagnosticHandler; 1008 } else { 1009 this.deferredDiagnosticHandler = new Log.DeferredDiagnosticHandler(log); 1010 compiler.setDeferredDiagnosticHandler(this.deferredDiagnosticHandler); 1011 } 1012 1013 // the following will be populated as needed 1014 topLevelClasses = List.nil(); 1015 packageInfoFiles = 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 findAnnotationsPresent(); 1037 } 1038 1039 /** Create a new round. */ 1040 private Round(Round prev, 1041 Set<JavaFileObject> newSourceFiles, Map<String,JavaFileObject> newClassFiles) { 1042 this(prev.number+1, prev.treesToClean, null); 1043 prev.newRound(); 1044 this.genClassFiles = prev.genClassFiles; 1045 1046 List<JCCompilationUnit> parsedFiles = compiler.parseFiles(newSourceFiles); 1047 roots = prev.roots.appendList(parsedFiles); 1048 1049 // Check for errors after parsing 1050 if (unrecoverableError()) 1051 return; 1052 1053 enterClassFiles(genClassFiles); 1054 List<ClassSymbol> newClasses = enterClassFiles(newClassFiles); 1055 genClassFiles.putAll(newClassFiles); 1056 enterTrees(roots); 1057 1058 if (unrecoverableError()) 1059 return; 1060 1061 topLevelClasses = join( 1062 getTopLevelClasses(parsedFiles), 1063 getTopLevelClassesFromClasses(newClasses)); 1064 1065 packageInfoFiles = join( 1066 getPackageInfoFiles(parsedFiles), 1067 getPackageInfoFilesFromClasses(newClasses)); 1068 1069 findAnnotationsPresent(); 1070 } 1071 1072 /** Create the next round to be used. */ 1073 Round next(Set<JavaFileObject> newSourceFiles, Map<String, JavaFileObject> newClassFiles) { 1074 return new Round(this, newSourceFiles, newClassFiles); 1075 } 1076 1077 /** Prepare the compiler for the final compilation. */ 1078 void finalCompiler() { 1079 newRound(); 1080 } 1081 1082 /** Return the number of errors found so far in this round. 1083 * This may include uncoverable errors, such as parse errors, 1084 * and transient errors, such as missing symbols. */ 1085 int errorCount() { 1086 return compiler.errorCount(); 1087 } 1088 1089 /** Return the number of warnings found so far in this round. */ 1090 int warningCount() { 1091 return compiler.warningCount(); 1092 } 1093 1094 /** Return whether or not an unrecoverable error has occurred. */ 1095 boolean unrecoverableError() { 1096 if (messager.errorRaised()) 1097 return true; 1098 1099 for (JCDiagnostic d: deferredDiagnosticHandler.getDiagnostics()) { 1100 switch (d.getKind()) { 1101 case WARNING: 1102 if (werror) 1103 return true; 1104 break; 1105 1106 case ERROR: 1107 if (fatalErrors || !d.isFlagSet(RECOVERABLE)) 1108 return true; 1109 break; 1110 } 1111 } 1112 1113 return false; 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 } 1127 1128 /** Enter a set of generated class files. */ 1129 private List<ClassSymbol> enterClassFiles(Map<String, JavaFileObject> classFiles) { 1130 List<ClassSymbol> list = List.nil(); 1131 1132 for (Map.Entry<String,JavaFileObject> entry : classFiles.entrySet()) { 1133 Name name = names.fromString(entry.getKey()); 1134 JavaFileObject file = entry.getValue(); 1135 if (file.getKind() != JavaFileObject.Kind.CLASS) 1136 throw new AssertionError(file); 1137 ClassSymbol cs; 1138 // TODO: for now, we assume that generated code is in a default module; 1139 // in time, we need a way to be able to specify the module for generated code 1140 if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) { 1141 Name packageName = Convert.packagePart(name); 1142 PackageSymbol p = symtab.enterPackage(defaultModule, packageName); 1143 if (p.package_info == null) 1144 p.package_info = symtab.enterClass(defaultModule, Convert.shortName(name), p); 1145 cs = p.package_info; 1146 cs.reset(); 1147 if (cs.classfile == null) 1148 cs.classfile = file; 1149 cs.completer = initialCompleter; 1150 } else { 1151 cs = symtab.enterClass(defaultModule, name); 1152 cs.reset(); 1153 cs.classfile = file; 1154 cs.completer = initialCompleter; 1155 cs.owner.members().enter(cs); //XXX - OverwriteBetweenCompilations; syms.getClass is not sufficient anymore 1156 } 1157 list = list.prepend(cs); 1158 } 1159 return list.reverse(); 1160 } 1161 1162 /** Enter a set of syntax trees. */ 1163 private void enterTrees(List<JCCompilationUnit> roots) { 1164 compiler.enterTrees(compiler.initModules(roots)); 1165 } 1166 1167 /** Run a processing round. */ 1168 void run(boolean lastRound, boolean errorStatus) { 1169 printRoundInfo(lastRound); 1170 1171 if (!taskListener.isEmpty()) 1172 taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND)); 1173 1174 try { 1175 if (lastRound) { 1176 filer.setLastRound(true); 1177 Set<Element> emptyRootElements = Collections.emptySet(); // immutable 1178 RoundEnvironment renv = new JavacRoundEnvironment(true, 1179 errorStatus, 1180 emptyRootElements, 1181 JavacProcessingEnvironment.this); 1182 discoveredProcs.iterator().runContributingProcs(renv); 1183 } else { 1184 discoverAndRunProcs(annotationsPresent, topLevelClasses, packageInfoFiles); 1185 } 1186 } catch (Throwable t) { 1187 // we're specifically expecting Abort here, but if any Throwable 1188 // comes by, we should flush all deferred diagnostics, rather than 1189 // drop them on the ground. 1190 deferredDiagnosticHandler.reportDeferredDiagnostics(); 1191 log.popDiagnosticHandler(deferredDiagnosticHandler); 1192 compiler.setDeferredDiagnosticHandler(null); 1193 throw t; 1194 } finally { 1195 if (!taskListener.isEmpty()) 1196 taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND)); 1197 } 1198 } 1199 1200 void showDiagnostics(boolean showAll) { 1201 Set<JCDiagnostic.Kind> kinds = EnumSet.allOf(JCDiagnostic.Kind.class); 1202 if (!showAll) { 1203 // suppress errors, which are all presumed to be transient resolve errors 1204 kinds.remove(JCDiagnostic.Kind.ERROR); 1205 } 1206 deferredDiagnosticHandler.reportDeferredDiagnostics(kinds); 1207 log.popDiagnosticHandler(deferredDiagnosticHandler); 1208 compiler.setDeferredDiagnosticHandler(null); 1209 } 1210 1211 /** Print info about this round. */ 1212 private void printRoundInfo(boolean lastRound) { 1213 if (printRounds || verbose) { 1214 List<ClassSymbol> tlc = lastRound ? List.<ClassSymbol>nil() : topLevelClasses; 1215 Set<TypeElement> ap = lastRound ? Collections.<TypeElement>emptySet() : annotationsPresent; 1216 log.printLines("x.print.rounds", 1217 number, 1218 "{" + tlc.toString(", ") + "}", 1219 ap, 1220 lastRound); 1221 } 1222 } 1223 1224 /** Prepare for new round of annotation processing. Cleans trees, resets symbols, and 1225 * asks selected services to prepare to a new round of annotation processing. 1226 */ 1227 private void newRound() { 1228 //ensure treesToClean contains all trees, including implicitly parsed ones 1229 for (Env<AttrContext> env : enter.getEnvs()) { 1230 treesToClean.add(env.toplevel); 1231 } 1232 for (JCCompilationUnit node : treesToClean) { 1233 treeCleaner.scan(node); 1234 } 1235 chk.newRound(); 1236 enter.newRound(); 1237 filer.newRound(); 1238 messager.newRound(); 1239 compiler.newRound(); 1240 modules.newRound(); 1241 types.newRound(); 1242 1243 boolean foundError = false; 1244 1245 for (ClassSymbol cs : symtab.getAllClasses()) { 1246 if (cs.kind == ERR) { 1247 foundError = true; 1248 break; 1249 } 1250 } 1251 1252 if (foundError) { 1253 for (ClassSymbol cs : symtab.getAllClasses()) { 1254 if (cs.classfile != null || cs.kind == ERR) { 1255 cs.reset(); 1256 cs.type = new ClassType(cs.type.getEnclosingType(), null, cs); 1257 if (cs.isCompleted()) { 1258 cs.completer = initialCompleter; 1259 } 1260 } 1261 } 1262 } 1263 } 1264 } 1265 1266 1267 // TODO: internal catch clauses?; catch and rethrow an annotation 1268 // processing error 1269 public boolean doProcessing(List<JCCompilationUnit> roots, 1270 List<ClassSymbol> classSymbols, 1271 Iterable<? extends PackageSymbol> pckSymbols, 1272 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { 1273 final Set<JCCompilationUnit> treesToClean = 1274 Collections.newSetFromMap(new IdentityHashMap<JCCompilationUnit, Boolean>()); 1275 1276 //fill already attributed implicit trees: 1277 for (Env<AttrContext> env : enter.getEnvs()) { 1278 treesToClean.add(env.toplevel); 1279 } 1280 1281 Set<PackageSymbol> specifiedPackages = new LinkedHashSet<>(); 1282 for (PackageSymbol psym : pckSymbols) 1283 specifiedPackages.add(psym); 1284 this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages); 1285 1286 Round round = new Round(roots, classSymbols, treesToClean, deferredDiagnosticHandler); 1287 1288 boolean errorStatus; 1289 boolean moreToDo; 1290 do { 1291 // Run processors for round n 1292 round.run(false, false); 1293 1294 // Processors for round n have run to completion. 1295 // Check for errors and whether there is more work to do. 1296 errorStatus = round.unrecoverableError(); 1297 moreToDo = moreToDo(); 1298 1299 round.showDiagnostics(errorStatus || showResolveErrors); 1300 1301 // Set up next round. 1302 // Copy mutable collections returned from filer. 1303 round = round.next( 1304 new LinkedHashSet<>(filer.getGeneratedSourceFileObjects()), 1305 new LinkedHashMap<>(filer.getGeneratedClasses())); 1306 1307 // Check for errors during setup. 1308 if (round.unrecoverableError()) 1309 errorStatus = true; 1310 1311 } while (moreToDo && !errorStatus); 1312 1313 // run last round 1314 round.run(true, errorStatus); 1315 round.showDiagnostics(true); 1316 1317 filer.warnIfUnclosedFiles(); 1318 warnIfUnmatchedOptions(); 1319 1320 /* 1321 * If an annotation processor raises an error in a round, 1322 * that round runs to completion and one last round occurs. 1323 * The last round may also occur because no more source or 1324 * class files have been generated. Therefore, if an error 1325 * was raised on either of the last *two* rounds, the compile 1326 * should exit with a nonzero exit code. The current value of 1327 * errorStatus holds whether or not an error was raised on the 1328 * second to last round; errorRaised() gives the error status 1329 * of the last round. 1330 */ 1331 if (messager.errorRaised() 1332 || werror && round.warningCount() > 0 && round.errorCount() > 0) 1333 errorStatus = true; 1334 1335 Set<JavaFileObject> newSourceFiles = 1336 new LinkedHashSet<>(filer.getGeneratedSourceFileObjects()); 1337 roots = round.roots; 1338 1339 errorStatus = errorStatus || (compiler.errorCount() > 0); 1340 1341 if (!errorStatus) 1342 round.finalCompiler(); 1343 1344 if (newSourceFiles.size() > 0) 1345 roots = roots.appendList(compiler.parseFiles(newSourceFiles)); 1346 1347 errorStatus = errorStatus || (compiler.errorCount() > 0); 1348 1349 // Free resources 1350 this.close(); 1351 1352 if (!taskListener.isEmpty()) 1353 taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING)); 1354 1355 if (errorStatus) { 1356 if (compiler.errorCount() == 0) 1357 compiler.log.nerrors++; 1358 return true; 1359 } 1360 1361 compiler.enterTreesIfNeeded(roots); 1362 1363 return true; 1364 } 1365 1366 private void warnIfUnmatchedOptions() { 1367 if (!unmatchedProcessorOptions.isEmpty()) { 1368 log.warning("proc.unmatched.processor.options", unmatchedProcessorOptions.toString()); 1369 } 1370 } 1371 1372 /** 1373 * Free resources related to annotation processing. 1374 */ 1375 public void close() { 1376 filer.close(); 1377 if (discoveredProcs != null) // Make calling close idempotent 1378 discoveredProcs.close(); 1379 discoveredProcs = null; 1380 } 1381 1382 private List<ClassSymbol> getTopLevelClasses(List<? extends JCCompilationUnit> units) { 1383 List<ClassSymbol> classes = List.nil(); 1384 for (JCCompilationUnit unit : units) { 1385 for (JCTree node : unit.defs) { 1386 if (node.hasTag(JCTree.Tag.CLASSDEF)) { 1387 ClassSymbol sym = ((JCClassDecl) node).sym; 1388 Assert.checkNonNull(sym); 1389 classes = classes.prepend(sym); 1390 } 1391 } 1392 } 1393 return classes.reverse(); 1394 } 1395 1396 private List<ClassSymbol> getTopLevelClassesFromClasses(List<? extends ClassSymbol> syms) { 1397 List<ClassSymbol> classes = List.nil(); 1398 for (ClassSymbol sym : syms) { 1399 if (!isPkgInfo(sym)) { 1400 classes = classes.prepend(sym); 1401 } 1402 } 1403 return classes.reverse(); 1404 } 1405 1406 private List<PackageSymbol> getPackageInfoFiles(List<? extends JCCompilationUnit> units) { 1407 List<PackageSymbol> packages = List.nil(); 1408 for (JCCompilationUnit unit : units) { 1409 if (isPkgInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE)) { 1410 packages = packages.prepend(unit.packge); 1411 } 1412 } 1413 return packages.reverse(); 1414 } 1415 1416 private List<PackageSymbol> getPackageInfoFilesFromClasses(List<? extends ClassSymbol> syms) { 1417 List<PackageSymbol> packages = List.nil(); 1418 for (ClassSymbol sym : syms) { 1419 if (isPkgInfo(sym)) { 1420 packages = packages.prepend((PackageSymbol) sym.owner); 1421 } 1422 } 1423 return packages.reverse(); 1424 } 1425 1426 // avoid unchecked warning from use of varargs 1427 private static <T> List<T> join(List<T> list1, List<T> list2) { 1428 return list1.appendList(list2); 1429 } 1430 1431 private boolean isPkgInfo(JavaFileObject fo, JavaFileObject.Kind kind) { 1432 return fo.isNameCompatible("package-info", kind); 1433 } 1434 1435 private boolean isPkgInfo(ClassSymbol sym) { 1436 return isPkgInfo(sym.classfile, JavaFileObject.Kind.CLASS) && (sym.packge().package_info == sym); 1437 } 1438 1439 /* 1440 * Called retroactively to determine if a class loader was required, 1441 * after we have failed to create one. 1442 */ 1443 private boolean needClassLoader(String procNames, Iterable<? extends Path> workingpath) { 1444 if (procNames != null) 1445 return true; 1446 1447 URL[] urls = new URL[1]; 1448 for(Path pathElement : workingpath) { 1449 try { 1450 urls[0] = pathElement.toUri().toURL(); 1451 if (ServiceProxy.hasService(Processor.class, urls)) 1452 return true; 1453 } catch (MalformedURLException ex) { 1454 throw new AssertionError(ex); 1455 } 1456 catch (ServiceProxy.ServiceConfigurationError e) { 1457 log.error("proc.bad.config.file", e.getLocalizedMessage()); 1458 return true; 1459 } 1460 } 1461 1462 return false; 1463 } 1464 1465 class ImplicitCompleter implements Completer { 1466 1467 private final JCCompilationUnit topLevel; 1468 1469 public ImplicitCompleter(JCCompilationUnit topLevel) { 1470 this.topLevel = topLevel; 1471 } 1472 1473 @Override public void complete(Symbol sym) throws CompletionFailure { 1474 compiler.readSourceFile(topLevel, (ClassSymbol) sym); 1475 } 1476 } 1477 1478 private final TreeScanner treeCleaner = new TreeScanner() { 1479 public void scan(JCTree node) { 1480 super.scan(node); 1481 if (node != null) 1482 node.type = null; 1483 } 1484 JCCompilationUnit topLevel; 1485 public void visitTopLevel(JCCompilationUnit node) { 1486 if (node.packge != null) { 1487 if (node.packge.package_info != null) { 1488 node.packge.package_info.reset(); 1489 } 1490 node.packge.reset(); 1491 } 1492 boolean isModuleInfo = node.sourcefile.isNameCompatible("module-info", Kind.SOURCE); 1493 if (isModuleInfo) { 1494 node.modle.reset(); 1495 node.modle.completer = sym -> modules.enter(List.of(node), node.modle.module_info); 1496 node.modle.module_info.reset(); 1497 node.modle.module_info.members_field = WriteableScope.create(node.modle.module_info); 1498 } 1499 node.packge = null; 1500 topLevel = node; 1501 try { 1502 super.visitTopLevel(node); 1503 } finally { 1504 topLevel = null; 1505 } 1506 } 1507 public void visitClassDef(JCClassDecl node) { 1508 if (node.sym != null) { 1509 node.sym.completer = new ImplicitCompleter(topLevel); 1510 } 1511 node.sym = null; 1512 super.visitClassDef(node); 1513 } 1514 public void visitMethodDef(JCMethodDecl node) { 1515 node.sym = null; 1516 super.visitMethodDef(node); 1517 } 1518 public void visitVarDef(JCVariableDecl node) { 1519 node.sym = null; 1520 super.visitVarDef(node); 1521 } 1522 public void visitNewClass(JCNewClass node) { 1523 node.constructor = null; 1524 super.visitNewClass(node); 1525 } 1526 public void visitAssignop(JCAssignOp node) { 1527 node.operator = null; 1528 super.visitAssignop(node); 1529 } 1530 public void visitUnary(JCUnary node) { 1531 node.operator = null; 1532 super.visitUnary(node); 1533 } 1534 public void visitBinary(JCBinary node) { 1535 node.operator = null; 1536 super.visitBinary(node); 1537 } 1538 public void visitSelect(JCFieldAccess node) { 1539 node.sym = null; 1540 super.visitSelect(node); 1541 } 1542 public void visitIdent(JCIdent node) { 1543 node.sym = null; 1544 super.visitIdent(node); 1545 } 1546 public void visitAnnotation(JCAnnotation node) { 1547 node.attribute = null; 1548 super.visitAnnotation(node); 1549 } 1550 }; 1551 1552 1553 private boolean moreToDo() { 1554 return filer.newFiles(); 1555 } 1556 1557 /** 1558 * {@inheritDoc} 1559 * 1560 * Command line options suitable for presenting to annotation 1561 * processors. 1562 * {@literal "-Afoo=bar"} should be {@literal "-Afoo" => "bar"}. 1563 */ 1564 @DefinedBy(Api.ANNOTATION_PROCESSING) 1565 public Map<String,String> getOptions() { 1566 return processorOptions; 1567 } 1568 1569 @DefinedBy(Api.ANNOTATION_PROCESSING) 1570 public Messager getMessager() { 1571 return messager; 1572 } 1573 1574 @DefinedBy(Api.ANNOTATION_PROCESSING) 1575 public Filer getFiler() { 1576 return filer; 1577 } 1578 1579 @DefinedBy(Api.ANNOTATION_PROCESSING) 1580 public JavacElements getElementUtils() { 1581 return elementUtils; 1582 } 1583 1584 @DefinedBy(Api.ANNOTATION_PROCESSING) 1585 public JavacTypes getTypeUtils() { 1586 return typeUtils; 1587 } 1588 1589 @DefinedBy(Api.ANNOTATION_PROCESSING) 1590 public SourceVersion getSourceVersion() { 1591 return Source.toSourceVersion(source); 1592 } 1593 1594 @DefinedBy(Api.ANNOTATION_PROCESSING) 1595 public Locale getLocale() { 1596 return messages.getCurrentLocale(); 1597 } 1598 1599 public Set<Symbol.PackageSymbol> getSpecifiedPackages() { 1600 return specifiedPackages; 1601 } 1602 1603 public static final Pattern noMatches = Pattern.compile("(\\P{all})+"); 1604 1605 /** 1606 * Convert import-style string for supported annotations into a 1607 * regex matching that string. If the string is not a valid 1608 * import-style string, return a regex that won't match anything. 1609 */ 1610 private static Pattern importStringToPattern(String s, Processor p, Log log) { 1611 if (MatchingUtils.isValidImportString(s)) { 1612 return MatchingUtils.validImportStringToPattern(s); 1613 } else { 1614 log.warning("proc.malformed.supported.string", s, p.getClass().getName()); 1615 return noMatches; // won't match any valid identifier 1616 } 1617 } 1618 1619 /** 1620 * For internal use only. This method may be removed without warning. 1621 */ 1622 public Context getContext() { 1623 return context; 1624 } 1625 1626 /** 1627 * For internal use only. This method may be removed without warning. 1628 */ 1629 public ClassLoader getProcessorClassLoader() { 1630 return processorClassLoader; 1631 } 1632 1633 public String toString() { 1634 return "javac ProcessingEnvironment"; 1635 } 1636 1637 public static boolean isValidOptionName(String optionName) { 1638 for(String s : optionName.split("\\.", -1)) { 1639 if (!SourceVersion.isIdentifier(s)) 1640 return false; 1641 } 1642 return true; 1643 } 1644} 1645