Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust: Placeholder queries for unused variable, unused value #17497

Merged
merged 10 commits into from
Sep 20, 2024
24 changes: 24 additions & 0 deletions rust/ql/src/queries/unusedentities/UnusedValue.qhelp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>

<overview>
<p>This rule finds values that are assigned to variables but never used. Unused values should be removed to increase readability and avoid confusion.</p>
</overview>

<recommendation>
<p>Remove any unused values. Also remove any variables that only hold unused values.</p>
</recommendation>

<example>
<p>In the following example, there is a variable <code>average</code> that is initialized to <code>0</code>, but that value is never used:</p>
<sample src="UnusedValueBad.rs" />
<p>The problem can be fixed by removing the unused value:</p>
<sample src="UnusedValueGood.rs" />
</example>

<references>
<li>GeeksforGeeks: <a href="https://www.geeksforgeeks.org/how-to-avoid-unused-variable-warning-in-rust/">How to avoid unused Variable warning in Rust?</a></li>
</references>
</qhelp>
15 changes: 15 additions & 0 deletions rust/ql/src/queries/unusedentities/UnusedValue.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* @name Unused value
* @description Unused values may be an indication that the code is incomplete or has a typo.
* @kind problem
* @problem.severity recommendation
* @precision medium
* @id rust/unused-value
* @tags maintainability
*/

import rust

from Locatable e
where none() // TODO: implement query
select e, "Variable is assigned a value that is never used."
11 changes: 11 additions & 0 deletions rust/ql/src/queries/unusedentities/UnusedValueBad.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fn get_average(values:&[i32]) -> f64 {
let mut sum = 0;
let mut average = 0.0; // BAD: unused value

for v in values {
sum += v;
}

average = sum as f64 / values.len() as f64;
return average;
}
11 changes: 11 additions & 0 deletions rust/ql/src/queries/unusedentities/UnusedValueGood.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fn get_average(values:&[i32]) -> f64 {
let mut sum = 0;
let average;

for v in values {
sum += v;
}

average = sum as f64 / values.len() as f64;
return average;
}
24 changes: 24 additions & 0 deletions rust/ql/src/queries/unusedentities/UnusedVariable.qhelp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>

<overview>
<p>This rule finds variables that are never accessed. Unused variables should be removed to increase readability and avoid confusion.</p>
</overview>

<recommendation>
<p>Remove any unused variables.</p>
</recommendation>

<example>
<p>In the following example, there is an unused variable <code>average</code> that is never used:</p>
<sample src="UnusedVariableBad.rs" />
<p>The problem can be fixed simply by removing the variable:</p>
<sample src="UnusedVariableGood.rs" />
</example>

<references>
<li>GeeksforGeeks: <a href="https://www.geeksforgeeks.org/how-to-avoid-unused-variable-warning-in-rust/">How to avoid unused Variable warning in Rust?</a></li>
</references>
</qhelp>
15 changes: 15 additions & 0 deletions rust/ql/src/queries/unusedentities/UnusedVariable.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* @name Unused variable
* @description Unused variables may be an indication that the code is incomplete or has a typo.
* @kind problem
* @problem.severity recommendation
* @precision medium
* @id rust/unused-variable
* @tags maintainability
*/

import rust

from Locatable e
where none() // TODO: implement query
select e, "Variable is not used."
10 changes: 10 additions & 0 deletions rust/ql/src/queries/unusedentities/UnusedVariableBad.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fn get_sum(values:&[i32]) -> i32 {
let mut sum = 0;
let mut average; // BAD: unused variable

for v in values {
sum += v;
}

return sum;
}
9 changes: 9 additions & 0 deletions rust/ql/src/queries/unusedentities/UnusedVariableGood.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fn get_sum(values:&[i32]) -> i32 {
let mut sum = 0;

for v in values {
sum += v;
}

return sum;
}
Empty file.
1 change: 1 addition & 0 deletions rust/ql/test/query-tests/unusedentities/UnusedValue.qlref
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
queries/unusedentities/UnusedValue.ql
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
queries/unusedentities/UnusedVariable.ql
152 changes: 152 additions & 0 deletions rust/ql/test/query-tests/unusedentities/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@

//fn cond() -> bool;

// --- locals ---

fn locals_1() {
let a = 1; // BAD: unused value [NOT DETECTED]
let b = 1;
let c = 1;
let d = String::from("a"); // BAD: unused value [NOT DETECTED]
let e = String::from("b");
let _ = 1; // (deliberately unused)

println!("use {}", b);

if cond() {
println!("use {}", c);
}

println!("use {}", e);
}

fn locals_2() {
let a: i32;
let b: i32; // BAD: unused variable [NOT DETECTED]
let mut c: i32;
let mut d: i32;
let mut e: i32;
let mut f: i32;
let g: i32;
let h: i32;
let i: i32;

b = 1; // BAD: unused value [NOT DETECTED]

c = 1; // BAD: unused value [NOT DETECTED]
c = 2;
println!("use {}", c);
c = 3; // BAD: unused value [NOT DETECTED]

d = 1;
if cond() {
d = 2; // BAD: unused value [NOT DETECTED]
d = 3;
} else {
}
println!("use {}", d);

e = 1; // BAD: unused value [NOT DETECTED]
if cond() {
e = 2;
} else {
e = 3;
}
println!("use {}", e);

f = 1;
f += 1;
println!("use {}", f);
f += 1; // BAD: unused value [NOT DETECTED]
f = 1;
f += 1; // BAD: unused value [NOT DETECTED]

g = if cond() { 1 } else { 2 }; // BAD: unused value (x2) [NOT DETECTED]
h = if cond() { 3 } else { 4 };
i = if cond() { h } else { 5 };
println!("use {}", i);

_ = 1; // (deliberately unused) [NOT DETECTED]
}

// --- structs ---

#[derive(Debug)]
struct MyStruct {
val: i64
}

impl MyStruct {
fn my_get(&mut self) -> i64 {
return self.val;
}
}

fn structs() {
let a = MyStruct {val : 1 }; // BAD: unused value [NOT DETECTED]
let b = MyStruct {val : 2 };
let c = MyStruct {val : 3 };
let mut d : MyStruct; // BAD: unused variable [NOT DETECTED]
let mut e : MyStruct;
let mut f : MyStruct;

println!("lets use {:?} and {}", b, c.val);

e = MyStruct {val : 4 };
println!("lets use {}", e.my_get());
e.val = 5;
println!("lets use {}", e.my_get());

f = MyStruct {val : 6 }; // BAD: unused value [NOT DETECTED]
f.val = 7; // BAD: unused value [NOT DETECTED]
}

// --- arrays ---

fn arrays() {
let is = [1, 2, 3]; // BAD: unused values (x3) [NOT DETECTED]
let js = [1, 2, 3];
let ks = [1, 2, 3];

println!("lets use {:?}", js);

for k in ks {
println!("lets use {}", k);
}
}

// --- constants and statics ---

const CON1: i32 = 1;
const CON2: i32 = 2; // BAD: unused value [NOT DETECTED]
static mut STAT1: i32 = 1;
static mut STAT2: i32 = 2; // BAD: unused value [NOT DETECTED]

fn statics() {
static mut STAT3: i32 = 0;
static mut STAT4: i32 = 0; // BAD: unused value [NOT DETECTED]

unsafe
{
let total = CON1 + STAT1 + STAT3;
}
}

// --- parameters ---

fn parameters(
x: i32,
y: i32, // BAD: unused variable [NOT DETECTED]
_z: i32 // (`_` is asking the compiler, and by extension us, to not warn that this is unused)
) -> i32 {
return x;
}

fn main() {
locals_1();
locals_2();
structs();
arrays();
statics();
println!("lets use result {}", parameters(1, 2, 3));
}
Loading