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                 Attribute.TypeCompound tc = new Attribute.TypeCompound(a.type, buf.toList(), new TypeAnnotationPosition());
 303                 a.attribute = tc;
 304                 return tc;
 305             } else {
 306                 // Use an existing TypeCompound
 307                 return a.attribute;
 308             }
 309         } else {
 310             Attribute.Compound ac = new Attribute.Compound(a.type, buf.toList());
 311             a.attribute = ac;
 312             return ac;
 313         }
 314     }
 315 
 316     Attribute enterAttributeValue(Type expected,
 317                                   JCExpression tree,
 318                                   Env<AttrContext> env) {
 319         //first, try completing the attribution value sym - if a completion
 320         //error is thrown, we should recover gracefully, and display an
 321         //ordinary resolution diagnostic.
 322         try {
 323             expected.tsym.complete();
 324         } catch(CompletionFailure e) {
 325             log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
 326             expected = syms.errType;
 327         }
 328         if (expected.hasTag(ARRAY)) {
 329             if (!tree.hasTag(NEWARRAY)) {
 330                 tree = make.at(tree.pos).
 331                     NewArray(null, List.<JCExpression>nil(), List.of(tree));
 332             }
 333             JCNewArray na = (JCNewArray)tree;
 334             if (na.elemtype != null) {
 335                 log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
 336             }
 337             ListBuffer<Attribute> buf = new ListBuffer<>();
 338             for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
 339                 buf.append(enterAttributeValue(types.elemtype(expected),
 340                                                l.head,
 341                                                env));
 342             }
 343             na.type = expected;
 344             return new Attribute.
 345                 Array(expected, buf.toArray(new Attribute[buf.length()]));
 346         }
 347         if (tree.hasTag(NEWARRAY)) { //error recovery
 348             if (!expected.isErroneous())
 349                 log.error(tree.pos(), "annotation.value.not.allowable.type");
 350             JCNewArray na = (JCNewArray)tree;
 351             if (na.elemtype != null) {
 352                 log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
 353             }
 354             for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
 355                 enterAttributeValue(syms.errType,
 356                                     l.head,
 357                                     env);
 358             }
 359             return new Attribute.Error(syms.errType);
 360         }
 361         if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
 362             if (tree.hasTag(ANNOTATION)) {
 363                 return enterAnnotation((JCAnnotation)tree, expected, env);
 364             } else {
 365                 log.error(tree.pos(), "annotation.value.must.be.annotation");
 366                 expected = syms.errType;
 367             }
 368         }
 369         if (tree.hasTag(ANNOTATION)) { //error recovery
 370             if (!expected.isErroneous())
 371                 log.error(tree.pos(), "annotation.not.valid.for.type", expected);
 372             enterAnnotation((JCAnnotation)tree, syms.errType, env);
 373             return new Attribute.Error(((JCAnnotation)tree).annotationType.type);
 374         }
 375         if (expected.isPrimitive() ||
 376             (types.isSameType(expected, syms.stringType) && !expected.hasTag(TypeTag.ERROR))) {
 377             Type result = attr.attribExpr(tree, env, expected);
 378             if (result.isErroneous())
 379                 return new Attribute.Error(result.getOriginalType());
 380             if (result.constValue() == null) {
 381                 log.error(tree.pos(), "attribute.value.must.be.constant");
 382                 return new Attribute.Error(expected);
 383             }
 384             result = cfolder.coerce(result, expected);
 385             return new Attribute.Constant(expected, result.constValue());
 386         }
 387         if (expected.tsym == syms.classType.tsym) {
 388             Type result = attr.attribExpr(tree, env, expected);
 389             if (result.isErroneous()) {
 390                 // Does it look like an unresolved class literal?
 391                 if (TreeInfo.name(tree) == names._class &&
 392                     ((JCFieldAccess) tree).selected.type.isErroneous()) {
 393                     Name n = (((JCFieldAccess) tree).selected).type.tsym.flatName();
 394                     return new Attribute.UnresolvedClass(expected,
 395                             types.createErrorType(n,
 396                                     syms.unknownSymbol, syms.classType));
 397                 } else {
 398                     return new Attribute.Error(result.getOriginalType());
 399                 }
 400             }
 401 
 402             // Class literals look like field accesses of a field named class
 403             // at the tree level
 404             if (TreeInfo.name(tree) != names._class) {
 405                 log.error(tree.pos(), "annotation.value.must.be.class.literal");
 406                 return new Attribute.Error(syms.errType);
 407             }
 408             return new Attribute.Class(types,
 409                                        (((JCFieldAccess) tree).selected).type);
 410         }
 411         if (expected.hasTag(CLASS) &&
 412             (expected.tsym.flags() & Flags.ENUM) != 0) {
 413             Type result = attr.attribExpr(tree, env, expected);
 414             Symbol sym = TreeInfo.symbol(tree);
 415             if (sym == null ||
 416                 TreeInfo.nonstaticSelect(tree) ||
 417                 sym.kind != Kinds.VAR ||
 418                 (sym.flags() & Flags.ENUM) == 0) {
 419                 log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
 420                 return new Attribute.Error(result.getOriginalType());
 421             }
 422             VarSymbol enumerator = (VarSymbol) sym;
 423             return new Attribute.Enum(expected, enumerator);
 424         }
 425         //error recovery:
 426         if (!expected.isErroneous())
 427             log.error(tree.pos(), "annotation.value.not.allowable.type");
 428         return new Attribute.Error(attr.attribExpr(tree, env, expected));
 429     }
 430 
 431     /* *********************************
 432      * Support for repeating annotations
 433      ***********************************/
 434 
 435     /* Process repeated annotations. This method returns the
 436      * synthesized container annotation or null IFF all repeating
 437      * annotation are invalid.  This method reports errors/warnings.
 438      */
 439     private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations,
 440             AnnotateRepeatedContext<T> ctx,
 441             Symbol on) {
 442         T firstOccurrence = annotations.head;
 443         List<Attribute> repeated = List.nil();
 444         Type origAnnoType = null;
 445         Type arrayOfOrigAnnoType = null;
 446         Type targetContainerType = null;
 447         MethodSymbol containerValueSymbol = null;
 448 
 449         Assert.check(!annotations.isEmpty() &&
 450                      !annotations.tail.isEmpty()); // i.e. size() > 1
 451 
 452         int count = 0;
 453         for (List<T> al = annotations;
 454              !al.isEmpty();
 455              al = al.tail)
 456         {
 457             count++;
 458 
 459             // There must be more than a single anno in the annotation list
 460             Assert.check(count > 1 || !al.tail.isEmpty());
 461 
 462             T currentAnno = al.head;
 463 
 464             origAnnoType = currentAnno.type;
 465             if (arrayOfOrigAnnoType == null) {
 466                 arrayOfOrigAnnoType = types.makeArrayType(origAnnoType);
 467             }
 468 
 469             // Only report errors if this isn't the first occurrence I.E. count > 1
 470             boolean reportError = count > 1;
 471             Type currentContainerType = getContainingType(currentAnno, ctx.pos.get(currentAnno), reportError);
 472             if (currentContainerType == null) {
 473                 continue;
 474             }
 475             // Assert that the target Container is == for all repeated
 476             // annos of the same annotation type, the types should
 477             // come from the same Symbol, i.e. be '=='
 478             Assert.check(targetContainerType == null || currentContainerType == targetContainerType);
 479             targetContainerType = currentContainerType;
 480 
 481             containerValueSymbol = validateContainer(targetContainerType, origAnnoType, ctx.pos.get(currentAnno));
 482 
 483             if (containerValueSymbol == null) { // Check of CA type failed
 484                 // errors are already reported
 485                 continue;
 486             }
 487 
 488             repeated = repeated.prepend(currentAnno);
 489         }
 490 
 491         if (!repeated.isEmpty()) {
 492             repeated = repeated.reverse();
 493             TreeMaker m = make.at(ctx.pos.get(firstOccurrence));
 494             Pair<MethodSymbol, Attribute> p =
 495                     new Pair<MethodSymbol, Attribute>(containerValueSymbol,
 496                                new Attribute.Array(arrayOfOrigAnnoType, repeated));
 497             if (ctx.isTypeCompound) {
 498                 /* TODO: the following code would be cleaner:
 499                 Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
 500                         ((Attribute.TypeCompound)annotations.head).position);
 501                 JCTypeAnnotation annoTree = m.TypeAnnotation(at);
 502                 at = enterTypeAnnotation(annoTree, targetContainerType, ctx.env);
 503                 */
 504                 // However, we directly construct the TypeCompound to keep the
 505                 // direct relation to the contained TypeCompounds.
 506                 Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
 507                         ((Attribute.TypeCompound)annotations.head).position);
 508 
 509                 // TODO: annotation applicability checks from below?
 510 
 511                 at.setSynthesized(true);
 512 
 513                 @SuppressWarnings("unchecked")
 514                 T x = (T) at;
 515                 return x;
 516             } else {
 517                 Attribute.Compound c = new Attribute.Compound(targetContainerType, List.of(p));
 518                 JCAnnotation annoTree = m.Annotation(c);
 519 
 520                 if (!chk.annotationApplicable(annoTree, on))
 521                     log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType);
 522 
 523                 if (!chk.validateAnnotationDeferErrors(annoTree))
 524                     log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType);
 525 
 526                 c = enterAnnotation(annoTree, targetContainerType, ctx.env);
 527                 c.setSynthesized(true);
 528 
 529                 @SuppressWarnings("unchecked")
 530                 T x = (T) c;
 531                 return x;
 532             }
 533         } else {
 534             return null; // errors should have been reported elsewhere
 535         }
 536     }
 537 
 538     /** Fetches the actual Type that should be the containing annotation. */
 539     private Type getContainingType(Attribute.Compound currentAnno,
 540             DiagnosticPosition pos,
 541             boolean reportError)
 542     {
 543         Type origAnnoType = currentAnno.type;
 544         TypeSymbol origAnnoDecl = origAnnoType.tsym;
 545 
 546         // Fetch the Repeatable annotation from the current
 547         // annotation's declaration, or null if it has none
 548         Attribute.Compound ca = origAnnoDecl.attribute(syms.repeatableType.tsym);
 549         if (ca == null) { // has no Repeatable annotation
 550             if (reportError)
 551                 log.error(pos, "duplicate.annotation.missing.container", origAnnoType, syms.repeatableType);
 552             return null;
 553         }
 554 
 555         return filterSame(extractContainingType(ca, pos, origAnnoDecl),
 556                           origAnnoType);
 557     }
 558 
 559     // returns null if t is same as 's', returns 't' otherwise
 560     private Type filterSame(Type t, Type s) {
 561         if (t == null || s == null) {
 562             return t;
 563         }
 564 
 565         return types.isSameType(t, s) ? null : t;
 566     }
 567 
 568     /** Extract the actual Type to be used for a containing annotation. */
 569     private Type extractContainingType(Attribute.Compound ca,
 570             DiagnosticPosition pos,
 571             TypeSymbol annoDecl)
 572     {
 573         // The next three checks check that the Repeatable annotation
 574         // on the declaration of the annotation type that is repeating is
 575         // valid.
 576 
 577         // Repeatable must have at least one element
 578         if (ca.values.isEmpty()) {
 579             log.error(pos, "invalid.repeatable.annotation", annoDecl);
 580             return null;
 581         }
 582         Pair<MethodSymbol,Attribute> p = ca.values.head;
 583         Name name = p.fst.name;
 584         if (name != names.value) { // should contain only one element, named "value"
 585             log.error(pos, "invalid.repeatable.annotation", annoDecl);
 586             return null;
 587         }
 588         if (!(p.snd instanceof Attribute.Class)) { // check that the value of "value" is an Attribute.Class
 589             log.error(pos, "invalid.repeatable.annotation", annoDecl);
 590             return null;
 591         }
 592 
 593         return ((Attribute.Class)p.snd).getValue();
 594     }
 595 
 596     /* Validate that the suggested targetContainerType Type is a valid
 597      * container type for repeated instances of originalAnnoType
 598      * annotations. Return null and report errors if this is not the
 599      * case, return the MethodSymbol of the value element in
 600      * targetContainerType if it is suitable (this is needed to
 601      * synthesize the container). */
 602     private MethodSymbol validateContainer(Type targetContainerType,
 603                                            Type originalAnnoType,
 604                                            DiagnosticPosition pos) {
 605         MethodSymbol containerValueSymbol = null;
 606         boolean fatalError = false;
 607 
 608         // Validate that there is a (and only 1) value method
 609         Scope scope = targetContainerType.tsym.members();
 610         int nr_value_elems = 0;
 611         boolean error = false;
 612         for(Symbol elm : scope.getElementsByName(names.value)) {
 613             nr_value_elems++;
 614 
 615             if (nr_value_elems == 1 &&
 616                 elm.kind == Kinds.MTH) {
 617                 containerValueSymbol = (MethodSymbol)elm;
 618             } else {
 619                 error = true;
 620             }
 621         }
 622         if (error) {
 623             log.error(pos,
 624                       "invalid.repeatable.annotation.multiple.values",
 625                       targetContainerType,
 626                       nr_value_elems);
 627             return null;
 628         } else if (nr_value_elems == 0) {
 629             log.error(pos,
 630                       "invalid.repeatable.annotation.no.value",
 631                       targetContainerType);
 632             return null;
 633         }
 634 
 635         // validate that the 'value' element is a method
 636         // probably "impossible" to fail this
 637         if (containerValueSymbol.kind != Kinds.MTH) {
 638             log.error(pos,
 639                       "invalid.repeatable.annotation.invalid.value",
 640                       targetContainerType);
 641             fatalError = true;
 642         }
 643 
 644         // validate that the 'value' element has the correct return type
 645         // i.e. array of original anno
 646         Type valueRetType = containerValueSymbol.type.getReturnType();
 647         Type expectedType = types.makeArrayType(originalAnnoType);
 648         if (!(types.isArray(valueRetType) &&
 649               types.isSameType(expectedType, valueRetType))) {
 650             log.error(pos,
 651                       "invalid.repeatable.annotation.value.return",
 652                       targetContainerType,
 653                       valueRetType,
 654                       expectedType);
 655             fatalError = true;
 656         }
 657         if (error) {
 658             fatalError = true;
 659         }
 660 
 661         // The conditions for a valid containing annotation are made
 662         // in Check.validateRepeatedAnnotaton();
 663 
 664         return fatalError ? null : containerValueSymbol;
 665     }
 666 }