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