@@ -66,6 +66,16 @@ class Annotation extends @annotation, Expr {
6666 */
6767 Expr getValue ( string name ) { filteredAnnotValue ( this , this .getAnnotationElement ( name ) , result ) }
6868
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+
6979 /**
7080 * If the value type of the annotation element with the specified `name` is an enum type,
7181 * gets the enum constant used as value for that element. This includes default values in
@@ -74,7 +84,7 @@ class Annotation extends @annotation, Expr {
7484 * If the element value type is an enum type array, use `getAnEnumConstantArrayValue`.
7585 */
7686 EnumConstant getEnumConstantValue ( string name ) {
77- result = this .getValue ( name ) .( FieldRead ) .getField ( )
87+ result = this .getNonArrayValue ( name ) .( FieldRead ) .getField ( )
7888 }
7989
8090 /**
@@ -87,20 +97,23 @@ class Annotation extends @annotation, Expr {
8797 string getStringValue ( string name ) {
8898 // Uses CompileTimeConstantExpr instead of StringLiteral because this can for example
8999 // be a read from a final variable as well.
90- result = this .getValue ( name ) .( CompileTimeConstantExpr ) .getStringValue ( )
100+ result = this .getNonArrayValue ( name ) .( CompileTimeConstantExpr ) .getStringValue ( )
91101 }
92102
93103 /**
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.
97107 *
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`.
99110 */
100111 int getIntValue ( string name ) {
101112 // Uses CompileTimeConstantExpr instead of IntegerLiteral because this can for example
102113 // 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" ] )
104117 }
105118
106119 /**
@@ -111,7 +124,7 @@ class Annotation extends @annotation, Expr {
111124 boolean getBooleanValue ( string name ) {
112125 // Uses CompileTimeConstantExpr instead of BooleanLiteral because this can for example
113126 // be a read from a final variable as well.
114- result = this .getValue ( name ) .( CompileTimeConstantExpr ) .getBooleanValue ( )
127+ result = this .getNonArrayValue ( name ) .( CompileTimeConstantExpr ) .getBooleanValue ( )
115128 }
116129
117130 /**
@@ -121,7 +134,9 @@ class Annotation extends @annotation, Expr {
121134 *
122135 * If the element value type is a `Class` array, use `getATypeArrayValue`.
123136 */
124- Type getTypeValue ( string name ) { result = this .getValue ( name ) .( TypeLiteral ) .getReferencedType ( ) }
137+ Type getTypeValue ( string name ) {
138+ result = this .getNonArrayValue ( name ) .( TypeLiteral ) .getReferencedType ( )
139+ }
125140
126141 /** Gets the element being annotated. */
127142 Element getTarget ( ) { result = this .getAnnotatedElement ( ) }
@@ -169,13 +184,16 @@ class Annotation extends @annotation, Expr {
169184
170185 /**
171186 * 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.
173189 *
174190 * If the annotation element is defined with an array initializer, then the result will be one of the
175191 * elements of that array. Otherwise, the result will be the single expression used as value.
176192 */
177193 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[]" ] )
179197 }
180198
181199 /**
@@ -194,14 +212,16 @@ class Annotation extends @annotation, Expr {
194212 * declared as an array type. This includes default values in case no explicit value is specified.
195213 *
196214 * 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.
199217 */
200218 Expr getArrayValue ( string name , int index ) {
201219 this .getType ( ) .getAnnotationElement ( name ) .getType ( ) instanceof Array and
202220 exists ( Expr value | value = this .getValue ( name ) |
203221 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 )
205225 else (
206226 index = 0 and result = value
207227 )
@@ -234,15 +254,21 @@ private predicate sourceAnnotValue(Annotation a, Method m, Expr val) {
234254
235255/** An abstract representation of language elements that can be annotated. */
236256class 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+ */
238261 predicate hasAnnotation ( ) { exists ( this .getAnAnnotation ( ) ) }
239262
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+ */
241267 predicate hasDeclaredAnnotation ( ) { exists ( this .getADeclaredAnnotation ( ) ) }
242268
243269 /**
244270 * Holds if this element has the specified annotation, including inherited
245- * annotations.
271+ * annotations. The retention policy of the annotation type is not considered.
246272 */
247273 predicate hasAnnotation ( string package , string name ) {
248274 exists ( AnnotationType at | at = this .getAnAnnotation ( ) .getType ( ) |
@@ -254,6 +280,7 @@ class Annotatable extends Element {
254280 * Gets an annotation that applies to this element, including inherited annotations.
255281 * The results only include _direct_ annotations; _indirect_ annotations, that is
256282 * repeated annotations in an (implicit) container annotation, are not included.
283+ * The retention policy of the annotation type is not considered.
257284 */
258285 cached
259286 Annotation getAnAnnotation ( ) {
@@ -263,6 +290,7 @@ class Annotatable extends Element {
263290
264291 /**
265292 * Gets an annotation that is declared on this element, excluding inherited annotations.
293+ * The retention policy of the annotation type is not considered.
266294 */
267295 Annotation getADeclaredAnnotation ( ) { result .getAnnotatedElement ( ) = this }
268296
@@ -302,6 +330,8 @@ class Annotatable extends Element {
302330 * - An annotation indirectly present on this element (in the form of a repeated annotation), or
303331 * - If an annotation of a type is neither directly nor indirectly present
304332 * the result is an associated inherited annotation (recursively)
333+ *
334+ * The retention policy of the annotation type is not considered.
305335 */
306336 Annotation getAnAssociatedAnnotation ( ) { result = this .getAnAssociatedAnnotation ( _) }
307337
@@ -320,6 +350,11 @@ class Annotatable extends Element {
320350 or
321351 this .( NestedClass ) .getEnclosingType ( ) .suppressesWarningsAbout ( category )
322352 or
353+ this .( LocalClassOrInterface )
354+ .getLocalTypeDeclStmt ( )
355+ .getEnclosingCallable ( )
356+ .suppressesWarningsAbout ( category )
357+ or
323358 this .( LocalVariableDecl ) .getCallable ( ) .suppressesWarningsAbout ( category )
324359 }
325360}
0 commit comments