1 //@run-rustfix
2 #![warn(clippy::manual_retain)]
3 #![allow(unused, clippy::redundant_clone)]
4 use std::collections::BTreeMap;
5 use std::collections::BTreeSet;
6 use std::collections::BinaryHeap;
7 use std::collections::HashMap;
8 use std::collections::HashSet;
9 use std::collections::VecDeque;
10
main()11 fn main() {
12 binary_heap_retain();
13 btree_set_retain();
14 btree_map_retain();
15 hash_set_retain();
16 hash_map_retain();
17 string_retain();
18 vec_deque_retain();
19 vec_retain();
20 _msrv_153();
21 _msrv_126();
22 _msrv_118();
23 }
24
binary_heap_retain()25 fn binary_heap_retain() {
26 // NOTE: Do not lint now, because binary_heap_retain is nightly API.
27 // And we need to add a test case for msrv if we update this implementation.
28 // https://github.com/rust-lang/rust/issues/71503
29 let mut heap = BinaryHeap::from([1, 2, 3]);
30 heap = heap.into_iter().filter(|x| x % 2 == 0).collect();
31 heap = heap.iter().filter(|&x| x % 2 == 0).copied().collect();
32 heap = heap.iter().filter(|&x| x % 2 == 0).cloned().collect();
33
34 // Do not lint, because type conversion is performed
35 heap = heap.into_iter().filter(|x| x % 2 == 0).collect::<BinaryHeap<i8>>();
36 heap = heap.iter().filter(|&x| x % 2 == 0).copied().collect::<BinaryHeap<i8>>();
37 heap = heap.iter().filter(|&x| x % 2 == 0).cloned().collect::<BinaryHeap<i8>>();
38
39 // Do not lint, because this expression is not assign.
40 let mut bar: BinaryHeap<i8> = heap.iter().filter(|&x| x % 2 == 0).copied().collect();
41 let mut foobar: BinaryHeap<i8> = heap.into_iter().filter(|x| x % 2 == 0).collect();
42
43 // Do not lint, because it is an assignment to a different variable.
44 bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect();
45 bar = foobar.into_iter().filter(|x| x % 2 == 0).collect();
46 }
47
btree_map_retain()48 fn btree_map_retain() {
49 let mut btree_map: BTreeMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
50 // Do lint.
51 btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
52 btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect();
53 btree_map = btree_map
54 .into_iter()
55 .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0))
56 .collect();
57
58 // Do not lint.
59 btree_map = btree_map
60 .into_iter()
61 .filter(|(x, _)| x % 2 == 0)
62 .collect::<BTreeMap<i8, i8>>();
63
64 // Do not lint, because this expression is not assign.
65 let mut foobar: BTreeMap<i8, i8> = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
66
67 // Do not lint, because it is an assignment to a different variable.
68 btree_map = foobar.into_iter().filter(|(k, _)| k % 2 == 0).collect();
69 }
70
btree_set_retain()71 fn btree_set_retain() {
72 let mut btree_set = BTreeSet::from([1, 2, 3, 4, 5, 6]);
73
74 // Do lint.
75 btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect();
76 btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
77 btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect();
78
79 // Do not lint, because type conversion is performed
80 btree_set = btree_set
81 .iter()
82 .filter(|&x| x % 2 == 0)
83 .copied()
84 .collect::<BTreeSet<i8>>();
85
86 btree_set = btree_set
87 .iter()
88 .filter(|&x| x % 2 == 0)
89 .cloned()
90 .collect::<BTreeSet<i8>>();
91
92 btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect::<BTreeSet<i8>>();
93
94 // Do not lint, because this expression is not assign.
95 let mut foobar: BTreeSet<i8> = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect();
96 let mut bar: BTreeSet<i8> = btree_set.into_iter().filter(|x| x % 2 == 0).collect();
97
98 // Do not lint, because it is an assignment to a different variable.
99 bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect();
100 bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect();
101 bar = foobar.into_iter().filter(|x| x % 2 == 0).collect();
102 }
103
hash_map_retain()104 fn hash_map_retain() {
105 let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
106 // Do lint.
107 hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
108 hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect();
109 hash_map = hash_map
110 .into_iter()
111 .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0))
112 .collect();
113
114 // Do not lint.
115 hash_map = hash_map
116 .into_iter()
117 .filter(|(x, _)| x % 2 == 0)
118 .collect::<HashMap<i8, i8>>();
119
120 // Do not lint, because this expression is not assign.
121 let mut foobar: HashMap<i8, i8> = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
122
123 // Do not lint, because it is an assignment to a different variable.
124 hash_map = foobar.into_iter().filter(|(k, _)| k % 2 == 0).collect();
125 }
126
hash_set_retain()127 fn hash_set_retain() {
128 let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]);
129 // Do lint.
130 hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect();
131 hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect();
132 hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
133
134 // Do not lint, because type conversion is performed
135 hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect::<HashSet<i8>>();
136 hash_set = hash_set
137 .iter()
138 .filter(|&x| x % 2 == 0)
139 .copied()
140 .collect::<HashSet<i8>>();
141
142 hash_set = hash_set
143 .iter()
144 .filter(|&x| x % 2 == 0)
145 .cloned()
146 .collect::<HashSet<i8>>();
147
148 // Do not lint, because this expression is not assign.
149 let mut bar: HashSet<i8> = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect();
150 let mut foobar: HashSet<i8> = hash_set.into_iter().filter(|x| x % 2 == 0).collect();
151
152 // Do not lint, because it is an assignment to a different variable.
153 bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect();
154 bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect();
155 bar = foobar.into_iter().filter(|&x| x % 2 == 0).collect();
156 }
157
string_retain()158 fn string_retain() {
159 let mut s = String::from("foobar");
160 // Do lint.
161 s = s.chars().filter(|&c| c != 'o').to_owned().collect();
162
163 // Do not lint, because this expression is not assign.
164 let mut bar: String = s.chars().filter(|&c| c != 'o').to_owned().collect();
165
166 // Do not lint, because it is an assignment to a different variable.
167 s = bar.chars().filter(|&c| c != 'o').to_owned().collect();
168 }
169
vec_retain()170 fn vec_retain() {
171 let mut vec = vec![0, 1, 2];
172 // Do lint.
173 vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect();
174 vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect();
175 vec = vec.into_iter().filter(|x| x % 2 == 0).collect();
176
177 // Do not lint, because type conversion is performed
178 vec = vec.into_iter().filter(|x| x % 2 == 0).collect::<Vec<i8>>();
179 vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect::<Vec<i8>>();
180 vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect::<Vec<i8>>();
181
182 // Do not lint, because this expression is not assign.
183 let mut bar: Vec<i8> = vec.iter().filter(|&x| x % 2 == 0).copied().collect();
184 let mut foobar: Vec<i8> = vec.into_iter().filter(|x| x % 2 == 0).collect();
185
186 // Do not lint, because it is an assignment to a different variable.
187 bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect();
188 bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect();
189 bar = foobar.into_iter().filter(|x| x % 2 == 0).collect();
190 }
191
vec_deque_retain()192 fn vec_deque_retain() {
193 let mut vec_deque = VecDeque::new();
194 vec_deque.extend(1..5);
195
196 // Do lint.
197 vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect();
198 vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect();
199 vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect();
200
201 // Do not lint, because type conversion is performed
202 vec_deque = vec_deque
203 .iter()
204 .filter(|&x| x % 2 == 0)
205 .copied()
206 .collect::<VecDeque<i8>>();
207 vec_deque = vec_deque
208 .iter()
209 .filter(|&x| x % 2 == 0)
210 .cloned()
211 .collect::<VecDeque<i8>>();
212 vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect::<VecDeque<i8>>();
213
214 // Do not lint, because this expression is not assign.
215 let mut bar: VecDeque<i8> = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect();
216 let mut foobar: VecDeque<i8> = vec_deque.into_iter().filter(|x| x % 2 == 0).collect();
217
218 // Do not lint, because it is an assignment to a different variable.
219 bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect();
220 bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect();
221 bar = foobar.into_iter().filter(|x| x % 2 == 0).collect();
222 }
223
224 #[clippy::msrv = "1.52"]
_msrv_153()225 fn _msrv_153() {
226 let mut btree_map: BTreeMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
227 btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
228
229 let mut btree_set = BTreeSet::from([1, 2, 3, 4, 5, 6]);
230 btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect();
231 }
232
233 #[clippy::msrv = "1.25"]
_msrv_126()234 fn _msrv_126() {
235 let mut s = String::from("foobar");
236 s = s.chars().filter(|&c| c != 'o').to_owned().collect();
237 }
238
239 #[clippy::msrv = "1.17"]
_msrv_118()240 fn _msrv_118() {
241 let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]);
242 hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect();
243 let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
244 hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
245 }
246