Skip to content

Commit daa57a9

Browse files
authored
Merge pull request github#18952 from geoffw0/unusedvarfix
Rust: Improve rust/unused-variable and rust/unused-value
2 parents 087c555 + 7717f92 commit daa57a9

File tree

7 files changed

+119
-23
lines changed

7 files changed

+119
-23
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ import UnusedVariable
1616
from AstNode write, Ssa::Variable v
1717
where
1818
variableWrite(write, v) and
19+
not v instanceof DiscardVariable and
20+
not write.isInMacroExpansion() and
21+
not isAllowableUnused(v) and
1922
// SSA definitions are only created for live writes
2023
not write = any(Ssa::WriteDefinition def).getWriteAccess().getAstNode() and
2124
// avoid overlap with the unused variable query
22-
not isUnused(v) and
23-
not v instanceof DiscardVariable and
24-
not write.isInMacroExpansion()
25+
not isUnused(v)
2526
select write, "Variable $@ is assigned a value that is never used.", v, v.getText()

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@ predicate isUnused(Variable v) {
1616
not exists(v.getInitializer())
1717
}
1818

19+
/**
20+
* A callable for which we have incomplete information, for example because an unexpanded
21+
* macro call is present. These callables are prone to false positive results from unused
22+
* entities queries, unless they are excluded from results.
23+
*/
24+
class IncompleteCallable extends Callable {
25+
IncompleteCallable() {
26+
exists(MacroExpr me |
27+
me.getEnclosingCallable() = this and
28+
not me.getMacroCall().hasExpanded()
29+
)
30+
}
31+
}
32+
1933
/**
2034
* Holds if variable `v` is in a context where we may not find a use for it,
2135
* but that's expected and should not be considered a problem.
@@ -24,6 +38,9 @@ predicate isAllowableUnused(Variable v) {
2438
// in a macro expansion
2539
v.getPat().isInMacroExpansion()
2640
or
41+
// declared in an incomplete callable
42+
v.getEnclosingCfgScope() instanceof IncompleteCallable
43+
or
2744
// a 'self' variable
2845
v.getText() = "self"
2946
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
extractionWarning
2+
| undefined_macros/main.rs:1:1:1:1 | semantic analyzer unavailable (not included as a module) |

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
| main.rs:284:13:284:17 | total | Variable $@ is assigned a value that is never used. | main.rs:252:13:252:17 | total | total |
1515
| main.rs:377:9:377:9 | x | Variable $@ is assigned a value that is never used. | main.rs:377:9:377:9 | x | x |
1616
| main.rs:385:17:385:17 | x | Variable $@ is assigned a value that is never used. | main.rs:385:17:385:17 | x | x |
17-
| main.rs:486:9:486:9 | c | Variable $@ is assigned a value that is never used. | main.rs:486:9:486:9 | c | c |
18-
| main.rs:519:9:519:20 | var_in_macro | Variable $@ is assigned a value that is never used. | main.rs:519:9:519:20 | var_in_macro | var_in_macro |
17+
| main.rs:531:9:531:20 | var_in_macro | Variable $@ is assigned a value that is never used. | main.rs:531:9:531:20 | var_in_macro | var_in_macro |
18+
| main.rs:540:9:540:9 | c | Variable $@ is assigned a value that is never used. | main.rs:540:9:540:9 | c | c |
1919
| more.rs:44:9:44:14 | a_ptr4 | Variable $@ is assigned a value that is never used. | more.rs:44:9:44:14 | a_ptr4 | a_ptr4 |
2020
| more.rs:59:9:59:13 | d_ptr | Variable $@ is assigned a value that is never used. | more.rs:59:9:59:13 | d_ptr | d_ptr |
2121
| more.rs:65:13:65:17 | f_ptr | Variable $@ is assigned a value that is never used. | more.rs:65:13:65:17 | f_ptr | f_ptr |

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

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -468,16 +468,70 @@ fn traits() {
468468

469469
// --- macros ---
470470

471-
fn macros() {
471+
macro_rules! set_value {
472+
($x:expr,$y:expr) => {
473+
$x = $y
474+
};
475+
}
476+
477+
macro_rules! use_value {
478+
($x:expr) => {
479+
println!("{}", $x)
480+
};
481+
}
482+
483+
fn macros1() {
484+
let a: u16;
485+
let b: u16 = 2;
486+
set_value!(a, 1);
487+
use_value!(b);
488+
489+
match std::env::args().nth(1).unwrap().parse::<u16>() {
490+
Ok(n) => {
491+
use_value!(n);
492+
}
493+
_ => {}
494+
}
495+
}
496+
497+
fn macros2() {
498+
let a: u16 = 3;
499+
println!("{}", a);
500+
501+
match std::env::args().nth(1).unwrap().parse::<u16>() {
502+
Ok(n) => {
503+
println!("{}", n);
504+
}
505+
_ => {}
506+
}
507+
}
508+
509+
fn macros3() {
472510
let x;
473511
println!(
474512
"The value of x is {}",
475513
({
476514
x = 10; // $ MISSING: Alert[rust/unused-value]
477515
10
478516
})
479-
)
517+
);
518+
}
519+
520+
macro_rules! let_in_macro {
521+
($e:expr) => {{
522+
let var_in_macro = 0;
523+
$e
524+
}};
480525
}
526+
527+
// Our analysis does not currently respect the hygiene rules of Rust macros
528+
// (https://veykril.github.io/tlborm/decl-macros/minutiae/hygiene.html), because
529+
// all we have access to is the expanded AST
530+
fn hygiene_mismatch() {
531+
let var_in_macro = 0; // $ SPURIOUS: Alert[rust/unused-value]
532+
let_in_macro!(var_in_macro);
533+
}
534+
481535
// --- references ---
482536

483537
fn references() {
@@ -505,21 +559,6 @@ trait MyTrait {
505559
fn my_func2(&self, x: i32) -> i32;
506560
}
507561

508-
macro_rules! let_in_macro {
509-
($e:expr) => {{
510-
let var_in_macro = 0;
511-
$e
512-
}};
513-
}
514-
515-
// Our analysis does not currently respect the hygiene rules of Rust macros
516-
// (https://veykril.github.io/tlborm/decl-macros/minutiae/hygiene.html), because
517-
// all we have access to is the expanded AST
518-
fn hygiene_mismatch() {
519-
let var_in_macro = 0; // $ SPURIOUS: Alert[rust/unused-value]
520-
let_in_macro!(var_in_macro);
521-
}
522-
523562
// --- main ---
524563

525564
fn main() {
@@ -534,7 +573,10 @@ fn main() {
534573
shadowing();
535574
func_ptrs();
536575
folds_and_closures();
537-
macros();
576+
macros1();
577+
macros2();
578+
macros3();
579+
hygiene_mismatch();
538580
references();
539581

540582
generics();
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
// --- undefined macro calls ---
3+
4+
fn undefined_macros1() {
5+
let a: u16;
6+
7+
undefined_macro_call!(d);
8+
}
9+
10+
fn undefined_macros2() {
11+
{
12+
let a: u16 = 1; // $ MISSING: Alert[rust/unused-value]
13+
}
14+
15+
undefined_macro_call!(5);
16+
17+
let b: u16; // $ MISSING: Alert[rust/unused-variable]
18+
}
19+
20+
fn undefined_macros3() {
21+
match std::env::args().nth(1).unwrap().parse::<u16>() {
22+
Ok(n) => {
23+
undefined_macro_call!(n);
24+
}
25+
_ => {}
26+
}
27+
}
28+
29+
fn main() {
30+
undefined_macros1();
31+
undefined_macros2();
32+
undefined_macros3();
33+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qltest_cargo_check: false

0 commit comments

Comments
 (0)