001 /*
002 * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package com.sun.tools.javac.processing;
027
028 import java.lang.annotation.Annotation;
029 import com.sun.tools.javac.tree.JCTree.*;
030 import javax.annotation.processing.*;
031 import javax.lang.model.element.*;
032 import javax.lang.model.type.DeclaredType;
033 import javax.lang.model.type.TypeMirror;
034 import javax.lang.model.util.*;
035 import java.util.*;
036
037 /**
038 * Object providing state about a prior round of annotation processing.
039 *
040 * <p><b>This is NOT part of any API supported by Sun Microsystems.
041 * If you write code that depends on this, you do so at your own risk.
042 * This code and its internal interfaces are subject to change or
043 * deletion without notice.</b>
044 */
045 public class JavacRoundEnvironment implements RoundEnvironment {
046 // Default equals and hashCode methods are okay.
047
048 private final boolean processingOver;
049 private final boolean errorRaised;
050 private final ProcessingEnvironment processingEnv;
051
052 // Caller must pass in an immutable set
053 private final Set<? extends Element> rootElements;
054
055 JavacRoundEnvironment(boolean processingOver,
056 boolean errorRaised,
057 Set<? extends Element> rootElements,
058 ProcessingEnvironment processingEnv) {
059 this.processingOver = processingOver;
060 this.errorRaised = errorRaised;
061 this.rootElements = rootElements;
062 this.processingEnv = processingEnv;
063 }
064
065 public String toString() {
066 return String.format("[errorRaised=%b, rootElements=%s, processingOver=%b]",
067 errorRaised,
068 rootElements,
069 processingOver);
070 }
071
072 public boolean processingOver() {
073 return processingOver;
074 }
075
076 /**
077 * Returns {@code true} if an error was raised in the prior round
078 * of processing; returns {@code false} otherwise.
079 *
080 * @return {@code true} if an error was raised in the prior round
081 * of processing; returns {@code false} otherwise.
082 */
083 public boolean errorRaised() {
084 return errorRaised;
085 }
086
087 /**
088 * Returns the type elements specified by the prior round.
089 *
090 * @return the types elements specified by the prior round, or an
091 * empty set if there were none
092 */
093 public Set<? extends Element> getRootElements() {
094 return rootElements;
095 }
096
097 private static final String NOT_AN_ANNOTATION_TYPE =
098 "The argument does not represent an annotation type: ";
099
100 /**
101 * Returns the elements annotated with the given annotation type.
102 * Only type elements <i>included</i> in this round of annotation
103 * processing, or declarations of members, parameters, or type
104 * parameters declared within those, are returned. Included type
105 * elements are {@linkplain #getSpecifiedTypeElements specified
106 * types} and any types nested within them.
107 *
108 * @param a annotation type being requested
109 * @return the elements annotated with the given annotation type,
110 * or an empty set if there are none
111 */
112 public Set<? extends Element> getElementsAnnotatedWith(TypeElement a) {
113 Set<Element> result = Collections.emptySet();
114 if (a.getKind() != ElementKind.ANNOTATION_TYPE)
115 throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
116
117 DeclaredType annotationTypeElement;
118 TypeMirror tm = a.asType();
119 if ( tm instanceof DeclaredType )
120 annotationTypeElement = (DeclaredType) a.asType();
121 else
122 throw new AssertionError("Bad implementation type for " + tm);
123
124 ElementScanner6<Set<Element>, DeclaredType> scanner =
125 new AnnotationSetScanner(result);
126
127 for (Element element : rootElements)
128 result = scanner.scan(element, annotationTypeElement);
129
130 return result;
131 }
132
133 // Could be written as a local class inside getElementsAnnotatedWith
134 private class AnnotationSetScanner extends
135 ElementScanner6<Set<Element>, DeclaredType> {
136 // Insertion-order preserving set
137 Set<Element> annotatedElements = new LinkedHashSet<Element>();
138
139 AnnotationSetScanner(Set<Element> defaultSet) {
140 super(defaultSet);
141 }
142
143 @Override
144 public Set<Element> scan(Element e, DeclaredType p) {
145 java.util.List<? extends AnnotationMirror> annotationMirrors =
146 processingEnv.getElementUtils().getAllAnnotationMirrors(e);
147 for (AnnotationMirror annotationMirror : annotationMirrors) {
148 if (annotationMirror.getAnnotationType().equals(p))
149 annotatedElements.add(e);
150 }
151 e.accept(this, p);
152 return annotatedElements;
153 }
154
155 }
156
157 /**
158 * {@inheritdoc}
159 */
160 public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a) {
161 if (!a.isAnnotation())
162 throw new IllegalArgumentException(NOT_AN_ANNOTATION_TYPE + a);
163 String name = a.getCanonicalName();
164 if (name == null)
165 return Collections.emptySet();
166 else {
167 TypeElement annotationType = processingEnv.getElementUtils().getTypeElement(name);
168 if (annotationType == null)
169 return Collections.emptySet();
170 else
171 return getElementsAnnotatedWith(annotationType);
172 }
173 }
174 }