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