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