@@ -61,7 +61,7 @@ class Annotation extends @annotation, Expr {
6161 /**
6262 * Gets the value of the annotation element with the specified `name`.
6363 * This includes default values in case no explicit value is specified.
64- * For elements with an array value type this might have an `ArrayInit` as result .
64+ * For elements with an array value type this might get an `ArrayInit` instance .
6565 * To properly handle array values, prefer the predicate `getAnArrayValue`.
6666 */
6767 Expr getValue ( string name ) { filteredAnnotValue ( this , this .getAnnotationElement ( name ) , result ) }
@@ -73,7 +73,9 @@ class Annotation extends @annotation, Expr {
7373 *
7474 * If the element value type is an enum type array, use `getAnEnumConstantArrayValue`.
7575 */
76- EnumConstant getEnumConstantValue ( string name ) { result = getValue ( name ) .( FieldRead ) .getField ( ) }
76+ EnumConstant getEnumConstantValue ( string name ) {
77+ result = this .getValue ( name ) .( FieldRead ) .getField ( )
78+ }
7779
7880 /**
7981 * If the value type of the annotation element with the specified `name` is `String`,
@@ -83,9 +85,9 @@ class Annotation extends @annotation, Expr {
8385 * If the element value type is a string array, use `getAStringArrayValue`.
8486 */
8587 string getStringValue ( string name ) {
86- // Uses CompileTimeConstantExpr instead of StringLiteral because value can
87- // be read of final variable as well
88- result = getValue ( name ) .( CompileTimeConstantExpr ) .getStringValue ( )
88+ // Uses CompileTimeConstantExpr instead of StringLiteral because this can for example
89+ // be a read from a final variable as well.
90+ result = this . getValue ( name ) .( CompileTimeConstantExpr ) .getStringValue ( )
8991 }
9092
9193 /**
@@ -96,9 +98,9 @@ class Annotation extends @annotation, Expr {
9698 * If the element value type is an `int` array, use `getAnIntArrayValue`.
9799 */
98100 int getIntValue ( string name ) {
99- // Uses CompileTimeConstantExpr instead of IntegerLiteral because value can
100- // be read of final variable as well
101- result = getValue ( name ) .( CompileTimeConstantExpr ) .getIntValue ( )
101+ // Uses CompileTimeConstantExpr instead of IntegerLiteral because this can for example
102+ // be a read from a final variable as well.
103+ result = this . getValue ( name ) .( CompileTimeConstantExpr ) .getIntValue ( )
102104 }
103105
104106 /**
@@ -107,19 +109,19 @@ class Annotation extends @annotation, Expr {
107109 * no explicit value is specified.
108110 */
109111 boolean getBooleanValue ( string name ) {
110- // Uses CompileTimeConstantExpr instead of BooleanLiteral because value can
111- // be read of final variable as well
112- result = getValue ( name ) .( CompileTimeConstantExpr ) .getBooleanValue ( )
112+ // Uses CompileTimeConstantExpr instead of BooleanLiteral because this can for example
113+ // be a read from a final variable as well.
114+ result = this . getValue ( name ) .( CompileTimeConstantExpr ) .getBooleanValue ( )
113115 }
114116
115117 /**
116- * If the annotation element with the specified `name` has a Java ` Class` as value type ,
117- * gets the referenced type used as value for that element . This includes default values
118- * in case no explicit value is specified.
118+ * If the value type of the annotation element with the specified `name` is `java.lang. Class`,
119+ * gets the type referred to by that `Class` . This includes default values in case no explicit
120+ * value is specified.
119121 *
120122 * If the element value type is a `Class` array, use `getATypeArrayValue`.
121123 */
122- Type getTypeValue ( string name ) { result = getValue ( name ) .( TypeLiteral ) .getReferencedType ( ) }
124+ Type getTypeValue ( string name ) { result = this . getValue ( name ) .( TypeLiteral ) .getReferencedType ( ) }
123125
124126 /** Gets the element being annotated. */
125127 Element getTarget ( ) { result = this .getAnnotatedElement ( ) }
@@ -134,21 +136,21 @@ class Annotation extends @annotation, Expr {
134136 * type. This includes default values in case no explicit value is specified.
135137 *
136138 * If the annotation element is defined with an array initializer, then the result will be one of the
137- * elements of that array. Otherwise, the result will be the single expression defined for the value.
139+ * elements of that array. Otherwise, the result will be the single expression used as value.
138140 */
139- Expr getAnArrayValue ( string name ) { result = getArrayValue ( name , _) }
141+ Expr getAnArrayValue ( string name ) { result = this . getArrayValue ( name , _) }
140142
141143 /**
142144 * DEPRECATED: Predicate has been renamed to `getAnArrayValue`
143145 */
144- deprecated Expr getAValue ( string name ) { result = getAnArrayValue ( name ) }
146+ deprecated Expr getAValue ( string name ) { result = this . getAnArrayValue ( name ) }
145147
146148 /**
147149 * Gets a value of the annotation element with the specified `name`, which must be declared as an enum
148150 * type array. This includes default values in case no explicit value is specified.
149151 *
150152 * If the annotation element is defined with an array initializer, then the result will be one of the
151- * elements of that array. Otherwise, the result will be the single expression defined for the value.
153+ * elements of that array. Otherwise, the result will be the single expression used as value.
152154 */
153155 EnumConstant getAnEnumConstantArrayValue ( string name ) {
154156 result = this .getAnArrayValue ( name ) .( FieldRead ) .getField ( )
@@ -159,7 +161,7 @@ class Annotation extends @annotation, Expr {
159161 * array. This includes default values in case no explicit value is specified.
160162 *
161163 * If the annotation element is defined with an array initializer, then the result will be one of the
162- * elements of that array. Otherwise, the result will be the single expression defined for the value.
164+ * elements of that array. Otherwise, the result will be the single expression used as value.
163165 */
164166 string getAStringArrayValue ( string name ) {
165167 result = this .getAnArrayValue ( name ) .( CompileTimeConstantExpr ) .getStringValue ( )
@@ -170,7 +172,7 @@ class Annotation extends @annotation, Expr {
170172 * array. This includes default values in case no explicit value is specified.
171173 *
172174 * If the annotation element is defined with an array initializer, then the result will be one of the
173- * elements of that array. Otherwise, the result will be the single expression defined for the value.
175+ * elements of that array. Otherwise, the result will be the single expression used as value.
174176 */
175177 int getAnIntArrayValue ( string name ) {
176178 result = this .getAnArrayValue ( name ) .( CompileTimeConstantExpr ) .getIntValue ( )
@@ -181,7 +183,7 @@ class Annotation extends @annotation, Expr {
181183 * array. This includes default values in case no explicit value is specified.
182184 *
183185 * If the annotation element is defined with an array initializer, then the result will be one of the
184- * elements of that array. Otherwise, the result will be the single expression defined for the value.
186+ * elements of that array. Otherwise, the result will be the single expression used as value.
185187 */
186188 Type getATypeArrayValue ( string name ) {
187189 result = this .getAnArrayValue ( name ) .( TypeLiteral ) .getReferencedType ( )
@@ -233,10 +235,10 @@ private predicate sourceAnnotValue(Annotation a, Method m, Expr val) {
233235/** An abstract representation of language elements that can be annotated. */
234236class Annotatable extends Element {
235237 /** Holds if this element has an annotation, including inherited annotations. */
236- predicate hasAnnotation ( ) { exists ( getAnAnnotation ( ) ) }
238+ predicate hasAnnotation ( ) { exists ( this . getAnAnnotation ( ) ) }
237239
238240 /** Holds if this element has a declared annotation, excluding inherited annotations. */
239- predicate hasDeclaredAnnotation ( ) { exists ( getADeclaredAnnotation ( ) ) }
241+ predicate hasDeclaredAnnotation ( ) { exists ( this . getADeclaredAnnotation ( ) ) }
240242
241243 /**
242244 * Holds if this element has the specified annotation, including inherited
@@ -253,21 +255,23 @@ class Annotatable extends Element {
253255 * The results only include _direct_ annotations; _indirect_ annotations, that is
254256 * repeated annotations in an (implicit) container annotation, are not included.
255257 */
256- // This predicate is overridden by Class to consider inherited annotations
257258 cached
258- Annotation getAnAnnotation ( ) { result = getADeclaredAnnotation ( ) }
259+ Annotation getAnAnnotation ( ) {
260+ // This predicate is overridden by Class to consider inherited annotations
261+ result = this .getADeclaredAnnotation ( )
262+ }
259263
260264 /**
261265 * Gets an annotation that is declared on this element, excluding inherited annotations.
262266 */
263267 Annotation getADeclaredAnnotation ( ) { result .getAnnotatedElement ( ) = this }
264268
265269 /** Gets an _indirect_ (= repeated) annotation. */
266- // 'indirect' as defined by https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/AnnotatedElement.html
267270 private Annotation getAnIndirectAnnotation ( ) {
271+ // 'indirect' as defined by https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/AnnotatedElement.html
268272 exists ( AnnotationType t , Annotation containerAnn |
269273 t = result .getType ( ) and
270- containerAnn = getADeclaredAnnotation ( ) and
274+ containerAnn = this . getADeclaredAnnotation ( ) and
271275 containerAnn .getType ( ) = t .getContainingAnnotationType ( )
272276 |
273277 result = containerAnn .getAnArrayValue ( "value" )
@@ -276,12 +280,14 @@ class Annotatable extends Element {
276280
277281 private Annotation getADeclaredAssociatedAnnotation ( AnnotationType t ) {
278282 // Direct or indirect annotation
279- result .getType ( ) = t and result = [ getADeclaredAnnotation ( ) , getAnIndirectAnnotation ( ) ]
283+ result .getType ( ) = t and
284+ result = [ this .getADeclaredAnnotation ( ) , this .getAnIndirectAnnotation ( ) ]
280285 }
281286
282287 private Annotation getAnAssociatedAnnotation ( AnnotationType t ) {
283- if exists ( getADeclaredAssociatedAnnotation ( t ) )
284- then result = getADeclaredAssociatedAnnotation ( t )
288+ // 'associated' as defined by https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/AnnotatedElement.html
289+ if exists ( this .getADeclaredAssociatedAnnotation ( t ) )
290+ then result = this .getADeclaredAssociatedAnnotation ( t )
285291 else (
286292 // Only if neither a direct nor an indirect annotation is present look for an inherited one
287293 t .isInherited ( ) and
@@ -297,8 +303,7 @@ class Annotatable extends Element {
297303 * - If an annotation of a type is neither directly nor indirectly present
298304 * the result is an associated inherited annotation (recursively)
299305 */
300- // 'associated' as defined by https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/AnnotatedElement.html
301- Annotation getAnAssociatedAnnotation ( ) { result = getAnAssociatedAnnotation ( _) }
306+ Annotation getAnAssociatedAnnotation ( ) { result = this .getAnAssociatedAnnotation ( _) }
302307
303308 /**
304309 * Holds if this or any enclosing `Annotatable` has a `@SuppressWarnings("<category>")`
@@ -333,12 +338,12 @@ class AnnotationType extends Interface {
333338
334339 /** Holds if this annotation type is annotated with the meta-annotation `@Inherited`. */
335340 predicate isInherited ( ) {
336- getADeclaredAnnotation ( ) .getType ( ) .hasQualifiedName ( "java.lang.annotation" , "Inherited" )
341+ this . getADeclaredAnnotation ( ) .getType ( ) .hasQualifiedName ( "java.lang.annotation" , "Inherited" )
337342 }
338343
339344 /** Holds if this annotation type is annotated with the meta-annotation `@Documented`. */
340345 predicate isDocumented ( ) {
341- getADeclaredAnnotation ( ) .getType ( ) .hasQualifiedName ( "java.lang.annotation" , "Documented" )
346+ this . getADeclaredAnnotation ( ) .getType ( ) .hasQualifiedName ( "java.lang.annotation" , "Documented" )
342347 }
343348
344349 /**
@@ -347,8 +352,8 @@ class AnnotationType extends Interface {
347352 * policy is specified the result is `CLASS`.
348353 */
349354 string getRetentionPolicy ( ) {
350- if getADeclaredAnnotation ( ) instanceof RetentionAnnotation
351- then result = getADeclaredAnnotation ( ) .( RetentionAnnotation ) .getRetentionPolicy ( )
355+ if this . getADeclaredAnnotation ( ) instanceof RetentionAnnotation
356+ then result = this . getADeclaredAnnotation ( ) .( RetentionAnnotation ) .getRetentionPolicy ( )
352357 else
353358 // If not explicitly specified retention is CLASS
354359 result = "CLASS"
@@ -358,29 +363,49 @@ class AnnotationType extends Interface {
358363 * Holds if the element type is a possible target for this annotation type.
359364 * The `elementType` is the name of one of the `java.lang.annotation.ElementType`
360365 * enum constants. If no explicit target is specified for this annotation type
361- * it is considered to be applicable to all elements .
366+ * it is considered to be applicable in all declaration contexts .
362367 */
363- // Note: Cannot use a predicate with string as result because annotation type without
364- // explicit @Target can be applied to all targets, requiring to hardcode element types here
365368 bindingset [ elementType]
366369 predicate isATargetType ( string elementType ) {
367- if getADeclaredAnnotation ( ) instanceof TargetAnnotation
368- then elementType = getADeclaredAnnotation ( ) .( TargetAnnotation ) .getATargetElementType ( )
370+ /*
371+ * Note: Cannot use a predicate with string as result because annotation type without
372+ * explicit @Target can be applied in all declaration contexts, requiring to hardcode
373+ * element types here; then the results could become outdated if this predicate is not
374+ * updated for future JDK versions, or it could have irritating results, e.g. RECORD_COMPONENT
375+ * for a database created for Java 8.
376+ *
377+ * Could in theory read java.lang.annotation.ElementType constants from database, but might
378+ * be brittle in case ElementType is not present in the database for whatever reason.
379+ */
380+
381+ if this .getADeclaredAnnotation ( ) instanceof TargetAnnotation
382+ then elementType = this .getADeclaredAnnotation ( ) .( TargetAnnotation ) .getATargetElementType ( )
369383 else
370- // No Target annotation means "applicable to all contexts" since JDK 14, see https://bugs.openjdk.java.net/browse/JDK-8231435
371- // The compiler does not completely implement that, but pretend it did
372- any ( )
384+ /*
385+ * Behavior for missing @Target annotation changed between Java versions. In older Java
386+ * versions it allowed usage in most (but not all) declaration contexts. Then for Java 14
387+ * JDK-8231435 changed it to allow usage in all declaration and type contexts. In Java 17
388+ * it was changed by JDK-8261610 to only allow usage in all declaration contexts, but not
389+ * in type contexts anymore. However, during these changes javac did not always comply with
390+ * the specification, see for example JDK-8254023.
391+ *
392+ * For simplicity pretend the latest behavior defined by the JLS applied in all versions;
393+ * that means any declaration context is allowed, but type contexts (represented by TYPE_USE,
394+ * see JLS 17 section 9.6.4.1) are not allowed.
395+ */
396+
397+ elementType != "TYPE_USE"
373398 }
374399
375400 /** Holds if this annotation type is annotated with the meta-annotation `@Repeatable`. */
376- predicate isRepeatable ( ) { getADeclaredAnnotation ( ) instanceof RepeatableAnnotation }
401+ predicate isRepeatable ( ) { this . getADeclaredAnnotation ( ) instanceof RepeatableAnnotation }
377402
378403 /**
379404 * If this annotation type is annotated with the meta-annotation `@Repeatable`,
380405 * gets the annotation type which acts as _containing annotation type_.
381406 */
382407 AnnotationType getContainingAnnotationType ( ) {
383- result = getADeclaredAnnotation ( ) .( RepeatableAnnotation ) .getContainingType ( )
408+ result = this . getADeclaredAnnotation ( ) .( RepeatableAnnotation ) .getContainingType ( )
384409 }
385410}
386411
0 commit comments