Skip to content

Commit 536f5c7

Browse files
Marcono1234smowton
authored andcommitted
Java: Add Annotation value convenience predicates
1 parent 3165bab commit 536f5c7

File tree

11 files changed

+85
-36
lines changed

11 files changed

+85
-36
lines changed

java/ql/lib/semmle/code/java/Annotation.qll

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,50 @@ class Annotation extends @annotation, Expr {
5050
/** Gets the value of the annotation element with the specified `name`. */
5151
Expr getValue(string name) { filteredAnnotValue(this, this.getAnnotationElement(name), result) }
5252

53+
/**
54+
* If the value type of the annotation element with the specified `name` is an enum type,
55+
* gets the enum constant used as value for that element.
56+
*/
57+
EnumConstant getValueEnumConstant(string name) {
58+
result = getValue(name).(FieldRead).getField()
59+
}
60+
61+
/**
62+
* If the value type of the annotation element with the specified `name` is `String`,
63+
* gets the string value used for that element.
64+
*/
65+
string getValueString(string name) {
66+
// Uses CompileTimeConstantExpr instead of StringLiteral because value can
67+
// be read of final variable as well
68+
result = getValue(name).(CompileTimeConstantExpr).getStringValue()
69+
}
70+
71+
/**
72+
* If the value type of the annotation element with the specified `name` is `int`,
73+
* gets the int value used for that element.
74+
*/
75+
int getValueInt(string name) {
76+
// Uses CompileTimeConstantExpr instead of IntegerLiteral because value can
77+
// be read of final variable as well
78+
result = getValue(name).(CompileTimeConstantExpr).getIntValue()
79+
}
80+
81+
/**
82+
* If the value type of the annotation element with the specified `name` is `boolean`,
83+
* gets the boolean value used for that element.
84+
*/
85+
boolean getValueBoolean(string name) {
86+
// Uses CompileTimeConstantExpr instead of BooleanLiteral because value can
87+
// be read of final variable as well
88+
result = getValue(name).(CompileTimeConstantExpr).getBooleanValue()
89+
}
90+
91+
/**
92+
* If the annotation element with the specified `name` has a Java `Class` as value type,
93+
* gets the referenced type used as value for that element.
94+
*/
95+
Type getValueClass(string name) { result = getValue(name).(TypeLiteral).getReferencedType() }
96+
5397
/** Gets the element being annotated. */
5498
Element getTarget() { result = this.getAnnotatedElement() }
5599

@@ -66,10 +110,24 @@ class Annotation extends @annotation, Expr {
66110
* be one of the elements of that array. Otherwise, the returned value will be the single
67111
* expression defined for the value.
68112
*/
69-
Expr getAValue(string name) {
113+
Expr getAValue(string name) { result = getAValue(name, _) }
114+
115+
/**
116+
* Gets the value at a given index of the annotation element with the specified `name`, which must be
117+
* declared as an array type.
118+
*
119+
* If the annotation element is defined with an array initializer, then the returned value will
120+
* be the elements at the given index of that array. Otherwise, if the index is 0 the returned value
121+
* will be the single expression defined for the value.
122+
*/
123+
Expr getAValue(string name, int index) {
70124
this.getType().getAnnotationElement(name).getType() instanceof Array and
71125
exists(Expr value | value = this.getValue(name) |
72-
if value instanceof ArrayInit then result = value.(ArrayInit).getAnInit() else result = value
126+
if value instanceof ArrayInit
127+
then result = value.(ArrayInit).getInit(index)
128+
else (
129+
index = 0 and result = value
130+
)
73131
)
74132
}
75133

java/ql/lib/semmle/code/java/JDKAnnotations.qll

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@ class OverrideAnnotation extends Annotation {
1818
class SuppressWarningsAnnotation extends Annotation {
1919
SuppressWarningsAnnotation() { this.getType().hasQualifiedName("java.lang", "SuppressWarnings") }
2020

21-
/** Gets the `StringLiteral` of a warning suppressed by this annotation. */
22-
StringLiteral getASuppressedWarningLiteral() {
23-
result = this.getAValue() or
24-
result = this.getAValue().(ArrayInit).getAnInit()
25-
}
21+
/**
22+
* Gets the `StringLiteral` of a warning suppressed by this annotation. To get the name of a suppressed
23+
* warning, prefer `getASuppressedWarning()`. That predicate considers more cases because it does not
24+
* restrict results to `StringLiteral`.
25+
*/
26+
StringLiteral getASuppressedWarningLiteral() { result = this.getAValue(_) }
2627

2728
/** Gets the name of a warning suppressed by this annotation. */
28-
string getASuppressedWarning() { result = this.getASuppressedWarningLiteral().getValue() }
29+
string getASuppressedWarning() {
30+
// Use CompileTimeConstantExpr because that covers more than StringLiteral result of getASuppressedWarningLiteral()
31+
result = this.getAValue(_).(CompileTimeConstantExpr).getStringValue()
32+
}
2933
}
3034

3135
/** A `@Target` annotation. */
@@ -40,10 +44,7 @@ class TargetAnnotation extends Annotation {
4044
*/
4145
Expr getATargetExpression() {
4246
not result instanceof ArrayInit and
43-
(
44-
result = this.getAValue() or
45-
result = this.getAValue().(ArrayInit).getAnInit()
46-
)
47+
result = this.getAValue(_)
4748
}
4849

4950
/**
@@ -54,7 +55,7 @@ class TargetAnnotation extends Annotation {
5455
*/
5556
string getATargetElementType() {
5657
exists(EnumConstant ec |
57-
ec = this.getATargetExpression().(VarAccess).getVariable() and
58+
ec = this.getATargetExpression().(FieldRead).getField() and
5859
ec.getDeclaringType().hasQualifiedName("java.lang.annotation", "ElementType")
5960
|
6061
result = ec.getName()
@@ -82,7 +83,7 @@ class RetentionAnnotation extends Annotation {
8283
*/
8384
string getRetentionPolicy() {
8485
exists(EnumConstant ec |
85-
ec = this.getRetentionPolicyExpression().(VarAccess).getVariable() and
86+
ec = this.getRetentionPolicyExpression().(FieldRead).getField() and
8687
ec.getDeclaringType().hasQualifiedName("java.lang.annotation", "RetentionPolicy")
8788
|
8889
result = ec.getName()

java/ql/lib/semmle/code/java/UnitTests.qll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,13 @@ class TestNGTestMethod extends Method {
161161
exists(TestNGTestAnnotation testAnnotation |
162162
testAnnotation = this.getAnAnnotation() and
163163
// The data provider must have the same name as the referenced data provider
164-
result.getDataProviderName() =
165-
testAnnotation.getValue("dataProvider").(StringLiteral).getValue()
164+
result.getDataProviderName() = testAnnotation.getValueString("dataProvider")
166165
|
167166
// Either the data provider should be on the current class, or a supertype
168167
this.getDeclaringType().getAnAncestor() = result.getDeclaringType()
169168
or
170169
// Or the data provider class should be declared
171-
result.getDeclaringType() =
172-
testAnnotation.getValue("dataProviderClass").(TypeLiteral).getReferencedType()
170+
result.getDeclaringType() = testAnnotation.getValueClass("dataProviderClass")
173171
)
174172
}
175173
}

java/ql/lib/semmle/code/java/frameworks/JAXB.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class JaxbType extends Class {
6060
this.getAnAnnotation() = a and
6161
a.getType().(JaxbAnnotationType).hasName("XmlAccessorType")
6262
|
63-
result.getAnAccess() = a.getValue("value")
63+
result = a.getValueEnumConstant("value")
6464
)
6565
}
6666

java/ql/lib/semmle/code/java/frameworks/JUnitAnnotations.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,5 @@ class RunWithAnnotation extends Annotation {
6464
/**
6565
* Gets the runner that will be used.
6666
*/
67-
Type getRunner() { result = this.getValue("value").(TypeLiteral).getReferencedType() }
67+
Type getRunner() { result = this.getValueClass("value") }
6868
}

java/ql/lib/semmle/code/java/frameworks/javaee/Persistence.qll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ class PersistentEntity extends RefType {
3737
*/
3838
string getAccessTypeFromAnnotation() {
3939
exists(AccessAnnotation accessType | accessType = this.getAnAnnotation() |
40-
result =
41-
accessType.getValue("value").(FieldRead).getField().(EnumConstant).getName().toLowerCase()
40+
result = accessType.getValueEnumConstant("value").getName().toLowerCase()
4241
)
4342
}
4443
}

java/ql/lib/semmle/code/java/frameworks/spring/SpringAutowire.qll

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,7 @@ class SpringQualifierDefinitionAnnotation extends Annotation {
311311
/**
312312
* Gets the value of the qualifier field for this qualifier.
313313
*/
314-
string getQualifierValue() {
315-
result = this.getValue("value").(CompileTimeConstantExpr).getStringValue()
316-
}
314+
string getQualifierValue() { result = this.getValueString("value") }
317315
}
318316

319317
/**
@@ -325,9 +323,7 @@ class SpringQualifierAnnotation extends Annotation {
325323
/**
326324
* Gets the value of the qualifier field for this qualifier.
327325
*/
328-
string getQualifierValue() {
329-
result = this.getValue("value").(CompileTimeConstantExpr).getStringValue()
330-
}
326+
string getQualifierValue() { result = getValueString("value") }
331327

332328
/**
333329
* Gets the bean definition in an XML file that this qualifier resolves to, if any.
@@ -350,9 +346,7 @@ class SpringResourceAnnotation extends Annotation {
350346
/**
351347
* Gets the specified name value, if any.
352348
*/
353-
string getNameValue() {
354-
result = this.getValue("name").(CompileTimeConstantExpr).getStringValue()
355-
}
349+
string getNameValue() { result = getValueString("name") }
356350

357351
/**
358352
* Gets the bean definition in an XML file that the resource resolves to, if any.

java/ql/lib/semmle/code/java/frameworks/spring/SpringComponentScan.qll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,7 @@ class SpringComponent extends RefType {
144144
if exists(this.getComponentAnnotation().getValue("value"))
145145
then
146146
// If the name has been specified in the component annotation, use that.
147-
result =
148-
this.getComponentAnnotation().getValue("value").(CompileTimeConstantExpr).getStringValue()
147+
result = getComponentAnnotation().getValueString("value")
149148
else
150149
// Otherwise use the name of the class, with the initial letter lower cased.
151150
exists(string name | name = this.getName() |

java/ql/lib/semmle/code/java/frameworks/spring/SpringController.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ class SpringRequestMappingMethod extends SpringControllerMethod {
155155

156156
/** Gets the "value" @RequestMapping annotation value, if present. */
157157
string getValue() {
158-
result = requestMappingAnnotation.getValue("value").(CompileTimeConstantExpr).getStringValue()
158+
result = requestMappingAnnotation.getValueString("value")
159159
}
160160

161161
/** Holds if this is considered an `@ResponseBody` method. */

java/ql/src/AlertSuppressionAnnotations.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class SuppressionAnnotation extends SuppressWarningsAnnotation {
2323
string text;
2424

2525
SuppressionAnnotation() {
26-
text = this.getASuppressedWarningLiteral().getValue() and
26+
text = this.getASuppressedWarning() and
2727
exists(getAnnotationText(text))
2828
}
2929

0 commit comments

Comments
 (0)