]> git.lizzy.rs Git - rust.git/blob - tests/compile-fail/methods.rs
88a1e7c4cf24e1f3d84b0cb4229efdfeefc7c0a0
[rust.git] / tests / compile-fail / 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)]
7
8 use std::collections::BTreeMap;
9 use std::collections::HashMap;
10 use std::collections::HashSet;
11 use std::ops::Mul;
12
13 struct T;
14
15 impl T {
16     fn add(self, other: T) -> T { self } //~ERROR defining a method called `add`
17     fn drop(&mut self) { } //~ERROR defining a method called `drop`
18
19     fn sub(&self, other: T) -> &T { self } // no error, self is a ref
20     fn div(self) -> T { self } // no error, different #arguments
21     fn rem(self, other: T) { } // no error, wrong return type
22
23     fn into_u32(self) -> u32 { 0 } // fine
24     fn into_u16(&self) -> u16 { 0 } //~ERROR methods called `into_*` usually take self by value
25
26     fn to_something(self) -> u32 { 0 } //~ERROR methods called `to_*` usually take self by reference
27
28     fn new(self) {}
29     //~^ ERROR methods called `new` usually take no self
30     //~| ERROR methods called `new` usually return `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) //~  ERROR called `map(f).unwrap_or(a)`
98                                //~| NOTE replace `map(|x| x + 1).unwrap_or(0)`
99                .unwrap_or(0); // should lint even though this call is on a separate line
100     // multi line cases
101     let _ = opt.map(|x| { //~ ERROR called `map(f).unwrap_or(a)`
102                         x + 1
103                     }
104               ).unwrap_or(0);
105     let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or(a)`
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) //~  ERROR called `map(f).unwrap_or_else(g)`
115                                //~| NOTE replace `map(|x| x + 1).unwrap_or_else(|| 0)`
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| { //~ ERROR called `map(f).unwrap_or_else(g)`
119                         x + 1
120                     }
121               ).unwrap_or_else(|| 0);
122     let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or_else(g)`
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
131 /// Struct to generate false positive for Iterator-based lints
132 #[derive(Copy, Clone)]
133 struct IteratorFalsePositives {
134     foo: u32,
135 }
136
137 impl IteratorFalsePositives {
138     fn filter(self) -> IteratorFalsePositives {
139         self
140     }
141
142     fn next(self) -> IteratorFalsePositives {
143         self
144     }
145
146     fn find(self) -> Option<u32> {
147         Some(self.foo)
148     }
149
150     fn position(self) -> Option<u32> {
151         Some(self.foo)
152     }
153
154     fn rposition(self) -> Option<u32> {
155         Some(self.foo)
156     }
157 }
158
159 /// Checks implementation of `FILTER_NEXT` lint
160 fn filter_next() {
161     let v = vec![3, 2, 1, 0, -1, -2, -3];
162
163     // check single-line case
164     let _ = v.iter().filter(|&x| *x < 0).next();
165     //~^ ERROR called `filter(p).next()` on an Iterator.
166     //~| NOTE replace `filter(|&x| *x < 0).next()`
167
168     // check multi-line case
169     let _ = v.iter().filter(|&x| { //~ERROR called `filter(p).next()` on an Iterator.
170                                 *x < 0
171                             }
172                    ).next();
173
174     // check that we don't lint if the caller is not an Iterator
175     let foo = IteratorFalsePositives { foo: 0 };
176     let _ = foo.filter().next();
177 }
178
179 /// Checks implementation of `SEARCH_IS_SOME` lint
180 fn search_is_some() {
181     let v = vec![3, 2, 1, 0, -1, -2, -3];
182
183     // check `find().is_some()`, single-line
184     let _ = v.iter().find(|&x| *x < 0).is_some();
185     //~^ ERROR called `is_some()` after searching
186     //~| NOTE replace `find(|&x| *x < 0).is_some()`
187
188     // check `find().is_some()`, multi-line
189     let _ = v.iter().find(|&x| { //~ERROR called `is_some()` after searching
190                               *x < 0
191                           }
192                    ).is_some();
193
194     // check `position().is_some()`, single-line
195     let _ = v.iter().position(|&x| x < 0).is_some();
196     //~^ ERROR called `is_some()` after searching
197     //~| NOTE replace `position(|&x| x < 0).is_some()`
198
199     // check `position().is_some()`, multi-line
200     let _ = v.iter().position(|&x| { //~ERROR called `is_some()` after searching
201                                   x < 0
202                               }
203                    ).is_some();
204
205     // check `rposition().is_some()`, single-line
206     let _ = v.iter().rposition(|&x| x < 0).is_some();
207     //~^ ERROR called `is_some()` after searching
208     //~| NOTE replace `rposition(|&x| x < 0).is_some()`
209
210     // check `rposition().is_some()`, multi-line
211     let _ = v.iter().rposition(|&x| { //~ERROR called `is_some()` after searching
212                                    x < 0
213                                }
214                    ).is_some();
215
216     // check that we don't lint if the caller is not an Iterator
217     let foo = IteratorFalsePositives { foo: 0 };
218     let _ = foo.find().is_some();
219     let _ = foo.position().is_some();
220     let _ = foo.rposition().is_some();
221 }
222
223 /// Checks implementation of the `OR_FUN_CALL` lint
224 fn or_fun_call() {
225     struct Foo;
226
227     impl Foo {
228         fn new() -> Foo { Foo }
229     }
230
231     enum Enum {
232         A(i32),
233     }
234
235     const fn make_const(i: i32) -> i32 { i }
236
237     fn make<T>() -> T { unimplemented!(); }
238
239     let with_enum = Some(Enum::A(1));
240     with_enum.unwrap_or(Enum::A(5));
241
242     let with_const_fn = Some(1);
243     with_const_fn.unwrap_or(make_const(5));
244
245     let with_constructor = Some(vec![1]);
246     with_constructor.unwrap_or(make());
247     //~^ERROR use of `unwrap_or`
248     //~|HELP try this
249     //~|SUGGESTION with_constructor.unwrap_or_else(make)
250
251     let with_new = Some(vec![1]);
252     with_new.unwrap_or(Vec::new());
253     //~^ERROR use of `unwrap_or`
254     //~|HELP try this
255     //~|SUGGESTION with_new.unwrap_or_default();
256
257     let with_const_args = Some(vec![1]);
258     with_const_args.unwrap_or(Vec::with_capacity(12));
259     //~^ERROR use of `unwrap_or`
260     //~|HELP try this
261     //~|SUGGESTION with_const_args.unwrap_or_else(|| Vec::with_capacity(12));
262
263     let with_err : Result<_, ()> = Ok(vec![1]);
264     with_err.unwrap_or(make());
265     //~^ERROR use of `unwrap_or`
266     //~|HELP try this
267     //~|SUGGESTION with_err.unwrap_or_else(|_| make());
268
269     let with_err_args : Result<_, ()> = Ok(vec![1]);
270     with_err_args.unwrap_or(Vec::with_capacity(12));
271     //~^ERROR use of `unwrap_or`
272     //~|HELP try this
273     //~|SUGGESTION with_err_args.unwrap_or_else(|_| Vec::with_capacity(12));
274
275     let with_default_trait = Some(1);
276     with_default_trait.unwrap_or(Default::default());
277     //~^ERROR use of `unwrap_or`
278     //~|HELP try this
279     //~|SUGGESTION with_default_trait.unwrap_or_default();
280
281     let with_default_type = Some(1);
282     with_default_type.unwrap_or(u64::default());
283     //~^ERROR use of `unwrap_or`
284     //~|HELP try this
285     //~|SUGGESTION with_default_type.unwrap_or_default();
286
287     let with_vec = Some(vec![1]);
288     with_vec.unwrap_or(vec![]);
289     //~^ERROR use of `unwrap_or`
290     //~|HELP try this
291     //~|SUGGESTION with_vec.unwrap_or_else(|| vec![]);
292
293     let without_default = Some(Foo);
294     without_default.unwrap_or(Foo::new());
295     //~^ERROR use of `unwrap_or`
296     //~|HELP try this
297     //~|SUGGESTION without_default.unwrap_or_else(Foo::new);
298
299     let mut map = HashMap::<u64, String>::new();
300     map.entry(42).or_insert(String::new());
301     //~^ERROR use of `or_insert` followed by a function call
302     //~|HELP try this
303     //~|SUGGESTION map.entry(42).or_insert_with(String::new);
304
305     let mut btree = BTreeMap::<u64, String>::new();
306     btree.entry(42).or_insert(String::new());
307     //~^ERROR use of `or_insert` followed by a function call
308     //~|HELP try this
309     //~|SUGGESTION btree.entry(42).or_insert_with(String::new);
310 }
311
312 #[allow(similar_names)]
313 fn main() {
314     use std::io;
315
316     let opt = Some(0);
317     let _ = opt.unwrap();  //~ERROR used unwrap() on an Option
318
319     let res: Result<i32, ()> = Ok(0);
320     let _ = res.unwrap();  //~ERROR used unwrap() on a Result
321
322     res.ok().expect("disaster!"); //~ERROR called `ok().expect()`
323     // the following should not warn, since `expect` isn't implemented unless
324     // the error type implements `Debug`
325     let res2: Result<i32, MyError> = Ok(0);
326     res2.ok().expect("oh noes!");
327     let res3: Result<u32, MyErrorWithParam<u8>>= Ok(0);
328     res3.ok().expect("whoof"); //~ERROR called `ok().expect()`
329     let res4: Result<u32, io::Error> = Ok(0);
330     res4.ok().expect("argh"); //~ERROR called `ok().expect()`
331     let res5: io::Result<u32> = Ok(0);
332     res5.ok().expect("oops"); //~ERROR called `ok().expect()`
333     let res6: Result<u32, &str> = Ok(0);
334     res6.ok().expect("meh"); //~ERROR called `ok().expect()`
335 }
336
337 struct MyError(()); // doesn't implement Debug
338
339 #[derive(Debug)]
340 struct MyErrorWithParam<T> {
341     x: T
342 }
343
344 #[allow(unnecessary_operation)]
345 fn starts_with() {
346     "".chars().next() == Some(' ');
347     //~^ ERROR starts_with
348     //~| HELP like this
349     //~| SUGGESTION "".starts_with(' ')
350
351     Some(' ') != "".chars().next();
352     //~^ ERROR starts_with
353     //~| HELP like this
354     //~| SUGGESTION !"".starts_with(' ')
355 }
356
357 fn use_extend_from_slice() {
358     let mut v : Vec<&'static str> = vec![];
359     v.extend(&["Hello", "World"]); //~ERROR use of `extend`
360     v.extend(&vec!["Some", "more"]);
361     //~^ERROR use of `extend`
362     //~| HELP try this
363     //~| SUGGESTION v.extend_from_slice(&vec!["Some", "more"]);
364
365     v.extend(vec!["And", "even", "more"].iter()); //~ERROR use of `extend`
366     let o : Option<&'static str> = None;
367     v.extend(o);
368     v.extend(Some("Bye"));
369     v.extend(vec!["Not", "like", "this"]);
370     v.extend(["But", "this"].iter());
371     //~^ERROR use of `extend
372     //~| HELP try this
373     //~| SUGGESTION v.extend_from_slice(&["But", "this"]);
374 }
375
376 fn clone_on_copy() {
377     42.clone(); //~ERROR using `clone` on a `Copy` type
378     vec![1].clone(); // ok, not a Copy type
379     Some(vec![1]).clone(); // ok, not a Copy type
380 }
381
382 fn clone_on_copy_generic<T: Copy>(t: T) {
383     t.clone(); //~ERROR using `clone` on a `Copy` type
384     Some(t).clone(); //~ERROR using `clone` on a `Copy` type
385 }
386
387 fn clone_on_double_ref() {
388     let x = vec![1];
389     let y = &&x;
390     let z: &Vec<_> = y.clone(); //~ERROR using `clone` on a double
391                                 //~| HELP try dereferencing it
392                                 //~| SUGGESTION let z: &Vec<_> = (*y).clone();
393                                 //~^^^ERROR using `clone` on a `Copy` type
394     println!("{:p} {:p}",*y, z);
395 }
396
397 fn single_char_pattern() {
398     let x = "foo";
399     x.split("x");
400     //~^ ERROR single-character string constant used as pattern
401     //~| HELP try using a char instead:
402     //~| SUGGESTION x.split('x');
403
404     x.split("xx");
405
406     x.split('x');
407
408     let y = "x";
409     x.split(y);
410
411     // Not yet testing for multi-byte characters
412     // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_single_char_pattern`
413     // should have done this but produced an ICE
414     //
415     // We may not want to suggest changing these anyway
416     // See: https://github.com/Manishearth/rust-clippy/issues/650#issuecomment-184328984
417     x.split("ß");
418     x.split("ℝ");
419     x.split("💣");
420     // Can't use this lint for unicode code points which don't fit in a char
421     x.split("❤️");
422
423     x.contains("x");
424     //~^ ERROR single-character string constant used as pattern
425     //~| HELP try using a char instead:
426     //~| SUGGESTION x.contains('x');
427     x.starts_with("x");
428     //~^ ERROR single-character string constant used as pattern
429     //~| HELP try using a char instead:
430     //~| SUGGESTION x.starts_with('x');
431     x.ends_with("x");
432     //~^ ERROR single-character string constant used as pattern
433     //~| HELP try using a char instead:
434     //~| SUGGESTION x.ends_with('x');
435     x.find("x");
436     //~^ ERROR single-character string constant used as pattern
437     //~| HELP try using a char instead:
438     //~| SUGGESTION x.find('x');
439     x.rfind("x");
440     //~^ ERROR single-character string constant used as pattern
441     //~| HELP try using a char instead:
442     //~| SUGGESTION x.rfind('x');
443     x.rsplit("x");
444     //~^ ERROR single-character string constant used as pattern
445     //~| HELP try using a char instead:
446     //~| SUGGESTION x.rsplit('x');
447     x.split_terminator("x");
448     //~^ ERROR single-character string constant used as pattern
449     //~| HELP try using a char instead:
450     //~| SUGGESTION x.split_terminator('x');
451     x.rsplit_terminator("x");
452     //~^ ERROR single-character string constant used as pattern
453     //~| HELP try using a char instead:
454     //~| SUGGESTION x.rsplit_terminator('x');
455     x.splitn(0, "x");
456     //~^ ERROR single-character string constant used as pattern
457     //~| HELP try using a char instead:
458     //~| SUGGESTION x.splitn(0, 'x');
459     x.rsplitn(0, "x");
460     //~^ ERROR single-character string constant used as pattern
461     //~| HELP try using a char instead:
462     //~| SUGGESTION x.rsplitn(0, 'x');
463     x.matches("x");
464     //~^ ERROR single-character string constant used as pattern
465     //~| HELP try using a char instead:
466     //~| SUGGESTION x.matches('x');
467     x.rmatches("x");
468     //~^ ERROR single-character string constant used as pattern
469     //~| HELP try using a char instead:
470     //~| SUGGESTION x.rmatches('x');
471     x.match_indices("x");
472     //~^ ERROR single-character string constant used as pattern
473     //~| HELP try using a char instead:
474     //~| SUGGESTION x.match_indices('x');
475     x.rmatch_indices("x");
476     //~^ ERROR single-character string constant used as pattern
477     //~| HELP try using a char instead:
478     //~| SUGGESTION x.rmatch_indices('x');
479     x.trim_left_matches("x");
480     //~^ ERROR single-character string constant used as pattern
481     //~| HELP try using a char instead:
482     //~| SUGGESTION x.trim_left_matches('x');
483     x.trim_right_matches("x");
484     //~^ ERROR single-character string constant used as pattern
485     //~| HELP try using a char instead:
486     //~| SUGGESTION x.trim_right_matches('x');
487
488     let h = HashSet::<String>::new();
489     h.contains("X"); // should not warn
490 }
491
492 #[allow(result_unwrap_used)]
493 fn temporary_cstring() {
494     use std::ffi::CString;
495
496     ( // extra parenthesis to better test spans
497     //~^ ERROR you are getting the inner pointer of a temporary `CString`
498     //~| NOTE that pointer will be invalid outside this expression
499         CString::new("foo").unwrap()
500         //~^ HELP assign the `CString` to a variable to extend its lifetime
501     ).as_ptr();
502 }