Skip to content

Commit abb7f40

Browse files
committed
Add assignment-in-expression.ql
1 parent cde0174 commit abb7f40

File tree

4 files changed

+96
-0
lines changed

4 files changed

+96
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Finds assignments which appear as part of another expression, i.e. the
3+
* assignment result is not discarded. This decreases readability and might
4+
* also indicate a bug in case the intention was to write `==` but by
5+
* accident only `=` was written.
6+
* E.g.:
7+
* ```java
8+
* String result;
9+
* doSomething(result = getResult());
10+
* ```
11+
* Should instead be written as:
12+
* ```java
13+
* String result = getResult();
14+
* doSomething(result);
15+
* ``
16+
*/
17+
18+
import java
19+
import lib.Expressions
20+
21+
from Assignment assign
22+
where
23+
// Result is not discarded
24+
not assign instanceof StmtExpr
25+
// Ignore if assignment appears in loop condition, e.g. `while ((r = read()) != -1)`
26+
and not any(LoopStmt l).getCondition() = assign.getParent+()
27+
// Ignore chained assignments in the form `a = b = 1`
28+
and not (
29+
assign instanceof AssignExpr
30+
and any(AssignExpr e).getRhs() = assign
31+
)
32+
// Ignore assignment in return, this is still somewhat readable, e.g. `return f = getResult();`
33+
and not any(ReturnStmt r).getResult() = assign
34+
select assign, "Should write assignment as separate statement for better readability"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
class Test {
2+
int f;
3+
int g = f = getInt(); // This is allowed
4+
int h = 1 + (f = getInt()); // This should be detected
5+
Exception e;
6+
7+
int getInt() {
8+
return 1;
9+
}
10+
11+
void sink(int i) { }
12+
13+
int test() {
14+
sink(f = 1);
15+
16+
int i;
17+
// Only permit multi assignment as StmtExpr
18+
sink(f = i = 1);
19+
f |= i |= 1; // This is not a normal multi assignment, should be detected
20+
21+
if (true) {
22+
// This is pretty exotic and should be detected
23+
throw e = new Exception();
24+
}
25+
26+
// Assignment in init and update of for loop should be detected
27+
for (int j = 1 + (i = getInt());; sink(f = getInt())) {
28+
}
29+
30+
// Should be detected; not a simple assignment as return result
31+
return 1 + (f = getInt());
32+
}
33+
34+
int testCorrect() {
35+
int i = 1;
36+
37+
// Multi assignment is allowed
38+
f = i = 2;
39+
40+
// Usage in loop is allowed
41+
while ((i = getInt()) != -1) {
42+
}
43+
for (; (i = getInt()) != -1;) {
44+
}
45+
do {} while ((i = getInt()) != -1);
46+
47+
// Unary assignments should not be detected
48+
sink(i++);
49+
50+
// Should not be detected, still quite readable and used by some libraries
51+
return f = getInt();
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| Test.java:4:18:4:29 | ...=... | Should write assignment as separate statement for better readability |
2+
| Test.java:14:14:14:18 | ...=... | Should write assignment as separate statement for better readability |
3+
| Test.java:18:14:18:22 | ...=... | Should write assignment as separate statement for better readability |
4+
| Test.java:19:14:19:19 | ...\|=... | Should write assignment as separate statement for better readability |
5+
| Test.java:23:19:23:37 | ...=... | Should write assignment as separate statement for better readability |
6+
| Test.java:27:27:27:38 | ...=... | Should write assignment as separate statement for better readability |
7+
| Test.java:27:48:27:59 | ...=... | Should write assignment as separate statement for better readability |
8+
| Test.java:31:21:31:32 | ...=... | Should write assignment as separate statement for better readability |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
./error-prone/assignment-in-expression.ql

0 commit comments

Comments
 (0)