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