JavacProcessingEnvironment.java revision 2897:524255b0bec0
11590Srgrimes/* 21590Srgrimes * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. 31590Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41590Srgrimes * 51590Srgrimes * This code is free software; you can redistribute it and/or modify it 61590Srgrimes * under the terms of the GNU General Public License version 2 only, as 71590Srgrimes * published by the Free Software Foundation. Oracle designates this 81590Srgrimes * particular file as subject to the "Classpath" exception as provided 91590Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101590Srgrimes * 111590Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121590Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131590Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141590Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151590Srgrimes * accompanied this code). 161590Srgrimes * 171590Srgrimes * You should have received a copy of the GNU General Public License version 181590Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191590Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201590Srgrimes * 211590Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221590Srgrimes * or visit www.oracle.com if you need additional information or have any 231590Srgrimes * questions. 241590Srgrimes */ 251590Srgrimes 261590Srgrimespackage com.sun.tools.javac.processing; 271590Srgrimes 281590Srgrimesimport java.io.Closeable; 291590Srgrimesimport java.io.File; 301590Srgrimesimport java.io.PrintWriter; 311590Srgrimesimport java.io.StringWriter; 321590Srgrimesimport java.net.MalformedURLException; 331590Srgrimesimport java.net.URL; 341590Srgrimesimport java.util.*; 3527753Scharnierimport java.util.regex.*; 361590Srgrimes 371590Srgrimesimport javax.annotation.processing.*; 381590Srgrimesimport javax.lang.model.SourceVersion; 391590Srgrimesimport javax.lang.model.element.*; 401590Srgrimesimport javax.lang.model.util.*; 4127753Scharnierimport javax.tools.JavaFileManager; 421590Srgrimesimport javax.tools.JavaFileObject; 4327753Scharnierimport javax.tools.StandardJavaFileManager; 4427753Scharnierimport static javax.tools.StandardLocation.*; 4550477Speter 461590Srgrimesimport com.sun.source.util.TaskEvent; 471590Srgrimesimport com.sun.tools.javac.api.MultiTaskListener; 481590Srgrimesimport com.sun.tools.javac.code.*; 491590Srgrimesimport com.sun.tools.javac.code.Symbol.*; 501590Srgrimesimport com.sun.tools.javac.code.Type.ClassType; 511590Srgrimesimport com.sun.tools.javac.code.Types; 521590Srgrimesimport com.sun.tools.javac.comp.AttrContext; 531590Srgrimesimport com.sun.tools.javac.comp.Check; 541590Srgrimesimport com.sun.tools.javac.comp.Enter; 5552419Sjulianimport com.sun.tools.javac.comp.Env; 5652419Sjulianimport com.sun.tools.javac.file.JavacFileManager; 571590Srgrimesimport com.sun.tools.javac.main.JavaCompiler; 5827753Scharnierimport com.sun.tools.javac.model.JavacElements; 591590Srgrimesimport com.sun.tools.javac.model.JavacTypes; 601590Srgrimesimport com.sun.tools.javac.tree.*; 611590Srgrimesimport com.sun.tools.javac.tree.JCTree.*; 621590Srgrimesimport com.sun.tools.javac.util.Abort; 631590Srgrimesimport com.sun.tools.javac.util.Assert; 641590Srgrimesimport com.sun.tools.javac.util.ClientCodeException; 651590Srgrimesimport com.sun.tools.javac.util.Context; 661590Srgrimesimport com.sun.tools.javac.util.Convert; 671590Srgrimesimport com.sun.tools.javac.util.DefinedBy; 681590Srgrimesimport com.sun.tools.javac.util.DefinedBy.Api; 691590Srgrimesimport com.sun.tools.javac.util.JCDiagnostic; 701590Srgrimesimport com.sun.tools.javac.util.JavacMessages; 7138185Sphkimport com.sun.tools.javac.util.List; 7236080Swollmanimport com.sun.tools.javac.util.Log; 731590Srgrimesimport com.sun.tools.javac.util.MatchingUtils; 7436080Swollmanimport com.sun.tools.javac.util.Name; 751590Srgrimesimport com.sun.tools.javac.util.Names; 7636080Swollmanimport com.sun.tools.javac.util.Options; 771590Srgrimesimport com.sun.tools.javac.util.ServiceLoader; 7836080Swollmanimport static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING; 7912316Speterimport static com.sun.tools.javac.code.Kinds.Kind.*; 8036080Swollmanimport static com.sun.tools.javac.main.Option.*; 811590Srgrimesimport static com.sun.tools.javac.comp.CompileStates.CompileState; 8236080Swollmanimport static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*; 831590Srgrimes 8436080Swollman/** 851590Srgrimes * Objects of this class hold and manage the state needed to support 8636080Swollman * annotation processing. 871590Srgrimes * 8836080Swollman * <p><b>This is NOT part of any supported API. 891590Srgrimes * If you write code that depends on this, you do so at your own risk. 9036080Swollman * This code and its internal interfaces are subject to change or 911590Srgrimes * deletion without notice.</b> 9236080Swollman */ 931590Srgrimespublic class JavacProcessingEnvironment implements ProcessingEnvironment, Closeable { 9436080Swollman private final Options options; 951590Srgrimes 9636080Swollman private final boolean printProcessorInfo; 971590Srgrimes private final boolean printRounds; 9836080Swollman private final boolean verbose; 991590Srgrimes private final boolean lint; 10036080Swollman private final boolean fatalErrors; 1011590Srgrimes private final boolean werror; 10236080Swollman private final boolean showResolveErrors; 1031590Srgrimes 10436080Swollman private final JavacFiler filer; 1051590Srgrimes private final JavacMessager messager; 10636080Swollman private final JavacElements elementUtils; 1071590Srgrimes private final JavacTypes typeUtils; 10836080Swollman private final Types types; 1091590Srgrimes private final JavaCompiler compiler; 11042778Sfenner 1111590Srgrimes /** 11242778Sfenner * Holds relevant state history of which processors have been 1139215Swollman * used. 11442778Sfenner */ 1151590Srgrimes private DiscoveredProcessors discoveredProcs; 11642778Sfenner 11711819Sjulian /** 11842778Sfenner * Map of processor-specific options. 11911819Sjulian */ 12042778Sfenner private final Map<String, String> processorOptions; 12111819Sjulian 12242778Sfenner /** 12316178Sjulian */ 12442778Sfenner private final Set<String> unmatchedProcessorOptions; 12516178Sjulian 12652419Sjulian /** 12752419Sjulian * Annotations implicitly processed and claimed by javac. 12854263Sshin */ 12954263Sshin private final Set<String> platformAnnotations; 13054263Sshin 13154263Sshin /** 13254263Sshin * Set of packages given on command line. 13354263Sshin */ 13454263Sshin private Set<PackageSymbol> specifiedPackages = Collections.emptySet(); 13554263Sshin 13654263Sshin /** The log to be used for error reporting. 13754263Sshin */ 13854263Sshin final Log log; 13954263Sshin 14054263Sshin /** Diagnostic factory. 14154263Sshin */ 14254263Sshin JCDiagnostic.Factory diags; 14354263Sshin 14454263Sshin /** 14554263Sshin * Source level of the compile. 14662605Sitojun */ 14762605Sitojun Source source; 14816080Salex 1491590Srgrimes private ClassLoader processorClassLoader; 1501590Srgrimes private SecurityException processorClassLoaderException; 1511590Srgrimes 1521590Srgrimes /** 1531590Srgrimes * JavacMessages object used for localization 1541590Srgrimes */ 1551590Srgrimes private JavacMessages messages; 1561590Srgrimes 15754263Sshin private MultiTaskListener taskListener; 1581590Srgrimes private final Symtab symtab; 15936080Swollman private final Names names; 1601590Srgrimes private final Enter enter; 16136080Swollman private final Completer initialCompleter; 16254263Sshin private final Check chk; 16336080Swollman 16454263Sshin private final Context context; 16536080Swollman 16654263Sshin /** Get the JavacProcessingEnvironment instance for this context. */ 16736080Swollman public static JavacProcessingEnvironment instance(Context context) { 16854263Sshin JavacProcessingEnvironment instance = context.get(JavacProcessingEnvironment.class); 16936080Swollman if (instance == null) 17054263Sshin instance = new JavacProcessingEnvironment(context); 17136080Swollman return instance; 17254263Sshin } 17354263Sshin 17454263Sshin protected JavacProcessingEnvironment(Context context) { 17554263Sshin this.context = context; 17654263Sshin context.put(JavacProcessingEnvironment.class, this); 17746097Sluigi log = Log.instance(context); 17854263Sshin source = Source.instance(context); 1791590Srgrimes diags = JCDiagnostic.Factory.instance(context); 18054263Sshin options = Options.instance(context); 1811590Srgrimes printProcessorInfo = options.isSet(XPRINTPROCESSORINFO); 1821590Srgrimes printRounds = options.isSet(XPRINTROUNDS); 18354263Sshin verbose = options.isSet(VERBOSE); 18454263Sshin lint = Lint.instance(context).isEnabled(PROCESSING); 18554263Sshin compiler = JavaCompiler.instance(context); 18654263Sshin if (options.isSet(PROC, "only") || options.isSet(XPRINT)) { 18754263Sshin compiler.shouldStopPolicyIfNoError = CompileState.PROCESS; 18854263Sshin } 18954263Sshin fatalErrors = options.isSet("fatalEnterError"); 19054263Sshin showResolveErrors = options.isSet("showResolveErrors"); 19154263Sshin werror = options.isSet(WERROR); 19254263Sshin platformAnnotations = initPlatformAnnotations(); 19354263Sshin 19454263Sshin // Initialize services before any processors are initialized 19554263Sshin // in case processors use them. 19654263Sshin filer = new JavacFiler(context); 19754263Sshin messager = new JavacMessager(context, this); 19854263Sshin elementUtils = JavacElements.instance(context); 19954263Sshin typeUtils = JavacTypes.instance(context); 20054263Sshin types = Types.instance(context); 20154263Sshin processorOptions = initProcessorOptions(); 20254263Sshin unmatchedProcessorOptions = initUnmatchedProcessorOptions(); 20354263Sshin messages = JavacMessages.instance(context); 20454263Sshin taskListener = MultiTaskListener.instance(context); 20554263Sshin symtab = Symtab.instance(context); 20654263Sshin names = Names.instance(context); 20754263Sshin enter = Enter.instance(context); 20862605Sitojun initialCompleter = ClassFinder.instance(context).getCompleter(); 20962605Sitojun chk = Check.instance(context); 21062605Sitojun initProcessorClassLoader(); 21162605Sitojun } 21262605Sitojun 21362605Sitojun public void setProcessors(Iterable<? extends Processor> processors) { 21462605Sitojun Assert.checkNull(discoveredProcs); 21562605Sitojun initProcessorIterator(processors); 21662605Sitojun } 21716178Sjulian 21816178Sjulian private Set<String> initPlatformAnnotations() { 21954263Sshin Set<String> platformAnnotations = new HashSet<>(); 22016178Sjulian platformAnnotations.add("java.lang.Deprecated"); 22154263Sshin platformAnnotations.add("java.lang.Override"); 22216178Sjulian platformAnnotations.add("java.lang.SuppressWarnings"); 22316178Sjulian platformAnnotations.add("java.lang.annotation.Documented"); 22452419Sjulian platformAnnotations.add("java.lang.annotation.Inherited"); 22552419Sjulian platformAnnotations.add("java.lang.annotation.Retention"); 22654263Sshin platformAnnotations.add("java.lang.annotation.Target"); 22752419Sjulian return Collections.unmodifiableSet(platformAnnotations); 22854263Sshin } 22954263Sshin 23054263Sshin private void initProcessorClassLoader() { 23152419Sjulian JavaFileManager fileManager = context.get(JavaFileManager.class); 23252419Sjulian try { 23311819Sjulian // If processorpath is not explicitly set, use the classpath. 23411819Sjulian processorClassLoader = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH) 23554263Sshin ? fileManager.getClassLoader(ANNOTATION_PROCESSOR_PATH) 23611819Sjulian : fileManager.getClassLoader(CLASS_PATH); 23754263Sshin 23811819Sjulian if (processorClassLoader != null && processorClassLoader instanceof Closeable) { 23954263Sshin compiler.closeables = compiler.closeables.prepend((Closeable) processorClassLoader); 24011819Sjulian } 24111819Sjulian } catch (SecurityException e) { 24214092Swollman processorClassLoaderException = e; 2431590Srgrimes } 2441590Srgrimes } 24554263Sshin 2461590Srgrimes private void initProcessorIterator(Iterable<? extends Processor> processors) { 24754263Sshin Iterator<? extends Processor> processorIterator; 2481590Srgrimes 24954263Sshin if (options.isSet(XPRINT)) { 2501590Srgrimes try { 25154263Sshin Processor processor = PrintingProcessor.class.newInstance(); 2521590Srgrimes processorIterator = List.of(processor).iterator(); 25314092Swollman } catch (Throwable t) { 2541590Srgrimes AssertionError assertError = 25513940Swollman new AssertionError("Problem instantiating PrintingProcessor."); 2561590Srgrimes assertError.initCause(t); 2571590Srgrimes throw assertError; 25854263Sshin } 2591590Srgrimes } else if (processors != null) { 26054263Sshin processorIterator = processors.iterator(); 2611590Srgrimes } else { 26254263Sshin String processorNames = options.get(PROCESSOR); 2631590Srgrimes if (processorClassLoaderException == null) { 26454263Sshin /* 2651590Srgrimes * If the "-processor" option is used, search the appropriate 26654263Sshin * path for the named class. Otherwise, use a service 2671590Srgrimes * provider mechanism to create the processor iterator. 26813940Swollman */ 2691590Srgrimes if (processorNames != null) { 27054263Sshin processorIterator = new NameProcessIterator(processorNames, processorClassLoader, log); 27154263Sshin } else { 27254263Sshin processorIterator = new ServiceIterator(processorClassLoader, log); 27354263Sshin } 27454263Sshin } else { 27562605Sitojun /* 27662605Sitojun * A security exception will occur if we can't create a classloader. 27762605Sitojun * Ignore the exception if, with hindsight, we didn't need it anyway 27854263Sshin * (i.e. no processor was specified either explicitly, or implicitly, 27914092Swollman * in service configuration file.) Otherwise, we cannot continue. 28014092Swollman */ 28114092Swollman processorIterator = handleServiceLoaderUnavailability("proc.cant.create.loader", 28213940Swollman processorClassLoaderException); 28313940Swollman } 28413940Swollman } 28513940Swollman discoveredProcs = new DiscoveredProcessors(processorIterator); 2861590Srgrimes } 2871590Srgrimes 2881590Srgrimes /** 2891590Srgrimes * Returns an empty processor iterator if no processors are on the 2901590Srgrimes * relevant path, otherwise if processors are present, logs an 2911590Srgrimes * error. Called when a service loader is unavailable for some 29238185Sphk * reason, either because a service loader class cannot be found 29338124Sphk * or because a security policy prevents class loaders from being 2941590Srgrimes * created. 2951590Srgrimes * 2961590Srgrimes * @param key The resource key to use to log an error message 2971590Srgrimes * @param e If non-null, pass this exception to Abort 2981590Srgrimes */ 2991590Srgrimes private Iterator<Processor> handleServiceLoaderUnavailability(String key, Exception e) { 30052419Sjulian JavaFileManager fileManager = context.get(JavaFileManager.class); 3011590Srgrimes 3021590Srgrimes if (fileManager instanceof JavacFileManager) { 3031590Srgrimes StandardJavaFileManager standardFileManager = (JavacFileManager) fileManager; 3041590Srgrimes Iterable<? extends File> workingPath = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH) 30554574Sguido ? standardFileManager.getLocation(ANNOTATION_PROCESSOR_PATH) 3061590Srgrimes : standardFileManager.getLocation(CLASS_PATH); 3071590Srgrimes 3081590Srgrimes if (needClassLoader(options.get(PROCESSOR), workingPath) ) 3091590Srgrimes handleException(key, e); 3101590Srgrimes 3111590Srgrimes } else { 3121590Srgrimes handleException(key, e); 3133534Sdg } 3143534Sdg 3153534Sdg java.util.List<Processor> pl = Collections.emptyList(); 3161590Srgrimes return pl.iterator(); 3171590Srgrimes } 3181590Srgrimes 3191590Srgrimes /** 32014092Swollman * Handle a security exception thrown during initializing the 3211590Srgrimes * Processor iterator. 3221590Srgrimes */ 32314092Swollman private void handleException(String key, Exception e) { 32414092Swollman if (e != null) { 32514092Swollman log.error(key, e.getLocalizedMessage()); 32611819Sjulian throw new Abort(e); 3271590Srgrimes } else { 3281590Srgrimes log.error(key); 32954263Sshin throw new Abort(); 33054263Sshin } 33154263Sshin } 33254263Sshin 33362605Sitojun /** 33462605Sitojun * Use a service loader appropriate for the platform to provide an 33562605Sitojun * iterator over annotations processors; fails if a loader is 33662605Sitojun * needed but unavailable. 3371590Srgrimes */ 3381590Srgrimes private class ServiceIterator implements Iterator<Processor> { 33916178Sjulian private Iterator<Processor> iterator; 34016178Sjulian private Log log; 34152419Sjulian private ServiceLoader<Processor> loader; 34252419Sjulian 34352419Sjulian ServiceIterator(ClassLoader classLoader, Log log) { 34413940Swollman this.log = log; 3451590Srgrimes try { 3461590Srgrimes try { 34713940Swollman loader = ServiceLoader.load(Processor.class, classLoader); 3481590Srgrimes this.iterator = loader.iterator(); 3495811Swollman } catch (Exception e) { 3501590Srgrimes // Fail softly if a loader is not actually needed. 3511590Srgrimes this.iterator = handleServiceLoaderUnavailability("proc.no.service", null); 3521590Srgrimes } 3531590Srgrimes } catch (Throwable t) { 3541590Srgrimes log.error("proc.service.problem"); 3551590Srgrimes throw new Abort(t); 3561590Srgrimes } 3571590Srgrimes } 3581590Srgrimes 3591590Srgrimes public boolean hasNext() { 3601590Srgrimes try { 3611590Srgrimes return iterator.hasNext(); 3621590Srgrimes } catch(ServiceConfigurationError sce) { 3631590Srgrimes log.error("proc.bad.config.file", sce.getLocalizedMessage()); 3641590Srgrimes throw new Abort(sce); 3651590Srgrimes } catch (Throwable t) { 3661590Srgrimes throw new Abort(t); 36754263Sshin } 36854263Sshin } 36954263Sshin 37054574Sguido public Processor next() { 37154574Sguido try { 37254574Sguido return iterator.next(); 3731590Srgrimes } catch (ServiceConfigurationError sce) { 3741590Srgrimes log.error("proc.bad.config.file", sce.getLocalizedMessage()); 3751590Srgrimes throw new Abort(sce); 3761590Srgrimes } catch (Throwable t) { 3771590Srgrimes throw new Abort(t); 3781590Srgrimes } 3791590Srgrimes } 3801590Srgrimes 3811590Srgrimes public void remove() { 3821590Srgrimes throw new UnsupportedOperationException(); 3831590Srgrimes } 3841590Srgrimes 3851590Srgrimes public void close() { 3861590Srgrimes if (loader != null) { 3879215Swollman try { 3885811Swollman loader.reload(); 3895811Swollman } catch(Exception e) { 3901590Srgrimes // Ignore problems during a call to reload. 3911590Srgrimes } 3921590Srgrimes } 3931590Srgrimes } 3941590Srgrimes } 3951590Srgrimes 3961590Srgrimes 3971590Srgrimes private static class NameProcessIterator implements Iterator<Processor> { 3981590Srgrimes Processor nextProc = null; 3991590Srgrimes Iterator<String> names; 4001590Srgrimes ClassLoader processorCL; 4011590Srgrimes Log log; 4021590Srgrimes 4031590Srgrimes NameProcessIterator(String names, ClassLoader processorCL, Log log) { 4041590Srgrimes this.names = Arrays.asList(names.split(",")).iterator(); 4051590Srgrimes this.processorCL = processorCL; 4061590Srgrimes this.log = log; 4071590Srgrimes } 4081590Srgrimes 4091590Srgrimes public boolean hasNext() { 4101590Srgrimes if (nextProc != null) 4111590Srgrimes return true; 4121590Srgrimes else { 4131590Srgrimes if (!names.hasNext()) 4141590Srgrimes return false; 4151590Srgrimes else { 4161590Srgrimes String processorName = names.next(); 4171590Srgrimes 4181590Srgrimes Processor processor; 4191590Srgrimes try { 4201590Srgrimes try { 4211590Srgrimes processor = 4221590Srgrimes (Processor) (processorCL.loadClass(processorName).newInstance()); 4231590Srgrimes } catch (ClassNotFoundException cnfe) { 4241590Srgrimes log.error("proc.processor.not.found", processorName); 4251590Srgrimes return false; 4261590Srgrimes } catch (ClassCastException cce) { 4271590Srgrimes log.error("proc.processor.wrong.type", processorName); 4281590Srgrimes return false; 4291590Srgrimes } catch (Exception e ) { 4301590Srgrimes log.error("proc.processor.cant.instantiate", processorName); 4311590Srgrimes return false; 4321590Srgrimes } 4331590Srgrimes } catch(ClientCodeException e) { 4341590Srgrimes throw e; 4351590Srgrimes } catch(Throwable t) { 4361590Srgrimes throw new AnnotationProcessingError(t); 4371590Srgrimes } 4381590Srgrimes nextProc = processor; 4391590Srgrimes return true; 4401590Srgrimes } 4411590Srgrimes 44236080Swollman } 4431590Srgrimes } 4441590Srgrimes 4451590Srgrimes public Processor next() { 44654263Sshin if (hasNext()) { 44754263Sshin Processor p = nextProc; 44854263Sshin nextProc = null; 44954263Sshin return p; 45054263Sshin } else 45138185Sphk throw new NoSuchElementException(); 45238185Sphk } 45338185Sphk 45438185Sphk public void remove () { 45538185Sphk throw new UnsupportedOperationException(); 45638185Sphk } 45738185Sphk } 45838185Sphk 45938185Sphk public boolean atLeastOneProcessor() { 46036080Swollman return discoveredProcs.iterator().hasNext(); 46138185Sphk } 4621590Srgrimes 4631590Srgrimes private Map<String, String> initProcessorOptions() { 46413431Speter Set<String> keySet = options.keySet(); 4651590Srgrimes Map<String, String> tempOptions = new LinkedHashMap<>(); 4661590Srgrimes 4671590Srgrimes for(String key : keySet) { 4681590Srgrimes if (key.startsWith("-A") && key.length() > 2) { 4691590Srgrimes int sepIndex = key.indexOf('='); 4701590Srgrimes String candidateKey = null; 47113431Speter String candidateValue = null; 47213431Speter 47313431Speter if (sepIndex == -1) 47413431Speter candidateKey = key.substring(2); 47513431Speter else if (sepIndex >= 3) { 47613431Speter candidateKey = key.substring(2, sepIndex); 47713431Speter candidateValue = (sepIndex < key.length()-1)? 4781590Srgrimes key.substring(sepIndex+1) : null; 47955533Sshin } 48054263Sshin tempOptions.put(candidateKey, candidateValue); 48154263Sshin } 48238185Sphk } 48354263Sshin 4841590Srgrimes return Collections.unmodifiableMap(tempOptions); 4851590Srgrimes } 4861590Srgrimes 48738185Sphk private Set<String> initUnmatchedProcessorOptions() { 4881590Srgrimes Set<String> unmatchedProcessorOptions = new HashSet<>(); 4891590Srgrimes unmatchedProcessorOptions.addAll(processorOptions.keySet()); 4901590Srgrimes return unmatchedProcessorOptions; 4911590Srgrimes } 4921590Srgrimes 4931590Srgrimes /** 4941590Srgrimes * State about how a processor has been used by the tool. If a 49538185Sphk * processor has been used on a prior round, its process method is 49654263Sshin * called on all subsequent rounds, perhaps with an empty set of 49754263Sshin * annotations to process. The {@code annotationSupported} method 49854263Sshin * caches the supported annotation information from the first (and 49954263Sshin * only) getSupportedAnnotationTypes call to the processor. 50054263Sshin */ 50154263Sshin static class ProcessorState { 50254263Sshin public Processor processor; 50354263Sshin public boolean contributed; 50454263Sshin private ArrayList<Pattern> supportedAnnotationPatterns; 50554263Sshin private ArrayList<String> supportedOptionNames; 50654263Sshin 50754263Sshin ProcessorState(Processor p, Log log, Source source, ProcessingEnvironment env) { 50854263Sshin processor = p; 50954263Sshin contributed = false; 51054263Sshin 51154263Sshin try { 51254263Sshin processor.init(env); 5131590Srgrimes 5141590Srgrimes checkSourceVersionCompatibility(source, log); 51554263Sshin 51654263Sshin supportedAnnotationPatterns = new ArrayList<>(); 51754263Sshin for (String importString : processor.getSupportedAnnotationTypes()) { 51854263Sshin supportedAnnotationPatterns.add(importStringToPattern(importString, 51954263Sshin processor, 52054263Sshin log)); 52154263Sshin } 52254263Sshin 52354263Sshin supportedOptionNames = new ArrayList<>(); 52454263Sshin for (String optionName : processor.getSupportedOptions() ) { 52554263Sshin if (checkOptionName(optionName, log)) 52662605Sitojun supportedOptionNames.add(optionName); 52762605Sitojun } 52862605Sitojun 52962605Sitojun } catch (ClientCodeException e) { 53062605Sitojun throw e; 53143722Sjhay } catch (Throwable t) { 53243722Sjhay throw new AnnotationProcessingError(t); 53311819Sjulian } 53411819Sjulian } 53543722Sjhay 53616178Sjulian /** 53716178Sjulian * Checks whether or not a processor's source version is 53816178Sjulian * compatible with the compilation source version. The 53952419Sjulian * processor's source version needs to be greater than or 54052419Sjulian * equal to the source version of the compile. 54152419Sjulian */ 54214092Swollman private void checkSourceVersionCompatibility(Source source, Log log) { 5431590Srgrimes SourceVersion procSourceVersion = processor.getSupportedSourceVersion(); 5441590Srgrimes 5451590Srgrimes if (procSourceVersion.compareTo(Source.toSourceVersion(source)) < 0 ) { 54614092Swollman log.warning("proc.processor.incompatible.source.version", 54713940Swollman procSourceVersion, 5481590Srgrimes processor.getClass().getName(), 5491590Srgrimes source.name); 5501590Srgrimes } 55113940Swollman } 55254574Sguido 55336080Swollman private boolean checkOptionName(String optionName, Log log) { 5541590Srgrimes boolean valid = isValidOptionName(optionName); 5551590Srgrimes if (!valid) 5561590Srgrimes log.error("proc.processor.bad.option.name", 5571590Srgrimes optionName, 5581590Srgrimes processor.getClass().getName()); 5591590Srgrimes return valid; 5601590Srgrimes } 5611590Srgrimes 5621590Srgrimes public boolean annotationSupported(String annotationName) { 5631590Srgrimes for(Pattern p: supportedAnnotationPatterns) { 5641590Srgrimes if (p.matcher(annotationName).matches()) 5651590Srgrimes return true; 5661590Srgrimes } 5671590Srgrimes return false; 5681590Srgrimes } 5691590Srgrimes 5701590Srgrimes /** 57154263Sshin * Remove options that are matched by this processor. 57254263Sshin */ 57354263Sshin public void removeSupportedOptions(Set<String> unmatchedProcessorOptions) { 57454263Sshin unmatchedProcessorOptions.removeAll(supportedOptionNames); 57554263Sshin } 57654263Sshin } 57754263Sshin 57854263Sshin // TODO: These two classes can probably be rewritten better... 57954263Sshin /** 58054263Sshin * This class holds information about the processors that have 58154263Sshin * been discoverd so far as well as the means to discover more, if 5821590Srgrimes * necessary. A single iterator should be used per round of 5831590Srgrimes * annotation processing. The iterator first visits already 58436080Swollman * discovered processors then fails over to the service provider 58536080Swollman * mechanism if additional queries are made. 5861590Srgrimes */ 5871590Srgrimes class DiscoveredProcessors implements Iterable<ProcessorState> { 58854263Sshin 5891590Srgrimes class ProcessorStateIterator implements Iterator<ProcessorState> { 5901590Srgrimes DiscoveredProcessors psi; 5911590Srgrimes Iterator<ProcessorState> innerIter; 5921590Srgrimes boolean onProcInterator; 5931590Srgrimes 5941590Srgrimes ProcessorStateIterator(DiscoveredProcessors psi) { 5951590Srgrimes this.psi = psi; 5961590Srgrimes this.innerIter = psi.procStateList.iterator(); 5971590Srgrimes this.onProcInterator = false; 5981590Srgrimes } 5991590Srgrimes 60036080Swollman public ProcessorState next() { 60138124Sphk if (!onProcInterator) { 60238124Sphk if (innerIter.hasNext()) 60338124Sphk return innerIter.next(); 60438124Sphk else 60538124Sphk onProcInterator = true; 60638124Sphk } 60738124Sphk 60838124Sphk if (psi.processorIterator.hasNext()) { 60938124Sphk ProcessorState ps = new ProcessorState(psi.processorIterator.next(), 61038124Sphk log, source, JavacProcessingEnvironment.this); 61138124Sphk psi.procStateList.add(ps); 61238124Sphk return ps; 61338124Sphk } else 61438124Sphk throw new NoSuchElementException(); 61538124Sphk } 61638124Sphk 61738124Sphk public boolean hasNext() { 61838124Sphk if (onProcInterator) 61938124Sphk return psi.processorIterator.hasNext(); 62038124Sphk else 62138124Sphk return innerIter.hasNext() || psi.processorIterator.hasNext(); 62238124Sphk } 62338124Sphk 62436080Swollman public void remove () { 62538185Sphk throw new UnsupportedOperationException(); 62638185Sphk } 6271590Srgrimes 6289776Sdg /** 6291590Srgrimes * Run all remaining processors on the procStateList that 6301590Srgrimes * have not already run this round with an empty set of 6311590Srgrimes * annotations. 6321590Srgrimes */ 6331590Srgrimes public void runContributingProcs(RoundEnvironment re) { 6341590Srgrimes if (!onProcInterator) { 6351590Srgrimes Set<TypeElement> emptyTypeElements = Collections.emptySet(); 6361590Srgrimes while(innerIter.hasNext()) { 6371590Srgrimes ProcessorState ps = innerIter.next(); 6381590Srgrimes if (ps.contributed) 6391590Srgrimes callProcessor(ps.processor, emptyTypeElements, re); 6401590Srgrimes } 6411590Srgrimes } 6421590Srgrimes } 6431590Srgrimes } 6441590Srgrimes 6451590Srgrimes Iterator<? extends Processor> processorIterator; 6461590Srgrimes ArrayList<ProcessorState> procStateList; 6471590Srgrimes 6481590Srgrimes public ProcessorStateIterator iterator() { 6491590Srgrimes return new ProcessorStateIterator(this); 6501590Srgrimes } 6511590Srgrimes 6521590Srgrimes DiscoveredProcessors(Iterator<? extends Processor> processorIterator) { 6531590Srgrimes this.processorIterator = processorIterator; 6541590Srgrimes this.procStateList = new ArrayList<>(); 6551590Srgrimes } 6561590Srgrimes 6571590Srgrimes /** 6581590Srgrimes * Free jar files, etc. if using a service loader. 6591590Srgrimes */ 6601590Srgrimes public void close() { 6611590Srgrimes if (processorIterator != null && 6621590Srgrimes processorIterator instanceof ServiceIterator) { 6631590Srgrimes ((ServiceIterator) processorIterator).close(); 6641590Srgrimes } 6651590Srgrimes } 6661590Srgrimes } 6671590Srgrimes 6681590Srgrimes private void discoverAndRunProcs(Set<TypeElement> annotationsPresent, 6691590Srgrimes List<ClassSymbol> topLevelClasses, 6701590Srgrimes List<PackageSymbol> packageInfoFiles) { 6711590Srgrimes Map<String, TypeElement> unmatchedAnnotations = new HashMap<>(annotationsPresent.size()); 6721590Srgrimes 6731590Srgrimes for(TypeElement a : annotationsPresent) { 6741590Srgrimes unmatchedAnnotations.put(a.getQualifiedName().toString(), 6751590Srgrimes a); 6761590Srgrimes } 6771590Srgrimes 6781590Srgrimes // Give "*" processors a chance to match 67954263Sshin if (unmatchedAnnotations.size() == 0) 6801590Srgrimes unmatchedAnnotations.put("", null); 6811590Srgrimes 6821590Srgrimes DiscoveredProcessors.ProcessorStateIterator psi = discoveredProcs.iterator(); 68354263Sshin // TODO: Create proper argument values; need past round 6841590Srgrimes // information to fill in this constructor. Note that the 1 6851590Srgrimes // st round of processing could be the last round if there 6861590Srgrimes // were parse errors on the initial source files; however, we 6871590Srgrimes // are not doing processing in that case. 6881590Srgrimes 6891590Srgrimes Set<Element> rootElements = new LinkedHashSet<>(); 6901590Srgrimes rootElements.addAll(topLevelClasses); 6911590Srgrimes rootElements.addAll(packageInfoFiles); 6921590Srgrimes rootElements = Collections.unmodifiableSet(rootElements); 6931590Srgrimes 6941590Srgrimes RoundEnvironment renv = new JavacRoundEnvironment(false, 6951590Srgrimes false, 6961590Srgrimes rootElements, 6971590Srgrimes JavacProcessingEnvironment.this); 69827753Scharnier 69958395Sguido while(unmatchedAnnotations.size() > 0 && psi.hasNext() ) { 70057914Sshin ProcessorState ps = psi.next(); 70127753Scharnier Set<String> matchedNames = new HashSet<>(); 70227753Scharnier Set<TypeElement> typeElements = new LinkedHashSet<>(); 7031590Srgrimes 7041590Srgrimes for (Map.Entry<String, TypeElement> entry: unmatchedAnnotations.entrySet()) { 70513433Speter String unmatchedAnnotationName = entry.getKey(); 70613433Speter if (ps.annotationSupported(unmatchedAnnotationName) ) { 70713433Speter matchedNames.add(unmatchedAnnotationName); 70813433Speter TypeElement te = entry.getValue(); 70913433Speter if (te != null) 71013433Speter typeElements.add(te); 71113433Speter } 71213433Speter } 71313433Speter 71413433Speter if (matchedNames.size() > 0 || ps.contributed) { 71513433Speter boolean processingResult = callProcessor(ps.processor, typeElements, renv); 71613433Speter ps.contributed = true; 71713433Speter ps.removeSupportedOptions(unmatchedProcessorOptions); 71813433Speter 71913433Speter if (printProcessorInfo || verbose) { 72013433Speter log.printLines("x.print.processor.info", 72113433Speter ps.processor.getClass().getName(), 72213433Speter matchedNames.toString(), 72313433Speter processingResult); 72413433Speter } 72513433Speter 72613433Speter if (processingResult) { 72713433Speter unmatchedAnnotations.keySet().removeAll(matchedNames); 72813433Speter } 72913433Speter 73013433Speter } 73113433Speter } 73213433Speter unmatchedAnnotations.remove(""); 73313433Speter 73413433Speter 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} 1477