Skip to content

Commit 2665f0c

Browse files
committed
Rust: Implement UnusedValue.ql
1 parent ce5cccc commit 2665f0c

File tree

6 files changed

+111
-66
lines changed

6 files changed

+111
-66
lines changed

rust/ql/src/queries/unusedentities/UnusedValue.ql

+12-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,16 @@
99
*/
1010

1111
import rust
12+
import codeql.rust.dataflow.Ssa
13+
import codeql.rust.dataflow.internal.SsaImpl
14+
import UnusedVariable
1215

13-
from Locatable e
14-
where none() // TODO: implement query
15-
select e, "Variable is assigned a value that is never used."
16+
from AstNode write, Ssa::Variable v
17+
where
18+
variableWrite(write, v) and
19+
// SSA definitions are only created for live writes
20+
not write = any(Ssa::WriteDefinition def).getWriteAccess().getAstNode() and
21+
// avoid overlap with the unused variable query
22+
not isUnused(v) and
23+
not v instanceof DiscardVariable
24+
select write, "Variable is assigned a value that is never used."

rust/ql/src/queries/unusedentities/UnusedVariable.ql

+2-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@
99
*/
1010

1111
import rust
12+
import UnusedVariable
1213

1314
from Variable v
14-
where
15-
not exists(v.getAnAccess()) and
16-
not exists(v.getInitializer()) and
17-
not v.getName().charAt(0) = "_" and
18-
exists(File f | f.getBaseName() = "main.rs" | v.getLocation().getFile() = f) // temporarily severely limit results
15+
where isUnused(v)
1916
select v, "Variable is not used."
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import rust
2+
3+
/** A deliberately unused variable. */
4+
class DiscardVariable extends Variable {
5+
DiscardVariable() { this.getName().charAt(0) = "_" }
6+
}
7+
8+
/** Holds if variable `v` is unused. */
9+
predicate isUnused(Variable v) {
10+
not exists(v.getAnAccess()) and
11+
not exists(v.getInitializer()) and
12+
not v instanceof DiscardVariable and
13+
exists(File f | f.getBaseName() = "main.rs" | v.getLocation().getFile() = f) // temporarily severely limit results
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
| main.rs:6:9:6:9 | a | Variable is assigned a value that is never used. |
2+
| main.rs:7:9:7:9 | b | Variable is assigned a value that is never used. |
3+
| main.rs:8:9:8:9 | c | Variable is assigned a value that is never used. |
4+
| main.rs:9:9:9:9 | d | Variable is assigned a value that is never used. |
5+
| main.rs:10:9:10:9 | e | Variable is assigned a value that is never used. |
6+
| main.rs:11:9:11:9 | f | Variable is assigned a value that is never used. |
7+
| main.rs:35:5:35:5 | b | Variable is assigned a value that is never used. |
8+
| main.rs:37:5:37:5 | c | Variable is assigned a value that is never used. |
9+
| main.rs:38:5:38:5 | c | Variable is assigned a value that is never used. |
10+
| main.rs:40:5:40:5 | c | Variable is assigned a value that is never used. |
11+
| main.rs:42:5:42:5 | d | Variable is assigned a value that is never used. |
12+
| main.rs:44:9:44:9 | d | Variable is assigned a value that is never used. |
13+
| main.rs:45:9:45:9 | d | Variable is assigned a value that is never used. |
14+
| main.rs:50:5:50:5 | e | Variable is assigned a value that is never used. |
15+
| main.rs:52:9:52:9 | e | Variable is assigned a value that is never used. |
16+
| main.rs:54:9:54:9 | e | Variable is assigned a value that is never used. |
17+
| main.rs:61:5:61:5 | f | Variable is assigned a value that is never used. |
18+
| main.rs:63:5:63:5 | f | Variable is assigned a value that is never used. |
19+
| main.rs:65:5:65:5 | g | Variable is assigned a value that is never used. |
20+
| main.rs:67:5:67:5 | i | Variable is assigned a value that is never used. |
21+
| main.rs:87:9:87:9 | a | Variable is assigned a value that is never used. |
22+
| main.rs:88:9:88:9 | b | Variable is assigned a value that is never used. |
23+
| main.rs:89:9:89:9 | c | Variable is assigned a value that is never used. |
24+
| main.rs:108:9:108:10 | is | Variable is assigned a value that is never used. |
25+
| main.rs:109:9:109:10 | js | Variable is assigned a value that is never used. |
26+
| main.rs:133:13:133:17 | total | Variable is assigned a value that is never used. |
27+
| main.rs:233:13:233:17 | total | Variable is assigned a value that is never used. |
28+
| main.rs:304:9:304:9 | x | Variable is assigned a value that is never used. |
29+
| main.rs:312:17:312:17 | x | Variable is assigned a value that is never used. |

rust/ql/test/query-tests/unusedentities/UnusedVariable.expected

+14-14
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@
77
| main.rs:174:9:174:9 | x | Variable is not used. |
88
| main.rs:202:17:202:17 | a | Variable is not used. |
99
| main.rs:210:20:210:22 | val | Variable is not used. |
10-
| main.rs:223:14:223:16 | val | Variable is not used. |
11-
| main.rs:225:9:225:12 | None | Variable is not used. |
12-
| main.rs:234:9:234:12 | None | Variable is not used. |
13-
| main.rs:240:22:240:24 | val | Variable is not used. |
10+
| main.rs:224:14:224:16 | val | Variable is not used. |
11+
| main.rs:226:9:226:12 | None | Variable is not used. |
12+
| main.rs:235:9:235:12 | None | Variable is not used. |
13+
| main.rs:241:22:241:24 | val | Variable is not used. |
1414
| main.rs:248:24:248:26 | val | Variable is not used. |
15-
| main.rs:257:13:257:15 | num | Variable is not used. |
16-
| main.rs:268:9:268:11 | Yes | Variable is not used. |
17-
| main.rs:269:9:269:10 | No | Variable is not used. |
18-
| main.rs:272:12:272:12 | j | Variable is not used. |
19-
| main.rs:282:12:282:14 | Yes | Variable is not used. |
20-
| main.rs:294:25:294:25 | y | Variable is not used. |
21-
| main.rs:298:28:298:28 | a | Variable is not used. |
22-
| main.rs:302:9:302:9 | p | Variable is not used. |
23-
| main.rs:309:13:309:13 | y | Variable is not used. |
24-
| main.rs:317:21:317:21 | y | Variable is not used. |
15+
| main.rs:256:13:256:15 | num | Variable is not used. |
16+
| main.rs:267:9:267:11 | Yes | Variable is not used. |
17+
| main.rs:268:9:268:10 | No | Variable is not used. |
18+
| main.rs:271:12:271:12 | j | Variable is not used. |
19+
| main.rs:281:12:281:14 | Yes | Variable is not used. |
20+
| main.rs:292:25:292:25 | y | Variable is not used. |
21+
| main.rs:295:28:295:28 | a | Variable is not used. |
22+
| main.rs:298:9:298:9 | p | Variable is not used. |
23+
| main.rs:305:13:305:13 | y | Variable is not used. |
24+
| main.rs:313:21:313:21 | y | Variable is not used. |

rust/ql/test/query-tests/unusedentities/main.rs

+40-44
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
// --- locals ---
44

55
fn locals_1() {
6-
let a = 1; // BAD: unused value [NOT DETECTED]
7-
let b = 1;
8-
let c = 1;
9-
let d = String::from("a"); // BAD: unused value [NOT DETECTED]
10-
let e = String::from("b");
11-
let f = 1;
6+
let a = 1; // BAD: unused value
7+
let b = 1; // SPURIOUS: unused value [macros not yet supported]
8+
let c = 1; // SPURIOUS: unused value [macros not yet supported]
9+
let d = String::from("a"); // BAD: unused value
10+
let e = String::from("b"); // SPURIOUS: unused value [macros not yet supported]
11+
let f = 1; // SPURIOUS: unused value [macros not yet supported]
1212
let _ = 1; // (deliberately unused)
1313

1414
println!("use {}", b);
@@ -32,39 +32,39 @@ fn locals_2() {
3232
let h: i32;
3333
let i: i32;
3434

35-
b = 1; // BAD: unused value [NOT DETECTED]
35+
b = 1; // BAD: unused value
3636

37-
c = 1; // BAD: unused value [NOT DETECTED]
38-
c = 2;
37+
c = 1; // BAD: unused value
38+
c = 2; // SPURIOUS: unused value [macros not yet supported]
3939
println!("use {}", c);
40-
c = 3; // BAD: unused value [NOT DETECTED]
40+
c = 3; // BAD: unused value
4141

42-
d = 1;
42+
d = 1; // SPURIOUS: unused value [macros not yet supported]
4343
if cond() {
44-
d = 2; // BAD: unused value [NOT DETECTED]
45-
d = 3;
44+
d = 2; // BAD: unused value
45+
d = 3; // SPURIOUS: unused value [macros not yet supported]
4646
} else {
4747
}
4848
println!("use {}", d);
4949

50-
e = 1; // BAD: unused value [NOT DETECTED]
50+
e = 1; // BAD: unused value
5151
if cond() {
52-
e = 2;
52+
e = 2; // SPURIOUS: unused value [macros not yet supported]
5353
} else {
54-
e = 3;
54+
e = 3; // SPURIOUS: unused value [macros not yet supported]
5555
}
5656
println!("use {}", e);
5757

5858
f = 1;
5959
f += 1;
6060
println!("use {}", f);
61-
f += 1; // BAD: unused value [NOT DETECTED]
61+
f += 1; // BAD: unused value
6262
f = 1;
63-
f += 1; // BAD: unused value [NOT DETECTED]
63+
f += 1; // BAD: unused value
6464

65-
g = if cond() { 1 } else { 2 }; // BAD: unused value (x2) [NOT DETECTED]
65+
g = if cond() { 1 } else { 2 }; // BAD: unused value
6666
h = if cond() { 3 } else { 4 };
67-
i = if cond() { h } else { 5 };
67+
i = if cond() { h } else { 5 }; // SPURIOUS: unused value [macros not yet supported]
6868
println!("use {}", i);
6969

7070
_ = 1; // (deliberately unused) [NOT DETECTED]
@@ -84,9 +84,9 @@ impl MyStruct {
8484
}
8585

8686
fn structs() {
87-
let a = MyStruct { val: 1 }; // BAD: unused value [NOT DETECTED]
88-
let b = MyStruct { val: 2 };
89-
let c = MyStruct { val: 3 };
87+
let a = MyStruct { val: 1 }; // BAD: unused value
88+
let b = MyStruct { val: 2 }; // SPURIOUS: unused value [macros not yet supported]
89+
let c = MyStruct { val: 3 }; // SPURIOUS: unused value [macros not yet supported]
9090
let mut d: MyStruct; // BAD: unused variable
9191
let mut e: MyStruct;
9292
let mut f: MyStruct;
@@ -105,8 +105,8 @@ fn structs() {
105105
// --- arrays ---
106106

107107
fn arrays() {
108-
let is = [1, 2, 3]; // BAD: unused values (x3) [NOT DETECTED]
109-
let js = [1, 2, 3];
108+
let is = [1, 2, 3]; // BAD: unused values (x3)
109+
let js = [1, 2, 3]; // SPURIOUS: unused value [macros not yet supported]
110110
let ks = [1, 2, 3];
111111

112112
println!("lets use {:?}", js);
@@ -130,7 +130,7 @@ fn statics() {
130130
static mut STAT4: i32 = 0; // BAD: unused value [NOT DETECTED]
131131

132132
unsafe {
133-
let total = CON1 + STAT1 + STAT3;
133+
let total = CON1 + STAT1 + STAT3; // BAD: unused value
134134
}
135135
}
136136

@@ -139,7 +139,7 @@ fn statics() {
139139
fn parameters(
140140
x: i32,
141141
y: i32, // BAD: unused variable
142-
_z: i32, // (`_` is asking the compiler, and by extension us, to not warn that this is unused)
142+
_z: i32, // (`_` is asking the compiler, and by extension us, to not warn that this is unused) TODO
143143
) -> i32 {
144144
return x;
145145
}
@@ -189,7 +189,7 @@ enum YesOrNo {
189189
No,
190190
}
191191

192-
use YesOrNo::{Yes, No}; // allows `Yes`, `No` to be accessed without qualifiers.
192+
use YesOrNo::{No, Yes}; // allows `Yes`, `No` to be accessed without qualifiers.
193193

194194
struct MyPoint {
195195
x: i64,
@@ -207,7 +207,8 @@ fn if_lets_matches() {
207207
}
208208

209209
let mut next = Some(30);
210-
while let Some(val) = next // BAD: unused variable
210+
while let Some(val) = // BAD: unused variable
211+
next
211212
{
212213
next = None;
213214
}
@@ -229,7 +230,7 @@ fn if_lets_matches() {
229230
let d = Some(70);
230231
match d {
231232
Some(val) => {
232-
total += val;
233+
total += val; // BAD: unused variable
233234
}
234235
None => { // SPURIOUS: unused variable 'None'
235236
}
@@ -239,8 +240,7 @@ fn if_lets_matches() {
239240
match e {
240241
Option::Some(val) => { // BAD: unused variable
241242
}
242-
Option::None => {
243-
}
243+
Option::None => {}
244244
}
245245

246246
let f = MyOption::Some(90);
@@ -250,10 +250,9 @@ fn if_lets_matches() {
250250
MyOption::None => {}
251251
}
252252

253-
let g : Result<i64, i64> = Ok(100);
253+
let g: Result<i64, i64> = Ok(100);
254254
match g {
255-
Ok(_) => {
256-
}
255+
Ok(_) => {}
257256
Err(num) => {} // BAD: unused variable
258257
}
259258

@@ -266,7 +265,7 @@ fn if_lets_matches() {
266265
let i = Yes;
267266
match i {
268267
Yes => {} // SPURIOUS: unused variable 'Yes'
269-
No => {} // SPURIOUS: unused variable 'No'
268+
No => {} // SPURIOUS: unused variable 'No'
270269
}
271270

272271
if let j = Yes { // BAD: unused variable
@@ -289,31 +288,28 @@ fn if_lets_matches() {
289288

290289
let p1 = MyPoint { x: 1, y: 2 };
291290
match p1 {
292-
MyPoint { x: 0, y: 0 } => {
293-
}
291+
MyPoint { x: 0, y: 0 } => {}
294292
MyPoint { x: 1, y } => { // BAD: unused variable
295293
}
296-
MyPoint { x: 2, y: _ } => {
297-
}
294+
MyPoint { x: 2, y: _ } => {}
298295
MyPoint { x: 3, y: a } => { // BAD: unused variable
299296
}
300-
MyPoint { x: 4, .. } => {
301-
}
297+
MyPoint { x: 4, .. } => {}
302298
p => { // BAD: unused variable
303299
}
304300
}
305301
}
306302

307303
fn shadowing() -> i32 {
308-
let x = 1; // BAD: unused value [NOT DETECTED]
304+
let x = 1; // BAD: unused value
309305
let mut y: i32; // BAD: unused variable
310306

311307
{
312308
let x = 2;
313309
let mut y: i32;
314310

315311
{
316-
let x = 3; // BAD: unused value [NOT DETECTED]
312+
let x = 3; // BAD: unused value
317313
let mut y: i32; // BAD: unused variable
318314
}
319315

0 commit comments

Comments
 (0)