#![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; fn main() { binary_heap_retain(); btree_set_retain(); btree_map_retain(); hash_set_retain(); hash_map_retain(); string_retain(); vec_deque_retain(); vec_retain(); _msrv_153(); _msrv_126(); _msrv_118(); issue_10393(); issue_12081(); } fn binary_heap_retain() { let mut binary_heap = BinaryHeap::from([1, 2, 3]); // Do lint. binary_heap.retain(|x| x % 2 == 0); binary_heap.retain(|x| x % 2 == 0); binary_heap.retain(|x| x % 2 == 0); // Do lint, because we use pattern matching let mut tuples = BinaryHeap::from([(0, 1), (1, 2), (2, 3)]); tuples.retain(|(ref x, ref y)| *x == 0); tuples.retain(|(x, y)| *x == 0); // Do not lint, because type conversion is performed binary_heap = binary_heap .into_iter() .filter(|x| x % 2 == 0) .collect::>(); binary_heap = binary_heap .iter() .filter(|&x| x % 2 == 0) .copied() .collect::>(); binary_heap = binary_heap .iter() .filter(|&x| x % 2 == 0) .cloned() .collect::>(); // Do not lint, because this expression is not assign. let mut bar: BinaryHeap = binary_heap.iter().filter(|&x| x % 2 == 0).copied().collect(); let mut foobar: BinaryHeap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect(); // Do not lint, because it is an assignment to a different variable. bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); } fn btree_map_retain() { let mut btree_map: BTreeMap = (0..8).map(|x| (x, x * 10)).collect(); // Do lint. btree_map.retain(|k, _| k % 2 == 0); btree_map.retain(|_, &mut v| v % 2 == 0); btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0)); // Do not lint, because the parameters are not matched in tuple pattern btree_map = btree_map.into_iter().filter(|t| t.0 % 2 == 0).collect(); // Do not lint. btree_map = btree_map .into_iter() .filter(|(x, _)| x % 2 == 0) .collect::>(); // Do not lint, because this expression is not assign. let mut foobar: BTreeMap = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); // Do not lint, because it is an assignment to a different variable. btree_map = foobar.into_iter().filter(|(k, _)| k % 2 == 0).collect(); } fn btree_set_retain() { let mut btree_set = BTreeSet::from([1, 2, 3, 4, 5, 6]); // Do lint. btree_set.retain(|x| x % 2 == 0); btree_set.retain(|x| x % 2 == 0); btree_set.retain(|x| x % 2 == 0); // Do lint, because we use pattern matching let mut tuples = BTreeSet::from([(0, 1), (1, 2), (2, 3)]); tuples.retain(|(ref x, ref y)| *x == 0); tuples.retain(|(x, y)| *x == 0); // Do not lint, because type conversion is performed btree_set = btree_set .iter() .filter(|&x| x % 2 == 0) .copied() .collect::>(); btree_set = btree_set .iter() .filter(|&x| x % 2 == 0) .cloned() .collect::>(); btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect::>(); // Do not lint, because this expression is not assign. let mut foobar: BTreeSet = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); let mut bar: BTreeSet = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); // Do not lint, because it is an assignment to a different variable. bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); } fn hash_map_retain() { let mut hash_map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); // Do lint. hash_map.retain(|k, _| k % 2 == 0); hash_map.retain(|_, &mut v| v % 2 == 0); hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0)); // Do not lint, because the parameters are not matched in tuple pattern hash_map = hash_map.into_iter().filter(|t| t.0 % 2 == 0).collect(); // Do not lint. hash_map = hash_map .into_iter() .filter(|(x, _)| x % 2 == 0) .collect::>(); // Do not lint, because this expression is not assign. let mut foobar: HashMap = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); // Do not lint, because it is an assignment to a different variable. hash_map = foobar.into_iter().filter(|(k, _)| k % 2 == 0).collect(); } fn hash_set_retain() { let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]); // Do lint. hash_set.retain(|x| x % 2 == 0); hash_set.retain(|x| x % 2 == 0); hash_set.retain(|x| x % 2 == 0); // Do lint, because we use pattern matching let mut tuples = HashSet::from([(0, 1), (1, 2), (2, 3)]); tuples.retain(|(ref x, ref y)| *x == 0); tuples.retain(|(x, y)| *x == 0); // Do not lint, because type conversion is performed hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect::>(); hash_set = hash_set .iter() .filter(|&x| x % 2 == 0) .copied() .collect::>(); hash_set = hash_set .iter() .filter(|&x| x % 2 == 0) .cloned() .collect::>(); // Do not lint, because this expression is not assign. let mut bar: HashSet = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect(); let mut foobar: HashSet = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); // Do not lint, because it is an assignment to a different variable. bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); bar = foobar.into_iter().filter(|&x| x % 2 == 0).collect(); } fn string_retain() { let mut s = String::from("foobar"); // Do lint. s.retain(|c| c != 'o'); // Do not lint, because this expression is not assign. let mut bar: String = s.chars().filter(|&c| c != 'o').to_owned().collect(); // Do not lint, because it is an assignment to a different variable. s = bar.chars().filter(|&c| c != 'o').to_owned().collect(); } fn vec_retain() { let mut vec = vec![0, 1, 2]; // Do lint. vec.retain(|x| x % 2 == 0); vec.retain(|x| x % 2 == 0); vec.retain(|x| x % 2 == 0); // Do lint, because we use pattern matching let mut tuples = vec![(0, 1), (1, 2), (2, 3)]; tuples.retain(|(ref x, ref y)| *x == 0); tuples.retain(|(x, y)| *x == 0); // Do not lint, because type conversion is performed vec = vec.into_iter().filter(|x| x % 2 == 0).collect::>(); vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect::>(); vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect::>(); // Do not lint, because this expression is not assign. let mut bar: Vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); let mut foobar: Vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); // Do not lint, because it is an assignment to a different variable. bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); } fn vec_deque_retain() { let mut vec_deque = VecDeque::new(); vec_deque.extend(1..5); // Do lint. vec_deque.retain(|x| x % 2 == 0); vec_deque.retain(|x| x % 2 == 0); vec_deque.retain(|x| x % 2 == 0); // Do not lint, because type conversion is performed vec_deque = vec_deque .iter() .filter(|&x| x % 2 == 0) .copied() .collect::>(); vec_deque = vec_deque .iter() .filter(|&x| x % 2 == 0) .cloned() .collect::>(); vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect::>(); // Do not lint, because this expression is not assign. let mut bar: VecDeque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect(); let mut foobar: VecDeque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect(); // Do not lint, because it is an assignment to a different variable. bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); } #[clippy::msrv = "1.69"] fn _msrv_169() { let mut binary_heap = BinaryHeap::from([1, 2, 3]); binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect(); } #[clippy::msrv = "1.52"] fn _msrv_153() { let mut btree_map: BTreeMap = (0..8).map(|x| (x, x * 10)).collect(); btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); let mut btree_set = BTreeSet::from([1, 2, 3, 4, 5, 6]); btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); } #[clippy::msrv = "1.25"] fn _msrv_126() { let mut s = String::from("foobar"); s = s.chars().filter(|&c| c != 'o').to_owned().collect(); } #[clippy::msrv = "1.17"] fn _msrv_118() { let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]); hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); let mut hash_map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); } fn issue_10393() { // Do lint let mut vec = vec![(0, 1), (1, 2), (2, 3)]; vec.retain(|(x, y)| *x == 0); // Do lint let mut tuples = vec![(true, -2), (false, 3)]; tuples.retain(|(_, n)| *n > 0); } fn issue_11457() { // Do not lint, as we need to modify the closure let mut vals = vec![1, 2, 3, 4]; vals = vals.iter().filter(|v| **v != 1).cloned().collect(); // Do not lint, as we need to modify the closure let mut s = String::from("foobar"); s = s.chars().filter(|c| *c != 'o').to_owned().collect(); } fn issue_12081() { let mut vec = vec![0, 1, 2]; // Do lint vec.retain(|&x| x == 0); vec.retain(|&x| x == 0); vec.retain(|&x| x == 0); // Do lint vec.retain(|x| *x == 0); vec.retain(|x| *x == 0); vec.retain(|x| *x == 0); }