]> git.lizzy.rs Git - rust.git/blob - tests/ui/methods.rs
Fix unnecessary_fold bug
[rust.git] / tests / ui / methods.rs
1
2 #![feature(const_fn)]
3
4 #![warn(clippy, clippy_pedantic)]
5 #![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default,
6     new_without_default_derive, missing_docs_in_private_items, needless_pass_by_value)]
7
8 use std::collections::BTreeMap;
9 use std::collections::HashMap;
10 use std::collections::HashSet;
11 use std::collections::VecDeque;
12 use std::ops::Mul;
13 use std::iter::FromIterator;
14 use std::rc::{self, Rc};
15 use std::sync::{self, Arc};
16
17 pub struct T;
18
19 impl T {
20     pub fn add(self, other: T) -> T { self }
21
22     pub(crate) fn drop(&mut self) { } // no error, not public interfact
23     fn neg(self) -> Self { self } // no error, private function
24     fn eq(&self, other: T) -> bool { true } // no error, private function
25
26     fn sub(&self, other: T) -> &T { self } // no error, self is a ref
27     fn div(self) -> T { self } // no error, different #arguments
28     fn rem(self, other: T) { } // no error, wrong return type
29
30     fn into_u32(self) -> u32 { 0 } // fine
31     fn into_u16(&self) -> u16 { 0 }
32
33     fn to_something(self) -> u32 { 0 }
34
35     fn new(self) {}
36 }
37
38 struct Lt<'a> {
39     foo: &'a u32,
40 }
41
42 impl<'a> Lt<'a> {
43     // The lifetime is different, but that’s irrelevant, see #734
44     #[allow(needless_lifetimes)]
45     pub fn new<'b>(s: &'b str) -> Lt<'b> { unimplemented!() }
46 }
47
48 struct Lt2<'a> {
49     foo: &'a u32,
50 }
51
52 impl<'a> Lt2<'a> {
53     // The lifetime is different, but that’s irrelevant, see #734
54     pub fn new(s: &str) -> Lt2 { unimplemented!() }
55 }
56
57 struct Lt3<'a> {
58     foo: &'a u32,
59 }
60
61 impl<'a> Lt3<'a> {
62     // The lifetime is different, but that’s irrelevant, see #734
63     pub fn new() -> Lt3<'static> { unimplemented!() }
64 }
65
66 #[derive(Clone,Copy)]
67 struct U;
68
69 impl U {
70     fn new() -> Self { U }
71     fn to_something(self) -> u32 { 0 } // ok because U is Copy
72 }
73
74 struct V<T> {
75     _dummy: T
76 }
77
78 impl<T> V<T> {
79     fn new() -> Option<V<T>> { None }
80 }
81
82 impl Mul<T> for T {
83     type Output = T;
84     fn mul(self, other: T) -> T { self } // no error, obviously
85 }
86
87 /// Utility macro to test linting behavior in `option_methods()`
88 /// The lints included in `option_methods()` should not lint if the call to map is partially
89 /// within a macro
90 macro_rules! opt_map {
91     ($opt:expr, $map:expr) => {($opt).map($map)};
92 }
93
94 /// Checks implementation of the following lints:
95 /// * `OPTION_MAP_UNWRAP_OR`
96 /// * `OPTION_MAP_UNWRAP_OR_ELSE`
97 /// * `OPTION_MAP_OR_NONE`
98 fn option_methods() {
99     let opt = Some(1);
100
101     // Check OPTION_MAP_UNWRAP_OR
102     // single line case
103     let _ = opt.map(|x| x + 1)
104
105                .unwrap_or(0); // should lint even though this call is on a separate line
106     // multi line cases
107     let _ = opt.map(|x| {
108                         x + 1
109                     }
110               ).unwrap_or(0);
111     let _ = opt.map(|x| x + 1)
112                .unwrap_or({
113                     0
114                 });
115     // single line `map(f).unwrap_or(None)` case
116     let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
117     // multiline `map(f).unwrap_or(None)` cases
118     let _ = opt.map(|x| {
119         Some(x + 1)
120     }
121     ).unwrap_or(None);
122     let _ = opt
123         .map(|x| Some(x + 1))
124         .unwrap_or(None);
125     // macro case
126     let _ = opt_map!(opt, |x| x + 1).unwrap_or(0); // should not lint
127
128     // Check OPTION_MAP_UNWRAP_OR_ELSE
129     // single line case
130     let _ = opt.map(|x| x + 1)
131
132                .unwrap_or_else(|| 0); // should lint even though this call is on a separate line
133     // multi line cases
134     let _ = opt.map(|x| {
135                         x + 1
136                     }
137               ).unwrap_or_else(|| 0);
138     let _ = opt.map(|x| x + 1)
139                .unwrap_or_else(||
140                     0
141                 );
142     // macro case
143     let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); // should not lint
144
145     // Check OPTION_MAP_OR_NONE
146     // single line case
147     let _ = opt.map_or(None, |x| Some(x + 1));
148     // multi line case
149     let _ = opt.map_or(None, |x| {
150                         Some(x + 1)
151                        }
152                 );
153 }
154
155 /// Checks implementation of the following lints:
156 /// * `RESULT_MAP_UNWRAP_OR_ELSE`
157 fn result_methods() {
158     let res: Result<i32, ()> = Ok(1);
159
160     // Check RESULT_MAP_UNWRAP_OR_ELSE
161     // single line case
162     let _ = res.map(|x| x + 1)
163
164                .unwrap_or_else(|e| 0); // should lint even though this call is on a separate line
165     // multi line cases
166     let _ = res.map(|x| {
167                         x + 1
168                     }
169               ).unwrap_or_else(|e| 0);
170     let _ = res.map(|x| x + 1)
171                .unwrap_or_else(|e|
172                     0
173                 );
174     // macro case
175     let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|e| 0); // should not lint
176 }
177
178 /// Struct to generate false positives for things with .iter()
179 #[derive(Copy, Clone)]
180 struct HasIter;
181
182 impl HasIter {
183     fn iter(self) -> IteratorFalsePositives {
184         IteratorFalsePositives { foo: 0 }
185     }
186
187     fn iter_mut(self) -> IteratorFalsePositives {
188         IteratorFalsePositives { foo: 0 }
189     }
190 }
191
192 /// Struct to generate false positive for Iterator-based lints
193 #[derive(Copy, Clone)]
194 struct IteratorFalsePositives {
195     foo: u32,
196 }
197
198 impl IteratorFalsePositives {
199     fn filter(self) -> IteratorFalsePositives {
200         self
201     }
202
203     fn next(self) -> IteratorFalsePositives {
204         self
205     }
206
207     fn find(self) -> Option<u32> {
208         Some(self.foo)
209     }
210
211     fn position(self) -> Option<u32> {
212         Some(self.foo)
213     }
214
215     fn rposition(self) -> Option<u32> {
216         Some(self.foo)
217     }
218
219     fn nth(self, n: usize) -> Option<u32> {
220         Some(self.foo)
221     }
222
223     fn skip(self, _: usize) -> IteratorFalsePositives {
224         self
225     }
226 }
227
228 /// Checks implementation of `FILTER_NEXT` lint
229 fn filter_next() {
230     let v = vec![3, 2, 1, 0, -1, -2, -3];
231
232     // check single-line case
233     let _ = v.iter().filter(|&x| *x < 0).next();
234
235     // check multi-line case
236     let _ = v.iter().filter(|&x| {
237                                 *x < 0
238                             }
239                    ).next();
240
241     // check that we don't lint if the caller is not an Iterator
242     let foo = IteratorFalsePositives { foo: 0 };
243     let _ = foo.filter().next();
244 }
245
246 /// Checks implementation of `SEARCH_IS_SOME` lint
247 fn search_is_some() {
248     let v = vec![3, 2, 1, 0, -1, -2, -3];
249
250     // check `find().is_some()`, single-line
251     let _ = v.iter().find(|&x| *x < 0).is_some();
252
253     // check `find().is_some()`, multi-line
254     let _ = v.iter().find(|&x| {
255                               *x < 0
256                           }
257                    ).is_some();
258
259     // check `position().is_some()`, single-line
260     let _ = v.iter().position(|&x| x < 0).is_some();
261
262     // check `position().is_some()`, multi-line
263     let _ = v.iter().position(|&x| {
264                                   x < 0
265                               }
266                    ).is_some();
267
268     // check `rposition().is_some()`, single-line
269     let _ = v.iter().rposition(|&x| x < 0).is_some();
270
271     // check `rposition().is_some()`, multi-line
272     let _ = v.iter().rposition(|&x| {
273                                    x < 0
274                                }
275                    ).is_some();
276
277     // check that we don't lint if the caller is not an Iterator
278     let foo = IteratorFalsePositives { foo: 0 };
279     let _ = foo.find().is_some();
280     let _ = foo.position().is_some();
281     let _ = foo.rposition().is_some();
282 }
283
284 /// Checks implementation of the `OR_FUN_CALL` lint
285 fn or_fun_call() {
286     struct Foo;
287
288     impl Foo {
289         fn new() -> Foo { Foo }
290     }
291
292     enum Enum {
293         A(i32),
294     }
295
296     const fn make_const(i: i32) -> i32 { i }
297
298     fn make<T>() -> T { unimplemented!(); }
299
300     let with_enum = Some(Enum::A(1));
301     with_enum.unwrap_or(Enum::A(5));
302
303     let with_const_fn = Some(1);
304     with_const_fn.unwrap_or(make_const(5));
305
306     let with_constructor = Some(vec![1]);
307     with_constructor.unwrap_or(make());
308
309     let with_new = Some(vec![1]);
310     with_new.unwrap_or(Vec::new());
311
312     let with_const_args = Some(vec![1]);
313     with_const_args.unwrap_or(Vec::with_capacity(12));
314
315     let with_err : Result<_, ()> = Ok(vec![1]);
316     with_err.unwrap_or(make());
317
318     let with_err_args : Result<_, ()> = Ok(vec![1]);
319     with_err_args.unwrap_or(Vec::with_capacity(12));
320
321     let with_default_trait = Some(1);
322     with_default_trait.unwrap_or(Default::default());
323
324     let with_default_type = Some(1);
325     with_default_type.unwrap_or(u64::default());
326
327     let with_vec = Some(vec![1]);
328     with_vec.unwrap_or(vec![]);
329
330     // FIXME #944: ~|SUGGESTION with_vec.unwrap_or_else(|| vec![]);
331
332     let without_default = Some(Foo);
333     without_default.unwrap_or(Foo::new());
334
335     let mut map = HashMap::<u64, String>::new();
336     map.entry(42).or_insert(String::new());
337
338     let mut btree = BTreeMap::<u64, String>::new();
339     btree.entry(42).or_insert(String::new());
340
341     let stringy = Some(String::from(""));
342     let _ = stringy.unwrap_or("".to_owned());
343 }
344
345 /// Checks implementation of `ITER_NTH` lint
346 fn iter_nth() {
347     let mut some_vec = vec![0, 1, 2, 3];
348     let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
349     let mut some_vec_deque: VecDeque<_> = some_vec.iter().cloned().collect();
350
351     {
352         // Make sure we lint `.iter()` for relevant types
353         let bad_vec = some_vec.iter().nth(3);
354         let bad_slice = &some_vec[..].iter().nth(3);
355         let bad_boxed_slice = boxed_slice.iter().nth(3);
356         let bad_vec_deque = some_vec_deque.iter().nth(3);
357     }
358
359     {
360         // Make sure we lint `.iter_mut()` for relevant types
361         let bad_vec = some_vec.iter_mut().nth(3);
362     }
363     {
364         let bad_slice = &some_vec[..].iter_mut().nth(3);
365     }
366     {
367         let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
368     }
369
370     // Make sure we don't lint for non-relevant types
371     let false_positive = HasIter;
372     let ok = false_positive.iter().nth(3);
373     let ok_mut = false_positive.iter_mut().nth(3);
374 }
375
376 /// Checks implementation of `ITER_SKIP_NEXT` lint
377 fn iter_skip_next() {
378     let mut some_vec = vec![0, 1, 2, 3];
379     let _ = some_vec.iter().skip(42).next();
380     let _ = some_vec.iter().cycle().skip(42).next();
381     let _ = (1..10).skip(10).next();
382     let _ = &some_vec[..].iter().skip(3).next();
383     let foo = IteratorFalsePositives { foo : 0 };
384     let _ = foo.skip(42).next();
385     let _ = foo.filter().skip(42).next();
386 }
387
388 /// Calls which should trigger the `UNNECESSARY_FOLD` lint
389 fn unnecessary_fold() {
390     // Can be replaced by .any
391     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
392     // Can be replaced by .all
393     let _ = (0..3).fold(true, |acc, x| acc && x > 2);
394     // Can be replaced by .sum
395     let _ = (0..3).fold(0, |acc, x| acc + x);
396     // Can be replaced by .product
397     let _ = (0..3).fold(1, |acc, x| acc * x);
398 }
399
400 /// Should trigger the `UNNECESSARY_FOLD` lint, with an error span including exactly `.fold(...)`
401 fn unnecessary_fold_span_for_multi_element_chain() {
402     let _ = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2);
403 }
404
405 /// Calls which should not trigger the `UNNECESSARY_FOLD` lint
406 fn unnecessary_fold_should_ignore() {
407     let _ = (0..3).fold(true, |acc, x| acc || x > 2);
408     let _ = (0..3).fold(false, |acc, x| acc && x > 2);
409     let _ = (0..3).fold(1, |acc, x| acc + x);
410     let _ = (0..3).fold(0, |acc, x| acc * x);
411     let _ = (0..3).fold(0, |acc, x| 1 + acc + x);
412
413     // We only match against an accumulator on the left
414     // hand side. We could lint for .sum and .product when
415     // it's on the right, but don't for now (and this wouldn't
416     // be valid if we extended the lint to cover arbitrary numeric
417     // types).
418     let _ = (0..3).fold(false, |acc, x| x > 2 || acc);
419     let _ = (0..3).fold(true, |acc, x| x > 2 && acc);
420     let _ = (0..3).fold(0, |acc, x| x + acc);
421     let _ = (0..3).fold(1, |acc, x| x * acc);
422
423     let _ = [(0..2), (0..3)].iter().fold(0, |a, b| a + b.len());
424     let _ = [(0..2), (0..3)].iter().fold(1, |a, b| a * b.len());
425 }
426
427 #[allow(similar_names)]
428 fn main() {
429     let opt = Some(0);
430     let _ = opt.unwrap();
431 }