]> git.lizzy.rs Git - rust.git/blob - tests/ui/methods.rs
Update OPTION_MAP_UNWRAP_OR lint
[rust.git] / tests / ui / methods.rs
1
2 #![feature(const_fn)]
3
4
5 #![warn(clippy, clippy_pedantic)]
6 #![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default, new_without_default_derive, missing_docs_in_private_items)]
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 struct T;
18
19 impl T {
20     fn add(self, other: T) -> T { self }
21     fn drop(&mut self) { }
22
23     fn sub(&self, other: T) -> &T { self } // no error, self is a ref
24     fn div(self) -> T { self } // no error, different #arguments
25     fn rem(self, other: T) { } // no error, wrong return type
26
27     fn into_u32(self) -> u32 { 0 } // fine
28     fn into_u16(&self) -> u16 { 0 }
29
30     fn to_something(self) -> u32 { 0 }
31
32     fn new(self) {}
33 }
34
35 struct Lt<'a> {
36     foo: &'a u32,
37 }
38
39 impl<'a> Lt<'a> {
40     // The lifetime is different, but that’s irrelevant, see #734
41     #[allow(needless_lifetimes)]
42     pub fn new<'b>(s: &'b str) -> Lt<'b> { unimplemented!() }
43 }
44
45 struct Lt2<'a> {
46     foo: &'a u32,
47 }
48
49 impl<'a> Lt2<'a> {
50     // The lifetime is different, but that’s irrelevant, see #734
51     pub fn new(s: &str) -> Lt2 { unimplemented!() }
52 }
53
54 struct Lt3<'a> {
55     foo: &'a u32,
56 }
57
58 impl<'a> Lt3<'a> {
59     // The lifetime is different, but that’s irrelevant, see #734
60     pub fn new() -> Lt3<'static> { unimplemented!() }
61 }
62
63 #[derive(Clone,Copy)]
64 struct U;
65
66 impl U {
67     fn new() -> Self { U }
68     fn to_something(self) -> u32 { 0 } // ok because U is Copy
69 }
70
71 struct V<T> {
72     _dummy: T
73 }
74
75 impl<T> V<T> {
76     fn new() -> Option<V<T>> { None }
77 }
78
79 impl Mul<T> for T {
80     type Output = T;
81     fn mul(self, other: T) -> T { self } // no error, obviously
82 }
83
84 /// Utility macro to test linting behavior in `option_methods()`
85 /// The lints included in `option_methods()` should not lint if the call to map is partially
86 /// within a macro
87 macro_rules! opt_map {
88     ($opt:expr, $map:expr) => {($opt).map($map)};
89 }
90
91 /// Checks implementation of the following lints:
92 /// * `OPTION_MAP_UNWRAP_OR`
93 /// * `OPTION_MAP_UNWRAP_OR_ELSE`
94 fn option_methods() {
95     let opt = Some(1);
96
97     // Check OPTION_MAP_UNWRAP_OR
98     // single line case
99     let _ = opt.map(|x| x + 1)
100
101                .unwrap_or(0); // should lint even though this call is on a separate line
102     // multi line cases
103     let _ = opt.map(|x| {
104                         x + 1
105                     }
106               ).unwrap_or(0);
107     let _ = opt.map(|x| x + 1)
108                .unwrap_or({
109                     0
110                 });
111     // map(f).unwrap_or(None) case
112     let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
113     // macro case
114     let _ = opt_map!(opt, |x| x + 1).unwrap_or(0); // should not lint
115
116     // Check OPTION_MAP_UNWRAP_OR_ELSE
117     // single line case
118     let _ = opt.map(|x| x + 1)
119
120                .unwrap_or_else(|| 0); // should lint even though this call is on a separate line
121     // multi line cases
122     let _ = opt.map(|x| {
123                         x + 1
124                     }
125               ).unwrap_or_else(|| 0);
126     let _ = opt.map(|x| x + 1)
127                .unwrap_or_else(||
128                     0
129                 );
130     // macro case
131     let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); // should not lint
132 }
133
134 /// Struct to generate false positives for things with .iter()
135 #[derive(Copy, Clone)]
136 struct HasIter;
137
138 impl HasIter {
139     fn iter(self) -> IteratorFalsePositives {
140         IteratorFalsePositives { foo: 0 }
141     }
142
143     fn iter_mut(self) -> IteratorFalsePositives {
144         IteratorFalsePositives { foo: 0 }
145     }
146 }
147
148 /// Struct to generate false positive for Iterator-based lints
149 #[derive(Copy, Clone)]
150 struct IteratorFalsePositives {
151     foo: u32,
152 }
153
154 impl IteratorFalsePositives {
155     fn filter(self) -> IteratorFalsePositives {
156         self
157     }
158
159     fn next(self) -> IteratorFalsePositives {
160         self
161     }
162
163     fn find(self) -> Option<u32> {
164         Some(self.foo)
165     }
166
167     fn position(self) -> Option<u32> {
168         Some(self.foo)
169     }
170
171     fn rposition(self) -> Option<u32> {
172         Some(self.foo)
173     }
174
175     fn nth(self, n: usize) -> Option<u32> {
176         Some(self.foo)
177     }
178
179     fn skip(self, _: usize) -> IteratorFalsePositives {
180         self
181     }
182 }
183
184 #[derive(Copy, Clone)]
185 struct HasChars;
186
187 impl HasChars {
188     fn chars(self) -> std::str::Chars<'static> {
189         "HasChars".chars()
190     }
191 }
192
193 /// Checks implementation of `FILTER_NEXT` lint
194 fn filter_next() {
195     let v = vec![3, 2, 1, 0, -1, -2, -3];
196
197     // check single-line case
198     let _ = v.iter().filter(|&x| *x < 0).next();
199
200     // check multi-line case
201     let _ = v.iter().filter(|&x| {
202                                 *x < 0
203                             }
204                    ).next();
205
206     // check that we don't lint if the caller is not an Iterator
207     let foo = IteratorFalsePositives { foo: 0 };
208     let _ = foo.filter().next();
209 }
210
211 /// Checks implementation of `SEARCH_IS_SOME` lint
212 fn search_is_some() {
213     let v = vec![3, 2, 1, 0, -1, -2, -3];
214
215     // check `find().is_some()`, single-line
216     let _ = v.iter().find(|&x| *x < 0).is_some();
217
218     // check `find().is_some()`, multi-line
219     let _ = v.iter().find(|&x| {
220                               *x < 0
221                           }
222                    ).is_some();
223
224     // check `position().is_some()`, single-line
225     let _ = v.iter().position(|&x| x < 0).is_some();
226
227     // check `position().is_some()`, multi-line
228     let _ = v.iter().position(|&x| {
229                                   x < 0
230                               }
231                    ).is_some();
232
233     // check `rposition().is_some()`, single-line
234     let _ = v.iter().rposition(|&x| x < 0).is_some();
235
236     // check `rposition().is_some()`, multi-line
237     let _ = v.iter().rposition(|&x| {
238                                    x < 0
239                                }
240                    ).is_some();
241
242     // check that we don't lint if the caller is not an Iterator
243     let foo = IteratorFalsePositives { foo: 0 };
244     let _ = foo.find().is_some();
245     let _ = foo.position().is_some();
246     let _ = foo.rposition().is_some();
247 }
248
249 /// Checks implementation of the `OR_FUN_CALL` lint
250 fn or_fun_call() {
251     struct Foo;
252
253     impl Foo {
254         fn new() -> Foo { Foo }
255     }
256
257     enum Enum {
258         A(i32),
259     }
260
261     const fn make_const(i: i32) -> i32 { i }
262
263     fn make<T>() -> T { unimplemented!(); }
264
265     let with_enum = Some(Enum::A(1));
266     with_enum.unwrap_or(Enum::A(5));
267
268     let with_const_fn = Some(1);
269     with_const_fn.unwrap_or(make_const(5));
270
271     let with_constructor = Some(vec![1]);
272     with_constructor.unwrap_or(make());
273
274     let with_new = Some(vec![1]);
275     with_new.unwrap_or(Vec::new());
276
277     let with_const_args = Some(vec![1]);
278     with_const_args.unwrap_or(Vec::with_capacity(12));
279
280     let with_err : Result<_, ()> = Ok(vec![1]);
281     with_err.unwrap_or(make());
282
283     let with_err_args : Result<_, ()> = Ok(vec![1]);
284     with_err_args.unwrap_or(Vec::with_capacity(12));
285
286     let with_default_trait = Some(1);
287     with_default_trait.unwrap_or(Default::default());
288
289     let with_default_type = Some(1);
290     with_default_type.unwrap_or(u64::default());
291
292     let with_vec = Some(vec![1]);
293     with_vec.unwrap_or(vec![]);
294
295     // FIXME #944: ~|SUGGESTION with_vec.unwrap_or_else(|| vec![]);
296
297     let without_default = Some(Foo);
298     without_default.unwrap_or(Foo::new());
299
300     let mut map = HashMap::<u64, String>::new();
301     map.entry(42).or_insert(String::new());
302
303     let mut btree = BTreeMap::<u64, String>::new();
304     btree.entry(42).or_insert(String::new());
305
306     let stringy = Some(String::from(""));
307     let _ = stringy.unwrap_or("".to_owned());
308 }
309
310 /// Checks implementation of `ITER_NTH` lint
311 fn iter_nth() {
312     let mut some_vec = vec![0, 1, 2, 3];
313     let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
314     let mut some_vec_deque: VecDeque<_> = some_vec.iter().cloned().collect();
315
316     {
317         // Make sure we lint `.iter()` for relevant types
318         let bad_vec = some_vec.iter().nth(3);
319         let bad_slice = &some_vec[..].iter().nth(3);
320         let bad_boxed_slice = boxed_slice.iter().nth(3);
321         let bad_vec_deque = some_vec_deque.iter().nth(3);
322     }
323
324     {
325         // Make sure we lint `.iter_mut()` for relevant types
326         let bad_vec = some_vec.iter_mut().nth(3);
327     }
328     {
329         let bad_slice = &some_vec[..].iter_mut().nth(3);
330     }
331     {
332         let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
333     }
334
335     // Make sure we don't lint for non-relevant types
336     let false_positive = HasIter;
337     let ok = false_positive.iter().nth(3);
338     let ok_mut = false_positive.iter_mut().nth(3);
339 }
340
341 /// Checks implementation of `ITER_SKIP_NEXT` lint
342 fn iter_skip_next() {
343     let mut some_vec = vec![0, 1, 2, 3];
344     let _ = some_vec.iter().skip(42).next();
345     let _ = some_vec.iter().cycle().skip(42).next();
346     let _ = (1..10).skip(10).next();
347     let _ = &some_vec[..].iter().skip(3).next();
348     let foo = IteratorFalsePositives { foo : 0 };
349     let _ = foo.skip(42).next();
350     let _ = foo.filter().skip(42).next();
351 }
352
353 struct GetFalsePositive {
354     arr: [u32; 3],
355 }
356
357 impl GetFalsePositive {
358     fn get(&self, pos: usize) -> Option<&u32> { self.arr.get(pos) }
359     fn get_mut(&mut self, pos: usize) -> Option<&mut u32> { self.arr.get_mut(pos) }
360 }
361
362 /// Checks implementation of `GET_UNWRAP` lint
363 fn get_unwrap() {
364     let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
365     let mut some_slice = &mut [0, 1, 2, 3];
366     let mut some_vec = vec![0, 1, 2, 3];
367     let mut some_vecdeque: VecDeque<_> = some_vec.iter().cloned().collect();
368     let mut some_hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(1, 'a'), (2, 'b')]);
369     let mut some_btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(1, 'a'), (2, 'b')]);
370     let mut false_positive = GetFalsePositive { arr: [0, 1, 2] };
371
372     { // Test `get().unwrap()`
373         let _ = boxed_slice.get(1).unwrap();
374         let _ = some_slice.get(0).unwrap();
375         let _ = some_vec.get(0).unwrap();
376         let _ = some_vecdeque.get(0).unwrap();
377         let _ = some_hashmap.get(&1).unwrap();
378         let _ = some_btreemap.get(&1).unwrap();
379         let _ = false_positive.get(0).unwrap();
380     }
381
382     { // Test `get_mut().unwrap()`
383         *boxed_slice.get_mut(0).unwrap() = 1;
384         *some_slice.get_mut(0).unwrap() = 1;
385         *some_vec.get_mut(0).unwrap() = 1;
386         *some_vecdeque.get_mut(0).unwrap() = 1;
387         // Check false positives
388         *some_hashmap.get_mut(&1).unwrap() = 'b';
389         *some_btreemap.get_mut(&1).unwrap() = 'b';
390         *false_positive.get_mut(0).unwrap() = 1;
391     }
392 }
393
394
395 #[allow(similar_names)]
396 fn main() {
397     use std::io;
398
399     let opt = Some(0);
400     let _ = opt.unwrap();
401
402     let res: Result<i32, ()> = Ok(0);
403     let _ = res.unwrap();
404
405     res.ok().expect("disaster!");
406     // the following should not warn, since `expect` isn't implemented unless
407     // the error type implements `Debug`
408     let res2: Result<i32, MyError> = Ok(0);
409     res2.ok().expect("oh noes!");
410     let res3: Result<u32, MyErrorWithParam<u8>>= Ok(0);
411     res3.ok().expect("whoof");
412     let res4: Result<u32, io::Error> = Ok(0);
413     res4.ok().expect("argh");
414     let res5: io::Result<u32> = Ok(0);
415     res5.ok().expect("oops");
416     let res6: Result<u32, &str> = Ok(0);
417     res6.ok().expect("meh");
418 }
419
420 struct MyError(()); // doesn't implement Debug
421
422 #[derive(Debug)]
423 struct MyErrorWithParam<T> {
424     x: T
425 }
426
427 #[allow(unnecessary_operation)]
428 fn starts_with() {
429     "".chars().next() == Some(' ');
430     Some(' ') != "".chars().next();
431 }
432
433 fn str_extend_chars() {
434     let abc = "abc";
435     let def = String::from("def");
436     let mut s = String::new();
437
438     s.push_str(abc);
439     s.extend(abc.chars());
440
441     s.push_str("abc");
442     s.extend("abc".chars());
443
444     s.push_str(&def);
445     s.extend(def.chars());
446
447     s.extend(abc.chars().skip(1));
448     s.extend("abc".chars().skip(1));
449     s.extend(['a', 'b', 'c'].iter());
450
451     let f = HasChars;
452     s.extend(f.chars());
453 }
454
455 fn clone_on_copy() {
456     42.clone();
457
458     vec![1].clone(); // ok, not a Copy type
459     Some(vec![1]).clone(); // ok, not a Copy type
460     (&42).clone();
461 }
462
463 fn clone_on_ref_ptr() {
464     let rc = Rc::new(true);
465     let arc = Arc::new(true);
466
467     let rcweak = Rc::downgrade(&rc);
468     let arc_weak = Arc::downgrade(&arc);
469
470     rc.clone();
471     Rc::clone(&rc);
472
473     arc.clone();
474     Arc::clone(&arc);
475
476     rcweak.clone();
477     rc::Weak::clone(&rcweak);
478
479     arc_weak.clone();
480     sync::Weak::clone(&arc_weak);
481
482
483 }
484
485 fn clone_on_copy_generic<T: Copy>(t: T) {
486     t.clone();
487
488     Some(t).clone();
489 }
490
491 fn clone_on_double_ref() {
492     let x = vec![1];
493     let y = &&x;
494     let z: &Vec<_> = y.clone();
495
496     println!("{:p} {:p}",*y, z);
497 }
498
499 fn single_char_pattern() {
500     let x = "foo";
501     x.split("x");
502     x.split("xx");
503     x.split('x');
504
505     let y = "x";
506     x.split(y);
507     // Not yet testing for multi-byte characters
508     // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_single_char_pattern`
509     // should have done this but produced an ICE
510     //
511     // We may not want to suggest changing these anyway
512     // See: https://github.com/rust-lang-nursery/rust-clippy/issues/650#issuecomment-184328984
513     x.split("ß");
514     x.split("ℝ");
515     x.split("💣");
516     // Can't use this lint for unicode code points which don't fit in a char
517     x.split("❤️");
518     x.contains("x");
519     x.starts_with("x");
520     x.ends_with("x");
521     x.find("x");
522     x.rfind("x");
523     x.rsplit("x");
524     x.split_terminator("x");
525     x.rsplit_terminator("x");
526     x.splitn(0, "x");
527     x.rsplitn(0, "x");
528     x.matches("x");
529     x.rmatches("x");
530     x.match_indices("x");
531     x.rmatch_indices("x");
532     x.trim_left_matches("x");
533     x.trim_right_matches("x");
534
535     let h = HashSet::<String>::new();
536     h.contains("X"); // should not warn
537 }
538
539 #[allow(result_unwrap_used)]
540 fn temporary_cstring() {
541     use std::ffi::CString;
542
543     CString::new("foo").unwrap().as_ptr();
544 }
545
546 fn iter_clone_collect() {
547     let v = [1,2,3,4,5];
548     let v2 : Vec<isize> = v.iter().cloned().collect();
549     let v3 : HashSet<isize> = v.iter().cloned().collect();
550     let v4 : VecDeque<isize> = v.iter().cloned().collect();
551 }
552
553 fn chars_cmp_with_unwrap() {
554     let s = String::from("foo");
555     if s.chars().next().unwrap() == 'f' { // s.starts_with('f')
556         // Nothing here
557     }
558     if s.chars().next_back().unwrap() == 'o' { // s.ends_with('o')
559         // Nothing here
560     }
561     if s.chars().last().unwrap() == 'o' { // s.ends_with('o')
562         // Nothing here
563     }
564     if s.chars().next().unwrap() != 'f' { // !s.starts_with('f')
565         // Nothing here
566     }
567     if s.chars().next_back().unwrap() != 'o' { // !s.ends_with('o')
568         // Nothing here
569     }
570     if s.chars().last().unwrap() != 'o' { // !s.ends_with('o')
571         // Nothing here
572     }
573 }
574
575 #[allow(unnecessary_operation)]
576 fn ends_with() {
577     "".chars().last() == Some(' ');
578     Some(' ') != "".chars().last();
579     "".chars().next_back() == Some(' ');
580     Some(' ') != "".chars().next_back();
581 }