• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package annotations.el;
2 
3 import java.util.LinkedHashSet;
4 import java.util.Set;
5 
6 import annotations.Annotation;
7 import annotations.field.AnnotationAFT;
8 import annotations.field.AnnotationFieldType;
9 
10 /*>>>
11 import org.checkerframework.checker.nullness.qual.*;
12 */
13 
14 /**
15  * A DefCollector supplies a visitor for the annotation definitions in an
16  * AScene.  First, call the DefCollector constructor passing the AScene.
17  * Then, call the visit method.
18  * This class exists primarily for the benefit of
19  * {@link annotations.io.IndexFileWriter#write(AScene, Writer)}.
20  */
21 public abstract class DefCollector {
22 
23     // The set of all definitions in the Scene, which the visitor iterates
24     // over.
25     private final Set<AnnotationDef> defs;
26 
27     /**
28      * Constructs a new {@link DefCollector}, which immediately collects all
29      * the definitions from annotations the given scene.  Next call
30      * {@link #visit} to have the definitions passed back to you in topological
31      * order.  If the scene contains two irreconcilable definitions of the
32      * same annotation type, a {@link DefException} is thrown.
33      */
DefCollector(AScene s)34     public DefCollector(AScene s)
35             throws DefException {
36         defs = new LinkedHashSet<AnnotationDef>();
37         collect(s);
38     }
39 
40     // The name "collect" in the methods below means to insert or add to
41     // the the DefCollector.  "Insert" or "add" would have been better, but
42     // at least the methods are private.
43 
getDef(String name)44     private AnnotationDef getDef(String name) {
45         for (AnnotationDef def : defs) {
46             if (def.name.equals(name)) {
47                 return def;
48             }
49         }
50         return null;
51     }
52 
53 
collect(AScene s)54     private void collect(AScene s)
55             throws DefException {
56         for (AElement p : s.packages.values()) {
57             collect(p);
58         }
59         for (AClass c : s.classes.values()) {
60             collect(c);
61         }
62     }
63 
addToDefs(AnnotationDef d)64     private void addToDefs(AnnotationDef d) throws DefException {
65         // TODO: this mimics the condition we have in collect, but
66         // i don't know if we need it
67         if (defs.contains(d)) {
68             return;
69         }
70         AnnotationDef oldD = getDef(d.name);
71         if (oldD == null) {
72             defs.add(d);
73         } else {
74             AnnotationDef ud = AnnotationDef.unify(oldD, d);
75             if (ud == null) {
76                 throw new DefException(d.name);
77             }
78             defs.remove(oldD);
79             defs.add(ud);
80         }
81     }
82 
collect(AnnotationDef d)83     private void collect(AnnotationDef d) throws DefException {
84         if (defs.contains(d)) {
85             return;
86         }
87 
88         // define the fields first
89         for (AnnotationFieldType aft : d.fieldTypes.values()) {
90             if (aft instanceof AnnotationAFT) {
91                 collect(((AnnotationAFT) aft).annotationDef);
92             }
93         }
94 
95         addToDefs(d);
96 
97         // TODO: In the future we want to add the defs of meta-annotations
98         // as well.  Enable this option by uncommenting the following line.
99         //
100         // For the time-being, the parser would fail, because of possible
101         // circular references (e.g. Documented and Retention).  When it is
102         // fixed, uncomment it
103         //
104         // collect((AElement)d);
105     }
106 
collect(AElement e)107     private void collect(AElement e)
108             throws DefException {
109         for (Annotation tla : e.tlAnnotationsHere) {
110             AnnotationDef tld = tla.def;
111             if (defs.contains(tld)) {
112                 continue;
113             }
114 
115             AnnotationDef d = tld;
116             collect(d);
117 
118             addToDefs(d);
119         }
120         if (e.type != null) {
121             collect(e.type);
122         }
123 
124     }
125 
collect(ATypeElement e)126     private void collect(ATypeElement e)
127             throws DefException {
128         collect((AElement) e);
129         for (AElement it : e.innerTypes.values()) {
130             collect(it);
131         }
132     }
133 
collect(ADeclaration d)134     private void collect(ADeclaration d)
135             throws DefException {
136         collect((AElement) d);
137         for (ATypeElement ia : d.insertAnnotations.values()) {
138             collect(ia);
139         }
140         for (ATypeElementWithType ic : d.insertTypecasts.values()) {
141             collect(ic);
142         }
143     }
144 
collect(AField f)145     private void collect(AField f)
146             throws DefException {
147         collect((ADeclaration) f);
148     }
149 
collect(AMethod m)150     private void collect(AMethod m)
151             throws DefException {
152         for (ATypeElement b : m.bounds.values()) {
153             collect(b);
154         }
155         collect((ADeclaration) m);
156         collect((ATypeElement) m.returnType);
157         collect(m.receiver);
158         for (AElement p : m.parameters.values()) {
159             collect(p);
160         }
161         for (AField l : m.body.locals.values()) {
162             collect(l);
163         }
164         for (ATypeElement tc : m.body.typecasts.values()) {
165             collect(tc);
166         }
167         for (ATypeElement i : m.body.instanceofs.values()) {
168             collect(i);
169         }
170         for (ATypeElement n : m.body.news.values()) {
171             collect(n);
172         }
173     }
174 
collect(AClass c)175     private void collect(AClass c)
176             throws DefException {
177         collect((ADeclaration) c);
178         for (ATypeElement b : c.bounds.values()) {
179             collect(b);
180         }
181         for (ATypeElement ei : c.extendsImplements.values()) {
182             collect(ei);
183         }
184         for (AMethod m : c.methods.values()) {
185             collect(m);
186         }
187         for (AField f : c.fields.values()) {
188             collect(f);
189         }
190     }
191 
192     /**
193      * Override this method to perform some sort of subclass-specific
194      * processing on the given {@link AnnotationDef}.
195      */
visitAnnotationDef(AnnotationDef d)196     protected abstract void visitAnnotationDef(AnnotationDef d);
197 
198     /**
199      * Calls {@link #visitAnnotationDef} on the definitions collected from
200      * the scene that was passed to the constructor.  Visiting is done in
201      * topological order:  if the definition of <code>A</code> contains a
202      * subannotation of type <code>B</code>, then <code>B</code> is
203      * guaranteed to be visited before <code>A</code>.
204      */
visit()205     public final void visit() {
206         for (AnnotationDef d : defs) {
207             visitAnnotationDef(d);
208         }
209     }
210 }
211