Annotate.java revision 2673:bf8500822576
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.Kind.*;
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        boolean elidedValue = false;
319        if (args.length() == 1 && !args.head.hasTag(ASSIGN)) {
320            // special case: elided "value=" assumed
321            elidedValue = true;
322            args.head = make.at(args.head.pos).
323                Assign(make.Ident(names.value), args.head);
324        }
325        ListBuffer<Pair<MethodSymbol,Attribute>> buf =
326            new ListBuffer<>();
327        for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
328            JCExpression t = tl.head;
329            if (!t.hasTag(ASSIGN)) {
330                log.error(t.pos(), "annotation.value.must.be.name.value");
331                enterAttributeValue(t.type = syms.errType, t, env);
332                continue;
333            }
334            JCAssign assign = (JCAssign)t;
335            if (!assign.lhs.hasTag(IDENT)) {
336                log.error(t.pos(), "annotation.value.must.be.name.value");
337                enterAttributeValue(t.type = syms.errType, t, env);
338                continue;
339            }
340            JCIdent left = (JCIdent)assign.lhs;
341            Symbol method = rs.resolveQualifiedMethod(elidedValue ? assign.rhs.pos() : left.pos(),
342                                                          env,
343                                                          a.type,
344                                                          left.name,
345                                                          List.<Type>nil(),
346                                                          null);
347            left.sym = method;
348            left.type = method.type;
349            if (method.owner != a.type.tsym && !isError)
350                log.error(left.pos(), "no.annotation.member", left.name, a.type);
351            Type result = method.type.getReturnType();
352            Attribute value = enterAttributeValue(result, assign.rhs, env);
353            if (!method.type.isErroneous())
354                buf.append(new Pair<>((MethodSymbol)method, value));
355            t.type = result;
356        }
357        return buf.toList();
358    }
359
360    Attribute enterAttributeValue(Type expected,
361                                  JCExpression tree,
362                                  Env<AttrContext> env) {
363        //first, try completing the attribution value sym - if a completion
364        //error is thrown, we should recover gracefully, and display an
365        //ordinary resolution diagnostic.
366        try {
367            expected.tsym.complete();
368        } catch(CompletionFailure e) {
369            log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
370            expected = syms.errType;
371        }
372        if (expected.hasTag(ARRAY)) {
373            if (!tree.hasTag(NEWARRAY)) {
374                tree = make.at(tree.pos).
375                    NewArray(null, List.<JCExpression>nil(), List.of(tree));
376            }
377            JCNewArray na = (JCNewArray)tree;
378            if (na.elemtype != null) {
379                log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
380            }
381            ListBuffer<Attribute> buf = new ListBuffer<>();
382            for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
383                buf.append(enterAttributeValue(types.elemtype(expected),
384                                               l.head,
385                                               env));
386            }
387            na.type = expected;
388            return new Attribute.
389                Array(expected, buf.toArray(new Attribute[buf.length()]));
390        }
391        if (tree.hasTag(NEWARRAY)) { //error recovery
392            if (!expected.isErroneous())
393                log.error(tree.pos(), "annotation.value.not.allowable.type");
394            JCNewArray na = (JCNewArray)tree;
395            if (na.elemtype != null) {
396                log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
397            }
398            for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
399                enterAttributeValue(syms.errType,
400                                    l.head,
401                                    env);
402            }
403            return new Attribute.Error(syms.errType);
404        }
405        if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
406            if (tree.hasTag(ANNOTATION)) {
407                return enterAnnotation((JCAnnotation)tree, expected, env);
408            } else {
409                log.error(tree.pos(), "annotation.value.must.be.annotation");
410                expected = syms.errType;
411            }
412        }
413        if (tree.hasTag(ANNOTATION)) { //error recovery
414            if (!expected.isErroneous())
415                log.error(tree.pos(), "annotation.not.valid.for.type", expected);
416            enterAnnotation((JCAnnotation)tree, syms.errType, env);
417            return new Attribute.Error(((JCAnnotation)tree).annotationType.type);
418        }
419        if (expected.isPrimitive() ||
420            (types.isSameType(expected, syms.stringType) && !expected.hasTag(TypeTag.ERROR))) {
421            Type result = attr.attribExpr(tree, env, expected);
422            if (result.isErroneous())
423                return new Attribute.Error(result.getOriginalType());
424            if (result.constValue() == null) {
425                log.error(tree.pos(), "attribute.value.must.be.constant");
426                return new Attribute.Error(expected);
427            }
428            result = cfolder.coerce(result, expected);
429            return new Attribute.Constant(expected, result.constValue());
430        }
431        if (expected.tsym == syms.classType.tsym) {
432            Type result = attr.attribExpr(tree, env, expected);
433            if (result.isErroneous()) {
434                // Does it look like an unresolved class literal?
435                if (TreeInfo.name(tree) == names._class &&
436                    ((JCFieldAccess) tree).selected.type.isErroneous()) {
437                    Name n = (((JCFieldAccess) tree).selected).type.tsym.flatName();
438                    return new Attribute.UnresolvedClass(expected,
439                            types.createErrorType(n,
440                                    syms.unknownSymbol, syms.classType));
441                } else {
442                    return new Attribute.Error(result.getOriginalType());
443                }
444            }
445
446            // Class literals look like field accesses of a field named class
447            // at the tree level
448            if (TreeInfo.name(tree) != names._class) {
449                log.error(tree.pos(), "annotation.value.must.be.class.literal");
450                return new Attribute.Error(syms.errType);
451            }
452            return new Attribute.Class(types,
453                                       (((JCFieldAccess) tree).selected).type);
454        }
455        if (expected.hasTag(CLASS) &&
456            (expected.tsym.flags() & Flags.ENUM) != 0) {
457            Type result = attr.attribExpr(tree, env, expected);
458            Symbol sym = TreeInfo.symbol(tree);
459            if (sym == null ||
460                TreeInfo.nonstaticSelect(tree) ||
461                sym.kind != VAR ||
462                (sym.flags() & Flags.ENUM) == 0) {
463                log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
464                return new Attribute.Error(result.getOriginalType());
465            }
466            VarSymbol enumerator = (VarSymbol) sym;
467            return new Attribute.Enum(expected, enumerator);
468        }
469        //error recovery:
470        if (!expected.isErroneous())
471            log.error(tree.pos(), "annotation.value.not.allowable.type");
472        return new Attribute.Error(attr.attribExpr(tree, env, expected));
473    }
474
475    /* *********************************
476     * Support for repeating annotations
477     ***********************************/
478
479    /* Process repeated annotations. This method returns the
480     * synthesized container annotation or null IFF all repeating
481     * annotation are invalid.  This method reports errors/warnings.
482     */
483    private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations,
484            AnnotationContext<T> ctx,
485            Symbol on) {
486        T firstOccurrence = annotations.head;
487        List<Attribute> repeated = List.nil();
488        Type origAnnoType = null;
489        Type arrayOfOrigAnnoType = null;
490        Type targetContainerType = null;
491        MethodSymbol containerValueSymbol = null;
492
493        Assert.check(!annotations.isEmpty() &&
494                     !annotations.tail.isEmpty()); // i.e. size() > 1
495
496        int count = 0;
497        for (List<T> al = annotations;
498             !al.isEmpty();
499             al = al.tail)
500        {
501            count++;
502
503            // There must be more than a single anno in the annotation list
504            Assert.check(count > 1 || !al.tail.isEmpty());
505
506            T currentAnno = al.head;
507
508            origAnnoType = currentAnno.type;
509            if (arrayOfOrigAnnoType == null) {
510                arrayOfOrigAnnoType = types.makeArrayType(origAnnoType);
511            }
512
513            // Only report errors if this isn't the first occurrence I.E. count > 1
514            boolean reportError = count > 1;
515            Type currentContainerType = getContainingType(currentAnno, ctx.pos.get(currentAnno), reportError);
516            if (currentContainerType == null) {
517                continue;
518            }
519            // Assert that the target Container is == for all repeated
520            // annos of the same annotation type, the types should
521            // come from the same Symbol, i.e. be '=='
522            Assert.check(targetContainerType == null || currentContainerType == targetContainerType);
523            targetContainerType = currentContainerType;
524
525            containerValueSymbol = validateContainer(targetContainerType, origAnnoType, ctx.pos.get(currentAnno));
526
527            if (containerValueSymbol == null) { // Check of CA type failed
528                // errors are already reported
529                continue;
530            }
531
532            repeated = repeated.prepend(currentAnno);
533        }
534
535        if (!repeated.isEmpty()) {
536            repeated = repeated.reverse();
537            TreeMaker m = make.at(ctx.pos.get(firstOccurrence));
538            Pair<MethodSymbol, Attribute> p =
539                    new Pair<MethodSymbol, Attribute>(containerValueSymbol,
540                               new Attribute.Array(arrayOfOrigAnnoType, repeated));
541            if (ctx.isTypeCompound) {
542                /* TODO: the following code would be cleaner:
543                Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
544                        ((Attribute.TypeCompound)annotations.head).position);
545                JCTypeAnnotation annoTree = m.TypeAnnotation(at);
546                at = enterTypeAnnotation(annoTree, targetContainerType, ctx.env);
547                */
548                // However, we directly construct the TypeCompound to keep the
549                // direct relation to the contained TypeCompounds.
550                Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
551                        ((Attribute.TypeCompound)annotations.head).position);
552
553                // TODO: annotation applicability checks from below?
554
555                at.setSynthesized(true);
556
557                @SuppressWarnings("unchecked")
558                T x = (T) at;
559                return x;
560            } else {
561                Attribute.Compound c = new Attribute.Compound(targetContainerType, List.of(p));
562                JCAnnotation annoTree = m.Annotation(c);
563
564                if (!chk.annotationApplicable(annoTree, on))
565                    log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType);
566
567                if (!chk.validateAnnotationDeferErrors(annoTree))
568                    log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType);
569
570                c = enterAnnotation(annoTree, targetContainerType, ctx.env);
571                c.setSynthesized(true);
572
573                @SuppressWarnings("unchecked")
574                T x = (T) c;
575                return x;
576            }
577        } else {
578            return null; // errors should have been reported elsewhere
579        }
580    }
581
582    /** Fetches the actual Type that should be the containing annotation. */
583    private Type getContainingType(Attribute.Compound currentAnno,
584            DiagnosticPosition pos,
585            boolean reportError)
586    {
587        Type origAnnoType = currentAnno.type;
588        TypeSymbol origAnnoDecl = origAnnoType.tsym;
589
590        // Fetch the Repeatable annotation from the current
591        // annotation's declaration, or null if it has none
592        Attribute.Compound ca = origAnnoDecl.attribute(syms.repeatableType.tsym);
593        if (ca == null) { // has no Repeatable annotation
594            if (reportError)
595                log.error(pos, "duplicate.annotation.missing.container", origAnnoType, syms.repeatableType);
596            return null;
597        }
598
599        return filterSame(extractContainingType(ca, pos, origAnnoDecl),
600                          origAnnoType);
601    }
602
603    // returns null if t is same as 's', returns 't' otherwise
604    private Type filterSame(Type t, Type s) {
605        if (t == null || s == null) {
606            return t;
607        }
608
609        return types.isSameType(t, s) ? null : t;
610    }
611
612    /** Extract the actual Type to be used for a containing annotation. */
613    private Type extractContainingType(Attribute.Compound ca,
614            DiagnosticPosition pos,
615            TypeSymbol annoDecl)
616    {
617        // The next three checks check that the Repeatable annotation
618        // on the declaration of the annotation type that is repeating is
619        // valid.
620
621        // Repeatable must have at least one element
622        if (ca.values.isEmpty()) {
623            log.error(pos, "invalid.repeatable.annotation", annoDecl);
624            return null;
625        }
626        Pair<MethodSymbol,Attribute> p = ca.values.head;
627        Name name = p.fst.name;
628        if (name != names.value) { // should contain only one element, named "value"
629            log.error(pos, "invalid.repeatable.annotation", annoDecl);
630            return null;
631        }
632        if (!(p.snd instanceof Attribute.Class)) { // check that the value of "value" is an Attribute.Class
633            log.error(pos, "invalid.repeatable.annotation", annoDecl);
634            return null;
635        }
636
637        return ((Attribute.Class)p.snd).getValue();
638    }
639
640    /* Validate that the suggested targetContainerType Type is a valid
641     * container type for repeated instances of originalAnnoType
642     * annotations. Return null and report errors if this is not the
643     * case, return the MethodSymbol of the value element in
644     * targetContainerType if it is suitable (this is needed to
645     * synthesize the container). */
646    private MethodSymbol validateContainer(Type targetContainerType,
647                                           Type originalAnnoType,
648                                           DiagnosticPosition pos) {
649        MethodSymbol containerValueSymbol = null;
650        boolean fatalError = false;
651
652        // Validate that there is a (and only 1) value method
653        Scope scope = targetContainerType.tsym.members();
654        int nr_value_elems = 0;
655        boolean error = false;
656        for(Symbol elm : scope.getSymbolsByName(names.value)) {
657            nr_value_elems++;
658
659            if (nr_value_elems == 1 &&
660                elm.kind == MTH) {
661                containerValueSymbol = (MethodSymbol)elm;
662            } else {
663                error = true;
664            }
665        }
666        if (error) {
667            log.error(pos,
668                      "invalid.repeatable.annotation.multiple.values",
669                      targetContainerType,
670                      nr_value_elems);
671            return null;
672        } else if (nr_value_elems == 0) {
673            log.error(pos,
674                      "invalid.repeatable.annotation.no.value",
675                      targetContainerType);
676            return null;
677        }
678
679        // validate that the 'value' element is a method
680        // probably "impossible" to fail this
681        if (containerValueSymbol.kind != MTH) {
682            log.error(pos,
683                      "invalid.repeatable.annotation.invalid.value",
684                      targetContainerType);
685            fatalError = true;
686        }
687
688        // validate that the 'value' element has the correct return type
689        // i.e. array of original anno
690        Type valueRetType = containerValueSymbol.type.getReturnType();
691        Type expectedType = types.makeArrayType(originalAnnoType);
692        if (!(types.isArray(valueRetType) &&
693              types.isSameType(expectedType, valueRetType))) {
694            log.error(pos,
695                      "invalid.repeatable.annotation.value.return",
696                      targetContainerType,
697                      valueRetType,
698                      expectedType);
699            fatalError = true;
700        }
701        if (error) {
702            fatalError = true;
703        }
704
705        // The conditions for a valid containing annotation are made
706        // in Check.validateRepeatedAnnotaton();
707
708        return fatalError ? null : containerValueSymbol;
709    }
710
711    private <T extends Attribute.Compound> AnnotationContext<T>
712            prepareEnterAnnotations(List<JCAnnotation> annotations,
713                                    Env<AttrContext> env,
714                                    Symbol sym,
715                                    AttributeCreator<T> creator,
716                                    boolean isTypeCompound) {
717        Map<TypeSymbol, ListBuffer<T>> annotated = new LinkedHashMap<>();
718        Map<T, DiagnosticPosition> pos = new HashMap<>();
719
720        for (List<JCAnnotation> al = annotations; !al.isEmpty(); al = al.tail) {
721            JCAnnotation a = al.head;
722            T c = creator.create(a, syms.annotationType, env);
723
724            Assert.checkNonNull(c, "Failed to create annotation");
725
726            if (annotated.containsKey(a.type.tsym)) {
727                if (!allowRepeatedAnnos) {
728                    log.error(a.pos(), "repeatable.annotations.not.supported.in.source");
729                    allowRepeatedAnnos = true;
730                }
731                ListBuffer<T> l = annotated.get(a.type.tsym);
732                l = l.append(c);
733                annotated.put(a.type.tsym, l);
734                pos.put(c, a.pos());
735            } else {
736                annotated.put(a.type.tsym, ListBuffer.of(c));
737                pos.put(c, a.pos());
738            }
739
740            // Note: @Deprecated has no effect on local variables and parameters
741            if (!c.type.isErroneous()
742                && sym.owner.kind != MTH
743                && types.isSameType(c.type, syms.deprecatedType)) {
744                sym.flags_field |= Flags.DEPRECATED;
745            }
746        }
747
748        return new AnnotationContext<>(env, annotated, pos,
749                                             isTypeCompound);
750    }
751
752    // Gather up annotations into a map from type symbols to lists of
753    // Compound attributes, then continue on with repeating
754    // annotations processing
755    private <T extends Attribute.Compound>
756            void attachAttributesLater(final List<JCAnnotation> annotations,
757                                       final Env<AttrContext> env,
758                                       final Symbol sym,
759                                       final boolean isTypeCompound,
760                                       final AttributeCreator<T> creator,
761                                       final AttributeAttacher<T> attacher) {
762        final AnnotationContext<T> ctx =
763            prepareEnterAnnotations(annotations, env, sym, creator, isTypeCompound);
764        final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated =
765            ctx.annotated;
766        boolean hasRepeated = false;
767
768        List<T> buf = List.<T>nil();
769        for (ListBuffer<T> lb : annotated.values()) {
770            if (lb.size() == 1) {
771                buf = buf.prepend(lb.first());
772            } else {
773                @SuppressWarnings("unchecked")
774                T res = (T) new Placeholder<>(ctx, lb.toList(), sym);
775                buf = buf.prepend(res);
776                hasRepeated = true;
777            }
778        }
779
780        final List<T> attrs = buf.reverse();
781
782        if (!isTypeCompound) {
783            // Attach declaration attributes early, so
784            // that @Repeatable and other annotations get attached.
785            // Since the attacher uses setDeclarationAttributes, this
786            // will be overwritten later.
787            attacher.attach(sym, attrs);
788        }
789        if (hasRepeated) {
790            repeated(new Annotate.Worker() {
791                    @Override
792                    public String toString() {
793                        return "repeated annotation pass of: " + sym + " in: " + sym.owner;
794                    }
795
796                    @Override
797                    public void run() {
798                        JavaFileObject oldSource =
799                            log.useSource(env.toplevel.sourcefile);
800                        try {
801                            attacher.attach(sym, replacePlaceholders(attrs, ctx, sym));
802                        } finally {
803                            log.useSource(oldSource);
804                        }
805                    }
806                });
807        } else {
808            attacher.attach(sym, attrs);
809        }
810    }
811
812    private interface AttributeAttacher<T extends Attribute.Compound> {
813        public void attach(Symbol sym, List<T> attrs);
814    }
815
816    private final AttributeAttacher<Attribute.Compound> declAnnotationsAttacher =
817        new AttributeAttacher<Attribute.Compound>() {
818            @Override
819            public void attach(Symbol sym, List<Attribute.Compound> attrs) {
820                sym.resetAnnotations();
821                sym.setDeclarationAttributes(attrs);
822            }
823        };
824
825    private final AttributeAttacher<Attribute.TypeCompound> typeAnnotationsAttacher =
826        new AttributeAttacher<Attribute.TypeCompound>() {
827            @Override
828            public void attach(Symbol sym, List<Attribute.TypeCompound> attrs) {
829                sym.appendUniqueTypeAttributes(attrs);
830            }
831        };
832
833    private <T extends Attribute.Compound> List<T>
834            replacePlaceholders(List<T> buf,
835                                Annotate.AnnotationContext<T> ctx,
836                                Symbol sym) {
837        List<T> result = List.nil();
838        for (T a : buf) {
839            if (a instanceof Placeholder) {
840                @SuppressWarnings("unchecked")
841                    T replacement = replaceOne((Placeholder<T>) a, ctx, sym);
842
843                if (null != replacement) {
844                    result = result.prepend(replacement);
845                }
846            } else {
847                result = result.prepend(a);
848            }
849        }
850
851        return result.reverse();
852    }
853
854    private <T extends Attribute.Compound> T replaceOne(Placeholder<T> placeholder,
855                                                        Annotate.AnnotationContext<T> ctx,
856                                                        Symbol sym) {
857        // Process repeated annotations
858        T validRepeated =
859            processRepeatedAnnotations(placeholder.getPlaceholderFor(),
860                                       ctx, sym);
861
862        if (validRepeated != null) {
863            // Check that the container isn't manually
864            // present along with repeated instances of
865            // its contained annotation.
866            ListBuffer<T> manualContainer = ctx.annotated.get(validRepeated.type.tsym);
867            if (manualContainer != null) {
868                log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present",
869                        manualContainer.first().type.tsym);
870            }
871        }
872
873        // A null return will delete the Placeholder
874        return validRepeated;
875    }
876
877/* ********************************************************************
878 * Annotation processing
879 *********************************************************************/
880
881    /** Queue annotations for later processing. */
882    void annotateLater(final List<JCAnnotation> annotations,
883                       final Env<AttrContext> localEnv,
884                       final Symbol s,
885                       final DiagnosticPosition deferPos) {
886        if (annotations.isEmpty()) {
887            return;
888        }
889        if (s.kind != PCK) {
890            s.resetAnnotations(); // mark Annotations as incomplete for now
891        }
892        normal(new Annotate.Worker() {
893                @Override
894                public String toString() {
895                    return "annotate " + annotations + " onto " + s + " in " + s.owner;
896                }
897
898                @Override
899                public void run() {
900                    Assert.check(s.kind == PCK || s.annotationsPendingCompletion());
901                    JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
902                    DiagnosticPosition prevLintPos =
903                        deferPos != null
904                        ? deferredLintHandler.setPos(deferPos)
905                        : deferredLintHandler.immediate();
906                    Lint prevLint = deferPos != null ? null : chk.setLint(lint);
907                    try {
908                        if (s.hasAnnotations() &&
909                            annotations.nonEmpty())
910                            log.error(annotations.head.pos,
911                                      "already.annotated",
912                                      Kinds.kindName(s), s);
913                        actualEnterAnnotations(annotations, localEnv, s);
914                    } finally {
915                        if (prevLint != null)
916                            chk.setLint(prevLint);
917                        deferredLintHandler.setPos(prevLintPos);
918                        log.useSource(prev);
919                    }
920                }
921            });
922
923        validate(new Annotate.Worker() { //validate annotations
924            @Override
925            public void run() {
926                JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
927                try {
928                    chk.validateAnnotations(annotations, s);
929                } finally {
930                    log.useSource(prev);
931                }
932            }
933        });
934    }
935
936    private interface AttributeCreator<T extends Attribute.Compound> {
937        public T create(JCAnnotation a, Type expected, Env<AttrContext> env);
938    }
939
940    // TODO: When SE8 features can be used, these can go away and be
941    // replaced by method refs.
942    private final AttributeCreator<Attribute.Compound> enterAnnotationsCreator =
943        new AttributeCreator<Attribute.Compound>() {
944        @Override
945        public Attribute.Compound create(JCAnnotation a,
946                                         Type expected,
947                                         Env<AttrContext> env) {
948            return enterAnnotation(a, syms.annotationType, env);
949        }
950    };
951    private final AttributeCreator<Attribute.TypeCompound> enterTypeAnnotationsCreator =
952        new AttributeCreator<Attribute.TypeCompound>() {
953        @Override
954        public Attribute.TypeCompound create(JCAnnotation a,
955                                             Type expected,
956                                             Env<AttrContext> env) {
957            return enterTypeAnnotation(a, syms.annotationType, env);
958        }
959    };
960
961    /** Enter a set of annotations. */
962    private void actualEnterAnnotations(List<JCAnnotation> annotations,
963                                        Env<AttrContext> env,
964                                        Symbol s) {
965        Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null");
966        attachAttributesLater(annotations, env, s, false,
967                              enterAnnotationsCreator,
968                              declAnnotationsAttacher);
969    }
970
971    /*
972     * If the symbol is non-null, attach the type annotation to it.
973     */
974    private void actualEnterTypeAnnotations(final List<JCAnnotation> annotations,
975                                            final Env<AttrContext> env,
976                                            final Symbol s,
977                                            final DiagnosticPosition deferPos) {
978        Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/");
979        JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
980        DiagnosticPosition prevLintPos = null;
981
982        if (deferPos != null) {
983            prevLintPos = deferredLintHandler.setPos(deferPos);
984        }
985        try {
986            attachAttributesLater(annotations, env, s, true,
987                                  enterTypeAnnotationsCreator,
988                                  typeAnnotationsAttacher);
989        } finally {
990            if (prevLintPos != null)
991                deferredLintHandler.setPos(prevLintPos);
992            log.useSource(prev);
993        }
994    }
995
996    public void annotateTypeLater(final JCTree tree,
997                                  final Env<AttrContext> env,
998                                  final Symbol sym,
999                                  final DiagnosticPosition deferPos) {
1000        Assert.checkNonNull(sym);
1001        normal(new Annotate.Worker() {
1002                @Override
1003                public String toString() {
1004                    return "type annotate " + tree + " onto " + sym + " in " + sym.owner;
1005                }
1006                @Override
1007                public void run() {
1008                    tree.accept(new TypeAnnotate(env, sym, deferPos));
1009                }
1010            });
1011    }
1012
1013    /**
1014     * We need to use a TreeScanner, because it is not enough to visit the top-level
1015     * annotations. We also need to visit type arguments, etc.
1016     */
1017    private class TypeAnnotate extends TreeScanner {
1018        private final Env<AttrContext> env;
1019        private final Symbol sym;
1020        private DiagnosticPosition deferPos;
1021
1022        public TypeAnnotate(final Env<AttrContext> env,
1023                            final Symbol sym,
1024                            final DiagnosticPosition deferPos) {
1025
1026            this.env = env;
1027            this.sym = sym;
1028            this.deferPos = deferPos;
1029        }
1030
1031        @Override
1032        public void visitAnnotatedType(final JCAnnotatedType tree) {
1033            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
1034            super.visitAnnotatedType(tree);
1035        }
1036
1037        @Override
1038        public void visitTypeParameter(final JCTypeParameter tree) {
1039            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
1040            super.visitTypeParameter(tree);
1041        }
1042
1043        @Override
1044        public void visitNewArray(final JCNewArray tree) {
1045            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
1046            for (List<JCAnnotation> dimAnnos : tree.dimAnnotations)
1047                actualEnterTypeAnnotations(dimAnnos, env, sym, deferPos);
1048            super.visitNewArray(tree);
1049        }
1050
1051        @Override
1052        public void visitMethodDef(final JCMethodDecl tree) {
1053            scan(tree.mods);
1054            scan(tree.restype);
1055            scan(tree.typarams);
1056            scan(tree.recvparam);
1057            scan(tree.params);
1058            scan(tree.thrown);
1059            scan(tree.defaultValue);
1060            // Do not annotate the body, just the signature.
1061            // scan(tree.body);
1062        }
1063
1064        @Override
1065        public void visitVarDef(final JCVariableDecl tree) {
1066            DiagnosticPosition prevPos = deferPos;
1067            deferPos = tree.pos();
1068            try {
1069                if (sym != null && sym.kind == VAR) {
1070                    // Don't visit a parameter once when the sym is the method
1071                    // and once when the sym is the parameter.
1072                    scan(tree.mods);
1073                    scan(tree.vartype);
1074                }
1075                scan(tree.init);
1076            } finally {
1077                deferPos = prevPos;
1078            }
1079        }
1080
1081        @Override
1082        public void visitClassDef(JCClassDecl tree) {
1083            // We can only hit a classdef if it is declared within
1084            // a method. Ignore it - the class will be visited
1085            // separately later.
1086        }
1087
1088        @Override
1089        public void visitNewClass(JCNewClass tree) {
1090            if (tree.def == null) {
1091                // For an anonymous class instantiation the class
1092                // will be visited separately.
1093                super.visitNewClass(tree);
1094            }
1095        }
1096    }
1097}
1098