Annotate.java revision 2628:8df25ec8c930
1/*
2 * Copyright (c) 2003, 2014, 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
26package com.sun.tools.javac.comp;
27
28import java.util.HashMap;
29import java.util.LinkedHashMap;
30import java.util.Map;
31
32import javax.tools.JavaFileObject;
33
34import com.sun.tools.javac.util.*;
35import com.sun.tools.javac.util.DefinedBy.Api;
36import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
37import com.sun.tools.javac.code.*;
38import com.sun.tools.javac.code.Symbol.*;
39import com.sun.tools.javac.tree.*;
40import com.sun.tools.javac.tree.JCTree.*;
41
42import static com.sun.tools.javac.code.Kinds.*;
43import static com.sun.tools.javac.code.TypeTag.ARRAY;
44import static com.sun.tools.javac.code.TypeTag.CLASS;
45import static com.sun.tools.javac.tree.JCTree.Tag.*;
46
47/** Enter annotations on symbols.  Annotations accumulate in a queue,
48 *  which is processed at the top level of any set of recursive calls
49 *  requesting it be processed.
50 *
51 *  <p><b>This is NOT part of any supported API.
52 *  If you write code that depends on this, you do so at your own risk.
53 *  This code and its internal interfaces are subject to change or
54 *  deletion without notice.</b>
55 */
56public class Annotate {
57    protected static final Context.Key<Annotate> annotateKey = new Context.Key<>();
58
59    public static Annotate instance(Context context) {
60        Annotate instance = context.get(annotateKey);
61        if (instance == null)
62            instance = new Annotate(context);
63        return instance;
64    }
65
66    private final Attr attr;
67    private final TreeMaker make;
68    private final Log log;
69    private final Symtab syms;
70    private final Names names;
71    private final Resolve rs;
72    private final Types types;
73    private final ConstFold cfolder;
74    private final Check chk;
75    private final Lint lint;
76    private final DeferredLintHandler deferredLintHandler;
77    private final Source source;
78
79    private boolean allowTypeAnnos;
80    private boolean allowRepeatedAnnos;
81
82    protected Annotate(Context context) {
83        context.put(annotateKey, this);
84        attr = Attr.instance(context);
85        make = TreeMaker.instance(context);
86        log = Log.instance(context);
87        syms = Symtab.instance(context);
88        names = Names.instance(context);
89        rs = Resolve.instance(context);
90        types = Types.instance(context);
91        cfolder = ConstFold.instance(context);
92        chk = Check.instance(context);
93        source = Source.instance(context);
94        lint = Lint.instance(context);
95        deferredLintHandler = DeferredLintHandler.instance(context);
96        allowRepeatedAnnos = source.allowRepeatedAnnotations();
97        allowTypeAnnos = source.allowTypeAnnotations();
98    }
99
100/* ********************************************************************
101 * Queue maintenance
102 *********************************************************************/
103
104    private int enterCount = 0;
105
106    ListBuffer<Worker> q = new ListBuffer<>();
107    ListBuffer<Worker> typesQ = new ListBuffer<>();
108    ListBuffer<Worker> repeatedQ = new ListBuffer<>();
109    ListBuffer<Worker> afterRepeatedQ = new ListBuffer<>();
110    ListBuffer<Worker> validateQ = new ListBuffer<>();
111
112    public void earlier(Worker a) {
113        q.prepend(a);
114    }
115
116    public void normal(Worker a) {
117        q.append(a);
118    }
119
120    public void typeAnnotation(Worker a) {
121        typesQ.append(a);
122    }
123
124    public void repeated(Worker a) {
125        repeatedQ.append(a);
126    }
127
128    public void afterRepeated(Worker a) {
129        afterRepeatedQ.append(a);
130    }
131
132    public void validate(Worker a) {
133        validateQ.append(a);
134    }
135
136    /** Called when the Enter phase starts. */
137    public void enterStart() {
138        enterCount++;
139    }
140
141    /** Called after the Enter phase completes. */
142    public void enterDone() {
143        enterCount--;
144        flush();
145    }
146
147    /** Variant which allows for a delayed flush of annotations.
148     * Needed by ClassReader */
149    public void enterDoneWithoutFlush() {
150        enterCount--;
151    }
152
153    public void flush() {
154        if (enterCount != 0) return;
155        enterCount++;
156        try {
157            while (q.nonEmpty()) {
158                q.next().run();
159            }
160            while (typesQ.nonEmpty()) {
161                typesQ.next().run();
162            }
163            while (repeatedQ.nonEmpty()) {
164                repeatedQ.next().run();
165            }
166            while (afterRepeatedQ.nonEmpty()) {
167                afterRepeatedQ.next().run();
168            }
169            while (validateQ.nonEmpty()) {
170                validateQ.next().run();
171            }
172        } finally {
173            enterCount--;
174        }
175    }
176
177    /** A client that needs to run during {@link #flush()} registers an worker
178     *  into one of the queues defined in this class. The queues are: {@link #earlier(Worker)},
179     *  {@link #normal(Worker)}, {@link #typeAnnotation(Worker)}, {@link #repeated(Worker)},
180     *  {@link #afterRepeated(Worker)}, {@link #validate(Worker)}.
181     *  The {@link Worker#run()} method will called inside the {@link #flush()}
182     *  call. Queues are empties in the abovementioned order.
183     */
184    public interface Worker {
185        void run();
186        String toString();
187    }
188
189    /**
190     * This context contains all the information needed to synthesize new
191     * annotations trees by the completer for repeating annotations.
192     */
193    private class AnnotationContext<T extends Attribute.Compound> {
194        public final Env<AttrContext> env;
195        public final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated;
196        public final Map<T, JCDiagnostic.DiagnosticPosition> pos;
197        public final boolean isTypeCompound;
198
199        public AnnotationContext(Env<AttrContext> env,
200                                 Map<Symbol.TypeSymbol, ListBuffer<T>> annotated,
201                                 Map<T, JCDiagnostic.DiagnosticPosition> pos,
202                                 boolean isTypeCompound) {
203            Assert.checkNonNull(env);
204            Assert.checkNonNull(annotated);
205            Assert.checkNonNull(pos);
206
207            this.env = env;
208            this.annotated = annotated;
209            this.pos = pos;
210            this.isTypeCompound = isTypeCompound;
211        }
212
213        public String toString() {
214            StringBuilder sb = new StringBuilder();
215            sb.append("RepeatedContext[");
216            for (Map.Entry<Symbol.TypeSymbol, ListBuffer<T>> entry :
217                     annotated.entrySet()) {
218                sb.append(" ");
219                sb.append(entry.getKey());
220                sb.append(" = { ");
221                sb.append(entry.getValue());
222                sb.append(" }");
223            }
224            sb.append(" ]");
225            return sb.toString();
226        }
227    }
228
229    private static class Placeholder<T extends Attribute.Compound> extends Attribute.Compound {
230
231        private final Annotate.AnnotationContext<T> ctx;
232        private final List<T> placeholderFor;
233        private final Symbol on;
234
235        public Placeholder(Annotate.AnnotationContext<T> ctx,
236                           List<T> placeholderFor, Symbol on) {
237            super(on.type, List.<Pair<Symbol.MethodSymbol, Attribute>>nil(),
238                  placeholderFor.head.position);
239            this.ctx = ctx;
240            this.placeholderFor = placeholderFor;
241            this.on = on;
242        }
243
244        @Override @DefinedBy(Api.LANGUAGE_MODEL)
245        public String toString() {
246            return "<placeholder: " + placeholderFor + " on: " + on + ">";
247    }
248
249        public List<T> getPlaceholderFor() {
250            return placeholderFor;
251        }
252
253        public Annotate.AnnotationContext<T> getRepeatedContext() {
254            return ctx;
255        }
256    }
257
258
259/* ********************************************************************
260 * Compute an attribute from its annotation.
261 *********************************************************************/
262
263    /** Process a single compound annotation, returning its
264     *  Attribute. Used from MemberEnter for attaching the attributes
265     *  to the annotated symbol.
266     */
267    Attribute.Compound enterAnnotation(JCAnnotation a,
268                                       Type expected,
269                                       Env<AttrContext> env) {
270        List<Pair<MethodSymbol,Attribute>> elems =
271            enterAttributeValues(a, expected, env);
272        Attribute.Compound ac = new Attribute.Compound(a.type, elems);
273        a.attribute = ac;
274
275        return ac;
276    }
277
278    Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a,
279                                               Type expected,
280                                               Env<AttrContext> env) {
281        List<Pair<MethodSymbol,Attribute>> elems =
282            enterAttributeValues(a, expected, env);
283
284        if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) {
285            // Create a new TypeCompound
286
287            Attribute.TypeCompound tc =
288                new Attribute.TypeCompound(a.type, elems,
289                // TODO: Eventually, we will get rid of this use of
290                // unknown, because we'll get a position from
291                // MemberEnter (task 8027262).
292                                           TypeAnnotationPosition.unknown);
293            a.attribute = tc;
294            return tc;
295        } else {
296            // Use an existing TypeCompound
297            return (Attribute.TypeCompound)a.attribute;
298        }
299    }
300
301    private List<Pair<MethodSymbol,Attribute>>
302            enterAttributeValues(JCAnnotation a,
303                                 Type expected,
304                                 Env<AttrContext> env) {
305        // The annotation might have had its type attributed (but not
306        // checked) by attr.attribAnnotationTypes during MemberEnter,
307        // in which case we do not need to do it again.
308        Type at = (a.annotationType.type != null ? a.annotationType.type
309                  : attr.attribType(a.annotationType, env));
310        a.type = chk.checkType(a.annotationType.pos(), at, expected);
311        boolean isError = a.type.isErroneous();
312        if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0 && !isError) {
313            log.error(a.annotationType.pos(),
314                      "not.annotation.type", a.type.toString());
315            isError = true;
316        }
317        List<JCExpression> args = a.args;
318        if (args.length() == 1 && !args.head.hasTag(ASSIGN)) {
319            // special case: elided "value=" assumed
320            args.head = make.at(args.head.pos).
321                Assign(make.Ident(names.value), args.head);
322        }
323        ListBuffer<Pair<MethodSymbol,Attribute>> buf =
324            new ListBuffer<>();
325        for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
326            JCExpression t = tl.head;
327            if (!t.hasTag(ASSIGN)) {
328                log.error(t.pos(), "annotation.value.must.be.name.value");
329                enterAttributeValue(t.type = syms.errType, t, env);
330                continue;
331            }
332            JCAssign assign = (JCAssign)t;
333            if (!assign.lhs.hasTag(IDENT)) {
334                log.error(t.pos(), "annotation.value.must.be.name.value");
335                enterAttributeValue(t.type = syms.errType, t, env);
336                continue;
337            }
338            JCIdent left = (JCIdent)assign.lhs;
339            Symbol method = rs.resolveQualifiedMethod(assign.rhs.pos(),
340                                                          env,
341                                                          a.type,
342                                                          left.name,
343                                                          List.<Type>nil(),
344                                                          null);
345            left.sym = method;
346            left.type = method.type;
347            if (method.owner != a.type.tsym && !isError)
348                log.error(left.pos(), "no.annotation.member", left.name, a.type);
349            Type result = method.type.getReturnType();
350            Attribute value = enterAttributeValue(result, assign.rhs, env);
351            if (!method.type.isErroneous())
352                buf.append(new Pair<>((MethodSymbol)method, value));
353            t.type = result;
354        }
355        return buf.toList();
356    }
357
358    Attribute enterAttributeValue(Type expected,
359                                  JCExpression tree,
360                                  Env<AttrContext> env) {
361        //first, try completing the attribution value sym - if a completion
362        //error is thrown, we should recover gracefully, and display an
363        //ordinary resolution diagnostic.
364        try {
365            expected.tsym.complete();
366        } catch(CompletionFailure e) {
367            log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
368            expected = syms.errType;
369        }
370        if (expected.hasTag(ARRAY)) {
371            if (!tree.hasTag(NEWARRAY)) {
372                tree = make.at(tree.pos).
373                    NewArray(null, List.<JCExpression>nil(), List.of(tree));
374            }
375            JCNewArray na = (JCNewArray)tree;
376            if (na.elemtype != null) {
377                log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
378            }
379            ListBuffer<Attribute> buf = new ListBuffer<>();
380            for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
381                buf.append(enterAttributeValue(types.elemtype(expected),
382                                               l.head,
383                                               env));
384            }
385            na.type = expected;
386            return new Attribute.
387                Array(expected, buf.toArray(new Attribute[buf.length()]));
388        }
389        if (tree.hasTag(NEWARRAY)) { //error recovery
390            if (!expected.isErroneous())
391                log.error(tree.pos(), "annotation.value.not.allowable.type");
392            JCNewArray na = (JCNewArray)tree;
393            if (na.elemtype != null) {
394                log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
395            }
396            for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
397                enterAttributeValue(syms.errType,
398                                    l.head,
399                                    env);
400            }
401            return new Attribute.Error(syms.errType);
402        }
403        if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
404            if (tree.hasTag(ANNOTATION)) {
405                return enterAnnotation((JCAnnotation)tree, expected, env);
406            } else {
407                log.error(tree.pos(), "annotation.value.must.be.annotation");
408                expected = syms.errType;
409            }
410        }
411        if (tree.hasTag(ANNOTATION)) { //error recovery
412            if (!expected.isErroneous())
413                log.error(tree.pos(), "annotation.not.valid.for.type", expected);
414            enterAnnotation((JCAnnotation)tree, syms.errType, env);
415            return new Attribute.Error(((JCAnnotation)tree).annotationType.type);
416        }
417        if (expected.isPrimitive() ||
418            (types.isSameType(expected, syms.stringType) && !expected.hasTag(TypeTag.ERROR))) {
419            Type result = attr.attribExpr(tree, env, expected);
420            if (result.isErroneous())
421                return new Attribute.Error(result.getOriginalType());
422            if (result.constValue() == null) {
423                log.error(tree.pos(), "attribute.value.must.be.constant");
424                return new Attribute.Error(expected);
425            }
426            result = cfolder.coerce(result, expected);
427            return new Attribute.Constant(expected, result.constValue());
428        }
429        if (expected.tsym == syms.classType.tsym) {
430            Type result = attr.attribExpr(tree, env, expected);
431            if (result.isErroneous()) {
432                // Does it look like an unresolved class literal?
433                if (TreeInfo.name(tree) == names._class &&
434                    ((JCFieldAccess) tree).selected.type.isErroneous()) {
435                    Name n = (((JCFieldAccess) tree).selected).type.tsym.flatName();
436                    return new Attribute.UnresolvedClass(expected,
437                            types.createErrorType(n,
438                                    syms.unknownSymbol, syms.classType));
439                } else {
440                    return new Attribute.Error(result.getOriginalType());
441                }
442            }
443
444            // Class literals look like field accesses of a field named class
445            // at the tree level
446            if (TreeInfo.name(tree) != names._class) {
447                log.error(tree.pos(), "annotation.value.must.be.class.literal");
448                return new Attribute.Error(syms.errType);
449            }
450            return new Attribute.Class(types,
451                                       (((JCFieldAccess) tree).selected).type);
452        }
453        if (expected.hasTag(CLASS) &&
454            (expected.tsym.flags() & Flags.ENUM) != 0) {
455            Type result = attr.attribExpr(tree, env, expected);
456            Symbol sym = TreeInfo.symbol(tree);
457            if (sym == null ||
458                TreeInfo.nonstaticSelect(tree) ||
459                sym.kind != Kinds.VAR ||
460                (sym.flags() & Flags.ENUM) == 0) {
461                log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
462                return new Attribute.Error(result.getOriginalType());
463            }
464            VarSymbol enumerator = (VarSymbol) sym;
465            return new Attribute.Enum(expected, enumerator);
466        }
467        //error recovery:
468        if (!expected.isErroneous())
469            log.error(tree.pos(), "annotation.value.not.allowable.type");
470        return new Attribute.Error(attr.attribExpr(tree, env, expected));
471    }
472
473    /* *********************************
474     * Support for repeating annotations
475     ***********************************/
476
477    /* Process repeated annotations. This method returns the
478     * synthesized container annotation or null IFF all repeating
479     * annotation are invalid.  This method reports errors/warnings.
480     */
481    private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations,
482            AnnotationContext<T> ctx,
483            Symbol on) {
484        T firstOccurrence = annotations.head;
485        List<Attribute> repeated = List.nil();
486        Type origAnnoType = null;
487        Type arrayOfOrigAnnoType = null;
488        Type targetContainerType = null;
489        MethodSymbol containerValueSymbol = null;
490
491        Assert.check(!annotations.isEmpty() &&
492                     !annotations.tail.isEmpty()); // i.e. size() > 1
493
494        int count = 0;
495        for (List<T> al = annotations;
496             !al.isEmpty();
497             al = al.tail)
498        {
499            count++;
500
501            // There must be more than a single anno in the annotation list
502            Assert.check(count > 1 || !al.tail.isEmpty());
503
504            T currentAnno = al.head;
505
506            origAnnoType = currentAnno.type;
507            if (arrayOfOrigAnnoType == null) {
508                arrayOfOrigAnnoType = types.makeArrayType(origAnnoType);
509            }
510
511            // Only report errors if this isn't the first occurrence I.E. count > 1
512            boolean reportError = count > 1;
513            Type currentContainerType = getContainingType(currentAnno, ctx.pos.get(currentAnno), reportError);
514            if (currentContainerType == null) {
515                continue;
516            }
517            // Assert that the target Container is == for all repeated
518            // annos of the same annotation type, the types should
519            // come from the same Symbol, i.e. be '=='
520            Assert.check(targetContainerType == null || currentContainerType == targetContainerType);
521            targetContainerType = currentContainerType;
522
523            containerValueSymbol = validateContainer(targetContainerType, origAnnoType, ctx.pos.get(currentAnno));
524
525            if (containerValueSymbol == null) { // Check of CA type failed
526                // errors are already reported
527                continue;
528            }
529
530            repeated = repeated.prepend(currentAnno);
531        }
532
533        if (!repeated.isEmpty()) {
534            repeated = repeated.reverse();
535            TreeMaker m = make.at(ctx.pos.get(firstOccurrence));
536            Pair<MethodSymbol, Attribute> p =
537                    new Pair<MethodSymbol, Attribute>(containerValueSymbol,
538                               new Attribute.Array(arrayOfOrigAnnoType, repeated));
539            if (ctx.isTypeCompound) {
540                /* TODO: the following code would be cleaner:
541                Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
542                        ((Attribute.TypeCompound)annotations.head).position);
543                JCTypeAnnotation annoTree = m.TypeAnnotation(at);
544                at = enterTypeAnnotation(annoTree, targetContainerType, ctx.env);
545                */
546                // However, we directly construct the TypeCompound to keep the
547                // direct relation to the contained TypeCompounds.
548                Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
549                        ((Attribute.TypeCompound)annotations.head).position);
550
551                // TODO: annotation applicability checks from below?
552
553                at.setSynthesized(true);
554
555                @SuppressWarnings("unchecked")
556                T x = (T) at;
557                return x;
558            } else {
559                Attribute.Compound c = new Attribute.Compound(targetContainerType, List.of(p));
560                JCAnnotation annoTree = m.Annotation(c);
561
562                if (!chk.annotationApplicable(annoTree, on))
563                    log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType);
564
565                if (!chk.validateAnnotationDeferErrors(annoTree))
566                    log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType);
567
568                c = enterAnnotation(annoTree, targetContainerType, ctx.env);
569                c.setSynthesized(true);
570
571                @SuppressWarnings("unchecked")
572                T x = (T) c;
573                return x;
574            }
575        } else {
576            return null; // errors should have been reported elsewhere
577        }
578    }
579
580    /** Fetches the actual Type that should be the containing annotation. */
581    private Type getContainingType(Attribute.Compound currentAnno,
582            DiagnosticPosition pos,
583            boolean reportError)
584    {
585        Type origAnnoType = currentAnno.type;
586        TypeSymbol origAnnoDecl = origAnnoType.tsym;
587
588        // Fetch the Repeatable annotation from the current
589        // annotation's declaration, or null if it has none
590        Attribute.Compound ca = origAnnoDecl.attribute(syms.repeatableType.tsym);
591        if (ca == null) { // has no Repeatable annotation
592            if (reportError)
593                log.error(pos, "duplicate.annotation.missing.container", origAnnoType, syms.repeatableType);
594            return null;
595        }
596
597        return filterSame(extractContainingType(ca, pos, origAnnoDecl),
598                          origAnnoType);
599    }
600
601    // returns null if t is same as 's', returns 't' otherwise
602    private Type filterSame(Type t, Type s) {
603        if (t == null || s == null) {
604            return t;
605        }
606
607        return types.isSameType(t, s) ? null : t;
608    }
609
610    /** Extract the actual Type to be used for a containing annotation. */
611    private Type extractContainingType(Attribute.Compound ca,
612            DiagnosticPosition pos,
613            TypeSymbol annoDecl)
614    {
615        // The next three checks check that the Repeatable annotation
616        // on the declaration of the annotation type that is repeating is
617        // valid.
618
619        // Repeatable must have at least one element
620        if (ca.values.isEmpty()) {
621            log.error(pos, "invalid.repeatable.annotation", annoDecl);
622            return null;
623        }
624        Pair<MethodSymbol,Attribute> p = ca.values.head;
625        Name name = p.fst.name;
626        if (name != names.value) { // should contain only one element, named "value"
627            log.error(pos, "invalid.repeatable.annotation", annoDecl);
628            return null;
629        }
630        if (!(p.snd instanceof Attribute.Class)) { // check that the value of "value" is an Attribute.Class
631            log.error(pos, "invalid.repeatable.annotation", annoDecl);
632            return null;
633        }
634
635        return ((Attribute.Class)p.snd).getValue();
636    }
637
638    /* Validate that the suggested targetContainerType Type is a valid
639     * container type for repeated instances of originalAnnoType
640     * annotations. Return null and report errors if this is not the
641     * case, return the MethodSymbol of the value element in
642     * targetContainerType if it is suitable (this is needed to
643     * synthesize the container). */
644    private MethodSymbol validateContainer(Type targetContainerType,
645                                           Type originalAnnoType,
646                                           DiagnosticPosition pos) {
647        MethodSymbol containerValueSymbol = null;
648        boolean fatalError = false;
649
650        // Validate that there is a (and only 1) value method
651        Scope scope = targetContainerType.tsym.members();
652        int nr_value_elems = 0;
653        boolean error = false;
654        for(Symbol elm : scope.getSymbolsByName(names.value)) {
655            nr_value_elems++;
656
657            if (nr_value_elems == 1 &&
658                elm.kind == Kinds.MTH) {
659                containerValueSymbol = (MethodSymbol)elm;
660            } else {
661                error = true;
662            }
663        }
664        if (error) {
665            log.error(pos,
666                      "invalid.repeatable.annotation.multiple.values",
667                      targetContainerType,
668                      nr_value_elems);
669            return null;
670        } else if (nr_value_elems == 0) {
671            log.error(pos,
672                      "invalid.repeatable.annotation.no.value",
673                      targetContainerType);
674            return null;
675        }
676
677        // validate that the 'value' element is a method
678        // probably "impossible" to fail this
679        if (containerValueSymbol.kind != Kinds.MTH) {
680            log.error(pos,
681                      "invalid.repeatable.annotation.invalid.value",
682                      targetContainerType);
683            fatalError = true;
684        }
685
686        // validate that the 'value' element has the correct return type
687        // i.e. array of original anno
688        Type valueRetType = containerValueSymbol.type.getReturnType();
689        Type expectedType = types.makeArrayType(originalAnnoType);
690        if (!(types.isArray(valueRetType) &&
691              types.isSameType(expectedType, valueRetType))) {
692            log.error(pos,
693                      "invalid.repeatable.annotation.value.return",
694                      targetContainerType,
695                      valueRetType,
696                      expectedType);
697            fatalError = true;
698        }
699        if (error) {
700            fatalError = true;
701        }
702
703        // The conditions for a valid containing annotation are made
704        // in Check.validateRepeatedAnnotaton();
705
706        return fatalError ? null : containerValueSymbol;
707    }
708
709    private <T extends Attribute.Compound> AnnotationContext<T>
710            prepareEnterAnnotations(List<JCAnnotation> annotations,
711                                    Env<AttrContext> env,
712                                    Symbol sym,
713                                    AttributeCreator<T> creator,
714                                    boolean isTypeCompound) {
715        Map<TypeSymbol, ListBuffer<T>> annotated = new LinkedHashMap<>();
716        Map<T, DiagnosticPosition> pos = new HashMap<>();
717
718        for (List<JCAnnotation> al = annotations; !al.isEmpty(); al = al.tail) {
719            JCAnnotation a = al.head;
720            T c = creator.create(a, syms.annotationType, env);
721
722            Assert.checkNonNull(c, "Failed to create annotation");
723
724            if (annotated.containsKey(a.type.tsym)) {
725                if (!allowRepeatedAnnos) {
726                    log.error(a.pos(), "repeatable.annotations.not.supported.in.source");
727                    allowRepeatedAnnos = true;
728                }
729                ListBuffer<T> l = annotated.get(a.type.tsym);
730                l = l.append(c);
731                annotated.put(a.type.tsym, l);
732                pos.put(c, a.pos());
733            } else {
734                annotated.put(a.type.tsym, ListBuffer.of(c));
735                pos.put(c, a.pos());
736            }
737
738            // Note: @Deprecated has no effect on local variables and parameters
739            if (!c.type.isErroneous()
740                && sym.owner.kind != MTH
741                && types.isSameType(c.type, syms.deprecatedType)) {
742                sym.flags_field |= Flags.DEPRECATED;
743            }
744        }
745
746        return new AnnotationContext<>(env, annotated, pos,
747                                             isTypeCompound);
748    }
749
750    // Gather up annotations into a map from type symbols to lists of
751    // Compound attributes, then continue on with repeating
752    // annotations processing
753    private <T extends Attribute.Compound>
754            void attachAttributesLater(final List<JCAnnotation> annotations,
755                                       final Env<AttrContext> env,
756                                       final Symbol sym,
757                                       final boolean isTypeCompound,
758                                       final AttributeCreator<T> creator,
759                                       final AttributeAttacher<T> attacher) {
760        final AnnotationContext<T> ctx =
761            prepareEnterAnnotations(annotations, env, sym, creator, isTypeCompound);
762        final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated =
763            ctx.annotated;
764        boolean hasRepeated = false;
765
766        List<T> buf = List.<T>nil();
767        for (ListBuffer<T> lb : annotated.values()) {
768            if (lb.size() == 1) {
769                buf = buf.prepend(lb.first());
770            } else {
771                @SuppressWarnings("unchecked")
772                T res = (T) new Placeholder<>(ctx, lb.toList(), sym);
773                buf = buf.prepend(res);
774                hasRepeated = true;
775            }
776        }
777
778        final List<T> attrs = buf.reverse();
779
780        if (!isTypeCompound) {
781            // Attach declaration attributes early, so
782            // that @Repeatable and other annotations get attached.
783            // Since the attacher uses setDeclarationAttributes, this
784            // will be overwritten later.
785            attacher.attach(sym, attrs);
786        }
787        if (hasRepeated) {
788            repeated(new Annotate.Worker() {
789                    @Override
790                    public String toString() {
791                        return "repeated annotation pass of: " + sym + " in: " + sym.owner;
792                    }
793
794                    @Override
795                    public void run() {
796                        JavaFileObject oldSource =
797                            log.useSource(env.toplevel.sourcefile);
798                        try {
799                            attacher.attach(sym, replacePlaceholders(attrs, ctx, sym));
800                        } finally {
801                            log.useSource(oldSource);
802                        }
803                    }
804                });
805        } else {
806            attacher.attach(sym, attrs);
807        }
808    }
809
810    private interface AttributeAttacher<T extends Attribute.Compound> {
811        public void attach(Symbol sym, List<T> attrs);
812    }
813
814    private final AttributeAttacher<Attribute.Compound> declAnnotationsAttacher =
815        new AttributeAttacher<Attribute.Compound>() {
816            @Override
817            public void attach(Symbol sym, List<Attribute.Compound> attrs) {
818                sym.resetAnnotations();
819                sym.setDeclarationAttributes(attrs);
820            }
821        };
822
823    private final AttributeAttacher<Attribute.TypeCompound> typeAnnotationsAttacher =
824        new AttributeAttacher<Attribute.TypeCompound>() {
825            @Override
826            public void attach(Symbol sym, List<Attribute.TypeCompound> attrs) {
827                sym.appendUniqueTypeAttributes(attrs);
828            }
829        };
830
831    private <T extends Attribute.Compound> List<T>
832            replacePlaceholders(List<T> buf,
833                                Annotate.AnnotationContext<T> ctx,
834                                Symbol sym) {
835        List<T> result = List.nil();
836        for (T a : buf) {
837            if (a instanceof Placeholder) {
838                @SuppressWarnings("unchecked")
839                    T replacement = replaceOne((Placeholder<T>) a, ctx, sym);
840
841                if (null != replacement) {
842                    result = result.prepend(replacement);
843                }
844            } else {
845                result = result.prepend(a);
846            }
847        }
848
849        return result.reverse();
850    }
851
852    private <T extends Attribute.Compound> T replaceOne(Placeholder<T> placeholder,
853                                                        Annotate.AnnotationContext<T> ctx,
854                                                        Symbol sym) {
855        // Process repeated annotations
856        T validRepeated =
857            processRepeatedAnnotations(placeholder.getPlaceholderFor(),
858                                       ctx, sym);
859
860        if (validRepeated != null) {
861            // Check that the container isn't manually
862            // present along with repeated instances of
863            // its contained annotation.
864            ListBuffer<T> manualContainer = ctx.annotated.get(validRepeated.type.tsym);
865            if (manualContainer != null) {
866                log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present",
867                        manualContainer.first().type.tsym);
868            }
869        }
870
871        // A null return will delete the Placeholder
872        return validRepeated;
873    }
874
875/* ********************************************************************
876 * Annotation processing
877 *********************************************************************/
878
879    /** Queue annotations for later processing. */
880    void annotateLater(final List<JCAnnotation> annotations,
881                       final Env<AttrContext> localEnv,
882                       final Symbol s,
883                       final DiagnosticPosition deferPos) {
884        if (annotations.isEmpty()) {
885            return;
886        }
887        if (s.kind != PCK) {
888            s.resetAnnotations(); // mark Annotations as incomplete for now
889        }
890        normal(new Annotate.Worker() {
891                @Override
892                public String toString() {
893                    return "annotate " + annotations + " onto " + s + " in " + s.owner;
894                }
895
896                @Override
897                public void run() {
898                    Assert.check(s.kind == PCK || s.annotationsPendingCompletion());
899                    JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
900                    DiagnosticPosition prevLintPos =
901                        deferPos != null
902                        ? deferredLintHandler.setPos(deferPos)
903                        : deferredLintHandler.immediate();
904                    Lint prevLint = deferPos != null ? null : chk.setLint(lint);
905                    try {
906                        if (s.hasAnnotations() &&
907                            annotations.nonEmpty())
908                            log.error(annotations.head.pos,
909                                      "already.annotated",
910                                      kindName(s), s);
911                        actualEnterAnnotations(annotations, localEnv, s);
912                    } finally {
913                        if (prevLint != null)
914                            chk.setLint(prevLint);
915                        deferredLintHandler.setPos(prevLintPos);
916                        log.useSource(prev);
917                    }
918                }
919            });
920
921        validate(new Annotate.Worker() { //validate annotations
922            @Override
923            public void run() {
924                JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
925                try {
926                    chk.validateAnnotations(annotations, s);
927                } finally {
928                    log.useSource(prev);
929                }
930            }
931        });
932    }
933
934    private interface AttributeCreator<T extends Attribute.Compound> {
935        public T create(JCAnnotation a, Type expected, Env<AttrContext> env);
936    }
937
938    // TODO: When SE8 features can be used, these can go away and be
939    // replaced by method refs.
940    private final AttributeCreator<Attribute.Compound> enterAnnotationsCreator =
941        new AttributeCreator<Attribute.Compound>() {
942        @Override
943        public Attribute.Compound create(JCAnnotation a,
944                                         Type expected,
945                                         Env<AttrContext> env) {
946            return enterAnnotation(a, syms.annotationType, env);
947        }
948    };
949    private final AttributeCreator<Attribute.TypeCompound> enterTypeAnnotationsCreator =
950        new AttributeCreator<Attribute.TypeCompound>() {
951        @Override
952        public Attribute.TypeCompound create(JCAnnotation a,
953                                             Type expected,
954                                             Env<AttrContext> env) {
955            return enterTypeAnnotation(a, syms.annotationType, env);
956        }
957    };
958
959    /** Enter a set of annotations. */
960    private void actualEnterAnnotations(List<JCAnnotation> annotations,
961                                        Env<AttrContext> env,
962                                        Symbol s) {
963        Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null");
964        attachAttributesLater(annotations, env, s, false,
965                              enterAnnotationsCreator,
966                              declAnnotationsAttacher);
967    }
968
969    /*
970     * If the symbol is non-null, attach the type annotation to it.
971     */
972    private void actualEnterTypeAnnotations(final List<JCAnnotation> annotations,
973                                            final Env<AttrContext> env,
974                                            final Symbol s,
975                                            final DiagnosticPosition deferPos) {
976        Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/");
977        JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
978        DiagnosticPosition prevLintPos = null;
979
980        if (deferPos != null) {
981            prevLintPos = deferredLintHandler.setPos(deferPos);
982        }
983        try {
984            attachAttributesLater(annotations, env, s, true,
985                                  enterTypeAnnotationsCreator,
986                                  typeAnnotationsAttacher);
987        } finally {
988            if (prevLintPos != null)
989                deferredLintHandler.setPos(prevLintPos);
990            log.useSource(prev);
991        }
992    }
993
994    public void annotateTypeLater(final JCTree tree,
995                                  final Env<AttrContext> env,
996                                  final Symbol sym,
997                                  final DiagnosticPosition deferPos) {
998        Assert.checkNonNull(sym);
999        normal(new Annotate.Worker() {
1000                @Override
1001                public String toString() {
1002                    return "type annotate " + tree + " onto " + sym + " in " + sym.owner;
1003                }
1004                @Override
1005                public void run() {
1006                    tree.accept(new TypeAnnotate(env, sym, deferPos));
1007                }
1008            });
1009    }
1010
1011    /**
1012     * We need to use a TreeScanner, because it is not enough to visit the top-level
1013     * annotations. We also need to visit type arguments, etc.
1014     */
1015    private class TypeAnnotate extends TreeScanner {
1016        private final Env<AttrContext> env;
1017        private final Symbol sym;
1018        private DiagnosticPosition deferPos;
1019
1020        public TypeAnnotate(final Env<AttrContext> env,
1021                            final Symbol sym,
1022                            final DiagnosticPosition deferPos) {
1023
1024            this.env = env;
1025            this.sym = sym;
1026            this.deferPos = deferPos;
1027        }
1028
1029        @Override
1030        public void visitAnnotatedType(final JCAnnotatedType tree) {
1031            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
1032            super.visitAnnotatedType(tree);
1033        }
1034
1035        @Override
1036        public void visitTypeParameter(final JCTypeParameter tree) {
1037            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
1038            super.visitTypeParameter(tree);
1039        }
1040
1041        @Override
1042        public void visitNewArray(final JCNewArray tree) {
1043            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
1044            for (List<JCAnnotation> dimAnnos : tree.dimAnnotations)
1045                actualEnterTypeAnnotations(dimAnnos, env, sym, deferPos);
1046            super.visitNewArray(tree);
1047        }
1048
1049        @Override
1050        public void visitMethodDef(final JCMethodDecl tree) {
1051            scan(tree.mods);
1052            scan(tree.restype);
1053            scan(tree.typarams);
1054            scan(tree.recvparam);
1055            scan(tree.params);
1056            scan(tree.thrown);
1057            scan(tree.defaultValue);
1058            // Do not annotate the body, just the signature.
1059            // scan(tree.body);
1060        }
1061
1062        @Override
1063        public void visitVarDef(final JCVariableDecl tree) {
1064            DiagnosticPosition prevPos = deferPos;
1065            deferPos = tree.pos();
1066            try {
1067                if (sym != null && sym.kind == Kinds.VAR) {
1068                    // Don't visit a parameter once when the sym is the method
1069                    // and once when the sym is the parameter.
1070                    scan(tree.mods);
1071                    scan(tree.vartype);
1072                }
1073                scan(tree.init);
1074            } finally {
1075                deferPos = prevPos;
1076            }
1077        }
1078
1079        @Override
1080        public void visitClassDef(JCClassDecl tree) {
1081            // We can only hit a classdef if it is declared within
1082            // a method. Ignore it - the class will be visited
1083            // separately later.
1084        }
1085
1086        @Override
1087        public void visitNewClass(JCNewClass tree) {
1088            if (tree.def == null) {
1089                // For an anonymous class instantiation the class
1090                // will be visited separately.
1091                super.visitNewClass(tree);
1092            }
1093        }
1094    }
1095}
1096