46 * are annotated onto the Symbol. However this class depends on the facts that |
46 * are annotated onto the Symbol. However this class depends on the facts that |
47 * List (in javac) is immutable. |
47 * List (in javac) is immutable. |
48 * |
48 * |
49 * An instance of this class can be in one of three states: |
49 * An instance of this class can be in one of three states: |
50 * |
50 * |
51 * NOT_STARTED indicates that the Symbol this instance belongs to have not been |
51 * NOT_STARTED indicates that the Symbol this instance belongs to has not been |
52 * annotated (yet). Specifically if the declaration is not annotated this |
52 * annotated (yet). Specifically if the declaration is not annotated this |
53 * instance will never move past NOT_STARTED. You can never go back to |
53 * instance will never move past NOT_STARTED. You can never go back to |
54 * NOT_STARTED. |
54 * NOT_STARTED. |
55 * |
55 * |
56 * IN_PROGRESS annotations have been found on the declaration. Will be processed |
56 * IN_PROGRESS annotations have been found on the declaration. Will be processed |
57 * later. You can reset to IN_PROGRESS. While IN_PROGRESS you can set the list |
57 * later. You can reset to IN_PROGRESS. While IN_PROGRESS you can set the list |
58 * of attributes (and this moves out of the IN_PROGRESS state). |
58 * of attributes (and this moves out of the IN_PROGRESS state). |
59 * |
59 * |
60 * "unnamed" this Annotations contains some attributes, possibly the final set. |
60 * "unnamed" this Annotations contains some attributes, possibly the final set. |
61 * While in this state you can only prepend or append to the attributes not set |
61 * While in this state you can only prepend or append to the attributes not set |
62 * it directly. You can also move back to the IN_PROGRESS sate using reset(). |
62 * it directly. You can also move back to the IN_PROGRESS state using reset(). |
63 * |
63 * |
64 * <p><b>This is NOT part of any supported API. If you write code that depends |
64 * <p><b>This is NOT part of any supported API. If you write code that depends |
65 * on this, you do so at your own risk. This code and its internal interfaces |
65 * on this, you do so at your own risk. This code and its internal interfaces |
66 * are subject to change or deletion without notice.</b> |
66 * are subject to change or deletion without notice.</b> |
67 */ |
67 */ |
68 public class Annotations { |
68 public class Annotations { |
69 |
69 |
70 private static final List<Attribute.Compound> NOT_STARTED = List.of(null); |
70 private static final List<Attribute.Compound> DECL_NOT_STARTED = List.of(null); |
71 private static final List<Attribute.Compound> IN_PROGRESS = List.of(null); |
71 private static final List<Attribute.Compound> DECL_IN_PROGRESS = List.of(null); |
|
72 |
72 /* |
73 /* |
73 * This field should never be null |
74 * This field should never be null |
74 */ |
75 */ |
75 private List<Attribute.Compound> attributes = NOT_STARTED; |
76 private List<Attribute.Compound> attributes = DECL_NOT_STARTED; |
|
77 |
76 /* |
78 /* |
77 * The Symbol this Annotations belong to |
79 * This field should never be null |
|
80 */ |
|
81 private List<Attribute.TypeCompound> type_attributes = List.<Attribute.TypeCompound>nil(); |
|
82 |
|
83 /* |
|
84 * The Symbol this Annotations instance belongs to |
78 */ |
85 */ |
79 private final Symbol sym; |
86 private final Symbol sym; |
80 |
87 |
81 public Annotations(Symbol sym) { |
88 public Annotations(Symbol sym) { |
82 this.sym = sym; |
89 this.sym = sym; |
83 } |
90 } |
84 |
91 |
85 public List<Attribute.Compound> getAttributes() { |
92 public List<Attribute.Compound> getDeclarationAttributes() { |
86 return filterSentinels(attributes); |
93 return filterDeclSentinels(attributes); |
87 } |
94 } |
88 |
95 |
89 public void setAttributes(List<Attribute.Compound> a) { |
96 public List<Attribute.TypeCompound> getTypeAttributes() { |
|
97 return type_attributes; |
|
98 } |
|
99 |
|
100 public void setDeclarationAttributes(List<Attribute.Compound> a) { |
90 Assert.check(pendingCompletion() || !isStarted()); |
101 Assert.check(pendingCompletion() || !isStarted()); |
91 if (a == null) { |
102 if (a == null) { |
92 throw new NullPointerException(); |
103 throw new NullPointerException(); |
93 } |
104 } |
94 attributes = a; |
105 attributes = a; |
95 } |
106 } |
96 |
107 |
|
108 public void setTypeAttributes(List<Attribute.TypeCompound> a) { |
|
109 if (a == null) { |
|
110 throw new NullPointerException(); |
|
111 } |
|
112 type_attributes = a; |
|
113 } |
|
114 |
97 public void setAttributes(Annotations other) { |
115 public void setAttributes(Annotations other) { |
98 if (other == null) { |
116 if (other == null) { |
99 throw new NullPointerException(); |
117 throw new NullPointerException(); |
100 } |
118 } |
101 setAttributes(other.getAttributes()); |
119 setDeclarationAttributes(other.getDeclarationAttributes()); |
102 } |
120 setTypeAttributes(other.getTypeAttributes()); |
103 |
121 } |
104 public void setAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) { |
122 |
|
123 public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.Compound> ctx) { |
105 Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK)); |
124 Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK)); |
106 |
125 this.setDeclarationAttributes(getAttributesForCompletion(ctx)); |
107 Map<Symbol.TypeSymbol, ListBuffer<Attribute.Compound>> annotated = ctx.annotated; |
126 } |
|
127 |
|
128 public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.TypeCompound> ctx) { |
|
129 this.appendUniqueTypes(getAttributesForCompletion(ctx)); |
|
130 } |
|
131 |
|
132 private <T extends Attribute.Compound> List<T> getAttributesForCompletion( |
|
133 final Annotate.AnnotateRepeatedContext<T> ctx) { |
|
134 |
|
135 Map<Symbol.TypeSymbol, ListBuffer<T>> annotated = ctx.annotated; |
108 boolean atLeastOneRepeated = false; |
136 boolean atLeastOneRepeated = false; |
109 List<Attribute.Compound> buf = List.<Attribute.Compound>nil(); |
137 List<T> buf = List.<T>nil(); |
110 for (ListBuffer<Attribute.Compound> lb : annotated.values()) { |
138 for (ListBuffer<T> lb : annotated.values()) { |
111 if (lb.size() == 1) { |
139 if (lb.size() == 1) { |
112 buf = buf.prepend(lb.first()); |
140 buf = buf.prepend(lb.first()); |
113 } else { // repeated |
141 } else { // repeated |
114 buf = buf.prepend(new Placeholder(lb.toList(), sym)); |
142 // This will break when other subtypes of Attributs.Compound |
|
143 // are introduced, because PlaceHolder is a subtype of TypeCompound. |
|
144 T res; |
|
145 @SuppressWarnings("unchecked") |
|
146 T ph = (T) new Placeholder<T>(ctx, lb.toList(), sym); |
|
147 res = ph; |
|
148 buf = buf.prepend(res); |
115 atLeastOneRepeated = true; |
149 atLeastOneRepeated = true; |
116 } |
150 } |
117 } |
151 } |
118 |
|
119 // Add non-repeating attributes |
|
120 setAttributes(buf.reverse()); |
|
121 |
152 |
122 if (atLeastOneRepeated) { |
153 if (atLeastOneRepeated) { |
123 // The Symbol s is now annotated with a combination of |
154 // The Symbol s is now annotated with a combination of |
124 // finished non-repeating annotations and placeholders for |
155 // finished non-repeating annotations and placeholders for |
125 // repeating annotations. |
156 // repeating annotations. |
126 // |
157 // |
127 // We need to do this in two passes because when creating |
158 // We need to do this in two passes because when creating |
128 // a container for a repeating annotation we must |
159 // a container for a repeating annotation we must |
129 // guarantee that the @ContainedBy on the |
160 // guarantee that the @Repeatable on the |
130 // contained annotation is fully annotated |
161 // contained annotation is fully annotated |
131 // |
162 // |
132 // The way we force this order is to do all repeating |
163 // The way we force this order is to do all repeating |
133 // annotations in a pass after all non-repeating are |
164 // annotations in a pass after all non-repeating are |
134 // finished. This will work because @ContainedBy |
165 // finished. This will work because @Repeatable |
135 // is non-repeating and therefore will be annotated in the |
166 // is non-repeating and therefore will be annotated in the |
136 // fist pass. |
167 // fist pass. |
137 |
168 |
138 // Queue a pass that will replace Attribute.Placeholders |
169 // Queue a pass that will replace Attribute.Placeholders |
139 // with Attribute.Compound (made from synthesized containers). |
170 // with Attribute.Compound (made from synthesized containers). |
140 ctx.annotateRepeated(new Annotate.Annotator() { |
171 ctx.annotateRepeated(new Annotate.Annotator() { |
141 |
|
142 @Override |
172 @Override |
143 public String toString() { |
173 public String toString() { |
144 return "repeated annotation pass of: " + sym + " in: " + sym.owner; |
174 return "repeated annotation pass of: " + sym + " in: " + sym.owner; |
145 } |
175 } |
146 |
176 |
191 attributes = attributes.prependList(l); |
243 attributes = attributes.prependList(l); |
192 } |
244 } |
193 return this; |
245 return this; |
194 } |
246 } |
195 |
247 |
196 private List<Attribute.Compound> filterSentinels(List<Attribute.Compound> a) { |
248 private List<Attribute.Compound> filterDeclSentinels(List<Attribute.Compound> a) { |
197 return (a == IN_PROGRESS || a == NOT_STARTED) |
249 return (a == DECL_IN_PROGRESS || a == DECL_NOT_STARTED) |
198 ? List.<Attribute.Compound>nil() |
250 ? List.<Attribute.Compound>nil() |
199 : a; |
251 : a; |
200 } |
252 } |
201 |
253 |
202 private boolean isStarted() { |
254 private boolean isStarted() { |
203 return attributes != NOT_STARTED; |
255 return attributes != DECL_NOT_STARTED; |
204 } |
256 } |
205 |
257 |
206 private List<Attribute.Compound> getPlaceholders() { |
258 private List<Attribute.Compound> getPlaceholders() { |
207 List<Attribute.Compound> res = List.<Attribute.Compound>nil(); |
259 List<Attribute.Compound> res = List.<Attribute.Compound>nil(); |
208 for (Attribute.Compound a : filterSentinels(attributes)) { |
260 for (Attribute.Compound a : filterDeclSentinels(attributes)) { |
|
261 if (a instanceof Placeholder) { |
|
262 res = res.prepend(a); |
|
263 } |
|
264 } |
|
265 return res.reverse(); |
|
266 } |
|
267 |
|
268 private List<Attribute.TypeCompound> getTypePlaceholders() { |
|
269 List<Attribute.TypeCompound> res = List.<Attribute.TypeCompound>nil(); |
|
270 for (Attribute.TypeCompound a : type_attributes) { |
209 if (a instanceof Placeholder) { |
271 if (a instanceof Placeholder) { |
210 res = res.prepend(a); |
272 res = res.prepend(a); |
211 } |
273 } |
212 } |
274 } |
213 return res.reverse(); |
275 return res.reverse(); |
214 } |
276 } |
215 |
277 |
216 /* |
278 /* |
217 * Replace Placeholders for repeating annotations with their containers |
279 * Replace Placeholders for repeating annotations with their containers |
218 */ |
280 */ |
219 private void complete(Annotate.AnnotateRepeatedContext ctx) { |
281 private <T extends Attribute.Compound> void complete(Annotate.AnnotateRepeatedContext<T> ctx) { |
220 Assert.check(!pendingCompletion()); |
|
221 Log log = ctx.log; |
282 Log log = ctx.log; |
222 Env<AttrContext> env = ctx.env; |
283 Env<AttrContext> env = ctx.env; |
223 JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); |
284 JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); |
224 try { |
285 try { |
225 |
286 // TODO: can we reduce duplication in the following branches? |
226 if (isEmpty()) { |
287 if (ctx.isTypeCompound) { |
227 return; |
288 Assert.check(!isTypesEmpty()); |
228 } |
289 |
229 |
290 if (isTypesEmpty()) { |
230 List<Attribute.Compound> result = List.nil(); |
291 return; |
231 for (Attribute.Compound a : getAttributes()) { |
292 } |
232 if (a instanceof Placeholder) { |
293 |
233 Attribute.Compound replacement = replaceOne((Placeholder) a, ctx); |
294 List<Attribute.TypeCompound> result = List.nil(); |
234 |
295 for (Attribute.TypeCompound a : getTypeAttributes()) { |
235 if (null != replacement) { |
296 if (a instanceof Placeholder) { |
236 result = result.prepend(replacement); |
297 @SuppressWarnings("unchecked") |
|
298 Placeholder<Attribute.TypeCompound> ph = (Placeholder<Attribute.TypeCompound>) a; |
|
299 Attribute.TypeCompound replacement = replaceOne(ph, ph.getRepeatedContext()); |
|
300 |
|
301 if (null != replacement) { |
|
302 result = result.prepend(replacement); |
|
303 } |
|
304 } else { |
|
305 result = result.prepend(a); |
237 } |
306 } |
238 } else { |
307 } |
239 result = result.prepend(a); |
308 |
240 } |
309 type_attributes = result.reverse(); |
241 } |
310 |
242 |
311 Assert.check(Annotations.this.getTypePlaceholders().isEmpty()); |
243 attributes = result.reverse(); |
312 } else { |
244 |
313 Assert.check(!pendingCompletion()); |
245 Assert.check(Annotations.this.getPlaceholders().isEmpty()); |
314 |
|
315 if (isEmpty()) { |
|
316 return; |
|
317 } |
|
318 |
|
319 List<Attribute.Compound> result = List.nil(); |
|
320 for (Attribute.Compound a : getDeclarationAttributes()) { |
|
321 if (a instanceof Placeholder) { |
|
322 @SuppressWarnings("unchecked") |
|
323 Attribute.Compound replacement = replaceOne((Placeholder<T>) a, ctx); |
|
324 |
|
325 if (null != replacement) { |
|
326 result = result.prepend(replacement); |
|
327 } |
|
328 } else { |
|
329 result = result.prepend(a); |
|
330 } |
|
331 } |
|
332 |
|
333 attributes = result.reverse(); |
|
334 |
|
335 Assert.check(Annotations.this.getPlaceholders().isEmpty()); |
|
336 } |
246 } finally { |
337 } finally { |
247 log.useSource(oldSource); |
338 log.useSource(oldSource); |
248 } |
339 } |
249 } |
340 } |
250 |
341 |
251 private Attribute.Compound replaceOne(Placeholder placeholder, Annotate.AnnotateRepeatedContext ctx) { |
342 private <T extends Attribute.Compound> T replaceOne(Placeholder<T> placeholder, Annotate.AnnotateRepeatedContext<T> ctx) { |
252 Log log = ctx.log; |
343 Log log = ctx.log; |
253 |
344 |
254 // Process repeated annotations |
345 // Process repeated annotations |
255 Attribute.Compound validRepeated = |
346 T validRepeated = ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym); |
256 ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym); |
|
257 |
347 |
258 if (validRepeated != null) { |
348 if (validRepeated != null) { |
259 // Check that the container isn't manually |
349 // Check that the container isn't manually |
260 // present along with repeated instances of |
350 // present along with repeated instances of |
261 // its contained annotation. |
351 // its contained annotation. |
262 ListBuffer<Attribute.Compound> manualContainer = ctx.annotated.get(validRepeated.type.tsym); |
352 ListBuffer<T> manualContainer = ctx.annotated.get(validRepeated.type.tsym); |
263 if (manualContainer != null) { |
353 if (manualContainer != null) { |
264 log.error(ctx.pos.get(manualContainer.first()), "invalid.containedby.annotation.repeated.and.container.present", |
354 log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present", |
265 manualContainer.first().type.tsym); |
355 manualContainer.first().type.tsym); |
266 } |
356 } |
267 } |
357 } |
268 |
358 |
269 // A null return will delete the Placeholder |
359 // A null return will delete the Placeholder |
270 return validRepeated; |
360 return validRepeated; |
271 |
361 } |
272 } |
362 |
273 |
363 private static class Placeholder<T extends Attribute.Compound> extends Attribute.TypeCompound { |
274 private static class Placeholder extends Attribute.Compound { |
364 |
275 |
365 private final Annotate.AnnotateRepeatedContext<T> ctx; |
276 private List<Attribute.Compound> placeholderFor; |
366 private final List<T> placeholderFor; |
277 private Symbol on; |
367 private final Symbol on; |
278 |
368 |
279 public Placeholder(List<Attribute.Compound> placeholderFor, Symbol on) { |
369 public Placeholder(Annotate.AnnotateRepeatedContext<T> ctx, List<T> placeholderFor, Symbol on) { |
280 super(Type.noType, List.<Pair<Symbol.MethodSymbol, Attribute>>nil()); |
370 super(on.type, List.<Pair<Symbol.MethodSymbol, Attribute>>nil(), |
|
371 ctx.isTypeCompound ? |
|
372 ((Attribute.TypeCompound)placeholderFor.head).position : |
|
373 null); |
|
374 this.ctx = ctx; |
281 this.placeholderFor = placeholderFor; |
375 this.placeholderFor = placeholderFor; |
282 this.on = on; |
376 this.on = on; |
283 } |
377 } |
284 |
378 |
285 @Override |
379 @Override |
286 public String toString() { |
380 public String toString() { |
287 return "<placeholder: " + placeholderFor + " on: " + on + ">"; |
381 return "<placeholder: " + placeholderFor + " on: " + on + ">"; |
288 } |
382 } |
289 |
383 |
290 public List<Attribute.Compound> getPlaceholderFor() { |
384 public List<T> getPlaceholderFor() { |
291 return placeholderFor; |
385 return placeholderFor; |
292 } |
386 } |
|
387 |
|
388 public Annotate.AnnotateRepeatedContext<T> getRepeatedContext() { |
|
389 return ctx; |
|
390 } |
293 } |
391 } |
294 } |
392 } |