5 #![deny(clippy, clippy_pedantic)]
6 #![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default)]
8 use std::collections::BTreeMap;
9 use std::collections::HashMap;
10 use std::collections::HashSet;
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`
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
23 fn into_u32(self) -> u32 { 0 } // fine
24 fn into_u16(&self) -> u16 { 0 } //~ERROR methods called `into_*` usually take self by value
26 fn to_something(self) -> u32 { 0 } //~ERROR methods called `to_*` usually take self by reference
29 //~^ ERROR methods called `new` usually take no self
30 //~| ERROR methods called `new` usually return `Self`
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!() }
48 // The lifetime is different, but that’s irrelevant, see #734
49 pub fn new(s: &str) -> Lt2 { unimplemented!() }
57 // The lifetime is different, but that’s irrelevant, see #734
58 pub fn new() -> Lt3<'static> { unimplemented!() }
65 fn new() -> Self { U }
66 fn to_something(self) -> u32 { 0 } // ok because U is Copy
74 fn new() -> Option<V<T>> { None }
79 fn mul(self, other: T) -> T { self } // no error, obviously
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
85 macro_rules! opt_map {
86 ($opt:expr, $map:expr) => {($opt).map($map)};
89 /// Checks implementation of the following lints:
90 /// * `OPTION_MAP_UNWRAP_OR`
91 /// * `OPTION_MAP_UNWRAP_OR_ELSE`
95 // Check OPTION_MAP_UNWRAP_OR
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
101 let _ = opt.map(|x| { //~ ERROR called `map(f).unwrap_or(a)`
105 let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or(a)`
110 let _ = opt_map!(opt, |x| x + 1).unwrap_or(0); // should not lint
112 // Check OPTION_MAP_UNWRAP_OR_ELSE
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
118 let _ = opt.map(|x| { //~ ERROR called `map(f).unwrap_or_else(g)`
121 ).unwrap_or_else(|| 0);
122 let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or_else(g)`
127 let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); // should not lint
131 /// Struct to generate false positive for Iterator-based lints
132 #[derive(Copy, Clone)]
133 struct IteratorFalsePositives {
137 impl IteratorFalsePositives {
138 fn filter(self) -> IteratorFalsePositives {
142 fn next(self) -> IteratorFalsePositives {
146 fn find(self) -> Option<u32> {
150 fn position(self) -> Option<u32> {
154 fn rposition(self) -> Option<u32> {
159 /// Checks implementation of `FILTER_NEXT` lint
161 let v = vec![3, 2, 1, 0, -1, -2, -3];
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()`
168 // check multi-line case
169 let _ = v.iter().filter(|&x| { //~ERROR called `filter(p).next()` on an Iterator.
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();
179 /// Checks implementation of `SEARCH_IS_SOME` lint
180 fn search_is_some() {
181 let v = vec![3, 2, 1, 0, -1, -2, -3];
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()`
188 // check `find().is_some()`, multi-line
189 let _ = v.iter().find(|&x| { //~ERROR called `is_some()` after searching
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()`
199 // check `position().is_some()`, multi-line
200 let _ = v.iter().position(|&x| { //~ERROR called `is_some()` after searching
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()`
210 // check `rposition().is_some()`, multi-line
211 let _ = v.iter().rposition(|&x| { //~ERROR called `is_some()` after searching
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();
223 /// Checks implementation of the `OR_FUN_CALL` lint
228 fn new() -> Foo { Foo }
235 const fn make_const(i: i32) -> i32 { i }
237 fn make<T>() -> T { unimplemented!(); }
239 let with_enum = Some(Enum::A(1));
240 with_enum.unwrap_or(Enum::A(5));
242 let with_const_fn = Some(1);
243 with_const_fn.unwrap_or(make_const(5));
245 let with_constructor = Some(vec![1]);
246 with_constructor.unwrap_or(make());
247 //~^ERROR use of `unwrap_or`
249 //~|SUGGESTION with_constructor.unwrap_or_else(make)
251 let with_new = Some(vec![1]);
252 with_new.unwrap_or(Vec::new());
253 //~^ERROR use of `unwrap_or`
255 //~|SUGGESTION with_new.unwrap_or_default();
257 let with_const_args = Some(vec![1]);
258 with_const_args.unwrap_or(Vec::with_capacity(12));
259 //~^ERROR use of `unwrap_or`
261 //~|SUGGESTION with_const_args.unwrap_or_else(|| Vec::with_capacity(12));
263 let with_err : Result<_, ()> = Ok(vec![1]);
264 with_err.unwrap_or(make());
265 //~^ERROR use of `unwrap_or`
267 //~|SUGGESTION with_err.unwrap_or_else(|_| make());
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`
273 //~|SUGGESTION with_err_args.unwrap_or_else(|_| Vec::with_capacity(12));
275 let with_default_trait = Some(1);
276 with_default_trait.unwrap_or(Default::default());
277 //~^ERROR use of `unwrap_or`
279 //~|SUGGESTION with_default_trait.unwrap_or_default();
281 let with_default_type = Some(1);
282 with_default_type.unwrap_or(u64::default());
283 //~^ERROR use of `unwrap_or`
285 //~|SUGGESTION with_default_type.unwrap_or_default();
287 let with_vec = Some(vec![1]);
288 with_vec.unwrap_or(vec![]);
289 //~^ERROR use of `unwrap_or`
291 //~|SUGGESTION with_vec.unwrap_or_else(|| vec![]);
293 let without_default = Some(Foo);
294 without_default.unwrap_or(Foo::new());
295 //~^ERROR use of `unwrap_or`
297 //~|SUGGESTION without_default.unwrap_or_else(Foo::new);
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
303 //~|SUGGESTION map.entry(42).or_insert_with(String::new);
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
309 //~|SUGGESTION btree.entry(42).or_insert_with(String::new);
312 #[allow(similar_names)]
317 let _ = opt.unwrap(); //~ERROR used unwrap() on an Option
319 let res: Result<i32, ()> = Ok(0);
320 let _ = res.unwrap(); //~ERROR used unwrap() on a Result
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()`
337 struct MyError(()); // doesn't implement Debug
340 struct MyErrorWithParam<T> {
344 #[allow(unnecessary_operation)]
346 "".chars().next() == Some(' ');
347 //~^ ERROR starts_with
349 //~| SUGGESTION "".starts_with(' ')
351 Some(' ') != "".chars().next();
352 //~^ ERROR starts_with
354 //~| SUGGESTION !"".starts_with(' ')
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`
363 //~| SUGGESTION v.extend_from_slice(&vec!["Some", "more"]);
365 v.extend(vec!["And", "even", "more"].iter()); //~ERROR use of `extend`
366 let o : Option<&'static str> = None;
368 v.extend(Some("Bye"));
369 v.extend(vec!["Not", "like", "this"]);
370 v.extend(["But", "this"].iter());
371 //~^ERROR use of `extend
373 //~| SUGGESTION v.extend_from_slice(&["But", "this"]);
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
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
387 fn clone_on_double_ref() {
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);
397 fn single_char_pattern() {
400 //~^ ERROR single-character string constant used as pattern
401 //~| HELP try using a char instead:
402 //~| SUGGESTION x.split('x');
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
415 // We may not want to suggest changing these anyway
416 // See: https://github.com/Manishearth/rust-clippy/issues/650#issuecomment-184328984
420 // Can't use this lint for unicode code points which don't fit in a char
424 //~^ ERROR single-character string constant used as pattern
425 //~| HELP try using a char instead:
426 //~| SUGGESTION x.contains('x');
428 //~^ ERROR single-character string constant used as pattern
429 //~| HELP try using a char instead:
430 //~| SUGGESTION x.starts_with('x');
432 //~^ ERROR single-character string constant used as pattern
433 //~| HELP try using a char instead:
434 //~| SUGGESTION x.ends_with('x');
436 //~^ ERROR single-character string constant used as pattern
437 //~| HELP try using a char instead:
438 //~| SUGGESTION x.find('x');
440 //~^ ERROR single-character string constant used as pattern
441 //~| HELP try using a char instead:
442 //~| SUGGESTION x.rfind('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');
456 //~^ ERROR single-character string constant used as pattern
457 //~| HELP try using a char instead:
458 //~| SUGGESTION x.splitn(0, 'x');
460 //~^ ERROR single-character string constant used as pattern
461 //~| HELP try using a char instead:
462 //~| SUGGESTION x.rsplitn(0, 'x');
464 //~^ ERROR single-character string constant used as pattern
465 //~| HELP try using a char instead:
466 //~| SUGGESTION x.matches('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');
488 let h = HashSet::<String>::new();
489 h.contains("X"); // should not warn
492 #[allow(result_unwrap_used)]
493 fn temporary_cstring() {
494 use std::ffi::CString;
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