diff --git a/rust/ql/lib/codeql/rust/elements/internal/AstNodeImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/AstNodeImpl.qll index 435d8e151912..b3dd56706032 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/AstNodeImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/AstNodeImpl.qll @@ -26,21 +26,29 @@ module Impl { result = getImmediateParent(e) } - /** Gets the nearest enclosing parent of `ast` that is an `AstNode`. */ - private AstNode getParentOfAst(AstNode ast) { - result = getParentOfAstStep*(getImmediateParent(ast)) - } - class AstNode extends Generated::AstNode { + /** + * Gets the nearest enclosing parent of this node, which is also an `AstNode`, + * if any. + */ + AstNode getParentNode() { result = getParentOfAstStep*(getImmediateParent(this)) } + /** Gets the immediately enclosing callable of this node, if any. */ cached Callable getEnclosingCallable() { - exists(AstNode p | p = getParentOfAst(this) | + exists(AstNode p | p = this.getParentNode() | result = p or not p instanceof Callable and result = p.getEnclosingCallable() ) } + + /** Holds if this node is inside a macro expansion. */ + predicate isInMacroExpansion() { + this = any(MacroCall mc).getExpanded() + or + this.getParentNode().isInMacroExpansion() + } } } diff --git a/rust/ql/src/queries/unusedentities/UnreachableCode.ql b/rust/ql/src/queries/unusedentities/UnreachableCode.ql index ffe6ce9d1c6e..aa49c30ce5ad 100644 --- a/rust/ql/src/queries/unusedentities/UnreachableCode.ql +++ b/rust/ql/src/queries/unusedentities/UnreachableCode.ql @@ -29,7 +29,10 @@ predicate hiddenNode(AstNode n) { not succ(n, _) and not succ(_, n) or - n instanceof ControlFlowGraphImpl::PostOrderTree // location is counter-intuitive + n instanceof ControlFlowGraphImpl::PostOrderTree and // location is counter-intuitive + not n instanceof MacroExpr + or + n.isInMacroExpansion() } /** diff --git a/rust/ql/src/queries/unusedentities/UnusedValue.ql b/rust/ql/src/queries/unusedentities/UnusedValue.ql index 6070927f640b..32b54fc7442c 100644 --- a/rust/ql/src/queries/unusedentities/UnusedValue.ql +++ b/rust/ql/src/queries/unusedentities/UnusedValue.ql @@ -20,5 +20,6 @@ where not write = any(Ssa::WriteDefinition def).getWriteAccess().getAstNode() and // avoid overlap with the unused variable query not isUnused(v) and - not v instanceof DiscardVariable -select write, "Variable is assigned a value that is never used." + not v instanceof DiscardVariable and + not write.isInMacroExpansion() +select write, "Variable $@ is assigned a value that is never used.", v, v.getName() diff --git a/rust/ql/src/queries/unusedentities/UnusedVariable.ql b/rust/ql/src/queries/unusedentities/UnusedVariable.ql index 0162d32ff8a3..339bb0967fbf 100644 --- a/rust/ql/src/queries/unusedentities/UnusedVariable.ql +++ b/rust/ql/src/queries/unusedentities/UnusedVariable.ql @@ -13,4 +13,4 @@ import UnusedVariable from Variable v where isUnused(v) -select v, "Variable is not used." +select v, "Variable '" + v + "' is not used." diff --git a/rust/ql/src/queries/unusedentities/UnusedVariable.qll b/rust/ql/src/queries/unusedentities/UnusedVariable.qll index 64cca6e237af..e52b836823b3 100644 --- a/rust/ql/src/queries/unusedentities/UnusedVariable.qll +++ b/rust/ql/src/queries/unusedentities/UnusedVariable.qll @@ -10,5 +10,6 @@ predicate isUnused(Variable v) { not exists(v.getAnAccess()) and not exists(v.getInitializer()) and not v instanceof DiscardVariable and + not v.getPat().isInMacroExpansion() and exists(File f | f.getBaseName() = "main.rs" | v.getLocation().getFile() = f) // temporarily severely limit results } diff --git a/rust/ql/test/query-tests/unusedentities/UnreachableCode.expected b/rust/ql/test/query-tests/unusedentities/UnreachableCode.expected index f2e266021aa6..5d7a60042230 100644 --- a/rust/ql/test/query-tests/unusedentities/UnreachableCode.expected +++ b/rust/ql/test/query-tests/unusedentities/UnreachableCode.expected @@ -1,16 +1,16 @@ -| unreachable.rs:11:9:11:23 | ExprStmt | This code is never reached. | | unreachable.rs:19:9:19:23 | ExprStmt | This code is never reached. | -| unreachable.rs:31:9:31:23 | ExprStmt | This code is never reached. | -| unreachable.rs:38:9:38:23 | ExprStmt | This code is never reached. | -| unreachable.rs:59:5:59:19 | ExprStmt | This code is never reached. | -| unreachable.rs:106:13:106:20 | ExprStmt | This code is never reached. | -| unreachable.rs:115:13:115:20 | ExprStmt | This code is never reached. | -| unreachable.rs:141:5:141:19 | ExprStmt | This code is never reached. | -| unreachable.rs:148:9:148:23 | ExprStmt | This code is never reached. | -| unreachable.rs:157:13:157:27 | ExprStmt | This code is never reached. | -| unreachable.rs:163:9:163:23 | ExprStmt | This code is never reached. | -| unreachable.rs:169:13:169:27 | ExprStmt | This code is never reached. | +| unreachable.rs:27:9:27:23 | ExprStmt | This code is never reached. | +| unreachable.rs:39:9:39:23 | ExprStmt | This code is never reached. | +| unreachable.rs:46:9:46:23 | ExprStmt | This code is never reached. | +| unreachable.rs:67:5:67:19 | ExprStmt | This code is never reached. | +| unreachable.rs:114:13:114:20 | MacroExpr | This code is never reached. | +| unreachable.rs:123:13:123:20 | MacroExpr | This code is never reached. | +| unreachable.rs:149:5:149:19 | ExprStmt | This code is never reached. | +| unreachable.rs:156:9:156:23 | ExprStmt | This code is never reached. | +| unreachable.rs:165:13:165:27 | ExprStmt | This code is never reached. | +| unreachable.rs:171:9:171:23 | ExprStmt | This code is never reached. | | unreachable.rs:177:13:177:27 | ExprStmt | This code is never reached. | -| unreachable.rs:180:5:180:19 | ExprStmt | This code is never reached. | -| unreachable.rs:204:9:204:23 | ExprStmt | This code is never reached. | -| unreachable.rs:220:9:220:23 | ExprStmt | This code is never reached. | +| unreachable.rs:185:13:185:27 | ExprStmt | This code is never reached. | +| unreachable.rs:188:5:188:19 | ExprStmt | This code is never reached. | +| unreachable.rs:212:9:212:23 | ExprStmt | This code is never reached. | +| unreachable.rs:228:9:228:23 | ExprStmt | This code is never reached. | diff --git a/rust/ql/test/query-tests/unusedentities/UnusedValue.expected b/rust/ql/test/query-tests/unusedentities/UnusedValue.expected index e2d0fa11faab..5b438d4c0de9 100644 --- a/rust/ql/test/query-tests/unusedentities/UnusedValue.expected +++ b/rust/ql/test/query-tests/unusedentities/UnusedValue.expected @@ -1,24 +1,20 @@ -| main.rs:6:9:6:9 | a | Variable is assigned a value that is never used. | -| main.rs:9:9:9:9 | d | Variable is assigned a value that is never used. | -| main.rs:35:5:35:5 | b | Variable is assigned a value that is never used. | -| main.rs:37:5:37:5 | c | Variable is assigned a value that is never used. | -| main.rs:40:5:40:5 | c | Variable is assigned a value that is never used. | -| main.rs:44:9:44:9 | d | Variable is assigned a value that is never used. | -| main.rs:50:5:50:5 | e | Variable is assigned a value that is never used. | -| main.rs:61:5:61:5 | f | Variable is assigned a value that is never used. | -| main.rs:63:5:63:5 | f | Variable is assigned a value that is never used. | -| main.rs:65:5:65:5 | g | Variable is assigned a value that is never used. | -| main.rs:87:9:87:9 | a | Variable is assigned a value that is never used. | -| main.rs:108:9:108:10 | is | Variable is assigned a value that is never used. | -| main.rs:131:13:131:17 | total | Variable is assigned a value that is never used. | -| main.rs:194:13:194:31 | res | Variable is assigned a value that is never used. | -| main.rs:206:9:206:24 | kind | Variable is assigned a value that is never used. | -| main.rs:210:9:210:32 | kind | Variable is assigned a value that is never used. | -| main.rs:266:13:266:17 | total | Variable is assigned a value that is never used. | -| main.rs:334:5:334:39 | kind | Variable is assigned a value that is never used. | -| main.rs:359:9:359:9 | x | Variable is assigned a value that is never used. | -| main.rs:367:17:367:17 | x | Variable is assigned a value that is never used. | -| more.rs:24:9:24:11 | val | Variable is assigned a value that is never used. | -| more.rs:44:9:44:14 | a_ptr4 | Variable is assigned a value that is never used. | -| more.rs:59:9:59:13 | d_ptr | Variable is assigned a value that is never used. | -| more.rs:65:9:65:17 | f_ptr | Variable is assigned a value that is never used. | +| main.rs:8:9:8:9 | a | Variable $@ is assigned a value that is never used. | main.rs:8:9:8:9 | a | a | +| main.rs:11:9:11:9 | d | Variable $@ is assigned a value that is never used. | main.rs:11:9:11:9 | d | d | +| main.rs:37:5:37:5 | b | Variable $@ is assigned a value that is never used. | main.rs:28:9:28:9 | b | b | +| main.rs:39:5:39:5 | c | Variable $@ is assigned a value that is never used. | main.rs:29:13:29:13 | c | c | +| main.rs:42:5:42:5 | c | Variable $@ is assigned a value that is never used. | main.rs:29:13:29:13 | c | c | +| main.rs:46:9:46:9 | d | Variable $@ is assigned a value that is never used. | main.rs:30:13:30:13 | d | d | +| main.rs:52:5:52:5 | e | Variable $@ is assigned a value that is never used. | main.rs:31:13:31:13 | e | e | +| main.rs:63:5:63:5 | f | Variable $@ is assigned a value that is never used. | main.rs:32:13:32:13 | f | f | +| main.rs:65:5:65:5 | f | Variable $@ is assigned a value that is never used. | main.rs:32:13:32:13 | f | f | +| main.rs:67:5:67:5 | g | Variable $@ is assigned a value that is never used. | main.rs:33:9:33:9 | g | g | +| main.rs:89:9:89:9 | a | Variable $@ is assigned a value that is never used. | main.rs:89:9:89:9 | a | a | +| main.rs:110:9:110:10 | is | Variable $@ is assigned a value that is never used. | main.rs:110:9:110:10 | is | is | +| main.rs:133:13:133:17 | total | Variable $@ is assigned a value that is never used. | main.rs:133:13:133:17 | total | total | +| main.rs:270:13:270:17 | total | Variable $@ is assigned a value that is never used. | main.rs:238:13:238:17 | total | total | +| main.rs:363:9:363:9 | x | Variable $@ is assigned a value that is never used. | main.rs:363:9:363:9 | x | x | +| main.rs:371:17:371:17 | x | Variable $@ is assigned a value that is never used. | main.rs:371:17:371:17 | x | x | +| more.rs:24:9:24:11 | val | Variable $@ is assigned a value that is never used. | more.rs:24:9:24:11 | val | val | +| 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 | +| 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 | +| more.rs:65:9:65:17 | f_ptr | Variable $@ is assigned a value that is never used. | more.rs:65:13:65:17 | f_ptr | f_ptr | diff --git a/rust/ql/test/query-tests/unusedentities/UnusedVariable.expected b/rust/ql/test/query-tests/unusedentities/UnusedVariable.expected index 804a0849e7aa..293fc4d9fed7 100644 --- a/rust/ql/test/query-tests/unusedentities/UnusedVariable.expected +++ b/rust/ql/test/query-tests/unusedentities/UnusedVariable.expected @@ -1,21 +1,21 @@ -| main.rs:25:9:25:9 | a | Variable is not used. | -| main.rs:90:13:90:13 | d | Variable is not used. | -| main.rs:139:5:139:5 | y | Variable is not used. | -| main.rs:166:9:166:9 | x | Variable is not used. | -| main.rs:236:17:236:17 | a | Variable is not used. | -| main.rs:244:20:244:22 | val | Variable is not used. | -| main.rs:258:14:258:16 | val | Variable is not used. | -| main.rs:273:22:273:24 | val | Variable is not used. | -| main.rs:280:24:280:26 | val | Variable is not used. | -| main.rs:288:13:288:15 | num | Variable is not used. | -| main.rs:303:12:303:12 | j | Variable is not used. | -| main.rs:323:25:323:25 | y | Variable is not used. | -| main.rs:326:28:326:28 | a | Variable is not used. | -| main.rs:329:9:329:9 | p | Variable is not used. | -| main.rs:347:9:347:13 | right | Variable is not used. | -| main.rs:353:9:353:14 | right2 | Variable is not used. | -| main.rs:360:13:360:13 | y | Variable is not used. | -| main.rs:368:21:368:21 | y | Variable is not used. | -| main.rs:413:26:413:28 | val | Variable is not used. | -| main.rs:416:21:416:23 | acc | Variable is not used. | -| main.rs:437:9:437:14 | unused | Variable is not used. | +| main.rs:27:9:27:9 | a | Variable 'a' is not used. | +| main.rs:92:13:92:13 | d | Variable 'd' is not used. | +| main.rs:141:5:141:5 | y | Variable 'y' is not used. | +| main.rs:168:9:168:9 | x | Variable 'x' is not used. | +| main.rs:240:17:240:17 | a | Variable 'a' is not used. | +| main.rs:248:20:248:22 | val | Variable 'val' is not used. | +| main.rs:262:14:262:16 | val | Variable 'val' is not used. | +| main.rs:277:22:277:24 | val | Variable 'val' is not used. | +| main.rs:284:24:284:26 | val | Variable 'val' is not used. | +| main.rs:292:13:292:15 | num | Variable 'num' is not used. | +| main.rs:307:12:307:12 | j | Variable 'j' is not used. | +| main.rs:327:25:327:25 | y | Variable 'y' is not used. | +| main.rs:330:28:330:28 | a | Variable 'a' is not used. | +| main.rs:333:9:333:9 | p | Variable 'p' is not used. | +| main.rs:351:9:351:13 | right | Variable 'right' is not used. | +| main.rs:357:9:357:14 | right2 | Variable 'right2' is not used. | +| main.rs:364:13:364:13 | y | Variable 'y' is not used. | +| main.rs:372:21:372:21 | y | Variable 'y' is not used. | +| main.rs:417:26:417:28 | val | Variable 'val' is not used. | +| main.rs:420:21:420:23 | acc | Variable 'acc' is not used. | +| main.rs:441:9:441:14 | unused | Variable 'unused' is not used. | diff --git a/rust/ql/test/query-tests/unusedentities/main.rs b/rust/ql/test/query-tests/unusedentities/main.rs index 07485e3af714..ee315f63d002 100644 --- a/rust/ql/test/query-tests/unusedentities/main.rs +++ b/rust/ql/test/query-tests/unusedentities/main.rs @@ -1,4 +1,6 @@ -//fn cond() -> bool; +mod unreachable; + +use unreachable::*; // --- locals --- @@ -191,7 +193,7 @@ fn loops() { } for x in 1..10 { - _ = format!("x is {x}"); // $ SPURIOUS: Alert[rust/unused-value] + _ = format!("x is {x}"); } for x in 1..10 { @@ -203,11 +205,13 @@ fn loops() { } for x in 1..10 { - assert_eq!(x, 1); // $ SPURIOUS: Alert[rust/unused-value] + assert_eq!(x, 1); + break; } for x in 1..10 { - assert_eq!(id(x), id(1)); // $ SPURIOUS: Alert[rust/unused-value] + assert_eq!(id(x), id(1)); + break; } } @@ -331,7 +335,7 @@ fn if_lets_matches() { } let duration1 = std::time::Duration::new(10, 0); // ten seconds - assert_eq!(duration1.as_secs(), 10); // $ SPURIOUS: Alert[rust/unused-value] + assert_eq!(duration1.as_secs(), 10); let duration2: Result = Ok(std::time::Duration::new(10, 0)); match duration2 { @@ -434,7 +438,7 @@ impl Incrementable for MyValue { fn increment( &mut self, times: i32, - unused: i32, // $ Alert[rust/unused-variable] + unused: &mut i32, // $ Alert[rust/unused-variable] ) { self.value += times; } @@ -443,9 +447,22 @@ impl Incrementable for MyValue { fn traits() { let mut i = MyValue { value: 0 }; let a = 1; - let b = 2; + let mut b = 2; + + i.increment(a, &mut b); +} - i.increment(a, b); +// --- macros --- + +fn macros() { + let x; + println!( + "The value of x is {}", + ({ + x = 10; // $ MISSING: Alert[rust/unused-value] + 10 + }) + ) } // --- main --- @@ -464,12 +481,14 @@ fn main() { folds_and_closures(); unreachable_if_1(); - unreachable_panic(); + // unreachable_panic(); unreachable_match(); - unreachable_loop(); + // unreachable_loop(); unreachable_paren(); unreachable_let_1(); unreachable_let_2(); unreachable_if_2(); unreachable_if_3(); + + macros(); } diff --git a/rust/ql/test/query-tests/unusedentities/options b/rust/ql/test/query-tests/unusedentities/options deleted file mode 100644 index cf148dd35f86..000000000000 --- a/rust/ql/test/query-tests/unusedentities/options +++ /dev/null @@ -1 +0,0 @@ -qltest_cargo_check: false diff --git a/rust/ql/test/query-tests/unusedentities/unreachable.rs b/rust/ql/test/query-tests/unusedentities/unreachable.rs index 3aecbed48866..9f206eb6eb33 100644 --- a/rust/ql/test/query-tests/unusedentities/unreachable.rs +++ b/rust/ql/test/query-tests/unusedentities/unreachable.rs @@ -1,12 +1,20 @@ -//fn cond() -> bool; -//fn get_a_number() -> i32; -//fn maybe_get_a_number() -> Option; +pub fn cond() -> bool { + get_a_number() == 1 +} + +fn get_a_number() -> i32 { + maybe_get_a_number().unwrap_or(0) +} + +fn maybe_get_a_number() -> Option { + std::env::args().nth(1).map(|s| s.parse::().unwrap()) +} // --- unreachable code -- fn do_something() {} -fn unreachable_if_1() { +pub fn unreachable_if_1() { if false { do_something(); // $ Alert[rust/dead-code] } else { @@ -59,7 +67,7 @@ fn unreachable_if_1() { do_something(); // $ Alert[rust/dead-code] } -fn unreachable_panic() { +pub fn unreachable_panic() { if cond() { do_something(); panic!("Oh no!!!"); @@ -119,7 +127,7 @@ fn unreachable_panic() { } } -fn unreachable_match() { +pub fn unreachable_match() { match get_a_number() { 1 => { return; @@ -141,7 +149,7 @@ fn unreachable_match() { do_something(); // $ Alert[rust/dead-code] } -fn unreachable_loop() { +pub fn unreachable_loop() { loop { do_something(); break; @@ -182,11 +190,11 @@ fn unreachable_loop() { do_something(); } -fn unreachable_paren() { +pub fn unreachable_paren() { let _ = (((1))); } -fn unreachable_let_1() { +pub fn unreachable_let_1() { if let Some(_) = maybe_get_a_number() { do_something(); return; @@ -207,7 +215,7 @@ fn unreachable_let_1() { do_something(); } -fn unreachable_let_2() { +pub fn unreachable_let_2() { let Some(_) = maybe_get_a_number() else { do_something(); return; @@ -224,7 +232,7 @@ fn unreachable_let_2() { do_something(); } -fn unreachable_if_2() { +pub fn unreachable_if_2() { if cond() { do_something(); return; @@ -235,7 +243,7 @@ fn unreachable_if_2() { do_something(); } -fn unreachable_if_3() { +pub fn unreachable_if_3() { if !cond() { do_something(); return;