@@ -61,7 +61,7 @@ class Annotation extends @annotation, Expr {
61
61
/**
62
62
* Gets the value of the annotation element with the specified `name`.
63
63
* 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 .
65
65
* To properly handle array values, prefer the predicate `getAnArrayValue`.
66
66
*/
67
67
Expr getValue ( string name ) { filteredAnnotValue ( this , this .getAnnotationElement ( name ) , result ) }
@@ -73,7 +73,9 @@ class Annotation extends @annotation, Expr {
73
73
*
74
74
* If the element value type is an enum type array, use `getAnEnumConstantArrayValue`.
75
75
*/
76
- EnumConstant getEnumConstantValue ( string name ) { result = getValue ( name ) .( FieldRead ) .getField ( ) }
76
+ EnumConstant getEnumConstantValue ( string name ) {
77
+ result = this .getValue ( name ) .( FieldRead ) .getField ( )
78
+ }
77
79
78
80
/**
79
81
* If the value type of the annotation element with the specified `name` is `String`,
@@ -83,9 +85,9 @@ class Annotation extends @annotation, Expr {
83
85
* If the element value type is a string array, use `getAStringArrayValue`.
84
86
*/
85
87
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 ( )
89
91
}
90
92
91
93
/**
@@ -96,9 +98,9 @@ class Annotation extends @annotation, Expr {
96
98
* If the element value type is an `int` array, use `getAnIntArrayValue`.
97
99
*/
98
100
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 ( )
102
104
}
103
105
104
106
/**
@@ -107,19 +109,19 @@ class Annotation extends @annotation, Expr {
107
109
* no explicit value is specified.
108
110
*/
109
111
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 ( )
113
115
}
114
116
115
117
/**
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.
119
121
*
120
122
* If the element value type is a `Class` array, use `getATypeArrayValue`.
121
123
*/
122
- Type getTypeValue ( string name ) { result = getValue ( name ) .( TypeLiteral ) .getReferencedType ( ) }
124
+ Type getTypeValue ( string name ) { result = this . getValue ( name ) .( TypeLiteral ) .getReferencedType ( ) }
123
125
124
126
/** Gets the element being annotated. */
125
127
Element getTarget ( ) { result = this .getAnnotatedElement ( ) }
@@ -134,21 +136,21 @@ class Annotation extends @annotation, Expr {
134
136
* type. This includes default values in case no explicit value is specified.
135
137
*
136
138
* 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.
138
140
*/
139
- Expr getAnArrayValue ( string name ) { result = getArrayValue ( name , _) }
141
+ Expr getAnArrayValue ( string name ) { result = this . getArrayValue ( name , _) }
140
142
141
143
/**
142
144
* DEPRECATED: Predicate has been renamed to `getAnArrayValue`
143
145
*/
144
- deprecated Expr getAValue ( string name ) { result = getAnArrayValue ( name ) }
146
+ deprecated Expr getAValue ( string name ) { result = this . getAnArrayValue ( name ) }
145
147
146
148
/**
147
149
* Gets a value of the annotation element with the specified `name`, which must be declared as an enum
148
150
* type array. This includes default values in case no explicit value is specified.
149
151
*
150
152
* 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.
152
154
*/
153
155
EnumConstant getAnEnumConstantArrayValue ( string name ) {
154
156
result = this .getAnArrayValue ( name ) .( FieldRead ) .getField ( )
@@ -159,7 +161,7 @@ class Annotation extends @annotation, Expr {
159
161
* array. This includes default values in case no explicit value is specified.
160
162
*
161
163
* 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.
163
165
*/
164
166
string getAStringArrayValue ( string name ) {
165
167
result = this .getAnArrayValue ( name ) .( CompileTimeConstantExpr ) .getStringValue ( )
@@ -170,7 +172,7 @@ class Annotation extends @annotation, Expr {
170
172
* array. This includes default values in case no explicit value is specified.
171
173
*
172
174
* 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.
174
176
*/
175
177
int getAnIntArrayValue ( string name ) {
176
178
result = this .getAnArrayValue ( name ) .( CompileTimeConstantExpr ) .getIntValue ( )
@@ -181,7 +183,7 @@ class Annotation extends @annotation, Expr {
181
183
* array. This includes default values in case no explicit value is specified.
182
184
*
183
185
* 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.
185
187
*/
186
188
Type getATypeArrayValue ( string name ) {
187
189
result = this .getAnArrayValue ( name ) .( TypeLiteral ) .getReferencedType ( )
@@ -233,10 +235,10 @@ private predicate sourceAnnotValue(Annotation a, Method m, Expr val) {
233
235
/** An abstract representation of language elements that can be annotated. */
234
236
class Annotatable extends Element {
235
237
/** Holds if this element has an annotation, including inherited annotations. */
236
- predicate hasAnnotation ( ) { exists ( getAnAnnotation ( ) ) }
238
+ predicate hasAnnotation ( ) { exists ( this . getAnAnnotation ( ) ) }
237
239
238
240
/** Holds if this element has a declared annotation, excluding inherited annotations. */
239
- predicate hasDeclaredAnnotation ( ) { exists ( getADeclaredAnnotation ( ) ) }
241
+ predicate hasDeclaredAnnotation ( ) { exists ( this . getADeclaredAnnotation ( ) ) }
240
242
241
243
/**
242
244
* Holds if this element has the specified annotation, including inherited
@@ -253,21 +255,23 @@ class Annotatable extends Element {
253
255
* The results only include _direct_ annotations; _indirect_ annotations, that is
254
256
* repeated annotations in an (implicit) container annotation, are not included.
255
257
*/
256
- // This predicate is overridden by Class to consider inherited annotations
257
258
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
+ }
259
263
260
264
/**
261
265
* Gets an annotation that is declared on this element, excluding inherited annotations.
262
266
*/
263
267
Annotation getADeclaredAnnotation ( ) { result .getAnnotatedElement ( ) = this }
264
268
265
269
/** 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
267
270
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
268
272
exists ( AnnotationType t , Annotation containerAnn |
269
273
t = result .getType ( ) and
270
- containerAnn = getADeclaredAnnotation ( ) and
274
+ containerAnn = this . getADeclaredAnnotation ( ) and
271
275
containerAnn .getType ( ) = t .getContainingAnnotationType ( )
272
276
|
273
277
result = containerAnn .getAnArrayValue ( "value" )
@@ -276,12 +280,14 @@ class Annotatable extends Element {
276
280
277
281
private Annotation getADeclaredAssociatedAnnotation ( AnnotationType t ) {
278
282
// Direct or indirect annotation
279
- result .getType ( ) = t and result = [ getADeclaredAnnotation ( ) , getAnIndirectAnnotation ( ) ]
283
+ result .getType ( ) = t and
284
+ result = [ this .getADeclaredAnnotation ( ) , this .getAnIndirectAnnotation ( ) ]
280
285
}
281
286
282
287
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 )
285
291
else (
286
292
// Only if neither a direct nor an indirect annotation is present look for an inherited one
287
293
t .isInherited ( ) and
@@ -297,8 +303,7 @@ class Annotatable extends Element {
297
303
* - If an annotation of a type is neither directly nor indirectly present
298
304
* the result is an associated inherited annotation (recursively)
299
305
*/
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 ( _) }
302
307
303
308
/**
304
309
* Holds if this or any enclosing `Annotatable` has a `@SuppressWarnings("<category>")`
@@ -333,12 +338,12 @@ class AnnotationType extends Interface {
333
338
334
339
/** Holds if this annotation type is annotated with the meta-annotation `@Inherited`. */
335
340
predicate isInherited ( ) {
336
- getADeclaredAnnotation ( ) .getType ( ) .hasQualifiedName ( "java.lang.annotation" , "Inherited" )
341
+ this . getADeclaredAnnotation ( ) .getType ( ) .hasQualifiedName ( "java.lang.annotation" , "Inherited" )
337
342
}
338
343
339
344
/** Holds if this annotation type is annotated with the meta-annotation `@Documented`. */
340
345
predicate isDocumented ( ) {
341
- getADeclaredAnnotation ( ) .getType ( ) .hasQualifiedName ( "java.lang.annotation" , "Documented" )
346
+ this . getADeclaredAnnotation ( ) .getType ( ) .hasQualifiedName ( "java.lang.annotation" , "Documented" )
342
347
}
343
348
344
349
/**
@@ -347,8 +352,8 @@ class AnnotationType extends Interface {
347
352
* policy is specified the result is `CLASS`.
348
353
*/
349
354
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 ( )
352
357
else
353
358
// If not explicitly specified retention is CLASS
354
359
result = "CLASS"
@@ -358,29 +363,49 @@ class AnnotationType extends Interface {
358
363
* Holds if the element type is a possible target for this annotation type.
359
364
* The `elementType` is the name of one of the `java.lang.annotation.ElementType`
360
365
* 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 .
362
367
*/
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
365
368
bindingset [ elementType]
366
369
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 ( )
369
383
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"
373
398
}
374
399
375
400
/** 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 }
377
402
378
403
/**
379
404
* If this annotation type is annotated with the meta-annotation `@Repeatable`,
380
405
* gets the annotation type which acts as _containing annotation type_.
381
406
*/
382
407
AnnotationType getContainingAnnotationType ( ) {
383
- result = getADeclaredAnnotation ( ) .( RepeatableAnnotation ) .getContainingType ( )
408
+ result = this . getADeclaredAnnotation ( ) .( RepeatableAnnotation ) .getContainingType ( )
384
409
}
385
410
}
386
411
0 commit comments