Java: Add convenience array value Annotation predicates

This commit is contained in:
Marcono1234
2022-03-28 00:07:28 +02:00
committed by Chris Smowton
parent 47e38952d1
commit 998aa95eae
8 changed files with 71 additions and 38 deletions

View File

@@ -46,13 +46,17 @@ class Annotation extends @annotation, Expr {
/**
* Gets a value of an annotation element. This includes default values in case
* no explicit value is specified.
* no explicit value is specified. For elements with an array value type this
* might have an `ArrayInit` as result. To properly handle array values, prefer
* the predicate `getAnArrayValue`.
*/
Expr getAValue() { filteredAnnotValue(this, _, result) }
/**
* Gets the value of the annotation element with the specified `name`.
* This includes default values in case no explicit value is specified.
* For elements with an array value type this might have an `ArrayInit` as result.
* To properly handle array values, prefer the predicate `getAnArrayValue`.
*/
Expr getValue(string name) { filteredAnnotValue(this, this.getAnnotationElement(name), result) }
@@ -60,6 +64,8 @@ class Annotation extends @annotation, Expr {
* 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
* case no explicit value is specified.
*
* If the element value type is an enum type array, use `getAnEnumConstantArrayValue`.
*/
EnumConstant getEnumConstantValue(string name) { result = getValue(name).(FieldRead).getField() }
@@ -67,6 +73,8 @@ class Annotation extends @annotation, Expr {
* If the value type of the annotation element with the specified `name` is `String`,
* gets the string value used for that element. This includes default values in case no
* explicit value is specified.
*
* If the element value type is a string array, use `getAStringArrayValue`.
*/
string getStringValue(string name) {
// Uses CompileTimeConstantExpr instead of StringLiteral because value can
@@ -78,6 +86,8 @@ class Annotation extends @annotation, Expr {
* 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 element value type is an `int` array, use `getAnIntArrayValue`.
*/
int getIntValue(string name) {
// Uses CompileTimeConstantExpr instead of IntegerLiteral because value can
@@ -100,6 +110,8 @@ class Annotation extends @annotation, Expr {
* If the annotation element with the specified `name` has a Java `Class` as value type,
* gets the referenced type used as value for that element. This includes default values
* in case no explicit value is specified.
*
* If the element value type is a `Class` array, use `getATypeArrayValue`.
*/
Type getTypeValue(string name) { result = getValue(name).(TypeLiteral).getReferencedType() }
@@ -125,6 +137,50 @@ class Annotation extends @annotation, Expr {
*/
deprecated Expr getAValue(string name) { result = getAnArrayValue(name) }
/**
* Gets a value of the annotation element with the specified `name`, which must be declared as an enum
* type array. 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 defined for the value.
*/
EnumConstant getAnEnumConstantArrayValue(string name) {
result = this.getAnArrayValue(name).(FieldRead).getField()
}
/**
* Gets a value of the annotation element with the specified `name`, which must be declared as a string
* array. 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 defined for the value.
*/
string getAStringArrayValue(string name) {
result = this.getAnArrayValue(name).(CompileTimeConstantExpr).getStringValue()
}
/**
* 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.
*
* 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 defined for the value.
*/
int getAnIntArrayValue(string name) {
result = this.getAnArrayValue(name).(CompileTimeConstantExpr).getIntValue()
}
/**
* Gets a value of the annotation element with the specified `name`, which must be declared as a `Class`
* array. 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 defined for the value.
*/
Type getATypeArrayValue(string name) {
result = this.getAnArrayValue(name).(TypeLiteral).getReferencedType()
}
/**
* Gets the value at a given index of the annotation element with the specified `name`, which must be
* declared as an array type. This includes default values in case no explicit value is specified.

View File

@@ -71,7 +71,8 @@ predicate depends(RefType t, RefType dep) {
a.getAnnotatedElement().(Member).getDeclaringType() = t
|
usesType(a.getType(), dep) or
usesType(a.getAValue().getType(), dep)
usesType(a.getAValue().getType(), dep) or
usesType(a.getAnArrayValue(_).getType(), dep)
)
or
// the type accessed in an `instanceof` expression in `t`.

View File

@@ -90,7 +90,7 @@ predicate numDepends(RefType t, RefType dep, int value) {
|
elem = a and usesType(a.getType(), dep)
or
elem = a.getAValue() and
elem = [a.getAValue(), a.getAnArrayValue(_)] and
elem.getFile().getExtension() = "java" and
usesType(elem.(Expr).getType(), dep)
)

View File

@@ -27,8 +27,8 @@ class SuppressWarningsAnnotation extends Annotation {
/** Gets the name of a warning suppressed by this annotation. */
string getASuppressedWarning() {
// Use CompileTimeConstantExpr because that covers more than StringLiteral result of getASuppressedWarningLiteral()
result = this.getAnArrayValue("value").(CompileTimeConstantExpr).getStringValue()
// Don't use getASuppressedWarningLiteral() because that restricts results to StringLiteral
result = this.getAStringArrayValue("value")
}
}
@@ -42,10 +42,7 @@ class TargetAnnotation extends Annotation {
* For example, the field access `ElementType.FIELD` is a target expression in
* `@Target({ElementType.FIELD, ElementType.METHOD})`.
*/
Expr getATargetExpression() {
not result instanceof ArrayInit and
result = this.getAnArrayValue("value")
}
Expr getATargetExpression() { result = this.getAnArrayValue("value") }
/**
* Gets the name of a target element type.
@@ -53,14 +50,7 @@ class TargetAnnotation extends Annotation {
* For example, `METHOD` is the name of a target element type in
* `@Target({ElementType.FIELD, ElementType.METHOD})`.
*/
string getATargetElementType() {
exists(EnumConstant ec |
ec = this.getATargetExpression().(FieldRead).getField() and
ec.getDeclaringType().hasQualifiedName("java.lang.annotation", "ElementType")
|
result = ec.getName()
)
}
string getATargetElementType() { result = this.getAnEnumConstantArrayValue("value").getName() }
}
/** A `@Retention` annotation. */

View File

@@ -225,9 +225,7 @@ class TestNGListenersAnnotation extends TestNGAnnotation {
/**
* Gets a listener defined in this annotation.
*/
TestNGListenerImpl getAListener() {
result = this.getAnArrayValue("value").(TypeLiteral).getReferencedType()
}
TestNGListenerImpl getAListener() { result = this.getATypeArrayValue("value") }
}
/**

View File

@@ -296,11 +296,7 @@ class JaxRSProducesAnnotation extends JaxRSAnnotation {
/**
* Gets a declared content type that can be produced by this resource.
*/
Expr getADeclaredContentTypeExpr() {
result = this.getAValue() and not result instanceof ArrayInit
or
result = this.getAValue().(ArrayInit).getAnInit()
}
Expr getADeclaredContentTypeExpr() { result = this.getAnArrayValue("value") }
}
/** An `@Consumes` annotation that describes content types can be consumed by this resource. */

View File

@@ -85,9 +85,7 @@ class IbatisSqlOperationAnnotation extends Annotation {
/**
* Gets this annotation's SQL statement string.
*/
string getSqlValue() {
result = this.getAnArrayValue("value").(CompileTimeConstantExpr).getStringValue()
}
string getSqlValue() { result = this.getAStringArrayValue("value") }
}
/**

View File

@@ -40,16 +40,10 @@ class SpringComponentScan extends Annotation {
*/
string getBasePackages() {
// "value" and "basePackages" are synonymous, and are simple strings
result = this.getAnArrayValue("basePackages").(StringLiteral).getValue()
result = this.getAStringArrayValue(["basePackages", "value"])
or
result = this.getAnArrayValue("value").(StringLiteral).getValue()
or
exists(TypeLiteral typeLiteral |
// Base package classes are type literals whose package should be considered a base package.
typeLiteral = this.getAnArrayValue("basePackageClasses")
|
result = typeLiteral.getReferencedType().(RefType).getPackage().getName()
)
// Base package classes are type literals whose package should be considered a base package.
result = this.getATypeArrayValue("basePackageClasses").(RefType).getPackage().getName()
}
}
@@ -203,7 +197,7 @@ class SpringComponent extends RefType {
.getType()
.hasQualifiedName("org.springframework.context.annotation", "Profile")
|
result = profileAnnotation.getAnArrayValue("value").(StringLiteral).getValue()
result = profileAnnotation.getAStringArrayValue("value")
)
}
}