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