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