1 /*
2  * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.tools.javac.processing;
27 
28 import java.lang.annotation.Annotation;
29 import javax.annotation.processing.*;
30 import javax.lang.model.element.*;
31 import javax.lang.model.util.*;
32 import java.util.*;
33 
34 import com.sun.tools.javac.code.Source.Feature;
35 import com.sun.tools.javac.util.DefinedBy;
36 import com.sun.tools.javac.util.DefinedBy.Api;
37 
38 /**
39  * Object providing state about a prior round of annotation processing.
40  *
41  * <p>The methods in this class do not take type annotations into account,
42  * as target types, not java elements.
43  *
44  * <p><b>This is NOT part of any supported API.
45  * If you write code that depends on this, you do so at your own risk.
46  * This code and its internal interfaces are subject to change or
47  * deletion without notice.</b>
48  */
49 public class JavacRoundEnvironment implements RoundEnvironment {
50     // Default equals and hashCode methods are okay.
51 
52     private final boolean processingOver;
53     private final boolean errorRaised;
54     private final ProcessingEnvironment processingEnv;
55     private final Elements eltUtils;
56 
57     private final boolean allowModules;
58 
59     // Caller must pass in an immutable set
60     private final Set<? extends Element> rootElements;
61 
JavacRoundEnvironment(boolean processingOver, boolean errorRaised, Set<? extends Element> rootElements, JavacProcessingEnvironment processingEnv)62     JavacRoundEnvironment(boolean processingOver,
63                           boolean errorRaised,
64                           Set<? extends Element> rootElements,
65                           JavacProcessingEnvironment processingEnv) {
66         this.processingOver = processingOver;
67         this.errorRaised = errorRaised;
68         this.rootElements = rootElements;
69         this.processingEnv = processingEnv;
70         this.allowModules = Feature.MODULES.allowedInSource(processingEnv.source);
71         this.eltUtils = processingEnv.getElementUtils();
72     }
73 
toString()74     public String toString() {
75         return String.format("[errorRaised=%b, rootElements=%s, processingOver=%b]",
76                              errorRaised,
77                              rootElements,
78                              processingOver);
79     }
80 
81     @DefinedBy(Api.ANNOTATION_PROCESSING)
processingOver()82     public boolean processingOver() {
83         return processingOver;
84     }
85 
86     /**
87      * Returns {@code true} if an error was raised in the prior round
88      * of processing; returns {@code false} otherwise.
89      *
90      * @return {@code true} if an error was raised in the prior round
91      * of processing; returns {@code false} otherwise.
92      */
93     @DefinedBy(Api.ANNOTATION_PROCESSING)
errorRaised()94     public boolean errorRaised() {
95         return errorRaised;
96     }
97 
98     /**
99      * Returns the type elements specified by the prior round.
100      *
101      * @return the types elements specified by the prior round, or an
102      * empty set if there were none
103      */
104     @DefinedBy(Api.ANNOTATION_PROCESSING)
getRootElements()105     public Set<? extends Element> getRootElements() {
106         return rootElements;
107     }
108 
109     /**
110      * Returns the elements annotated with the given annotation type.
111      * Only type elements <i>included</i> in this round of annotation
112      * processing, or declarations of members, parameters, or type
113      * parameters declared within those, are returned.  Included type
114      * elements are {@linkplain #getRootElements specified
115      * types} and any types nested within them.
116      *
117      * @param a  annotation type being requested
118      * @return the elements annotated with the given annotation type,
119      * or an empty set if there are none
120      */
121     @DefinedBy(Api.ANNOTATION_PROCESSING)
getElementsAnnotatedWith(TypeElement a)122     public Set<? extends Element> getElementsAnnotatedWith(TypeElement a) {
123         throwIfNotAnnotation(a);
124 
125         Set<Element> result = Collections.emptySet();
126         ElementScanner9<Set<Element>, TypeElement> scanner =
127             new AnnotationSetScanner(result);
128 
129         for (Element element : rootElements)
130             result = scanner.scan(element, a);
131 
132         return result;
133     }
134 
135     @DefinedBy(Api.ANNOTATION_PROCESSING)
getElementsAnnotatedWithAny(TypeElement... annotations)136     public Set<? extends Element> getElementsAnnotatedWithAny(TypeElement... annotations) {
137         // Don't bother to special-case annotations.length == 1 as
138         // return getElementsAnnotatedWith(annotations[0]);
139 
140         Set<TypeElement> annotationSet = new LinkedHashSet<>(annotations.length);
141         for (TypeElement annotation : annotations) {
142             throwIfNotAnnotation(annotation);
143             annotationSet.add(annotation);
144         }
145 
146         Set<Element> result = Collections.emptySet();
147         ElementScanner9<Set<Element>, Set<TypeElement>> scanner =
148             new AnnotationSetMultiScanner(result);
149 
150         for (Element element : rootElements)
151             result = scanner.scan(element, annotationSet);
152 
153         return result;
154     }
155 
156     // Could be written as a local class inside getElementsAnnotatedWith
157     private class AnnotationSetScanner extends
158         ElementScanningIncludingTypeParameters<Set<Element>, TypeElement> {
159         // Insertion-order preserving set
160         private Set<Element> annotatedElements = new LinkedHashSet<>();
161 
AnnotationSetScanner(Set<Element> defaultSet)162         AnnotationSetScanner(Set<Element> defaultSet) {
163             super(defaultSet);
164         }
165 
166         @Override @DefinedBy(Api.LANGUAGE_MODEL)
scan(Element e, TypeElement annotation)167         public Set<Element> scan(Element e, TypeElement annotation) {
168             for (AnnotationMirror annotMirror :  eltUtils.getAllAnnotationMirrors(e)) {
169                 if (annotation.equals(mirrorAsElement(annotMirror))) {
170                     annotatedElements.add(e);
171                     break;
172                 }
173             }
174             e.accept(this, annotation);
175             return annotatedElements;
176         }
177 
178         @Override @DefinedBy(Api.LANGUAGE_MODEL)
visitModule(ModuleElement e, TypeElement annotation)179         public Set<Element> visitModule(ModuleElement e, TypeElement annotation) {
180             // Do not scan a module
181             return annotatedElements;
182         }
183 
184         @Override @DefinedBy(Api.LANGUAGE_MODEL)
visitPackage(PackageElement e, TypeElement annotation)185         public Set<Element> visitPackage(PackageElement e, TypeElement annotation) {
186             // Do not scan a package
187             return annotatedElements;
188         }
189     }
190 
191     // Could be written as a local class inside getElementsAnnotatedWithAny
192     private class AnnotationSetMultiScanner extends
193         ElementScanningIncludingTypeParameters<Set<Element>, Set<TypeElement>> {
194         // Insertion-order preserving set
195         private Set<Element> annotatedElements = new LinkedHashSet<>();
196 
AnnotationSetMultiScanner(Set<Element> defaultSet)197         AnnotationSetMultiScanner(Set<Element> defaultSet) {
198             super(defaultSet);
199         }
200 
201         @Override @DefinedBy(Api.LANGUAGE_MODEL)
scan(Element e, Set<TypeElement> annotations)202         public Set<Element> scan(Element e, Set<TypeElement> annotations) {
203             for (AnnotationMirror annotMirror : eltUtils.getAllAnnotationMirrors(e)) {
204                 if (annotations.contains(mirrorAsElement(annotMirror))) {
205                     annotatedElements.add(e);
206                     break;
207                 }
208             }
209             e.accept(this, annotations);
210             return annotatedElements;
211         }
212 
213         @Override @DefinedBy(Api.LANGUAGE_MODEL)
visitModule(ModuleElement e, Set<TypeElement> annotations)214         public Set<Element> visitModule(ModuleElement e, Set<TypeElement> annotations) {
215             // Do not scan a module
216             return annotatedElements;
217         }
218 
219         @Override @DefinedBy(Api.LANGUAGE_MODEL)
visitPackage(PackageElement e, Set<TypeElement> annotations)220         public Set<Element> visitPackage(PackageElement e, Set<TypeElement> annotations) {
221             // Do not scan a package
222             return annotatedElements;
223         }
224     }
225 
226     private static abstract class ElementScanningIncludingTypeParameters<R, P>
227         extends ElementScanner9<R, P> {
228 
ElementScanningIncludingTypeParameters(R defaultValue)229         protected ElementScanningIncludingTypeParameters(R defaultValue) {
230             super(defaultValue);
231         }
232 
233         @Override @DefinedBy(Api.LANGUAGE_MODEL)
visitType(TypeElement e, P p)234         public R visitType(TypeElement e, P p) {
235             // Type parameters are not considered to be enclosed by a type
236             scan(e.getTypeParameters(), p);
237             return super.visitType(e, p);
238         }
239 
240         @Override @DefinedBy(Api.LANGUAGE_MODEL)
visitExecutable(ExecutableElement e, P p)241         public R visitExecutable(ExecutableElement e, P p) {
242             // Type parameters are not considered to be enclosed by an executable
243             scan(e.getTypeParameters(), p);
244             return super.visitExecutable(e, p);
245         }
246     }
247 
248     /**
249      * {@inheritDoc}
250      */
251     @DefinedBy(Api.ANNOTATION_PROCESSING)
getElementsAnnotatedWith(Class<? extends Annotation> a)252     public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a) {
253         throwIfNotAnnotation(a);
254         String name = a.getCanonicalName();
255 
256         if (name == null)
257             return Collections.emptySet();
258         else {
259             TypeElement annotationType = annotationToElement(a);
260 
261             if (annotationType == null)
262                 return Collections.emptySet();
263             else
264                 return getElementsAnnotatedWith(annotationType);
265         }
266     }
267 
268     @DefinedBy(Api.ANNOTATION_PROCESSING)
getElementsAnnotatedWithAny(Set<Class<? extends Annotation>> annotations)269     public Set<? extends Element> getElementsAnnotatedWithAny(Set<Class<? extends Annotation>> annotations) {
270         List<TypeElement> annotationsAsElements = new ArrayList<>(annotations.size());
271 
272         for (Class<? extends Annotation> annotation : annotations) {
273             throwIfNotAnnotation(annotation);
274             String name = annotation.getCanonicalName();
275             if (name == null)
276                 continue;
277             annotationsAsElements.add(annotationToElement(annotation));
278         }
279 
280         return getElementsAnnotatedWithAny(annotationsAsElements.toArray(new TypeElement[0]));
281     }
282 
annotationToElement(Class<? extends Annotation> annotation)283     private TypeElement annotationToElement(Class<? extends Annotation> annotation) {
284         // First, try an element lookup based on the annotation's
285         // canonical name. If that fails or is ambiguous, try a lookup
286         // using a particular module, perhaps an unnamed one. This
287         // offers more compatibility for compiling in single-module
288         // mode where the runtime module of an annotation type may
289         // differ from the single module being compiled.
290         String name = annotation.getCanonicalName();
291         TypeElement annotationElement = eltUtils.getTypeElement(name);
292         if (annotationElement != null)
293             return annotationElement;
294         else if (allowModules) {
295             String moduleName = Objects.requireNonNullElse(annotation.getModule().getName(), "");
296             return eltUtils.getTypeElement(eltUtils.getModuleElement(moduleName), name);
297         } else {
298             return null;
299         }
300     }
301 
mirrorAsElement(AnnotationMirror annotationMirror)302     private Element mirrorAsElement(AnnotationMirror annotationMirror) {
303         return annotationMirror.getAnnotationType().asElement();
304     }
305 
306     private static final String NOT_AN_ANNOTATION_TYPE =
307         "The argument does not represent an annotation type: ";
308 
throwIfNotAnnotation(Class<? extends Annotation> a)309     private void throwIfNotAnnotation(Class<? extends Annotation> a) {
310         if (!a.isAnnotation())
311             throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
312     }
313 
throwIfNotAnnotation(TypeElement a)314     private void throwIfNotAnnotation(TypeElement a) {
315         if (a.getKind() != ElementKind.ANNOTATION_TYPE)
316             throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
317     }
318 }
319