2023-07-02 07:35:19 -05:00
|
|
|
#![allow(unused, clippy::useless_vec)]
|
2023-03-10 03:53:50 -06:00
|
|
|
#![warn(clippy::collection_is_never_read)]
|
|
|
|
|
|
|
|
use std::collections::{HashMap, HashSet};
|
|
|
|
|
|
|
|
fn main() {}
|
|
|
|
|
|
|
|
fn not_a_collection() {
|
|
|
|
// TODO: Expand `collection_is_never_read` beyond collections?
|
|
|
|
let mut x = 10; // Ok
|
|
|
|
x += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn no_access_at_all() {
|
|
|
|
// Other lints should catch this.
|
|
|
|
let x = vec![1, 2, 3]; // Ok
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_without_read() {
|
|
|
|
// The main use case for `collection_is_never_read`.
|
|
|
|
let mut x = HashMap::new(); // WARNING
|
|
|
|
x.insert(1, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_without_write() {
|
|
|
|
let mut x = vec![1, 2, 3]; // Ok
|
|
|
|
let _ = x.len();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_and_read() {
|
|
|
|
let mut x = vec![1, 2, 3]; // Ok
|
|
|
|
x.push(4);
|
|
|
|
let _ = x.len();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_after_read() {
|
|
|
|
// TODO: Warn here, but this requires more extensive data flow analysis.
|
|
|
|
let mut x = vec![1, 2, 3]; // Ok
|
|
|
|
let _ = x.len();
|
|
|
|
x.push(4); // Pointless
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_before_reassign() {
|
|
|
|
// TODO: Warn here, but this requires more extensive data flow analysis.
|
|
|
|
let mut x = HashMap::new(); // Ok
|
|
|
|
x.insert(1, 2); // Pointless
|
|
|
|
x = HashMap::new();
|
|
|
|
let _ = x.len();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_in_closure() {
|
|
|
|
let mut x = HashMap::new(); // Ok
|
|
|
|
x.insert(1, 2);
|
|
|
|
let _ = || {
|
|
|
|
let _ = x.len();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_in_closure() {
|
|
|
|
let mut x = vec![1, 2, 3]; // WARNING
|
|
|
|
let _ = || {
|
|
|
|
x.push(4);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_in_format() {
|
|
|
|
let mut x = HashMap::new(); // Ok
|
|
|
|
x.insert(1, 2);
|
|
|
|
format!("{x:?}");
|
|
|
|
}
|
|
|
|
|
|
|
|
fn shadowing_1() {
|
|
|
|
let x = HashMap::<usize, usize>::new(); // Ok
|
|
|
|
let _ = x.len();
|
|
|
|
let mut x = HashMap::new(); // WARNING
|
|
|
|
x.insert(1, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn shadowing_2() {
|
|
|
|
let mut x = HashMap::new(); // WARNING
|
|
|
|
x.insert(1, 2);
|
|
|
|
let x = HashMap::<usize, usize>::new(); // Ok
|
|
|
|
let _ = x.len();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(clippy::let_unit_value)]
|
2023-04-11 08:31:08 -05:00
|
|
|
fn fake_read_1() {
|
|
|
|
let mut x = vec![1, 2, 3]; // WARNING
|
2023-03-10 03:53:50 -06:00
|
|
|
x.reverse();
|
|
|
|
let _: () = x.clear();
|
|
|
|
}
|
|
|
|
|
2023-04-11 08:31:08 -05:00
|
|
|
fn fake_read_2() {
|
|
|
|
let mut x = vec![1, 2, 3]; // WARNING
|
|
|
|
x.reverse();
|
|
|
|
println!("{:?}", x.push(5));
|
|
|
|
}
|
|
|
|
|
2023-03-10 03:53:50 -06:00
|
|
|
fn assignment() {
|
|
|
|
let mut x = vec![1, 2, 3]; // WARNING
|
|
|
|
let y = vec![4, 5, 6]; // Ok
|
|
|
|
x = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(clippy::self_assignment)]
|
|
|
|
fn self_assignment() {
|
|
|
|
let mut x = vec![1, 2, 3]; // WARNING
|
|
|
|
x = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn method_argument_but_not_target() {
|
|
|
|
struct MyStruct;
|
|
|
|
impl MyStruct {
|
|
|
|
fn my_method(&self, _argument: &[usize]) {}
|
|
|
|
}
|
|
|
|
let my_struct = MyStruct;
|
|
|
|
|
|
|
|
let mut x = vec![1, 2, 3]; // Ok
|
|
|
|
x.reverse();
|
|
|
|
my_struct.my_method(&x);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn insert_is_not_a_read() {
|
|
|
|
let mut x = HashSet::new(); // WARNING
|
|
|
|
x.insert(5);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn insert_is_a_read() {
|
|
|
|
let mut x = HashSet::new(); // Ok
|
|
|
|
if x.insert(5) {
|
|
|
|
println!("5 was inserted");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn not_read_if_return_value_not_used() {
|
|
|
|
// `is_empty` does not modify the set, so it's a query. But since the return value is not used, the
|
|
|
|
// lint does not consider it a read here.
|
|
|
|
let x = vec![1, 2, 3]; // WARNING
|
|
|
|
x.is_empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn extension_traits() {
|
|
|
|
trait VecExt<T> {
|
|
|
|
fn method_with_side_effect(&self);
|
|
|
|
fn method_without_side_effect(&self);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> VecExt<T> for Vec<T> {
|
|
|
|
fn method_with_side_effect(&self) {
|
|
|
|
println!("my length: {}", self.len());
|
|
|
|
}
|
|
|
|
fn method_without_side_effect(&self) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
let x = vec![1, 2, 3]; // Ok
|
|
|
|
x.method_with_side_effect();
|
|
|
|
|
|
|
|
let y = vec![1, 2, 3]; // Ok (false negative)
|
|
|
|
y.method_without_side_effect();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn function_argument() {
|
|
|
|
#[allow(clippy::ptr_arg)]
|
|
|
|
fn foo<T>(v: &Vec<T>) -> usize {
|
|
|
|
v.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
let x = vec![1, 2, 3]; // Ok
|
|
|
|
foo(&x);
|
|
|
|
}
|
2023-04-11 08:31:08 -05:00
|
|
|
|
2023-04-23 06:03:09 -05:00
|
|
|
fn supported_types() {
|
|
|
|
let mut x = std::collections::BTreeMap::new(); // WARNING
|
|
|
|
x.insert(true, 1);
|
|
|
|
|
|
|
|
let mut x = std::collections::BTreeSet::new(); // WARNING
|
|
|
|
x.insert(1);
|
|
|
|
|
|
|
|
let mut x = std::collections::BinaryHeap::new(); // WARNING
|
|
|
|
x.push(1);
|
|
|
|
|
|
|
|
let mut x = std::collections::HashMap::new(); // WARNING
|
|
|
|
x.insert(1, 2);
|
|
|
|
|
|
|
|
let mut x = std::collections::HashSet::new(); // WARNING
|
|
|
|
x.insert(1);
|
|
|
|
|
|
|
|
let mut x = std::collections::LinkedList::new(); // WARNING
|
|
|
|
x.push_front(1);
|
|
|
|
|
|
|
|
let mut x = Some(true); // WARNING
|
|
|
|
x.insert(false);
|
|
|
|
|
|
|
|
let mut x = String::from("hello"); // WARNING
|
|
|
|
x.push('!');
|
|
|
|
|
|
|
|
let mut x = Vec::new(); // WARNING
|
|
|
|
x.clear();
|
|
|
|
x.push(1);
|
|
|
|
|
|
|
|
let mut x = std::collections::VecDeque::new(); // WARNING
|
|
|
|
x.push_front(1);
|
2023-04-11 08:31:08 -05:00
|
|
|
}
|