mirror of
https://github.com/github/codeql.git
synced 2025-12-21 19:26:31 +01:00
Java: Add annotation tests
This commit is contained in:
committed by
Chris Smowton
parent
8c9bdeb3be
commit
37b18914ac
@@ -66,6 +66,16 @@ class Annotation extends @annotation, Expr {
|
||||
*/
|
||||
Expr getValue(string name) { filteredAnnotValue(this, this.getAnnotationElement(name), result) }
|
||||
|
||||
/**
|
||||
* Gets the value of the annotation element, if its type is not an array.
|
||||
* This guarantees that for consistency even elements of type array with a
|
||||
* single value have no result, to prevent accidental error-prone usage.
|
||||
*/
|
||||
private Expr getNonArrayValue(string name) {
|
||||
result = this.getValue(name) and
|
||||
not this.getAnnotationElement(name).getType() instanceof Array
|
||||
}
|
||||
|
||||
/**
|
||||
* If the value type of the annotation element with the specified `name` is an enum type,
|
||||
* gets the enum constant used as value for that element. This includes default values in
|
||||
@@ -74,7 +84,7 @@ class Annotation extends @annotation, Expr {
|
||||
* If the element value type is an enum type array, use `getAnEnumConstantArrayValue`.
|
||||
*/
|
||||
EnumConstant getEnumConstantValue(string name) {
|
||||
result = this.getValue(name).(FieldRead).getField()
|
||||
result = this.getNonArrayValue(name).(FieldRead).getField()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,20 +97,23 @@ class Annotation extends @annotation, Expr {
|
||||
string getStringValue(string name) {
|
||||
// Uses CompileTimeConstantExpr instead of StringLiteral because this can for example
|
||||
// be a read from a final variable as well.
|
||||
result = this.getValue(name).(CompileTimeConstantExpr).getStringValue()
|
||||
result = this.getNonArrayValue(name).(CompileTimeConstantExpr).getStringValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* If the value type of the annotation element with the specified `name` is `int`,
|
||||
* gets the int value used for that element. This includes default values in case no
|
||||
* explicit value is specified.
|
||||
* If the value type of the annotation element with the specified `name` is `int` or
|
||||
* a smaller integral type or `char`, gets the int value used for that element.
|
||||
* This includes default values in case no explicit value is specified.
|
||||
*
|
||||
* If the element value type is an `int` array, use `getAnIntArrayValue`.
|
||||
* If the element value type is an `int` array or an array of a smaller integral
|
||||
* type or `char`, use `getAnIntArrayValue`.
|
||||
*/
|
||||
int getIntValue(string name) {
|
||||
// Uses CompileTimeConstantExpr instead of IntegerLiteral because this can for example
|
||||
// be a read from a final variable as well.
|
||||
result = this.getValue(name).(CompileTimeConstantExpr).getIntValue()
|
||||
result = this.getNonArrayValue(name).(CompileTimeConstantExpr).getIntValue() and
|
||||
// Verify that type is integral; ignore floating point elements with IntegerLiteral as value
|
||||
this.getAnnotationElement(name).getType().hasName(["byte", "short", "int", "char"])
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +124,7 @@ class Annotation extends @annotation, Expr {
|
||||
boolean getBooleanValue(string name) {
|
||||
// Uses CompileTimeConstantExpr instead of BooleanLiteral because this can for example
|
||||
// be a read from a final variable as well.
|
||||
result = this.getValue(name).(CompileTimeConstantExpr).getBooleanValue()
|
||||
result = this.getNonArrayValue(name).(CompileTimeConstantExpr).getBooleanValue()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +134,9 @@ class Annotation extends @annotation, Expr {
|
||||
*
|
||||
* If the element value type is a `Class` array, use `getATypeArrayValue`.
|
||||
*/
|
||||
Type getTypeValue(string name) { result = this.getValue(name).(TypeLiteral).getReferencedType() }
|
||||
Type getTypeValue(string name) {
|
||||
result = this.getNonArrayValue(name).(TypeLiteral).getReferencedType()
|
||||
}
|
||||
|
||||
/** Gets the element being annotated. */
|
||||
Element getTarget() { result = this.getAnnotatedElement() }
|
||||
@@ -169,13 +184,16 @@ class Annotation extends @annotation, Expr {
|
||||
|
||||
/**
|
||||
* Gets a value of the annotation element with the specified `name`, which must be declared as an `int`
|
||||
* array. This includes default values in case no explicit value is specified.
|
||||
* array or an array of a smaller integral type or `char`. This includes default values in case no
|
||||
* explicit value is specified.
|
||||
*
|
||||
* If the annotation element is defined with an array initializer, then the result will be one of the
|
||||
* elements of that array. Otherwise, the result will be the single expression used as value.
|
||||
*/
|
||||
int getAnIntArrayValue(string name) {
|
||||
result = this.getAnArrayValue(name).(CompileTimeConstantExpr).getIntValue()
|
||||
result = this.getAnArrayValue(name).(CompileTimeConstantExpr).getIntValue() and
|
||||
// Verify that type is integral; ignore floating point elements with IntegerLiteral as value
|
||||
this.getAnnotationElement(name).getType().hasName(["byte[]", "short[]", "int[]", "char[]"])
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,14 +212,16 @@ class Annotation extends @annotation, Expr {
|
||||
* declared as an array type. This includes default values in case no explicit value is specified.
|
||||
*
|
||||
* If the annotation element is defined with an array initializer, then the result will be the element
|
||||
* at the given index of that array. Otherwise, the result will be the single expression defined for
|
||||
* the value and the `index` will be 0.
|
||||
* at the given index of that array, starting at 0. Otherwise, the result will be the single expression
|
||||
* defined for the value and the `index` will be 0.
|
||||
*/
|
||||
Expr getArrayValue(string name, int index) {
|
||||
this.getType().getAnnotationElement(name).getType() instanceof Array and
|
||||
exists(Expr value | value = this.getValue(name) |
|
||||
if value instanceof ArrayInit
|
||||
then result = value.(ArrayInit).getInit(index)
|
||||
then
|
||||
// TODO: Currently reports incorrect index values in some cases, see https://github.com/github/codeql/issues/8645
|
||||
result = value.(ArrayInit).getInit(index)
|
||||
else (
|
||||
index = 0 and result = value
|
||||
)
|
||||
@@ -234,15 +254,21 @@ private predicate sourceAnnotValue(Annotation a, Method m, Expr val) {
|
||||
|
||||
/** An abstract representation of language elements that can be annotated. */
|
||||
class Annotatable extends Element {
|
||||
/** Holds if this element has an annotation, including inherited annotations. */
|
||||
/**
|
||||
* Holds if this element has an annotation, including inherited annotations.
|
||||
* The retention policy of the annotation type is not considered.
|
||||
*/
|
||||
predicate hasAnnotation() { exists(this.getAnAnnotation()) }
|
||||
|
||||
/** Holds if this element has a declared annotation, excluding inherited annotations. */
|
||||
/**
|
||||
* Holds if this element has a declared annotation, excluding inherited annotations.
|
||||
* The retention policy of the annotation type is not considered.
|
||||
*/
|
||||
predicate hasDeclaredAnnotation() { exists(this.getADeclaredAnnotation()) }
|
||||
|
||||
/**
|
||||
* Holds if this element has the specified annotation, including inherited
|
||||
* annotations.
|
||||
* annotations. The retention policy of the annotation type is not considered.
|
||||
*/
|
||||
predicate hasAnnotation(string package, string name) {
|
||||
exists(AnnotationType at | at = this.getAnAnnotation().getType() |
|
||||
@@ -254,6 +280,7 @@ class Annotatable extends Element {
|
||||
* Gets an annotation that applies to this element, including inherited annotations.
|
||||
* The results only include _direct_ annotations; _indirect_ annotations, that is
|
||||
* repeated annotations in an (implicit) container annotation, are not included.
|
||||
* The retention policy of the annotation type is not considered.
|
||||
*/
|
||||
cached
|
||||
Annotation getAnAnnotation() {
|
||||
@@ -263,6 +290,7 @@ class Annotatable extends Element {
|
||||
|
||||
/**
|
||||
* Gets an annotation that is declared on this element, excluding inherited annotations.
|
||||
* The retention policy of the annotation type is not considered.
|
||||
*/
|
||||
Annotation getADeclaredAnnotation() { result.getAnnotatedElement() = this }
|
||||
|
||||
@@ -302,6 +330,8 @@ class Annotatable extends Element {
|
||||
* - An annotation indirectly present on this element (in the form of a repeated annotation), or
|
||||
* - If an annotation of a type is neither directly nor indirectly present
|
||||
* the result is an associated inherited annotation (recursively)
|
||||
*
|
||||
* The retention policy of the annotation type is not considered.
|
||||
*/
|
||||
Annotation getAnAssociatedAnnotation() { result = this.getAnAssociatedAnnotation(_) }
|
||||
|
||||
@@ -320,6 +350,11 @@ class Annotatable extends Element {
|
||||
or
|
||||
this.(NestedClass).getEnclosingType().suppressesWarningsAbout(category)
|
||||
or
|
||||
this.(LocalClassOrInterface)
|
||||
.getLocalTypeDeclStmt()
|
||||
.getEnclosingCallable()
|
||||
.suppressesWarningsAbout(category)
|
||||
or
|
||||
this.(LocalVariableDecl).getCallable().suppressesWarningsAbout(category)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user