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