@@ -66,6 +66,16 @@ class Annotation extends @annotation, Expr {
66
66
*/
67
67
Expr getValue ( string name ) { filteredAnnotValue ( this , this .getAnnotationElement ( name ) , result ) }
68
68
69
+ /**
70
+ * Gets the value of the annotation element, if its type is not an array.
71
+ * This guarantees that for consistency even elements of type array with a
72
+ * single value have no result, to prevent accidental error-prone usage.
73
+ */
74
+ private Expr getNonArrayValue ( string name ) {
75
+ result = this .getValue ( name ) and
76
+ not this .getAnnotationElement ( name ) .getType ( ) instanceof Array
77
+ }
78
+
69
79
/**
70
80
* If the value type of the annotation element with the specified `name` is an enum type,
71
81
* gets the enum constant used as value for that element. This includes default values in
@@ -74,7 +84,7 @@ class Annotation extends @annotation, Expr {
74
84
* If the element value type is an enum type array, use `getAnEnumConstantArrayValue`.
75
85
*/
76
86
EnumConstant getEnumConstantValue ( string name ) {
77
- result = this .getValue ( name ) .( FieldRead ) .getField ( )
87
+ result = this .getNonArrayValue ( name ) .( FieldRead ) .getField ( )
78
88
}
79
89
80
90
/**
@@ -87,20 +97,23 @@ class Annotation extends @annotation, Expr {
87
97
string getStringValue ( string name ) {
88
98
// Uses CompileTimeConstantExpr instead of StringLiteral because this can for example
89
99
// be a read from a final variable as well.
90
- result = this .getValue ( name ) .( CompileTimeConstantExpr ) .getStringValue ( )
100
+ result = this .getNonArrayValue ( name ) .( CompileTimeConstantExpr ) .getStringValue ( )
91
101
}
92
102
93
103
/**
94
- * If the value type of the annotation element with the specified `name` is `int`,
95
- * gets the int value used for that element. This includes default values in case no
96
- * explicit value is specified.
104
+ * If the value type of the annotation element with the specified `name` is `int` or
105
+ * a smaller integral type or `char`, gets the int value used for that element.
106
+ * This includes default values in case no explicit value is specified.
97
107
*
98
- * If the element value type is an `int` array, use `getAnIntArrayValue`.
108
+ * If the element value type is an `int` array or an array of a smaller integral
109
+ * type or `char`, use `getAnIntArrayValue`.
99
110
*/
100
111
int getIntValue ( string name ) {
101
112
// Uses CompileTimeConstantExpr instead of IntegerLiteral because this can for example
102
113
// be a read from a final variable as well.
103
- result = this .getValue ( name ) .( CompileTimeConstantExpr ) .getIntValue ( )
114
+ result = this .getNonArrayValue ( name ) .( CompileTimeConstantExpr ) .getIntValue ( ) and
115
+ // Verify that type is integral; ignore floating point elements with IntegerLiteral as value
116
+ this .getAnnotationElement ( name ) .getType ( ) .hasName ( [ "byte" , "short" , "int" , "char" ] )
104
117
}
105
118
106
119
/**
@@ -111,7 +124,7 @@ class Annotation extends @annotation, Expr {
111
124
boolean getBooleanValue ( string name ) {
112
125
// Uses CompileTimeConstantExpr instead of BooleanLiteral because this can for example
113
126
// be a read from a final variable as well.
114
- result = this .getValue ( name ) .( CompileTimeConstantExpr ) .getBooleanValue ( )
127
+ result = this .getNonArrayValue ( name ) .( CompileTimeConstantExpr ) .getBooleanValue ( )
115
128
}
116
129
117
130
/**
@@ -121,7 +134,9 @@ class Annotation extends @annotation, Expr {
121
134
*
122
135
* If the element value type is a `Class` array, use `getATypeArrayValue`.
123
136
*/
124
- Type getTypeValue ( string name ) { result = this .getValue ( name ) .( TypeLiteral ) .getReferencedType ( ) }
137
+ Type getTypeValue ( string name ) {
138
+ result = this .getNonArrayValue ( name ) .( TypeLiteral ) .getReferencedType ( )
139
+ }
125
140
126
141
/** Gets the element being annotated. */
127
142
Element getTarget ( ) { result = this .getAnnotatedElement ( ) }
@@ -169,13 +184,16 @@ class Annotation extends @annotation, Expr {
169
184
170
185
/**
171
186
* Gets a value of the annotation element with the specified `name`, which must be declared as an `int`
172
- * array. This includes default values in case no explicit value is specified.
187
+ * array or an array of a smaller integral type or `char`. This includes default values in case no
188
+ * explicit value is specified.
173
189
*
174
190
* If the annotation element is defined with an array initializer, then the result will be one of the
175
191
* elements of that array. Otherwise, the result will be the single expression used as value.
176
192
*/
177
193
int getAnIntArrayValue ( string name ) {
178
- result = this .getAnArrayValue ( name ) .( CompileTimeConstantExpr ) .getIntValue ( )
194
+ result = this .getAnArrayValue ( name ) .( CompileTimeConstantExpr ) .getIntValue ( ) and
195
+ // Verify that type is integral; ignore floating point elements with IntegerLiteral as value
196
+ this .getAnnotationElement ( name ) .getType ( ) .hasName ( [ "byte[]" , "short[]" , "int[]" , "char[]" ] )
179
197
}
180
198
181
199
/**
@@ -194,14 +212,16 @@ class Annotation extends @annotation, Expr {
194
212
* declared as an array type. This includes default values in case no explicit value is specified.
195
213
*
196
214
* If the annotation element is defined with an array initializer, then the result will be the element
197
- * at the given index of that array. Otherwise, the result will be the single expression defined for
198
- * the value and the `index` will be 0.
215
+ * at the given index of that array, starting at 0 . Otherwise, the result will be the single expression
216
+ * defined for the value and the `index` will be 0.
199
217
*/
200
218
Expr getArrayValue ( string name , int index ) {
201
219
this .getType ( ) .getAnnotationElement ( name ) .getType ( ) instanceof Array and
202
220
exists ( Expr value | value = this .getValue ( name ) |
203
221
if value instanceof ArrayInit
204
- then result = value .( ArrayInit ) .getInit ( index )
222
+ then
223
+ // TODO: Currently reports incorrect index values in some cases, see https://github.com/github/codeql/issues/8645
224
+ result = value .( ArrayInit ) .getInit ( index )
205
225
else (
206
226
index = 0 and result = value
207
227
)
@@ -234,15 +254,21 @@ private predicate sourceAnnotValue(Annotation a, Method m, Expr val) {
234
254
235
255
/** An abstract representation of language elements that can be annotated. */
236
256
class Annotatable extends Element {
237
- /** Holds if this element has an annotation, including inherited annotations. */
257
+ /**
258
+ * Holds if this element has an annotation, including inherited annotations.
259
+ * The retention policy of the annotation type is not considered.
260
+ */
238
261
predicate hasAnnotation ( ) { exists ( this .getAnAnnotation ( ) ) }
239
262
240
- /** Holds if this element has a declared annotation, excluding inherited annotations. */
263
+ /**
264
+ * Holds if this element has a declared annotation, excluding inherited annotations.
265
+ * The retention policy of the annotation type is not considered.
266
+ */
241
267
predicate hasDeclaredAnnotation ( ) { exists ( this .getADeclaredAnnotation ( ) ) }
242
268
243
269
/**
244
270
* Holds if this element has the specified annotation, including inherited
245
- * annotations.
271
+ * annotations. The retention policy of the annotation type is not considered.
246
272
*/
247
273
predicate hasAnnotation ( string package , string name ) {
248
274
exists ( AnnotationType at | at = this .getAnAnnotation ( ) .getType ( ) |
@@ -254,6 +280,7 @@ class Annotatable extends Element {
254
280
* Gets an annotation that applies to this element, including inherited annotations.
255
281
* The results only include _direct_ annotations; _indirect_ annotations, that is
256
282
* repeated annotations in an (implicit) container annotation, are not included.
283
+ * The retention policy of the annotation type is not considered.
257
284
*/
258
285
cached
259
286
Annotation getAnAnnotation ( ) {
@@ -263,6 +290,7 @@ class Annotatable extends Element {
263
290
264
291
/**
265
292
* Gets an annotation that is declared on this element, excluding inherited annotations.
293
+ * The retention policy of the annotation type is not considered.
266
294
*/
267
295
Annotation getADeclaredAnnotation ( ) { result .getAnnotatedElement ( ) = this }
268
296
@@ -302,6 +330,8 @@ class Annotatable extends Element {
302
330
* - An annotation indirectly present on this element (in the form of a repeated annotation), or
303
331
* - If an annotation of a type is neither directly nor indirectly present
304
332
* the result is an associated inherited annotation (recursively)
333
+ *
334
+ * The retention policy of the annotation type is not considered.
305
335
*/
306
336
Annotation getAnAssociatedAnnotation ( ) { result = this .getAnAssociatedAnnotation ( _) }
307
337
@@ -320,6 +350,11 @@ class Annotatable extends Element {
320
350
or
321
351
this .( NestedClass ) .getEnclosingType ( ) .suppressesWarningsAbout ( category )
322
352
or
353
+ this .( LocalClassOrInterface )
354
+ .getLocalTypeDeclStmt ( )
355
+ .getEnclosingCallable ( )
356
+ .suppressesWarningsAbout ( category )
357
+ or
323
358
this .( LocalVariableDecl ) .getCallable ( ) .suppressesWarningsAbout ( category )
324
359
}
325
360
}
0 commit comments