Skip to content

Commit 44fe494

Browse files
committedJul 18, 2024
Extend assertion-arguments-switched.ql to cover more constant expressions
1 parent d0e40f5 commit 44fe494

File tree

3 files changed

+71
-13
lines changed

3 files changed

+71
-13
lines changed
 

‎codeql-custom-queries-java/queries/unit-tests/assertion-arguments-constant.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ from MethodAccess assertCall, AssertMethod assertMethod
1616
where
1717
assertMethod = assertCall.getMethod()
1818
and forex(int inputParamIndex | inputParamIndex = assertMethod.getAnInputParamIndex() |
19-
assertCall.getArgument(inputParamIndex) instanceof CompileTimeConstantOrLiteral
19+
assertCall.getArgument(inputParamIndex) instanceof ConstantExpr
2020
)
2121
select assertCall, "Assertion will always have the same outcome"

‎codeql-custom-queries-java/queries/unit-tests/assertion-arguments-switched.ql

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,60 @@
99
* assertEquals(actual, "expected");
1010
* ```
1111
* SonarSource rule: [RSPEC-3415](https://rules.sonarsource.com/java/RSPEC-3415)
12+
*
13+
* @kind problem
14+
* @id TODO
1215
*/
1316

14-
import java
15-
import lib.AssertLib
17+
import java
18+
import lib.AssertLib
1619

17-
from MethodAccess assertCall, AssertTwoArgumentsMethod assertMethod
20+
/**
21+
* Expression which seems to be intended as 'expected' argument for an assertion.
22+
*/
23+
class ExpectedValueExpr extends Expr {
24+
ExpectedValueExpr() {
25+
// Note: Can cause false positives if the value of a constant (= 'actual') defined in the same
26+
// project is being checked, but on the other hand there are also cases where the constant is
27+
// is intended as 'expected' value
28+
this instanceof ConstantExpr
29+
or
30+
exists(MethodAccess call, Method m |
31+
call = this and
32+
m = call.getMethod() and
33+
m.isStatic() and
34+
forall(Expr arg | arg = call.getAnArgument() | arg instanceof ExpectedValueExpr) and
35+
// Only consider methods from third-party libraries or JDK, otherwise intention might be to
36+
// test result of method
37+
not m.getSourceDeclaration().fromSource()
38+
)
39+
or
40+
exists(ClassInstanceExpr newExpr |
41+
newExpr = this and
42+
forall(Expr arg | arg = newExpr.getAnArgument() | arg instanceof ExpectedValueExpr)
43+
// Do not exclude types declared in same project, assume that `newExpr` is always the 'expected' value
44+
// If `newExpr` is intended as 'actual' then this might be misuse of `assertEquals` for `equals`
45+
// implementation check (which is discouraged)
46+
)
47+
or
48+
exists(ArrayCreationExpr newArray | newArray = this |
49+
// Either creates array with constant dimensions
50+
forex(Expr dimExpr | dimExpr = newArray.getADimension() |
51+
dimExpr instanceof ExpectedValueExpr
52+
)
53+
or
54+
// Or with init containing constants (checked transitively)
55+
forex(Expr initValue | initValue = newArray.getInit().getAnInit+() |
56+
initValue instanceof ArrayInit or initValue instanceof ExpectedValueExpr
57+
)
58+
)
59+
}
60+
}
61+
62+
from MethodAccess assertCall, AssertTwoArgumentsMethod assertMethod
1863
where
19-
assertMethod = assertCall.getMethod()
20-
and assertCall.getArgument(assertMethod.getAssertionParamIndex()) instanceof CompileTimeConstantOrLiteral
21-
// Ignore if both arguments are constant, that is already detected by separate query
22-
and not assertCall.getArgument(assertMethod.getFixedParamIndex()) instanceof CompileTimeConstantOrLiteral
64+
assertMethod = assertCall.getMethod() and
65+
assertCall.getArgument(assertMethod.getAssertionParamIndex()) instanceof ExpectedValueExpr and
66+
// Ignore if both arguments are constant, that is already detected by separate query
67+
not assertCall.getArgument(assertMethod.getFixedParamIndex()) instanceof ExpectedValueExpr
2368
select assertCall, "Assertion arguments are switched"

‎codeql-custom-queries-java/queries/unit-tests/lib/AssertLib.qll

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,13 +200,26 @@ abstract class AssertThrowsMethod extends AssertMethod {
200200
}
201201

202202
/**
203-
* A compile time constant expression or any literal.
203+
* An expression with constant value.
204204
*/
205-
class CompileTimeConstantOrLiteral extends Expr {
206-
CompileTimeConstantOrLiteral() {
205+
class ConstantExpr extends Expr {
206+
ConstantExpr() {
207207
// CompileTimeConstantExpr does not include NullLiteral and TypeLiteral
208208
this instanceof CompileTimeConstantExpr
209-
or this instanceof NullLiteral
210-
or this instanceof TypeLiteral
209+
or
210+
this instanceof NullLiteral
211+
or
212+
this instanceof TypeLiteral
213+
or
214+
this.(FieldRead).getField() instanceof EnumConstant
215+
or
216+
exists(Field f |
217+
f = this.(FieldRead).getField() and
218+
f.isStatic() and
219+
f.isFinal() and
220+
// And field is declared in third-party library or JDK, otherwise test might intentionally
221+
// use constant as 'actual' argument to check its value
222+
not f.fromSource()
223+
)
211224
}
212225
}

0 commit comments

Comments
 (0)