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