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