1 /*
2  * Copyright (c) 2003, 2013, 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.comp;
27 
28 import java.util.Map;
29 
30 import com.sun.tools.javac.util.*;
31 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
32 import com.sun.tools.javac.code.*;
33 import com.sun.tools.javac.code.Symbol.*;
34 import com.sun.tools.javac.tree.*;
35 import com.sun.tools.javac.tree.JCTree.*;
36 
37 import static com.sun.tools.javac.code.TypeTag.ARRAY;
38 import static com.sun.tools.javac.code.TypeTag.CLASS;
39 import static com.sun.tools.javac.tree.JCTree.Tag.*;
40 import javax.lang.model.type.ErrorType;
41 
42 /** Enter annotations on symbols.  Annotations accumulate in a queue,
43  *  which is processed at the top level of any set of recursive calls
44  *  requesting it be processed.
45  *
46  *  <p><b>This is NOT part of any supported API.
47  *  If you write code that depends on this, you do so at your own risk.
48  *  This code and its internal interfaces are subject to change or
49  *  deletion without notice.</b>
50  */
51 public class Annotate {
52     protected static final Context.Key<Annotate> annotateKey =
53         new Context.Key<Annotate>();
54 
instance(Context context)55     public static Annotate instance(Context context) {
56         Annotate instance = context.get(annotateKey);
57         if (instance == null)
58             instance = new Annotate(context);
59         return instance;
60     }
61 
62     final Attr attr;
63     final TreeMaker make;
64     final Log log;
65     final Symtab syms;
66     final Names names;
67     final Resolve rs;
68     final Types types;
69     final ConstFold cfolder;
70     final Check chk;
71 
Annotate(Context context)72     protected Annotate(Context context) {
73         context.put(annotateKey, this);
74         attr = Attr.instance(context);
75         make = TreeMaker.instance(context);
76         log = Log.instance(context);
77         syms = Symtab.instance(context);
78         names = Names.instance(context);
79         rs = Resolve.instance(context);
80         types = Types.instance(context);
81         cfolder = ConstFold.instance(context);
82         chk = Check.instance(context);
83     }
84 
85 /* ********************************************************************
86  * Queue maintenance
87  *********************************************************************/
88 
89     private int enterCount = 0;
90 
91     ListBuffer<Worker> q = new ListBuffer<Worker>();
92     ListBuffer<Worker> typesQ = new ListBuffer<Worker>();
93     ListBuffer<Worker> repeatedQ = new ListBuffer<Worker>();
94     ListBuffer<Worker> afterRepeatedQ = new ListBuffer<Worker>();
95     ListBuffer<Worker> validateQ = new ListBuffer<Worker>();
96 
earlier(Worker a)97     public void earlier(Worker a) {
98         q.prepend(a);
99     }
100 
normal(Worker a)101     public void normal(Worker a) {
102         q.append(a);
103     }
104 
typeAnnotation(Worker a)105     public void typeAnnotation(Worker a) {
106         typesQ.append(a);
107     }
108 
repeated(Worker a)109     public void repeated(Worker a) {
110         repeatedQ.append(a);
111     }
112 
afterRepeated(Worker a)113     public void afterRepeated(Worker a) {
114         afterRepeatedQ.append(a);
115     }
116 
validate(Worker a)117     public void validate(Worker a) {
118         validateQ.append(a);
119     }
120 
121     /** Called when the Enter phase starts. */
enterStart()122     public void enterStart() {
123         enterCount++;
124     }
125 
126     /** Called after the Enter phase completes. */
enterDone()127     public void enterDone() {
128         enterCount--;
129         flush();
130     }
131 
132     /** Variant which allows for a delayed flush of annotations.
133      * Needed by ClassReader */
enterDoneWithoutFlush()134     public void enterDoneWithoutFlush() {
135         enterCount--;
136     }
137 
flush()138     public void flush() {
139         if (enterCount != 0) return;
140         enterCount++;
141         try {
142             while (q.nonEmpty()) {
143                 q.next().run();
144             }
145             while (typesQ.nonEmpty()) {
146                 typesQ.next().run();
147             }
148             while (repeatedQ.nonEmpty()) {
149                 repeatedQ.next().run();
150             }
151             while (afterRepeatedQ.nonEmpty()) {
152                 afterRepeatedQ.next().run();
153             }
154             while (validateQ.nonEmpty()) {
155                 validateQ.next().run();
156             }
157         } finally {
158             enterCount--;
159         }
160     }
161 
162     /** A client that needs to run during {@link #flush()} registers an worker
163      *  into one of the queues defined in this class. The queues are: {@link #earlier(Worker)},
164      *  {@link #normal(Worker)}, {@link #typeAnnotation(Worker)}, {@link #repeated(Worker)},
165      *  {@link #afterRepeated(Worker)}, {@link #validate(Worker)}.
166      *  The {@link Worker#run()} method will called inside the {@link #flush()}
167      *  call. Queues are empties in the abovementioned order.
168      */
169     public interface Worker {
run()170         void run();
toString()171         String toString();
172     }
173 
174     /**
175      * This context contains all the information needed to synthesize new
176      * annotations trees by the completer for repeating annotations.
177      */
178     public class AnnotateRepeatedContext<T extends Attribute.Compound> {
179         public final Env<AttrContext> env;
180         public final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated;
181         public final Map<T, JCDiagnostic.DiagnosticPosition> pos;
182         public final Log log;
183         public final boolean isTypeCompound;
184 
AnnotateRepeatedContext(Env<AttrContext> env, Map<Symbol.TypeSymbol, ListBuffer<T>> annotated, Map<T, JCDiagnostic.DiagnosticPosition> pos, Log log, boolean isTypeCompound)185         public AnnotateRepeatedContext(Env<AttrContext> env,
186                                        Map<Symbol.TypeSymbol, ListBuffer<T>> annotated,
187                                        Map<T, JCDiagnostic.DiagnosticPosition> pos,
188                                        Log log,
189                                        boolean isTypeCompound) {
190             Assert.checkNonNull(env);
191             Assert.checkNonNull(annotated);
192             Assert.checkNonNull(pos);
193             Assert.checkNonNull(log);
194 
195             this.env = env;
196             this.annotated = annotated;
197             this.pos = pos;
198             this.log = log;
199             this.isTypeCompound = isTypeCompound;
200         }
201 
202         /**
203          * Process a list of repeating annotations returning a new
204          * Attribute.Compound that is the attribute for the synthesized tree
205          * for the container.
206          *
207          * @param repeatingAnnotations a List of repeating annotations
208          * @return a new Attribute.Compound that is the container for the repeatingAnnotations
209          */
processRepeatedAnnotations(List<T> repeatingAnnotations, Symbol sym)210         public T processRepeatedAnnotations(List<T> repeatingAnnotations, Symbol sym) {
211             return Annotate.this.processRepeatedAnnotations(repeatingAnnotations, this, sym);
212         }
213 
214         /**
215          * Queue the Worker a on the repeating annotations queue of the
216          * Annotate instance this context belongs to.
217          *
218          * @param a the Worker to enqueue for repeating annotation annotating
219          */
annotateRepeated(Worker a)220         public void annotateRepeated(Worker a) {
221             Annotate.this.repeated(a);
222         }
223     }
224 
225 /* ********************************************************************
226  * Compute an attribute from its annotation.
227  *********************************************************************/
228 
229     /** Process a single compound annotation, returning its
230      *  Attribute. Used from MemberEnter for attaching the attributes
231      *  to the annotated symbol.
232      */
enterAnnotation(JCAnnotation a, Type expected, Env<AttrContext> env)233     Attribute.Compound enterAnnotation(JCAnnotation a,
234                                        Type expected,
235                                        Env<AttrContext> env) {
236         return enterAnnotation(a, expected, env, false);
237     }
238 
enterTypeAnnotation(JCAnnotation a, Type expected, Env<AttrContext> env)239     Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a,
240             Type expected,
241             Env<AttrContext> env) {
242         return (Attribute.TypeCompound) enterAnnotation(a, expected, env, true);
243     }
244 
245     // boolean typeAnnotation determines whether the method returns
246     // a Compound (false) or TypeCompound (true).
enterAnnotation(JCAnnotation a, Type expected, Env<AttrContext> env, boolean typeAnnotation)247     Attribute.Compound enterAnnotation(JCAnnotation a,
248             Type expected,
249             Env<AttrContext> env,
250             boolean typeAnnotation) {
251         // The annotation might have had its type attributed (but not checked)
252         // by attr.attribAnnotationTypes during MemberEnter, in which case we do not
253         // need to do it again.
254         Type at = (a.annotationType.type != null ? a.annotationType.type
255                   : attr.attribType(a.annotationType, env));
256         a.type = chk.checkType(a.annotationType.pos(), at, expected);
257         if (a.type.isErroneous()) {
258             // Need to make sure nested (anno)trees does not have null as .type
259             attr.postAttr(a);
260 
261             if (typeAnnotation) {
262                 return new Attribute.TypeCompound(a.type, List.<Pair<MethodSymbol,Attribute>>nil(),
263                         new TypeAnnotationPosition());
264             } else {
265                 return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil());
266             }
267         }
268         if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0) {
269             log.error(a.annotationType.pos(),
270                       "not.annotation.type", a.type.toString());
271 
272             // Need to make sure nested (anno)trees does not have null as .type
273             attr.postAttr(a);
274 
275             if (typeAnnotation) {
276                 return new Attribute.TypeCompound(a.type, List.<Pair<MethodSymbol,Attribute>>nil(), null);
277             } else {
278                 return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil());
279             }
280         }
281         List<JCExpression> args = a.args;
282         if (args.length() == 1 && !args.head.hasTag(ASSIGN)) {
283             // special case: elided "value=" assumed
284             args.head = make.at(args.head.pos).
285                 Assign(make.Ident(names.value), args.head);
286         }
287         ListBuffer<Pair<MethodSymbol,Attribute>> buf =
288             new ListBuffer<>();
289         for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
290             JCExpression t = tl.head;
291             if (!t.hasTag(ASSIGN)) {
292                 log.error(t.pos(), "annotation.value.must.be.name.value");
293                 continue;
294             }
295             JCAssign assign = (JCAssign)t;
296             if (!assign.lhs.hasTag(IDENT)) {
297                 log.error(t.pos(), "annotation.value.must.be.name.value");
298                 continue;
299             }
300             JCIdent left = (JCIdent)assign.lhs;
301             Symbol method = rs.resolveQualifiedMethod(assign.rhs.pos(),
302                                                           env,
303                                                           a.type,
304                                                           left.name,
305                                                           List.<Type>nil(),
306                                                           null);
307             left.sym = method;
308             left.type = method.type;
309             if (method.owner != a.type.tsym)
310                 log.error(left.pos(), "no.annotation.member", left.name, a.type);
311             Type result = method.type.getReturnType();
312             Attribute value = enterAttributeValue(result, assign.rhs, env);
313             if (!method.type.isErroneous())
314                 buf.append(new Pair<>((MethodSymbol)method, value));
315             t.type = result;
316         }
317         if (typeAnnotation) {
318             if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) {
319                 // Create a new TypeCompound
320                 Attribute.TypeCompound tc = new Attribute.TypeCompound(a.type, buf.toList(), new TypeAnnotationPosition());
321                 a.attribute = tc;
322                 return tc;
323             } else {
324                 // Use an existing TypeCompound
325                 return a.attribute;
326             }
327         } else {
328             Attribute.Compound ac = new Attribute.Compound(a.type, buf.toList());
329             a.attribute = ac;
330             return ac;
331         }
332     }
333 
enterAttributeValue(Type expected, JCExpression tree, Env<AttrContext> env)334     Attribute enterAttributeValue(Type expected,
335                                   JCExpression tree,
336                                   Env<AttrContext> env) {
337         //first, try completing the attribution value sym - if a completion
338         //error is thrown, we should recover gracefully, and display an
339         //ordinary resolution diagnostic.
340         try {
341             expected.tsym.complete();
342         } catch(CompletionFailure e) {
343             log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
344             expected = syms.errType;
345         }
346         if (expected.hasTag(ARRAY)) {
347             if (!tree.hasTag(NEWARRAY)) {
348                 tree = make.at(tree.pos).
349                     NewArray(null, List.<JCExpression>nil(), List.of(tree));
350             }
351             JCNewArray na = (JCNewArray)tree;
352             if (na.elemtype != null) {
353                 log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
354             }
355             ListBuffer<Attribute> buf = new ListBuffer<Attribute>();
356             for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
357                 buf.append(enterAttributeValue(types.elemtype(expected),
358                                                l.head,
359                                                env));
360             }
361             na.type = expected;
362             return new Attribute.
363                 Array(expected, buf.toArray(new Attribute[buf.length()]));
364         }
365         if (tree.hasTag(NEWARRAY)) { //error recovery
366             if (!expected.isErroneous())
367                 log.error(tree.pos(), "annotation.value.not.allowable.type");
368             JCNewArray na = (JCNewArray)tree;
369             if (na.elemtype != null) {
370                 log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
371             }
372             for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
373                 enterAttributeValue(syms.errType,
374                                     l.head,
375                                     env);
376             }
377             return new Attribute.Error(syms.errType);
378         }
379         if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
380             if (tree.hasTag(ANNOTATION)) {
381                 return enterAnnotation((JCAnnotation)tree, expected, env);
382             } else {
383                 log.error(tree.pos(), "annotation.value.must.be.annotation");
384                 expected = syms.errType;
385             }
386         }
387         if (tree.hasTag(ANNOTATION)) { //error recovery
388             if (!expected.isErroneous())
389                 log.error(tree.pos(), "annotation.not.valid.for.type", expected);
390             enterAnnotation((JCAnnotation)tree, syms.errType, env);
391             return new Attribute.Error(((JCAnnotation)tree).annotationType.type);
392         }
393         if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) {
394             Type result = attr.attribExpr(tree, env, expected);
395             if (result.isErroneous())
396                 return new Attribute.Error(result.getOriginalType());
397             if (result.constValue() == null) {
398                 log.error(tree.pos(), "attribute.value.must.be.constant");
399                 return new Attribute.Error(expected);
400             }
401             result = cfolder.coerce(result, expected);
402             return new Attribute.Constant(expected, result.constValue());
403         }
404         if (expected.tsym == syms.classType.tsym) {
405             Type result = attr.attribExpr(tree, env, expected);
406             if (result.isErroneous()) {
407                 // Does it look like an unresolved class literal?
408                 if (TreeInfo.name(tree) == names._class &&
409                     ((JCFieldAccess) tree).selected.type.isErroneous()) {
410                     Name n = (((JCFieldAccess) tree).selected).type.tsym.flatName();
411                     return new Attribute.UnresolvedClass(expected,
412                             types.createErrorType(n,
413                                     syms.unknownSymbol, syms.classType));
414                 } else {
415                     return new Attribute.Error(result.getOriginalType());
416                 }
417             }
418 
419             // Class literals look like field accesses of a field named class
420             // at the tree level
421             if (TreeInfo.name(tree) != names._class) {
422                 log.error(tree.pos(), "annotation.value.must.be.class.literal");
423                 return new Attribute.Error(syms.errType);
424             }
425             return new Attribute.Class(types,
426                                        (((JCFieldAccess) tree).selected).type);
427         }
428         if (expected.hasTag(CLASS) &&
429             (expected.tsym.flags() & Flags.ENUM) != 0) {
430             Type result = attr.attribExpr(tree, env, expected);
431             Symbol sym = TreeInfo.symbol(tree);
432             if (sym == null ||
433                 TreeInfo.nonstaticSelect(tree) ||
434                 sym.kind != Kinds.VAR ||
435                 (sym.flags() & Flags.ENUM) == 0) {
436                 log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
437                 return new Attribute.Error(result.getOriginalType());
438             }
439             VarSymbol enumerator = (VarSymbol) sym;
440             return new Attribute.Enum(expected, enumerator);
441         }
442         //error recovery:
443         if (!expected.isErroneous())
444             log.error(tree.pos(), "annotation.value.not.allowable.type");
445         return new Attribute.Error(attr.attribExpr(tree, env, expected));
446     }
447 
448     /* *********************************
449      * Support for repeating annotations
450      ***********************************/
451 
452     /* Process repeated annotations. This method returns the
453      * synthesized container annotation or null IFF all repeating
454      * annotation are invalid.  This method reports errors/warnings.
455      */
processRepeatedAnnotations(List<T> annotations, AnnotateRepeatedContext<T> ctx, Symbol on)456     private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations,
457             AnnotateRepeatedContext<T> ctx,
458             Symbol on) {
459         T firstOccurrence = annotations.head;
460         List<Attribute> repeated = List.nil();
461         Type origAnnoType = null;
462         Type arrayOfOrigAnnoType = null;
463         Type targetContainerType = null;
464         MethodSymbol containerValueSymbol = null;
465 
466         Assert.check(!annotations.isEmpty() &&
467                      !annotations.tail.isEmpty()); // i.e. size() > 1
468 
469         int count = 0;
470         for (List<T> al = annotations;
471              !al.isEmpty();
472              al = al.tail)
473         {
474             count++;
475 
476             // There must be more than a single anno in the annotation list
477             Assert.check(count > 1 || !al.tail.isEmpty());
478 
479             T currentAnno = al.head;
480 
481             origAnnoType = currentAnno.type;
482             if (arrayOfOrigAnnoType == null) {
483                 arrayOfOrigAnnoType = types.makeArrayType(origAnnoType);
484             }
485 
486             // Only report errors if this isn't the first occurrence I.E. count > 1
487             boolean reportError = count > 1;
488             Type currentContainerType = getContainingType(currentAnno, ctx.pos.get(currentAnno), reportError);
489             if (currentContainerType == null) {
490                 continue;
491             }
492             // Assert that the target Container is == for all repeated
493             // annos of the same annotation type, the types should
494             // come from the same Symbol, i.e. be '=='
495             Assert.check(targetContainerType == null || currentContainerType == targetContainerType);
496             targetContainerType = currentContainerType;
497 
498             containerValueSymbol = validateContainer(targetContainerType, origAnnoType, ctx.pos.get(currentAnno));
499 
500             if (containerValueSymbol == null) { // Check of CA type failed
501                 // errors are already reported
502                 continue;
503             }
504 
505             repeated = repeated.prepend(currentAnno);
506         }
507 
508         if (!repeated.isEmpty()) {
509             repeated = repeated.reverse();
510             TreeMaker m = make.at(ctx.pos.get(firstOccurrence));
511             Pair<MethodSymbol, Attribute> p =
512                     new Pair<MethodSymbol, Attribute>(containerValueSymbol,
513                                                       new Attribute.Array(arrayOfOrigAnnoType, repeated));
514             if (ctx.isTypeCompound) {
515                 /* TODO: the following code would be cleaner:
516                 Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
517                         ((Attribute.TypeCompound)annotations.head).position);
518                 JCTypeAnnotation annoTree = m.TypeAnnotation(at);
519                 at = enterTypeAnnotation(annoTree, targetContainerType, ctx.env);
520                 */
521                 // However, we directly construct the TypeCompound to keep the
522                 // direct relation to the contained TypeCompounds.
523                 Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
524                         ((Attribute.TypeCompound)annotations.head).position);
525 
526                 // TODO: annotation applicability checks from below?
527 
528                 at.setSynthesized(true);
529 
530                 @SuppressWarnings("unchecked")
531                 T x = (T) at;
532                 return x;
533             } else {
534                 Attribute.Compound c = new Attribute.Compound(targetContainerType, List.of(p));
535                 JCAnnotation annoTree = m.Annotation(c);
536 
537                 if (!chk.annotationApplicable(annoTree, on))
538                     log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType);
539 
540                 if (!chk.validateAnnotationDeferErrors(annoTree))
541                     log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType);
542 
543                 c = enterAnnotation(annoTree, targetContainerType, ctx.env);
544                 c.setSynthesized(true);
545 
546                 @SuppressWarnings("unchecked")
547                 T x = (T) c;
548                 return x;
549             }
550         } else {
551             return null; // errors should have been reported elsewhere
552         }
553     }
554 
555     /** Fetches the actual Type that should be the containing annotation. */
getContainingType(Attribute.Compound currentAnno, DiagnosticPosition pos, boolean reportError)556     private Type getContainingType(Attribute.Compound currentAnno,
557             DiagnosticPosition pos,
558             boolean reportError)
559     {
560         Type origAnnoType = currentAnno.type;
561         TypeSymbol origAnnoDecl = origAnnoType.tsym;
562 
563         // Fetch the Repeatable annotation from the current
564         // annotation's declaration, or null if it has none
565         Attribute.Compound ca = origAnnoDecl.attribute(syms.repeatableType.tsym);
566         if (ca == null) { // has no Repeatable annotation
567             if (reportError)
568                 log.error(pos, "duplicate.annotation.missing.container", origAnnoType, syms.repeatableType);
569             return null;
570         }
571 
572         return filterSame(extractContainingType(ca, pos, origAnnoDecl),
573                           origAnnoType);
574     }
575 
576     // returns null if t is same as 's', returns 't' otherwise
filterSame(Type t, Type s)577     private Type filterSame(Type t, Type s) {
578         if (t == null || s == null) {
579             return t;
580         }
581 
582         return types.isSameType(t, s) ? null : t;
583     }
584 
585     /** Extract the actual Type to be used for a containing annotation. */
extractContainingType(Attribute.Compound ca, DiagnosticPosition pos, TypeSymbol annoDecl)586     private Type extractContainingType(Attribute.Compound ca,
587             DiagnosticPosition pos,
588             TypeSymbol annoDecl)
589     {
590         // The next three checks check that the Repeatable annotation
591         // on the declaration of the annotation type that is repeating is
592         // valid.
593 
594         // Repeatable must have at least one element
595         if (ca.values.isEmpty()) {
596             log.error(pos, "invalid.repeatable.annotation", annoDecl);
597             return null;
598         }
599         Pair<MethodSymbol,Attribute> p = ca.values.head;
600         Name name = p.fst.name;
601         if (name != names.value) { // should contain only one element, named "value"
602             log.error(pos, "invalid.repeatable.annotation", annoDecl);
603             return null;
604         }
605         if (!(p.snd instanceof Attribute.Class)) { // check that the value of "value" is an Attribute.Class
606             log.error(pos, "invalid.repeatable.annotation", annoDecl);
607             return null;
608         }
609 
610         return ((Attribute.Class)p.snd).getValue();
611     }
612 
613     /* Validate that the suggested targetContainerType Type is a valid
614      * container type for repeated instances of originalAnnoType
615      * annotations. Return null and report errors if this is not the
616      * case, return the MethodSymbol of the value element in
617      * targetContainerType if it is suitable (this is needed to
618      * synthesize the container). */
validateContainer(Type targetContainerType, Type originalAnnoType, DiagnosticPosition pos)619     private MethodSymbol validateContainer(Type targetContainerType,
620                                            Type originalAnnoType,
621                                            DiagnosticPosition pos) {
622         MethodSymbol containerValueSymbol = null;
623         boolean fatalError = false;
624 
625         // Validate that there is a (and only 1) value method
626         Scope scope = targetContainerType.tsym.members();
627         int nr_value_elems = 0;
628         boolean error = false;
629         for(Symbol elm : scope.getElementsByName(names.value)) {
630             nr_value_elems++;
631 
632             if (nr_value_elems == 1 &&
633                 elm.kind == Kinds.MTH) {
634                 containerValueSymbol = (MethodSymbol)elm;
635             } else {
636                 error = true;
637             }
638         }
639         if (error) {
640             log.error(pos,
641                       "invalid.repeatable.annotation.multiple.values",
642                       targetContainerType,
643                       nr_value_elems);
644             return null;
645         } else if (nr_value_elems == 0) {
646             log.error(pos,
647                       "invalid.repeatable.annotation.no.value",
648                       targetContainerType);
649             return null;
650         }
651 
652         // validate that the 'value' element is a method
653         // probably "impossible" to fail this
654         if (containerValueSymbol.kind != Kinds.MTH) {
655             log.error(pos,
656                       "invalid.repeatable.annotation.invalid.value",
657                       targetContainerType);
658             fatalError = true;
659         }
660 
661         // validate that the 'value' element has the correct return type
662         // i.e. array of original anno
663         Type valueRetType = containerValueSymbol.type.getReturnType();
664         Type expectedType = types.makeArrayType(originalAnnoType);
665         if (!(types.isArray(valueRetType) &&
666               types.isSameType(expectedType, valueRetType))) {
667             log.error(pos,
668                       "invalid.repeatable.annotation.value.return",
669                       targetContainerType,
670                       valueRetType,
671                       expectedType);
672             fatalError = true;
673         }
674         if (error) {
675             fatalError = true;
676         }
677 
678         // The conditions for a valid containing annotation are made
679         // in Check.validateRepeatedAnnotaton();
680 
681         return fatalError ? null : containerValueSymbol;
682     }
683 }
684