KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > apt > dispatch > RoundEnvImpl


1 /*******************************************************************************
2  * Copyright (c) 2005, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.apt.dispatch;
12
13 import java.lang.annotation.Annotation JavaDoc;
14 import java.util.Collections JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Set JavaDoc;
17
18 import javax.annotation.processing.RoundEnvironment;
19 import javax.lang.model.element.Element;
20 import javax.lang.model.element.ElementKind;
21 import javax.lang.model.element.TypeElement;
22 import javax.lang.model.util.ElementFilter;
23
24 import org.eclipse.jdt.internal.compiler.apt.model.Factory;
25 import org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl;
26 import org.eclipse.jdt.internal.compiler.apt.util.ManyToMany;
27 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
28 import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
29 import org.eclipse.jdt.internal.compiler.lookup.Binding;
30 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
31 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
32 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
33 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
34 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
35
36 public class RoundEnvImpl implements RoundEnvironment
37 {
38     private final BaseProcessingEnvImpl _processingEnv;
39     private final boolean _isLastRound;
40     private final CompilationUnitDeclaration[] _units;
41     private final ManyToMany<TypeElement, Element> _annoToUnit;
42     private final ReferenceBinding[] _binaryTypes;
43     private final Factory _factory;
44     private Set JavaDoc<Element> _rootElements = null;
45
46     public RoundEnvImpl(CompilationUnitDeclaration[] units, ReferenceBinding[] binaryTypeBindings, boolean isLastRound, BaseProcessingEnvImpl env) {
47         _processingEnv = env;
48         _isLastRound = isLastRound;
49         _units = units;
50         _factory = _processingEnv.getFactory();
51         
52         // Discover the annotations that will be passed to Processor.process()
53
AnnotationDiscoveryVisitor visitor = new AnnotationDiscoveryVisitor(_processingEnv);
54         if (_units != null) {
55             for (CompilationUnitDeclaration unit : _units) {
56                 unit.traverse(visitor, unit.scope);
57             }
58         }
59         _annoToUnit = visitor._annoToElement;
60         if (binaryTypeBindings != null) collectAnnotations(binaryTypeBindings);
61         _binaryTypes = binaryTypeBindings;
62     }
63
64     private void collectAnnotations(ReferenceBinding[] referenceBindings) {
65         for (ReferenceBinding referenceBinding : referenceBindings) {
66             // collect all annotations from the binary types
67
AnnotationBinding[] annotationBindings = referenceBinding.getAnnotations();
68             for (AnnotationBinding annotationBinding : annotationBindings) {
69                 TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType());
70                 Element element = _factory.newElement(referenceBinding);
71                 _annoToUnit.put(anno, element);
72             }
73             FieldBinding[] fieldBindings = referenceBinding.fields();
74             for (FieldBinding fieldBinding : fieldBindings) {
75                 annotationBindings = fieldBinding.getAnnotations();
76                 for (AnnotationBinding annotationBinding : annotationBindings) {
77                     TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType());
78                     Element element = _factory.newElement(fieldBinding);
79                     _annoToUnit.put(anno, element);
80                 }
81             }
82             MethodBinding[] methodBindings = referenceBinding.methods();
83             for (MethodBinding methodBinding : methodBindings) {
84                 annotationBindings = methodBinding.getAnnotations();
85                 for (AnnotationBinding annotationBinding : annotationBindings) {
86                     TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType());
87                     Element element = _factory.newElement(methodBinding);
88                     _annoToUnit.put(anno, element);
89                 }
90             }
91             ReferenceBinding[] memberTypes = referenceBinding.memberTypes();
92             collectAnnotations(memberTypes);
93         }
94     }
95
96     /**
97      * Return the set of annotation types that were discovered on the root elements.
98      * This does not include inherited annotations, only those directly on the root
99      * elements.
100      * @return a set of annotation types, possibly empty.
101      */

102     public Set JavaDoc<TypeElement> getRootAnnotations()
103     {
104         return Collections.unmodifiableSet(_annoToUnit.getKeySet());
105     }
106
107     @Override JavaDoc
108     public boolean errorRaised()
109     {
110         return _processingEnv.errorRaised();
111     }
112
113     /**
114      * From the set of root elements and their enclosed elements, return the subset that are annotated
115      * with {@code a}. If {@code a} is annotated with the {@link java.lang.annotations.Inherited}
116      * annotation, include those elements that inherit the annotation from their superclasses.
117      * Note that {@link java.lang.annotations.Inherited} only applies to classes (i.e. TypeElements).
118      */

119     @Override JavaDoc
120     public Set JavaDoc<? extends Element> getElementsAnnotatedWith(TypeElement a)
121     {
122         if (a.getKind() != ElementKind.ANNOTATION_TYPE) {
123             throw new IllegalArgumentException JavaDoc("Argument must represent an annotation type"); //$NON-NLS-1$
124
}
125         Binding annoBinding = ((TypeElementImpl)a)._binding;
126         if (0 != (annoBinding.getAnnotationTagBits() & TagBits.AnnotationInherited)) {
127             Set JavaDoc<Element> annotatedElements = new HashSet JavaDoc<Element>(_annoToUnit.getValues(a));
128             // For all other root elements that are TypeElements, and for their recursively enclosed
129
// types, add each element if it has a superclass are annotated with 'a'
130
ReferenceBinding annoTypeBinding = (ReferenceBinding)((TypeElementImpl)a)._binding;
131             for (TypeElement element : ElementFilter.typesIn(getRootElements())) {
132                 ReferenceBinding typeBinding = (ReferenceBinding)((TypeElementImpl)element)._binding;
133                 addAnnotatedElements(annoTypeBinding, typeBinding, annotatedElements);
134             }
135             return Collections.unmodifiableSet(annotatedElements);
136         }
137         return Collections.unmodifiableSet(_annoToUnit.getValues(a));
138     }
139     
140     /**
141      * For every type in types that is a class and that is annotated with anno, either directly or by inheritance,
142      * add that type to result. Recursively descend on each types's child classes as well.
143      * @param anno the compiler binding for an annotation type
144      * @param types a set of types, not necessarily all classes
145      * @param result must be a modifiable Set; will accumulate annotated classes
146      */

147     private void addAnnotatedElements(ReferenceBinding anno, ReferenceBinding type, Set JavaDoc<Element> result) {
148         if (type.isClass()) {
149             if (inheritsAnno(type, anno)) {
150                 result.add(_factory.newElement(type));
151             }
152         }
153         for (ReferenceBinding element : type.memberTypes()) {
154             addAnnotatedElements(anno, element, result);
155         }
156     }
157     
158     /**
159      * Check whether an element has a superclass that is annotated with an @Inherited annotation.
160      * @param element must be a class (not an interface, enum, etc.).
161      * @param anno must be an annotation type, and must be @Inherited
162      * @return true if element has a superclass that is annotated with anno
163      */

164     private boolean inheritsAnno(ReferenceBinding element, ReferenceBinding anno) {
165         do {
166             AnnotationBinding[] annos = element.getAnnotations();
167             for (AnnotationBinding annoBinding : annos) {
168                 if (annoBinding.getAnnotationType() == anno) {
169                     // element is annotated with anno
170
return true;
171                 }
172             }
173         } while (null != (element = element.superclass()));
174         return false;
175     }
176     
177     @Override JavaDoc
178     public Set JavaDoc<? extends Element> getElementsAnnotatedWith(Class JavaDoc<? extends Annotation JavaDoc> a)
179     {
180         String JavaDoc canonicalName = a.getCanonicalName();
181         if (canonicalName == null) {
182             // null for anonymous and local classes or an array of those
183
throw new IllegalArgumentException JavaDoc("Argument must represent an annotation type"); //$NON-NLS-1$
184
}
185         TypeElement annoType = _processingEnv.getElementUtils().getTypeElement(canonicalName);
186         return getElementsAnnotatedWith(annoType);
187     }
188
189     @Override JavaDoc
190     public Set JavaDoc<? extends Element> getRootElements()
191     {
192         if (_units == null) {
193             return Collections.emptySet();
194         }
195         if (_rootElements == null) {
196             Set JavaDoc<Element> elements = new HashSet JavaDoc<Element>(_units.length);
197             for (CompilationUnitDeclaration unit : _units) {
198                 if (null == unit.scope || null == unit.scope.topLevelTypes)
199                     continue;
200                 for (SourceTypeBinding binding : unit.scope.topLevelTypes) {
201                     Element element = _factory.newElement(binding);
202                     if (null == element) {
203                         throw new IllegalArgumentException JavaDoc("Top-level type binding could not be converted to element: " + binding); //$NON-NLS-1$
204
}
205                     elements.add(element);
206                 }
207             }
208             if (this._binaryTypes != null) {
209                 for (ReferenceBinding typeBinding : _binaryTypes) {
210                     TypeElement element = (TypeElement)_factory.newElement(typeBinding);
211                     if (null == element) {
212                         throw new IllegalArgumentException JavaDoc("Top-level type binding could not be converted to element: " + typeBinding); //$NON-NLS-1$
213
}
214                     elements.add(element);
215                 }
216             }
217             _rootElements = elements;
218         }
219         return _rootElements;
220     }
221
222     @Override JavaDoc
223     public boolean processingOver()
224     {
225         return _isLastRound;
226     }
227
228 }
229
Popular Tags