001 /* Copyright (c) 2005-2008, Torbjorn Ekman 002 * All rights reserved. 003 * 004 * Redistribution and use in source and binary forms, with or without 005 * modification, are permitted provided that the following conditions are met: 006 * 007 * 1. Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * 010 * 2. Redistributions in binary form must reproduce the above copyright notice, 011 * this list of conditions and the following disclaimer in the documentation 012 * and/or other materials provided with the distribution. 013 * 014 * 3. Neither the name of the copyright holder nor the names of its 015 * contributors may be used to endorse or promote products derived from this 016 * software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 * POSSIBILITY OF SUCH DAMAGE. 029 */ 030 031 aspect Annotations { 032 // 7.4.1.1 Package Annotations 033 034 /* Annotations may be used on package declarations, with the restriction that 035 at most one annotated package declaration is permitted for a given package. 036 The manner in which this restriction is enforced must, of necessity, vary 037 from implementation to implementation. The following scheme is strongly 038 recommended for file-system-based implementations: The sole annotated 039 package declaration, if it exists, is placed in a source file called 040 package-info.java in the directory containing the source files for the 041 package. */ 042 public void AnnotatedCompilationUnit.nameCheck() { 043 super.nameCheck(); 044 if (!relativeName().endsWith("package-info.java")) { 045 error("package annotations should be in a file package-info.java"); 046 } 047 } 048 049 // 9.6 Annotation Types 050 051 /* The Identifier in an annotation type declaration specifies the name of the 052 annotation type. A compile-time error occurs if an annotation type has the same 053 simple name as any of its enclosing classes or interfaces. 054 Comment: This is common for all type declarations and need thus no specific 055 implementation. */ 056 057 // 9.6.1.1 058 059 /* If an annotation a on an annotation declaration corresponds to an 060 annotation type T, and T has a (meta-)annotation m that corresponds to 061 annotation.Target, then m must have either an element whose matches the 062 annotated declaration, or a compile-time error occurs.*/ 063 public void Annotation.checkModifiers() { 064 super.checkModifiers(); 065 if (decl() instanceof AnnotationDecl) { 066 AnnotationDecl T = (AnnotationDecl) decl(); 067 Annotation m = T.annotation(lookupType("java.lang.annotation", "Target")); 068 if (m != null && m.getNumElementValuePair() == 1 && m.getElementValuePair(0).getName().equals("value")) { 069 ElementValue v = m.getElementValuePair(0).getElementValue(); 070 //System.out.println("ElementValue: \n" + v.dumpTree()); 071 //System.out.println("Annotation: \n" + dumpTree()); 072 if (!v.validTarget(this)) { 073 errorf("annotation type %s is not applicable to this kind of declaration", T.typeName()); 074 } 075 } 076 } 077 } 078 inh TypeDecl Annotation.lookupType(String packageName, String typeName); 079 inh TypeDecl Modifiers.lookupType(String packageName, String typeName); 080 syn boolean ElementValue.validTarget(Annotation a) = false; 081 eq ElementConstantValue.validTarget(Annotation a) { 082 Variable v = getExpr().varDecl(); 083 if (v == null) { 084 return true; 085 } 086 return v.hostType().fullName().equals("java.lang.annotation.ElementType") && a.mayUseAnnotationTarget(v.name()); 087 } 088 eq ElementArrayValue.validTarget(Annotation a) { 089 for (int i = 0; i < getNumElementValue(); i++) { 090 if (getElementValue(i).validTarget(a)) { 091 return true; 092 } 093 } 094 return false; 095 } 096 inh boolean Annotation.mayUseAnnotationTarget(String name); 097 // 7.4.1 098 eq AnnotatedCompilationUnit.getModifiers().mayUseAnnotationTarget(String name) = 099 name.equals("PACKAGE"); 100 // 8.1.1, 9.1.1 101 eq TypeDecl.getModifiers().mayUseAnnotationTarget(String name) = 102 name.equals("TYPE"); 103 // 9.6 104 eq AnnotationDecl.getModifiers().mayUseAnnotationTarget(String name) = 105 name.equals("ANNOTATION_TYPE") || name.equals("TYPE"); 106 // 8.3.1, 9.3, 8.9 107 eq FieldDeclaration.getModifiers().mayUseAnnotationTarget(String name) = 108 name.equals("FIELD"); 109 // 8.4.1 110 eq ParameterDeclaration.getModifiers().mayUseAnnotationTarget(String name) = 111 name.equals("PARAMETER"); 112 // 8.4.3, 9.4 113 eq MethodDecl.getModifiers().mayUseAnnotationTarget(String name) = 114 name.equals("METHOD"); 115 // 8.8.3 116 eq ConstructorDecl.getModifiers().mayUseAnnotationTarget(String name) = 117 name.equals("CONSTRUCTOR"); 118 // 14.4 119 eq VariableDeclaration.getModifiers().mayUseAnnotationTarget(String name) = 120 name.equals("LOCAL_VARIABLE"); 121 eq Program.getChild().mayUseAnnotationTarget(String name) = false; 122 eq ElementAnnotationValue.getAnnotation().mayUseAnnotationTarget(String name) = true; 123 124 /* The direct superinterface of an annotation type is always 125 annotation.Annotation.*/ 126 syn lazy List AnnotationDecl.getSuperInterfaceList() { 127 return new List().add(new TypeAccess("java.lang.annotation", "Annotation")); 128 } 129 130 public void AnnotationDecl.typeCheck() { 131 super.typeCheck(); 132 for (int i = 0; i < getNumBodyDecl(); i++) { 133 if (getBodyDecl(i) instanceof MethodDecl) { 134 MethodDecl m = (MethodDecl) getBodyDecl(i); 135 if (!m.type().isValidAnnotationMethodReturnType()) { 136 m.error("invalid type for annotation member"); 137 } 138 if (m.annotationMethodOverride()) { 139 m.errorf("annotation method overrides %s", m.signature()); 140 } 141 } 142 } 143 if (containsElementOf(this)) { 144 error("cyclic annotation element type"); 145 } 146 } 147 /* It is a compile-time error if the return type of a method declared in an 148 annotation type is any type other than one of the following: one of the 149 primitive types, String, Class and any invocation of Class, an enum type 150 (�8.9), an annotation type, or an array (�10) of one of the preceding types.*/ 151 syn boolean TypeDecl.isValidAnnotationMethodReturnType() = false; 152 eq PrimitiveType.isValidAnnotationMethodReturnType() = true; 153 eq ReferenceType.isValidAnnotationMethodReturnType() { 154 if (isString()) { 155 return true; 156 } 157 if (fullName().equals("java.lang.Class")) { 158 return true; 159 } 160 // include generic versions of Class 161 if (erasure().fullName().equals("java.lang.Class")) { 162 return true; 163 } 164 return false; 165 } 166 eq EnumDecl.isValidAnnotationMethodReturnType() = true; 167 168 /** 169 * Nested array types are not valid annotation element types. 170 * <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#jls-9.6.1">JLSv7 $9.6.1</a> 171 */ 172 eq ArrayDecl.isValidAnnotationMethodReturnType() = 173 !componentType().isArrayDecl() && componentType().isValidAnnotationMethodReturnType(); 174 175 eq AnnotationDecl.isValidAnnotationMethodReturnType() = true; 176 177 /* It is also a compile-time error if any method declared in an annotation type has a 178 signature that is override-equivalent to that of any public or protected method 179 declared in class Object or in the interface annotation.Annotation*/ 180 syn boolean MethodDecl.annotationMethodOverride() = 181 !hostType().ancestorMethods(signature()).isEmpty(); 182 183 /* It is a compile-time error if an annotation type T contains an element of 184 type T, either directly or indirectly.*/ 185 syn boolean AnnotationDecl.containsElementOf(TypeDecl typeDecl) circular [false] { 186 for (int i = 0; i < getNumBodyDecl(); i++) { 187 if (getBodyDecl(i) instanceof MethodDecl) { 188 MethodDecl m = (MethodDecl) getBodyDecl(i); 189 if (m.type() == typeDecl) { 190 return true; 191 } 192 if (m.type() instanceof AnnotationDecl && ((AnnotationDecl) m.type()).containsElementOf(typeDecl)) { 193 return true; 194 } 195 } 196 } 197 return false; 198 } 199 200 /* An ElementValue is used to specify a default value. It is a compile-time error 201 if the type of the element is not commensurate (�9.7) with the default value 202 specified. An ElementValue is always FP-strict (�15.4).*/ 203 public void AnnotationMethodDecl.typeCheck() { 204 super.typeCheck(); 205 if (hasDefaultValue() && !type().commensurateWith(getDefaultValue())) { 206 errorf("%s is not commensurate with %s", 207 type().typeName(), getDefaultValue().type().typeName()); 208 } 209 } 210 211 // 9.6.1 Predefined Annotation Types 212 213 // 9.6.1.1 Target 214 public void ElementConstantValue.nameCheck() { 215 if (enclosingAnnotationDecl().fullName().equals("java.lang.annotation.Target")) { 216 Variable v = getExpr().varDecl(); 217 if (v != null && v.hostType().fullName().equals("java.lang.annotation.ElementType")) { 218 if (lookupElementTypeValue(v.name()) != this) { 219 error("repeated annotation target"); 220 } 221 } 222 } 223 } 224 inh ElementValue ElementConstantValue.lookupElementTypeValue(String name); 225 eq ElementArrayValue.getElementValue().lookupElementTypeValue(String name) = 226 definesElementTypeValue(name); 227 eq Program.getChild().lookupElementTypeValue(String name) = null; 228 syn ElementValue ElementValue.definesElementTypeValue(String name) = null; 229 eq ElementConstantValue.definesElementTypeValue(String name) { 230 Variable v = getExpr().varDecl(); 231 if (v != null && v.hostType().fullName().equals("java.lang.annotation.ElementType") && v.name().equals(name)) { 232 return this; 233 } 234 return null; 235 } 236 eq ElementArrayValue.definesElementTypeValue(String name) { 237 for (int i = 0; i < getNumElementValue(); i++) { 238 if (getElementValue(i).definesElementTypeValue(name) != null) { 239 return getElementValue(i).definesElementTypeValue(name); 240 } 241 } 242 return null; 243 } 244 245 // 9.6.1.2 Retention TODO 246 247 248 249 // 9.6.1.3 Inherited 250 /* Indicates that an annotation type is automatically inherited. If an Inherited 251 meta-annotation is present on an annotation type declaration, and the user 252 queries the annotation type on a class declaration, and the class declaration 253 has no annotation for this type, then the class's superclass will automatically 254 be queried for the annotation type. This process will be repeated until an 255 annotation for this type is found, or the top of the class hierarchy (Object) 256 is reached. If no superclass has an annotation for this type, then the query 257 will indicate that the class in question has no such annotation. 258 259 Note that this meta-annotation type has no effect if the annotated type is used 260 to annotate anything other than a class. Note also that this meta-annotation 261 only causes annotations to be inherited from superclasses; annotations on 262 implemented interfaces have no effect.*/ 263 264 syn Annotation Modifiers.annotation(TypeDecl typeDecl) { 265 for (int i = 0; i < getNumModifier(); i++) { 266 if (getModifier(i) instanceof Annotation) { 267 Annotation a = (Annotation) getModifier(i); 268 if (a.type() == typeDecl) { 269 return a; 270 } 271 } 272 } 273 return null; 274 } 275 276 syn boolean Modifiers.hasAnnotation(String packageName, String name) { 277 for (int i = 0; i < getNumModifier(); i++) { 278 if (getModifier(i).isAnnotation(packageName, name)) { 279 return true; 280 } 281 } 282 return false; 283 } 284 285 syn boolean Modifier.isAnnotation(String packageName, String name) = false; 286 eq Annotation.isAnnotation(String packageName, String name) = 287 decl().isType(packageName, name); 288 289 syn boolean TypeDecl.isType(String packageName, String name) = 290 getID().equals(name) && packageName().equals(packageName); 291 292 syn Annotation TypeDecl.annotation(TypeDecl typeDecl) = 293 getModifiers().annotation(typeDecl); 294 295 eq ClassDecl.annotation(TypeDecl typeDecl) { 296 Annotation a = super.annotation(typeDecl); 297 if (a != null) { 298 return a; 299 } 300 if (hasSuperclass()) { 301 // If the queried annotation is itself annotation with @Inherited then 302 // delegate the query to the superclass 303 if (typeDecl.annotation(lookupType("java.lang.annotation", "Inherited")) != null) { 304 return superclass().annotation(typeDecl); 305 } 306 } 307 return null; 308 } 309 310 // 9.6.1.4 Override 311 public void Annotation.checkOverride() { 312 if (decl().fullName().equals("java.lang.Override") && enclosingBodyDecl() instanceof MethodDecl) { 313 MethodDecl m = (MethodDecl) enclosingBodyDecl(); 314 if (!m.hostType().isClassDecl()) { 315 error("override annotation not valid for interface methods"); 316 } else { 317 boolean found = false; 318 for (Iterator iter = m.hostType().ancestorMethods(m.signature()).iterator(); iter.hasNext(); ) { 319 MethodDecl decl = (MethodDecl) iter.next(); 320 if (m.overrides(decl) && decl.hostType().isClassDecl()) { 321 found = true; 322 } 323 } 324 if (!found) { 325 error("method does not override a method from its superclass"); 326 } 327 } 328 } 329 } 330 inh BodyDecl Annotation.enclosingBodyDecl(); 331 332 // 9.6.1.5 SuppressWarnings 333 /* The annotation type SuppressWarnings supports programmer control over warnings 334 otherwise issued by the Java compiler. It contains a single element that is an 335 array of String. If a program declaration is annotated with the annotation 336 @SuppressWarnings(value = {S1, ... , Sk}), then a Java compiler must not report 337 any warning identified by one of S1, ... , Sk if that warning would have been 338 generated as a result of the annotated declaration or any of its parts. 339 Unchecked warnings are identified by the string "unchecked"*/ 340 inh boolean Access.withinSuppressWarnings(String annot); 341 inh boolean BodyDecl.withinSuppressWarnings(String annot); 342 eq Program.getChild().withinSuppressWarnings(String annot) = false; 343 344 eq BodyDecl.getChild().withinSuppressWarnings(String annot) = 345 hasAnnotationSuppressWarnings(annot) || hasAnnotationSuppressWarnings(annot) 346 || withinSuppressWarnings(annot); 347 eq ClassDecl.getSuperClass().withinSuppressWarnings(String annot) = 348 hasAnnotationSuppressWarnings(annot) || withinSuppressWarnings(annot); 349 eq ClassDecl.getImplements().withinSuppressWarnings(String annot) = 350 hasAnnotationSuppressWarnings(annot) || withinSuppressWarnings(annot); 351 eq InterfaceDecl.getSuperInterface().withinSuppressWarnings(String annot) = 352 hasAnnotationSuppressWarnings(annot) || withinSuppressWarnings(annot); 353 inh boolean TypeDecl.withinSuppressWarnings(String annot); 354 355 syn boolean TypeDecl.hasAnnotationSuppressWarnings(String annot) = getModifiers().hasAnnotationSuppressWarnings(annot); 356 syn boolean BodyDecl.hasAnnotationSuppressWarnings(String annot) = false; 357 eq MemberTypeDecl.hasAnnotationSuppressWarnings(String annot) = typeDecl().hasAnnotationSuppressWarnings(annot); 358 eq MethodDecl.hasAnnotationSuppressWarnings(String annot) = getModifiers().hasAnnotationSuppressWarnings(annot); 359 eq ConstructorDecl.hasAnnotationSuppressWarnings(String annot) = getModifiers().hasAnnotationSuppressWarnings(annot); 360 eq FieldDeclaration.hasAnnotationSuppressWarnings(String annot) = getModifiers().hasAnnotationSuppressWarnings(annot); 361 362 syn boolean Modifiers.hasAnnotationSuppressWarnings(String annot) { 363 Annotation a = annotation(lookupType("java.lang", "SuppressWarnings")); 364 if (a != null && a.getNumElementValuePair() == 1 365 && a.getElementValuePair(0).getName().equals("value")) { 366 return a.getElementValuePair(0).getElementValue().hasValue(annot); 367 } 368 return false; 369 } 370 syn boolean ElementValue.hasValue(String annot) = false; 371 eq ElementConstantValue.hasValue(String annot) = 372 getExpr().type().isString() && getExpr().isConstant() 373 && getExpr().constant().stringValue().equals(annot); 374 eq ElementArrayValue.hasValue(String annot) { 375 for (int i = 0; i < getNumElementValue(); i++) { 376 if (getElementValue(i).hasValue(annot)) { 377 return true; 378 } 379 } 380 return false; 381 } 382 383 // 9.6.1.6 Deprecated 384 /*A program element annotated @Deprecated is one that programmers are discouraged 385 from using, typically because it is dangerous, or because a better alternative 386 exists. A Java compiler must produce a warning when a deprecated type, method, 387 field, or constructor is used (overridden, invoked, or referenced by name) 388 unless: 389 * The use is within an entity that itself is is annotated with the annotation @Deprecated; or 390 * The declaration and use are both within the same outermost class; or 391 * The use site is within an entity that is annotated to suppress the 392 warning with the annotation @SuppressWarnings("deprecation") 393 Use of the annotation @Deprecated on a local variable declaration or on a 394 parameter declaration has no effect.*/ 395 syn boolean Modifiers.hasDeprecatedAnnotation() = hasAnnotation("java.lang", "Deprecated"); 396 397 syn boolean TypeDecl.isDeprecated() = getModifiers().hasDeprecatedAnnotation(); 398 syn boolean MemberTypeDecl.isDeprecated() = typeDecl().isDeprecated(); 399 syn boolean MethodDecl.isDeprecated() = getModifiers().hasDeprecatedAnnotation(); 400 syn boolean ConstructorDecl.isDeprecated() = getModifiers().hasDeprecatedAnnotation(); 401 syn boolean FieldDeclaration.isDeprecated() = getModifiers().hasDeprecatedAnnotation(); 402 syn boolean BodyDecl.isDeprecated() = false; 403 404 public void TypeAccess.checkModifiers() { 405 if (decl().isDeprecated() && 406 !withinDeprecatedAnnotation() && 407 (hostType() == null || hostType().topLevelType() != decl().topLevelType()) && 408 !withinSuppressWarnings("deprecation")) 409 warning(decl().typeName() + " has been deprecated"); 410 } 411 412 public void MethodAccess.checkModifiers() { 413 if (decl().isDeprecated() && 414 !withinDeprecatedAnnotation() && 415 hostType().topLevelType() != decl().hostType().topLevelType() && 416 !withinSuppressWarnings("deprecation")) 417 warning(decl().signature() + " in " + decl().hostType().typeName() + " has been deprecated"); 418 } 419 420 public void VarAccess.checkModifiers() { 421 if (decl() instanceof FieldDeclaration) { 422 FieldDeclaration f = (FieldDeclaration) decl(); 423 if (f.isDeprecated() && 424 !withinDeprecatedAnnotation() && 425 hostType().topLevelType() != f.hostType().topLevelType() && 426 !withinSuppressWarnings("deprecation")) 427 warning(f.name() + " in " + f.hostType().typeName() + " has been deprecated"); 428 } 429 } 430 431 public void ConstructorAccess.checkModifiers() { 432 if (decl().isDeprecated() && 433 !withinDeprecatedAnnotation() && 434 hostType().topLevelType() != decl().hostType().topLevelType() && 435 !withinSuppressWarnings("deprecation")) 436 warning(decl().signature() + " in " + decl().hostType().typeName() + " has been deprecated"); 437 } 438 439 public void ClassInstanceExpr.checkModifiers() { 440 if (decl().isDeprecated() && 441 !withinDeprecatedAnnotation() && 442 hostType().topLevelType() != decl().hostType().topLevelType() && 443 !withinSuppressWarnings("deprecation")) 444 warning(decl().signature() + " in " + decl().hostType().typeName() + " has been deprecated"); 445 } 446 447 eq Program.getChild().withinDeprecatedAnnotation() = false; 448 inh boolean Access.withinDeprecatedAnnotation(); 449 inh boolean BodyDecl.withinDeprecatedAnnotation(); 450 451 eq BodyDecl.getChild().withinDeprecatedAnnotation() = 452 isDeprecated() || isDeprecated() || withinDeprecatedAnnotation(); 453 eq ClassDecl.getSuperClass().withinDeprecatedAnnotation() = isDeprecated() || withinDeprecatedAnnotation(); 454 eq ClassDecl.getImplements().withinDeprecatedAnnotation() = isDeprecated() || withinDeprecatedAnnotation(); 455 eq InterfaceDecl.getSuperInterface().withinDeprecatedAnnotation() = isDeprecated() || withinDeprecatedAnnotation(); 456 inh boolean TypeDecl.withinDeprecatedAnnotation(); 457 458 // 9.7 Annotations 459 460 public void Annotation.typeCheck() { 461 if (!decl().isAnnotationDecl()) { 462 /* TypeName names the annotation type corresponding to the annotation. It is a 463 compile-time error if TypeName does not name an annotation type.*/ 464 if (!decl().isUnknown()) { 465 errorf("%s is not an annotation type", decl().typeName()); 466 } 467 } else { 468 TypeDecl typeDecl = decl(); 469 /* It is a compile-time error if a declaration is annotated with more than one 470 annotation for a given annotation type.*/ 471 if (lookupAnnotation(typeDecl) != this) { 472 errorf("duplicate annotation %s", typeDecl.typeName()); 473 } 474 /* Annotations must contain an element-value pair for every element of the 475 corresponding annotation type, except for those elements with default 476 values, or a compile-time error occurs. Annotations may, but are not 477 required to, contain element-value pairs for elements with default values.*/ 478 for (int i = 0; i < typeDecl.getNumBodyDecl(); i++) { 479 if (typeDecl.getBodyDecl(i) instanceof MethodDecl) { 480 MethodDecl decl = (MethodDecl) typeDecl.getBodyDecl(i); 481 if (elementValueFor(decl.name()) == null && (!(decl instanceof AnnotationMethodDecl) || !((AnnotationMethodDecl) decl).hasDefaultValue())) { 482 errorf("missing value for %s", decl.name()); 483 } 484 } 485 } 486 /* The Identifier in an ElementValuePair must be the simple name of one of the 487 elements of the annotation type identified by TypeName in the containing 488 annotation. Otherwise, a compile-time error occurs. (In other words, the 489 identifier in an element-value pair must also be a method name in the interface 490 identified by TypeName.) */ 491 for (int i = 0; i < getNumElementValuePair(); i++) { 492 ElementValuePair pair = getElementValuePair(i); 493 if (typeDecl.memberMethods(pair.getName()).isEmpty()) { 494 errorf("can not find element named %s in %s", pair.getName(), typeDecl.typeName()); 495 } 496 } 497 } 498 checkOverride(); 499 } 500 501 syn lazy TypeDecl Annotation.decl() = getAccess().type(); 502 503 inh Annotation Annotation.lookupAnnotation(TypeDecl typeDecl); 504 inh Annotation ElementAnnotationValue.lookupAnnotation(TypeDecl typeDecl); 505 eq Modifiers.getModifier(int index).lookupAnnotation(TypeDecl typeDecl) { 506 return annotation(typeDecl); 507 } 508 eq ElementAnnotationValue.getAnnotation().lookupAnnotation(TypeDecl typeDecl) = 509 getAnnotation().type() == typeDecl ? getAnnotation() : lookupAnnotation(typeDecl); 510 511 eq Program.getChild(int i).lookupAnnotation(TypeDecl typeDecl) = null; 512 513 syn ElementValue Annotation.elementValueFor(String name) { 514 for (int i = 0; i < getNumElementValuePair(); i++) { 515 ElementValuePair pair = getElementValuePair(i); 516 if (pair.getName().equals(name)) { 517 return pair.getElementValue(); 518 } 519 } 520 return null; 521 } 522 523 /* The annotation type named by an annotation must be accessible (�6.6) at the 524 point where the annotation is used, or a compile-time error occurs. 525 Comment: This is done by the access control framework*/ 526 527 /** 528 * The return type of this method defines the element type of the element-value 529 * pair. An ElementValueArrayInitializer is similar to a normal array initializer 530 * (�10.6), except that annotations are permitted in place of expressions. 531 */ 532 syn lazy TypeDecl ElementValuePair.type() { 533 Map<String,SimpleSet> methodMap = enclosingAnnotationDecl().localMethodsSignatureMap(); 534 SimpleSet set = methodMap.get(getName() + "()"); 535 if (set != null) { 536 return ((MethodDecl) set.iterator().next()).type(); 537 } else { 538 return unknownType(); 539 } 540 } 541 inh TypeDecl ElementValuePair.unknownType(); 542 543 inh TypeDecl ElementValuePair.enclosingAnnotationDecl(); 544 inh TypeDecl ElementValue.enclosingAnnotationDecl(); 545 eq Annotation.getElementValuePair().enclosingAnnotationDecl() = decl(); 546 eq Program.getChild().enclosingAnnotationDecl() = unknownType(); 547 548 /* An element type T is commensurate with an element value V if and only if one of the following conditions is true: 549 * T is an array type E[] and either: 550 o V is an ElementValueArrayInitializer and each ElementValueInitializer (analogous to a variable initializer in an array initializer) in V is commensurate with E. Or 551 o V is an ElementValue that is commensurate with T. 552 * The type of V is assignment compatible (�5.2) with T and, furthermore: 553 o If T is a primitive type or String, V is a constant expression (�15.28). 554 o V is not null. 555 o if T is Class, or an invocation of Class, and V is a class literal (�15.8.2). 556 o If T is an enum type, and V is an enum constant. */ 557 syn boolean TypeDecl.commensurateWith(ElementValue value) = value.commensurateWithTypeDecl(this); 558 syn boolean ElementValue.commensurateWithTypeDecl(TypeDecl type) = false; 559 eq ElementConstantValue.commensurateWithTypeDecl(TypeDecl type) { 560 Expr v = getExpr(); 561 if (!v.type().assignConversionTo(type, v)) { 562 return false; 563 } 564 if ((type.isPrimitive() || type.isString()) && !v.isConstant()) { 565 return false; 566 } 567 if (v.type().isNull()) { 568 return false; 569 } 570 if (type.fullName().equals("java.lang.Class") && !v.isClassAccess()) { 571 return false; 572 } 573 if (type.isEnumDecl() && (v.varDecl() == null || !(v.varDecl() instanceof EnumConstant))) { 574 return false; 575 } 576 return true; 577 } 578 eq ElementAnnotationValue.commensurateWithTypeDecl(TypeDecl type) { 579 return type() == type; 580 } 581 582 eq ArrayDecl.commensurateWith(ElementValue value) = value.commensurateWithArrayDecl(this); 583 syn boolean ElementValue.commensurateWithArrayDecl(ArrayDecl type) = 584 type.componentType().commensurateWith(this); 585 eq ElementArrayValue.commensurateWithArrayDecl(ArrayDecl type) { 586 for (int i = 0; i < getNumElementValue(); i++) { 587 if (!type.componentType().commensurateWith(getElementValue(i))) { 588 return false; 589 } 590 } 591 return true; 592 } 593 /* It is a compile-time error if the element type is not commensurate with the ElementValue.*/ 594 public void ElementValuePair.typeCheck() { 595 if (!type().commensurateWith(getElementValue())) { 596 errorf("can not construct annotation with %s = %s; %s is not commensurate with %s", 597 getName(), getElementValue().prettyPrint(), type().typeName(), getElementValue().type().typeName()); 598 } 599 } 600 601 inh TypeDecl ElementValue.declType(); 602 603 eq ElementValuePair.getChild().declType() = type(); 604 eq ElementArrayValue.getChild().declType() = declType().elementType(); 605 eq AnnotationMethodDecl.getChild().declType() = type(); 606 607 syn TypeDecl ElementValue.type() = unknownType(); 608 eq ElementConstantValue.type() = getExpr().type(); 609 eq ElementAnnotationValue.type() = getAnnotation().type(); 610 611 syn TypeDecl Annotation.type() = getAccess().type(); 612 inh TypeDecl ElementValue.unknownType(); 613 614 /* If the element type is not an annotation type or an array type, ElementValue 615 must be a ConditionalExpression (�15.25) 616 TODO: How to enforce this. Is this already enforced? 617 */ 618 619 /* If the element type is an array type and the corresponding ElementValue is not 620 an ElementValueArrayInitializer, an array value whose sole element is the value 621 represented by the ElementValue is associated with the element. Otherwise, the 622 value represented by ElementValue is associated with the element. */ 623 rewrite ElementValuePair { 624 when(type().isArrayDecl() && getElementValue() instanceof ElementConstantValue) 625 to ElementValuePair { 626 setElementValue(new ElementArrayValue(new List().add(getElementValue()))); 627 return this; 628 } 629 } 630 631 /* An annotation on an annotation type declaration is known as a meta-annotation. 632 An annotation type may be used to annotate its own declaration. More generally, 633 circularities in the transitive closure of the "annotates" relation are 634 permitted. For example, it is legal to annotate an annotation type declaration 635 with another annotation type, and to annotate the latter type's declaration 636 with the former type. (The pre-defined meta-annotation types contain several 637 such circularities.) 638 Comment: no problems with reference attributes. 639 */ 640 syn boolean Annotation.isMetaAnnotation() = hostType().isAnnotationDecl(); 641 inh TypeDecl Annotation.hostType(); 642 syn boolean TypeDecl.isAnnotationDecl() = false; 643 eq AnnotationDecl.isAnnotationDecl() = true; 644 645 // name binding 646 eq Annotation.getAccess().nameType() = NameType.TYPE_NAME; 647 eq ElementConstantValue.getExpr().nameType() = NameType.EXPRESSION_NAME; 648 649 eq AnnotatedCompilationUnit.getModifiers().hostPackage() = packageName(); 650 651 // provide error message for method calls in 652 eq ElementConstantValue.getExpr().methodHost() = enclosingAnnotationDecl().typeName(); 653 654 } 655 656 aspect AnnotationPrettyPrinting { 657 658 public void AnnotatedCompilationUnit.prettyPrint(PrettyPrinter out) { 659 out.print(getModifiers()); 660 super.prettyPrint(out); 661 } 662 663 }