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