]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/methods/mod.rs
Auto merge of #4430 - lzutao:defid_trait_alias, r=flip1995
[rust.git] / clippy_lints / src / methods / mod.rs
1 mod option_map_unwrap_or;
2 mod unnecessary_filter_map;
3
4 use std::borrow::Cow;
5 use std::fmt;
6 use std::iter;
7
8 use if_chain::if_chain;
9 use matches::matches;
10 use rustc::hir;
11 use rustc::hir::intravisit::{self, Visitor};
12 use rustc::lint::{in_external_macro, LateContext, LateLintPass, Lint, LintArray, LintContext, LintPass};
13 use rustc::ty::{self, Predicate, Ty};
14 use rustc::{declare_lint_pass, declare_tool_lint};
15 use rustc_errors::Applicability;
16 use syntax::ast;
17 use syntax::source_map::Span;
18 use syntax::symbol::LocalInternedString;
19
20 use crate::utils::sugg;
21 use crate::utils::usage::mutated_variables;
22 use crate::utils::{
23     get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy,
24     is_ctor_function, is_expn_of, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method,
25     match_type, match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, single_segment_path,
26     snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_sugg,
27     span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
28 };
29 use crate::utils::{paths, span_help_and_lint};
30
31 declare_clippy_lint! {
32     /// **What it does:** Checks for `.unwrap()` calls on `Option`s.
33     ///
34     /// **Why is this bad?** Usually it is better to handle the `None` case, or to
35     /// at least call `.expect(_)` with a more helpful message. Still, for a lot of
36     /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
37     /// `Allow` by default.
38     ///
39     /// **Known problems:** None.
40     ///
41     /// **Example:**
42     ///
43     /// Using unwrap on an `Option`:
44     ///
45     /// ```rust
46     /// let opt = Some(1);
47     /// opt.unwrap();
48     /// ```
49     ///
50     /// Better:
51     ///
52     /// ```rust
53     /// let opt = Some(1);
54     /// opt.expect("more helpful message");
55     /// ```
56     pub OPTION_UNWRAP_USED,
57     restriction,
58     "using `Option.unwrap()`, which should at least get a better message using `expect()`"
59 }
60
61 declare_clippy_lint! {
62     /// **What it does:** Checks for `.unwrap()` calls on `Result`s.
63     ///
64     /// **Why is this bad?** `result.unwrap()` will let the thread panic on `Err`
65     /// values. Normally, you want to implement more sophisticated error handling,
66     /// and propagate errors upwards with `try!`.
67     ///
68     /// Even if you want to panic on errors, not all `Error`s implement good
69     /// messages on display. Therefore, it may be beneficial to look at the places
70     /// where they may get displayed. Activate this lint to do just that.
71     ///
72     /// **Known problems:** None.
73     ///
74     /// **Example:**
75     /// Using unwrap on an `Option`:
76     ///
77     /// ```rust
78     /// let res: Result<usize, ()> = Ok(1);
79     /// res.unwrap();
80     /// ```
81     ///
82     /// Better:
83     ///
84     /// ```rust
85     /// let res: Result<usize, ()> = Ok(1);
86     /// res.expect("more helpful message");
87     /// ```
88     pub RESULT_UNWRAP_USED,
89     restriction,
90     "using `Result.unwrap()`, which might be better handled"
91 }
92
93 declare_clippy_lint! {
94     /// **What it does:** Checks for methods that should live in a trait
95     /// implementation of a `std` trait (see [llogiq's blog
96     /// post](http://llogiq.github.io/2015/07/30/traits.html) for further
97     /// information) instead of an inherent implementation.
98     ///
99     /// **Why is this bad?** Implementing the traits improve ergonomics for users of
100     /// the code, often with very little cost. Also people seeing a `mul(...)`
101     /// method
102     /// may expect `*` to work equally, so you should have good reason to disappoint
103     /// them.
104     ///
105     /// **Known problems:** None.
106     ///
107     /// **Example:**
108     /// ```ignore
109     /// struct X;
110     /// impl X {
111     ///     fn add(&self, other: &X) -> X {
112     ///         ..
113     ///     }
114     /// }
115     /// ```
116     pub SHOULD_IMPLEMENT_TRAIT,
117     style,
118     "defining a method that should be implementing a std trait"
119 }
120
121 declare_clippy_lint! {
122     /// **What it does:** Checks for methods with certain name prefixes and which
123     /// doesn't match how self is taken. The actual rules are:
124     ///
125     /// |Prefix |`self` taken          |
126     /// |-------|----------------------|
127     /// |`as_`  |`&self` or `&mut self`|
128     /// |`from_`| none                 |
129     /// |`into_`|`self`                |
130     /// |`is_`  |`&self` or none       |
131     /// |`to_`  |`&self`               |
132     ///
133     /// **Why is this bad?** Consistency breeds readability. If you follow the
134     /// conventions, your users won't be surprised that they, e.g., need to supply a
135     /// mutable reference to a `as_..` function.
136     ///
137     /// **Known problems:** None.
138     ///
139     /// **Example:**
140     /// ```ignore
141     /// impl X {
142     ///     fn as_str(self) -> &str {
143     ///         ..
144     ///     }
145     /// }
146     /// ```
147     pub WRONG_SELF_CONVENTION,
148     style,
149     "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
150 }
151
152 declare_clippy_lint! {
153     /// **What it does:** This is the same as
154     /// [`wrong_self_convention`](#wrong_self_convention), but for public items.
155     ///
156     /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention).
157     ///
158     /// **Known problems:** Actually *renaming* the function may break clients if
159     /// the function is part of the public interface. In that case, be mindful of
160     /// the stability guarantees you've given your users.
161     ///
162     /// **Example:**
163     /// ```rust
164     /// # struct X;
165     /// impl<'a> X {
166     ///     pub fn as_str(self) -> &'a str {
167     ///         "foo"
168     ///     }
169     /// }
170     /// ```
171     pub WRONG_PUB_SELF_CONVENTION,
172     restriction,
173     "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
174 }
175
176 declare_clippy_lint! {
177     /// **What it does:** Checks for usage of `ok().expect(..)`.
178     ///
179     /// **Why is this bad?** Because you usually call `expect()` on the `Result`
180     /// directly to get a better error message.
181     ///
182     /// **Known problems:** The error type needs to implement `Debug`
183     ///
184     /// **Example:**
185     /// ```ignore
186     /// x.ok().expect("why did I do this again?")
187     /// ```
188     pub OK_EXPECT,
189     style,
190     "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
191 }
192
193 declare_clippy_lint! {
194     /// **What it does:** Checks for usage of `_.map(_).unwrap_or(_)`.
195     ///
196     /// **Why is this bad?** Readability, this can be written more concisely as
197     /// `_.map_or(_, _)`.
198     ///
199     /// **Known problems:** The order of the arguments is not in execution order
200     ///
201     /// **Example:**
202     /// ```rust
203     /// # let x = Some(1);
204     /// x.map(|a| a + 1).unwrap_or(0);
205     /// ```
206     pub OPTION_MAP_UNWRAP_OR,
207     pedantic,
208     "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`"
209 }
210
211 declare_clippy_lint! {
212     /// **What it does:** Checks for usage of `_.map(_).unwrap_or_else(_)`.
213     ///
214     /// **Why is this bad?** Readability, this can be written more concisely as
215     /// `_.map_or_else(_, _)`.
216     ///
217     /// **Known problems:** The order of the arguments is not in execution order.
218     ///
219     /// **Example:**
220     /// ```rust
221     /// # let x = Some(1);
222     /// # fn some_function() -> usize { 1 }
223     /// x.map(|a| a + 1).unwrap_or_else(some_function);
224     /// ```
225     pub OPTION_MAP_UNWRAP_OR_ELSE,
226     pedantic,
227     "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`"
228 }
229
230 declare_clippy_lint! {
231     /// **What it does:** Checks for usage of `result.map(_).unwrap_or_else(_)`.
232     ///
233     /// **Why is this bad?** Readability, this can be written more concisely as
234     /// `result.ok().map_or_else(_, _)`.
235     ///
236     /// **Known problems:** None.
237     ///
238     /// **Example:**
239     /// ```rust
240     /// # let x: Result<usize, ()> = Ok(1);
241     /// # fn some_function(foo: ()) -> usize { 1 }
242     /// x.map(|a| a + 1).unwrap_or_else(some_function);
243     /// ```
244     pub RESULT_MAP_UNWRAP_OR_ELSE,
245     pedantic,
246     "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.ok().map_or_else(g, f)`"
247 }
248
249 declare_clippy_lint! {
250     /// **What it does:** Checks for usage of `_.map_or(None, _)`.
251     ///
252     /// **Why is this bad?** Readability, this can be written more concisely as
253     /// `_.and_then(_)`.
254     ///
255     /// **Known problems:** The order of the arguments is not in execution order.
256     ///
257     /// **Example:**
258     /// ```ignore
259     /// opt.map_or(None, |a| a + 1)
260     /// ```
261     pub OPTION_MAP_OR_NONE,
262     style,
263     "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
264 }
265
266 declare_clippy_lint! {
267     /// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`.
268     ///
269     /// **Why is this bad?** Readability, this can be written more concisely as
270     /// `_.map(|x| y)`.
271     ///
272     /// **Known problems:** None
273     ///
274     /// **Example:**
275     ///
276     /// ```rust
277     /// let x = Some("foo");
278     /// let _ = x.and_then(|s| Some(s.len()));
279     /// ```
280     ///
281     /// The correct use would be:
282     ///
283     /// ```rust
284     /// let x = Some("foo");
285     /// let _ = x.map(|s| s.len());
286     /// ```
287     pub OPTION_AND_THEN_SOME,
288     complexity,
289     "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`"
290 }
291
292 declare_clippy_lint! {
293     /// **What it does:** Checks for usage of `_.filter(_).next()`.
294     ///
295     /// **Why is this bad?** Readability, this can be written more concisely as
296     /// `_.find(_)`.
297     ///
298     /// **Known problems:** None.
299     ///
300     /// **Example:**
301     /// ```rust
302     /// # let vec = vec![1];
303     /// vec.iter().filter(|x| **x == 0).next();
304     /// ```
305     /// Could be written as
306     /// ```rust
307     /// # let vec = vec![1];
308     /// vec.iter().find(|x| **x == 0);
309     /// ```
310     pub FILTER_NEXT,
311     complexity,
312     "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"
313 }
314
315 declare_clippy_lint! {
316     /// **What it does:** Checks for usage of `_.map(_).flatten(_)`,
317     ///
318     /// **Why is this bad?** Readability, this can be written more concisely as a
319     /// single method call.
320     ///
321     /// **Known problems:**
322     ///
323     /// **Example:**
324     /// ```rust
325     /// let vec = vec![vec![1]];
326     /// vec.iter().map(|x| x.iter()).flatten();
327     /// ```
328     pub MAP_FLATTEN,
329     pedantic,
330     "using combinations of `flatten` and `map` which can usually be written as a single method call"
331 }
332
333 declare_clippy_lint! {
334     /// **What it does:** Checks for usage of `_.filter(_).map(_)`,
335     /// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar.
336     ///
337     /// **Why is this bad?** Readability, this can be written more concisely as a
338     /// single method call.
339     ///
340     /// **Known problems:** Often requires a condition + Option/Iterator creation
341     /// inside the closure.
342     ///
343     /// **Example:**
344     /// ```rust
345     /// let vec = vec![1];
346     /// vec.iter().filter(|x| **x == 0).map(|x| *x * 2);
347     /// ```
348     pub FILTER_MAP,
349     pedantic,
350     "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call"
351 }
352
353 declare_clippy_lint! {
354     /// **What it does:** Checks for usage of `_.filter_map(_).next()`.
355     ///
356     /// **Why is this bad?** Readability, this can be written more concisely as a
357     /// single method call.
358     ///
359     /// **Known problems:** None
360     ///
361     /// **Example:**
362     /// ```rust
363     ///  (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
364     /// ```
365     /// Can be written as
366     ///
367     /// ```rust
368     ///  (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
369     /// ```
370     pub FILTER_MAP_NEXT,
371     pedantic,
372     "using combination of `filter_map` and `next` which can usually be written as a single method call"
373 }
374
375 declare_clippy_lint! {
376     /// **What it does:** Checks for usage of `flat_map(|x| x)`.
377     ///
378     /// **Why is this bad?** Readability, this can be written more concisely by using `flatten`.
379     ///
380     /// **Known problems:** None
381     ///
382     /// **Example:**
383     /// ```rust
384     /// # let iter = vec![vec![0]].into_iter();
385     /// iter.flat_map(|x| x);
386     /// ```
387     /// Can be written as
388     /// ```rust
389     /// # let iter = vec![vec![0]].into_iter();
390     /// iter.flatten();
391     /// ```
392     pub FLAT_MAP_IDENTITY,
393     complexity,
394     "call to `flat_map` where `flatten` is sufficient"
395 }
396
397 declare_clippy_lint! {
398     /// **What it does:** Checks for usage of `_.find(_).map(_)`.
399     ///
400     /// **Why is this bad?** Readability, this can be written more concisely as a
401     /// single method call.
402     ///
403     /// **Known problems:** Often requires a condition + Option/Iterator creation
404     /// inside the closure.
405     ///
406     /// **Example:**
407     /// ```rust
408     ///  (0..3).find(|x| *x == 2).map(|x| x * 2);
409     /// ```
410     /// Can be written as
411     /// ```rust
412     ///  (0..3).find_map(|x| if x == 2 { Some(x * 2) } else { None });
413     /// ```
414     pub FIND_MAP,
415     pedantic,
416     "using a combination of `find` and `map` can usually be written as a single method call"
417 }
418
419 declare_clippy_lint! {
420     /// **What it does:** Checks for an iterator search (such as `find()`,
421     /// `position()`, or `rposition()`) followed by a call to `is_some()`.
422     ///
423     /// **Why is this bad?** Readability, this can be written more concisely as
424     /// `_.any(_)`.
425     ///
426     /// **Known problems:** None.
427     ///
428     /// **Example:**
429     /// ```rust
430     /// # let vec = vec![1];
431     /// vec.iter().find(|x| **x == 0).is_some();
432     /// ```
433     /// Could be written as
434     /// ```rust
435     /// # let vec = vec![1];
436     /// vec.iter().any(|x| *x == 0);
437     /// ```
438     pub SEARCH_IS_SOME,
439     complexity,
440     "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`"
441 }
442
443 declare_clippy_lint! {
444     /// **What it does:** Checks for usage of `.chars().next()` on a `str` to check
445     /// if it starts with a given char.
446     ///
447     /// **Why is this bad?** Readability, this can be written more concisely as
448     /// `_.starts_with(_)`.
449     ///
450     /// **Known problems:** None.
451     ///
452     /// **Example:**
453     /// ```rust
454     /// let name = "foo";
455     /// if name.chars().next() == Some('_') {};
456     /// ```
457     /// Could be written as
458     /// ```rust
459     /// let name = "foo";
460     /// if name.starts_with('_') {};
461     /// ```
462     pub CHARS_NEXT_CMP,
463     complexity,
464     "using `.chars().next()` to check if a string starts with a char"
465 }
466
467 declare_clippy_lint! {
468     /// **What it does:** Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
469     /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
470     /// `unwrap_or_default` instead.
471     ///
472     /// **Why is this bad?** The function will always be called and potentially
473     /// allocate an object acting as the default.
474     ///
475     /// **Known problems:** If the function has side-effects, not calling it will
476     /// change the semantic of the program, but you shouldn't rely on that anyway.
477     ///
478     /// **Example:**
479     /// ```rust
480     /// # let foo = Some(String::new());
481     /// foo.unwrap_or(String::new());
482     /// ```
483     /// this can instead be written:
484     /// ```rust
485     /// # let foo = Some(String::new());
486     /// foo.unwrap_or_else(String::new);
487     /// ```
488     /// or
489     /// ```rust
490     /// # let foo = Some(String::new());
491     /// foo.unwrap_or_default();
492     /// ```
493     pub OR_FUN_CALL,
494     perf,
495     "using any `*or` method with a function call, which suggests `*or_else`"
496 }
497
498 declare_clippy_lint! {
499     /// **What it does:** Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
500     /// etc., and suggests to use `unwrap_or_else` instead
501     ///
502     /// **Why is this bad?** The function will always be called.
503     ///
504     /// **Known problems:** If the function has side-effects, not calling it will
505     /// change the semantics of the program, but you shouldn't rely on that anyway.
506     ///
507     /// **Example:**
508     /// ```rust
509     /// # let foo = Some(String::new());
510     /// # let err_code = "418";
511     /// # let err_msg = "I'm a teapot";
512     /// foo.expect(&format!("Err {}: {}", err_code, err_msg));
513     /// ```
514     /// or
515     /// ```rust
516     /// # let foo = Some(String::new());
517     /// # let err_code = "418";
518     /// # let err_msg = "I'm a teapot";
519     /// foo.expect(format!("Err {}: {}", err_code, err_msg).as_str());
520     /// ```
521     /// this can instead be written:
522     /// ```rust
523     /// # let foo = Some(String::new());
524     /// # let err_code = "418";
525     /// # let err_msg = "I'm a teapot";
526     /// foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg));
527     /// ```
528     pub EXPECT_FUN_CALL,
529     perf,
530     "using any `expect` method with a function call"
531 }
532
533 declare_clippy_lint! {
534     /// **What it does:** Checks for usage of `.clone()` on a `Copy` type.
535     ///
536     /// **Why is this bad?** The only reason `Copy` types implement `Clone` is for
537     /// generics, not for using the `clone` method on a concrete type.
538     ///
539     /// **Known problems:** None.
540     ///
541     /// **Example:**
542     /// ```rust
543     /// 42u64.clone();
544     /// ```
545     pub CLONE_ON_COPY,
546     complexity,
547     "using `clone` on a `Copy` type"
548 }
549
550 declare_clippy_lint! {
551     /// **What it does:** Checks for usage of `.clone()` on a ref-counted pointer,
552     /// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
553     /// function syntax instead (e.g., `Rc::clone(foo)`).
554     ///
555     /// **Why is this bad?** Calling '.clone()' on an Rc, Arc, or Weak
556     /// can obscure the fact that only the pointer is being cloned, not the underlying
557     /// data.
558     ///
559     /// **Example:**
560     /// ```rust
561     /// # use std::rc::Rc;
562     /// let x = Rc::new(1);
563     /// x.clone();
564     /// ```
565     pub CLONE_ON_REF_PTR,
566     restriction,
567     "using 'clone' on a ref-counted pointer"
568 }
569
570 declare_clippy_lint! {
571     /// **What it does:** Checks for usage of `.clone()` on an `&&T`.
572     ///
573     /// **Why is this bad?** Cloning an `&&T` copies the inner `&T`, instead of
574     /// cloning the underlying `T`.
575     ///
576     /// **Known problems:** None.
577     ///
578     /// **Example:**
579     /// ```rust
580     /// fn main() {
581     ///     let x = vec![1];
582     ///     let y = &&x;
583     ///     let z = y.clone();
584     ///     println!("{:p} {:p}", *y, z); // prints out the same pointer
585     /// }
586     /// ```
587     pub CLONE_DOUBLE_REF,
588     correctness,
589     "using `clone` on `&&T`"
590 }
591
592 declare_clippy_lint! {
593     /// **What it does:** Checks for `new` not returning `Self`.
594     ///
595     /// **Why is this bad?** As a convention, `new` methods are used to make a new
596     /// instance of a type.
597     ///
598     /// **Known problems:** None.
599     ///
600     /// **Example:**
601     /// ```ignore
602     /// impl Foo {
603     ///     fn new(..) -> NotAFoo {
604     ///     }
605     /// }
606     /// ```
607     pub NEW_RET_NO_SELF,
608     style,
609     "not returning `Self` in a `new` method"
610 }
611
612 declare_clippy_lint! {
613     /// **What it does:** Checks for string methods that receive a single-character
614     /// `str` as an argument, e.g., `_.split("x")`.
615     ///
616     /// **Why is this bad?** Performing these methods using a `char` is faster than
617     /// using a `str`.
618     ///
619     /// **Known problems:** Does not catch multi-byte unicode characters.
620     ///
621     /// **Example:**
622     /// `_.split("x")` could be `_.split('x')`
623     pub SINGLE_CHAR_PATTERN,
624     perf,
625     "using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
626 }
627
628 declare_clippy_lint! {
629     /// **What it does:** Checks for getting the inner pointer of a temporary
630     /// `CString`.
631     ///
632     /// **Why is this bad?** The inner pointer of a `CString` is only valid as long
633     /// as the `CString` is alive.
634     ///
635     /// **Known problems:** None.
636     ///
637     /// **Example:**
638     /// ```rust,ignore
639     /// let c_str = CString::new("foo").unwrap().as_ptr();
640     /// unsafe {
641     ///     call_some_ffi_func(c_str);
642     /// }
643     /// ```
644     /// Here `c_str` point to a freed address. The correct use would be:
645     /// ```rust,ignore
646     /// let c_str = CString::new("foo").unwrap();
647     /// unsafe {
648     ///     call_some_ffi_func(c_str.as_ptr());
649     /// }
650     /// ```
651     pub TEMPORARY_CSTRING_AS_PTR,
652     correctness,
653     "getting the inner pointer of a temporary `CString`"
654 }
655
656 declare_clippy_lint! {
657     /// **What it does:** Checks for use of `.iter().nth()` (and the related
658     /// `.iter_mut().nth()`) on standard library types with O(1) element access.
659     ///
660     /// **Why is this bad?** `.get()` and `.get_mut()` are more efficient and more
661     /// readable.
662     ///
663     /// **Known problems:** None.
664     ///
665     /// **Example:**
666     /// ```rust
667     /// let some_vec = vec![0, 1, 2, 3];
668     /// let bad_vec = some_vec.iter().nth(3);
669     /// let bad_slice = &some_vec[..].iter().nth(3);
670     /// ```
671     /// The correct use would be:
672     /// ```rust
673     /// let some_vec = vec![0, 1, 2, 3];
674     /// let bad_vec = some_vec.get(3);
675     /// let bad_slice = &some_vec[..].get(3);
676     /// ```
677     pub ITER_NTH,
678     perf,
679     "using `.iter().nth()` on a standard library type with O(1) element access"
680 }
681
682 declare_clippy_lint! {
683     /// **What it does:** Checks for use of `.skip(x).next()` on iterators.
684     ///
685     /// **Why is this bad?** `.nth(x)` is cleaner
686     ///
687     /// **Known problems:** None.
688     ///
689     /// **Example:**
690     /// ```rust
691     /// let some_vec = vec![0, 1, 2, 3];
692     /// let bad_vec = some_vec.iter().skip(3).next();
693     /// let bad_slice = &some_vec[..].iter().skip(3).next();
694     /// ```
695     /// The correct use would be:
696     /// ```rust
697     /// let some_vec = vec![0, 1, 2, 3];
698     /// let bad_vec = some_vec.iter().nth(3);
699     /// let bad_slice = &some_vec[..].iter().nth(3);
700     /// ```
701     pub ITER_SKIP_NEXT,
702     style,
703     "using `.skip(x).next()` on an iterator"
704 }
705
706 declare_clippy_lint! {
707     /// **What it does:** Checks for use of `.get().unwrap()` (or
708     /// `.get_mut().unwrap`) on a standard library type which implements `Index`
709     ///
710     /// **Why is this bad?** Using the Index trait (`[]`) is more clear and more
711     /// concise.
712     ///
713     /// **Known problems:** Not a replacement for error handling: Using either
714     /// `.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic`
715     /// if the value being accessed is `None`. If the use of `.get().unwrap()` is a
716     /// temporary placeholder for dealing with the `Option` type, then this does
717     /// not mitigate the need for error handling. If there is a chance that `.get()`
718     /// will be `None` in your program, then it is advisable that the `None` case
719     /// is handled in a future refactor instead of using `.unwrap()` or the Index
720     /// trait.
721     ///
722     /// **Example:**
723     /// ```rust
724     /// let mut some_vec = vec![0, 1, 2, 3];
725     /// let last = some_vec.get(3).unwrap();
726     /// *some_vec.get_mut(0).unwrap() = 1;
727     /// ```
728     /// The correct use would be:
729     /// ```rust
730     /// let mut some_vec = vec![0, 1, 2, 3];
731     /// let last = some_vec[3];
732     /// some_vec[0] = 1;
733     /// ```
734     pub GET_UNWRAP,
735     restriction,
736     "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
737 }
738
739 declare_clippy_lint! {
740     /// **What it does:** Checks for the use of `.extend(s.chars())` where s is a
741     /// `&str` or `String`.
742     ///
743     /// **Why is this bad?** `.push_str(s)` is clearer
744     ///
745     /// **Known problems:** None.
746     ///
747     /// **Example:**
748     /// ```rust
749     /// let abc = "abc";
750     /// let def = String::from("def");
751     /// let mut s = String::new();
752     /// s.extend(abc.chars());
753     /// s.extend(def.chars());
754     /// ```
755     /// The correct use would be:
756     /// ```rust
757     /// let abc = "abc";
758     /// let def = String::from("def");
759     /// let mut s = String::new();
760     /// s.push_str(abc);
761     /// s.push_str(&def);
762     /// ```
763     pub STRING_EXTEND_CHARS,
764     style,
765     "using `x.extend(s.chars())` where s is a `&str` or `String`"
766 }
767
768 declare_clippy_lint! {
769     /// **What it does:** Checks for the use of `.cloned().collect()` on slice to
770     /// create a `Vec`.
771     ///
772     /// **Why is this bad?** `.to_vec()` is clearer
773     ///
774     /// **Known problems:** None.
775     ///
776     /// **Example:**
777     /// ```rust
778     /// let s = [1, 2, 3, 4, 5];
779     /// let s2: Vec<isize> = s[..].iter().cloned().collect();
780     /// ```
781     /// The better use would be:
782     /// ```rust
783     /// let s = [1, 2, 3, 4, 5];
784     /// let s2: Vec<isize> = s.to_vec();
785     /// ```
786     pub ITER_CLONED_COLLECT,
787     style,
788     "using `.cloned().collect()` on slice to create a `Vec`"
789 }
790
791 declare_clippy_lint! {
792     /// **What it does:** Checks for usage of `.chars().last()` or
793     /// `.chars().next_back()` on a `str` to check if it ends with a given char.
794     ///
795     /// **Why is this bad?** Readability, this can be written more concisely as
796     /// `_.ends_with(_)`.
797     ///
798     /// **Known problems:** None.
799     ///
800     /// **Example:**
801     /// ```ignore
802     /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-')
803     /// ```
804     pub CHARS_LAST_CMP,
805     style,
806     "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char"
807 }
808
809 declare_clippy_lint! {
810     /// **What it does:** Checks for usage of `.as_ref()` or `.as_mut()` where the
811     /// types before and after the call are the same.
812     ///
813     /// **Why is this bad?** The call is unnecessary.
814     ///
815     /// **Known problems:** None.
816     ///
817     /// **Example:**
818     /// ```rust
819     /// # fn do_stuff(x: &[i32]) {}
820     /// let x: &[i32] = &[1, 2, 3, 4, 5];
821     /// do_stuff(x.as_ref());
822     /// ```
823     /// The correct use would be:
824     /// ```rust
825     /// # fn do_stuff(x: &[i32]) {}
826     /// let x: &[i32] = &[1, 2, 3, 4, 5];
827     /// do_stuff(x);
828     /// ```
829     pub USELESS_ASREF,
830     complexity,
831     "using `as_ref` where the types before and after the call are the same"
832 }
833
834 declare_clippy_lint! {
835     /// **What it does:** Checks for using `fold` when a more succinct alternative exists.
836     /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
837     /// `sum` or `product`.
838     ///
839     /// **Why is this bad?** Readability.
840     ///
841     /// **Known problems:** False positive in pattern guards. Will be resolved once
842     /// non-lexical lifetimes are stable.
843     ///
844     /// **Example:**
845     /// ```rust
846     /// let _ = (0..3).fold(false, |acc, x| acc || x > 2);
847     /// ```
848     /// This could be written as:
849     /// ```rust
850     /// let _ = (0..3).any(|x| x > 2);
851     /// ```
852     pub UNNECESSARY_FOLD,
853     style,
854     "using `fold` when a more succinct alternative exists"
855 }
856
857 declare_clippy_lint! {
858     /// **What it does:** Checks for `filter_map` calls which could be replaced by `filter` or `map`.
859     /// More specifically it checks if the closure provided is only performing one of the
860     /// filter or map operations and suggests the appropriate option.
861     ///
862     /// **Why is this bad?** Complexity. The intent is also clearer if only a single
863     /// operation is being performed.
864     ///
865     /// **Known problems:** None
866     ///
867     /// **Example:**
868     /// ```rust
869     /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
870     /// ```
871     /// As there is no transformation of the argument this could be written as:
872     /// ```rust
873     /// let _ = (0..3).filter(|&x| x > 2);
874     /// ```
875     ///
876     /// ```rust
877     /// let _ = (0..4).filter_map(i32::checked_abs);
878     /// ```
879     /// As there is no conditional check on the argument this could be written as:
880     /// ```rust
881     /// let _ = (0..4).map(i32::checked_abs);
882     /// ```
883     pub UNNECESSARY_FILTER_MAP,
884     complexity,
885     "using `filter_map` when a more succinct alternative exists"
886 }
887
888 declare_clippy_lint! {
889     /// **What it does:** Checks for `into_iter` calls on types which should be replaced by `iter` or
890     /// `iter_mut`.
891     ///
892     /// **Why is this bad?** Arrays and `PathBuf` do not yet have an `into_iter` method which move out
893     /// their content into an iterator. Auto-referencing resolves the `into_iter` call to its reference
894     /// instead, like `<&[T; N] as IntoIterator>::into_iter`, which just iterates over item references
895     /// like calling `iter` would. Furthermore, when the standard library actually
896     /// [implements the `into_iter` method](https://github.com/rust-lang/rust/issues/25725) which moves
897     /// the content out of the array, the original use of `into_iter` got inferred with the wrong type
898     /// and the code will be broken.
899     ///
900     /// **Known problems:** None
901     ///
902     /// **Example:**
903     ///
904     /// ```rust
905     /// let _ = [1, 2, 3].into_iter().map(|x| *x).collect::<Vec<u32>>();
906     /// ```
907     /// Could be written as:
908     /// ```rust
909     /// let _ = [1, 2, 3].iter().map(|x| *x).collect::<Vec<u32>>();
910     /// ```
911     pub INTO_ITER_ON_ARRAY,
912     correctness,
913     "using `.into_iter()` on an array"
914 }
915
916 declare_clippy_lint! {
917     /// **What it does:** Checks for `into_iter` calls on references which should be replaced by `iter`
918     /// or `iter_mut`.
919     ///
920     /// **Why is this bad?** Readability. Calling `into_iter` on a reference will not move out its
921     /// content into the resulting iterator, which is confusing. It is better just call `iter` or
922     /// `iter_mut` directly.
923     ///
924     /// **Known problems:** None
925     ///
926     /// **Example:**
927     ///
928     /// ```rust
929     /// let _ = (&vec![3, 4, 5]).into_iter();
930     /// ```
931     pub INTO_ITER_ON_REF,
932     style,
933     "using `.into_iter()` on a reference"
934 }
935
936 declare_clippy_lint! {
937     /// **What it does:** Checks for calls to `map` followed by a `count`.
938     ///
939     /// **Why is this bad?** It looks suspicious. Maybe `map` was confused with `filter`.
940     /// If the `map` call is intentional, this should be rewritten.
941     ///
942     /// **Known problems:** None
943     ///
944     /// **Example:**
945     ///
946     /// ```rust
947     /// let _ = (0..3).map(|x| x + 2).count();
948     /// ```
949     pub SUSPICIOUS_MAP,
950     complexity,
951     "suspicious usage of map"
952 }
953
954 declare_lint_pass!(Methods => [
955     OPTION_UNWRAP_USED,
956     RESULT_UNWRAP_USED,
957     SHOULD_IMPLEMENT_TRAIT,
958     WRONG_SELF_CONVENTION,
959     WRONG_PUB_SELF_CONVENTION,
960     OK_EXPECT,
961     OPTION_MAP_UNWRAP_OR,
962     OPTION_MAP_UNWRAP_OR_ELSE,
963     RESULT_MAP_UNWRAP_OR_ELSE,
964     OPTION_MAP_OR_NONE,
965     OPTION_AND_THEN_SOME,
966     OR_FUN_CALL,
967     EXPECT_FUN_CALL,
968     CHARS_NEXT_CMP,
969     CHARS_LAST_CMP,
970     CLONE_ON_COPY,
971     CLONE_ON_REF_PTR,
972     CLONE_DOUBLE_REF,
973     NEW_RET_NO_SELF,
974     SINGLE_CHAR_PATTERN,
975     SEARCH_IS_SOME,
976     TEMPORARY_CSTRING_AS_PTR,
977     FILTER_NEXT,
978     FILTER_MAP,
979     FILTER_MAP_NEXT,
980     FLAT_MAP_IDENTITY,
981     FIND_MAP,
982     MAP_FLATTEN,
983     ITER_NTH,
984     ITER_SKIP_NEXT,
985     GET_UNWRAP,
986     STRING_EXTEND_CHARS,
987     ITER_CLONED_COLLECT,
988     USELESS_ASREF,
989     UNNECESSARY_FOLD,
990     UNNECESSARY_FILTER_MAP,
991     INTO_ITER_ON_ARRAY,
992     INTO_ITER_ON_REF,
993     SUSPICIOUS_MAP,
994 ]);
995
996 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
997     #[allow(clippy::cognitive_complexity)]
998     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
999         if in_macro(expr.span) {
1000             return;
1001         }
1002
1003         let (method_names, arg_lists) = method_calls(expr, 2);
1004         let method_names: Vec<LocalInternedString> = method_names.iter().map(|s| s.as_str()).collect();
1005         let method_names: Vec<&str> = method_names.iter().map(std::convert::AsRef::as_ref).collect();
1006
1007         match method_names.as_slice() {
1008             ["unwrap", "get"] => lint_get_unwrap(cx, expr, arg_lists[1], false),
1009             ["unwrap", "get_mut"] => lint_get_unwrap(cx, expr, arg_lists[1], true),
1010             ["unwrap", ..] => lint_unwrap(cx, expr, arg_lists[0]),
1011             ["expect", "ok"] => lint_ok_expect(cx, expr, arg_lists[1]),
1012             ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0]),
1013             ["unwrap_or_else", "map"] => lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]),
1014             ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]),
1015             ["and_then", ..] => lint_option_and_then_some(cx, expr, arg_lists[0]),
1016             ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
1017             ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]),
1018             ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]),
1019             ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]),
1020             ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]),
1021             ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
1022             ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
1023             ["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0]),
1024             ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]),
1025             ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0]),
1026             ["is_some", "position"] => lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0]),
1027             ["is_some", "rposition"] => lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0]),
1028             ["extend", ..] => lint_extend(cx, expr, arg_lists[0]),
1029             ["as_ptr", "unwrap"] | ["as_ptr", "expect"] => {
1030                 lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0])
1031             },
1032             ["nth", "iter"] => lint_iter_nth(cx, expr, arg_lists[1], false),
1033             ["nth", "iter_mut"] => lint_iter_nth(cx, expr, arg_lists[1], true),
1034             ["next", "skip"] => lint_iter_skip_next(cx, expr),
1035             ["collect", "cloned"] => lint_iter_cloned_collect(cx, expr, arg_lists[1]),
1036             ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]),
1037             ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]),
1038             ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0]),
1039             ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]),
1040             ["count", "map"] => lint_suspicious_map(cx, expr),
1041             _ => {},
1042         }
1043
1044         match expr.node {
1045             hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args) => {
1046                 lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
1047                 lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
1048
1049                 let self_ty = cx.tables.expr_ty_adjusted(&args[0]);
1050                 if args.len() == 1 && method_call.ident.name == sym!(clone) {
1051                     lint_clone_on_copy(cx, expr, &args[0], self_ty);
1052                     lint_clone_on_ref_ptr(cx, expr, &args[0]);
1053                 }
1054
1055                 match self_ty.sty {
1056                     ty::Ref(_, ty, _) if ty.sty == ty::Str => {
1057                         for &(method, pos) in &PATTERN_METHODS {
1058                             if method_call.ident.name.as_str() == method && args.len() > pos {
1059                                 lint_single_char_pattern(cx, expr, &args[pos]);
1060                             }
1061                         }
1062                     },
1063                     ty::Ref(..) if method_call.ident.name == sym!(into_iter) => {
1064                         lint_into_iter(cx, expr, self_ty, *method_span);
1065                     },
1066                     _ => (),
1067                 }
1068             },
1069             hir::ExprKind::Binary(op, ref lhs, ref rhs)
1070                 if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne =>
1071             {
1072                 let mut info = BinaryExprInfo {
1073                     expr,
1074                     chain: lhs,
1075                     other: rhs,
1076                     eq: op.node == hir::BinOpKind::Eq,
1077                 };
1078                 lint_binary_expr_with_method_call(cx, &mut info);
1079             }
1080             _ => (),
1081         }
1082     }
1083
1084     fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem) {
1085         if in_external_macro(cx.sess(), impl_item.span) {
1086             return;
1087         }
1088         let name = impl_item.ident.name.as_str();
1089         let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id);
1090         let item = cx.tcx.hir().expect_item(parent);
1091         let def_id = cx.tcx.hir().local_def_id(item.hir_id);
1092         let ty = cx.tcx.type_of(def_id);
1093         if_chain! {
1094             if let hir::ImplItemKind::Method(ref sig, id) = impl_item.node;
1095             if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next();
1096             if let hir::ItemKind::Impl(_, _, _, _, None, _, _) = item.node;
1097
1098             let method_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
1099             let method_sig = cx.tcx.fn_sig(method_def_id);
1100             let method_sig = cx.tcx.erase_late_bound_regions(&method_sig);
1101
1102             let first_arg_ty = &method_sig.inputs().iter().next();
1103
1104             // check conventions w.r.t. conversion method names and predicates
1105             if let Some(first_arg_ty) = first_arg_ty;
1106
1107             then {
1108                 if cx.access_levels.is_exported(impl_item.hir_id) {
1109                 // check missing trait implementations
1110                     for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS {
1111                         if name == method_name &&
1112                         sig.decl.inputs.len() == n_args &&
1113                         out_type.matches(cx, &sig.decl.output) &&
1114                         self_kind.matches(cx, ty, first_arg_ty) {
1115                             span_lint(cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, &format!(
1116                                 "defining a method called `{}` on this type; consider implementing \
1117                                 the `{}` trait or choosing a less ambiguous name", name, trait_name));
1118                         }
1119                     }
1120                 }
1121
1122                 if let Some((ref conv, self_kinds)) = &CONVENTIONS
1123                     .iter()
1124                     .find(|(ref conv, _)| conv.check(&name))
1125                 {
1126                     if !self_kinds.iter().any(|k| k.matches(cx, ty, first_arg_ty)) {
1127                         let lint = if item.vis.node.is_pub() {
1128                             WRONG_PUB_SELF_CONVENTION
1129                         } else {
1130                             WRONG_SELF_CONVENTION
1131                         };
1132
1133                         span_lint(
1134                             cx,
1135                             lint,
1136                             first_arg.pat.span,
1137                             &format!(
1138                                "methods called `{}` usually take {}; consider choosing a less \
1139                                  ambiguous name",
1140                                 conv,
1141                                 &self_kinds
1142                                     .iter()
1143                                     .map(|k| k.description())
1144                                     .collect::<Vec<_>>()
1145                                     .join(" or ")
1146                             ),
1147                         );
1148                     }
1149                 }
1150             }
1151         }
1152
1153         if let hir::ImplItemKind::Method(_, _) = impl_item.node {
1154             let ret_ty = return_ty(cx, impl_item.hir_id);
1155
1156             // walk the return type and check for Self (this does not check associated types)
1157             if ret_ty.walk().any(|inner_type| same_tys(cx, ty, inner_type)) {
1158                 return;
1159             }
1160
1161             // if return type is impl trait, check the associated types
1162             if let ty::Opaque(def_id, _) = ret_ty.sty {
1163                 // one of the associated types must be Self
1164                 for predicate in &cx.tcx.predicates_of(def_id).predicates {
1165                     match predicate {
1166                         (Predicate::Projection(poly_projection_predicate), _) => {
1167                             let binder = poly_projection_predicate.ty();
1168                             let associated_type = binder.skip_binder();
1169
1170                             // walk the associated type and check for Self
1171                             for inner_type in associated_type.walk() {
1172                                 if same_tys(cx, ty, inner_type) {
1173                                     return;
1174                                 }
1175                             }
1176                         },
1177                         (_, _) => {},
1178                     }
1179                 }
1180             }
1181
1182             if name == "new" && !same_tys(cx, ret_ty, ty) {
1183                 span_lint(
1184                     cx,
1185                     NEW_RET_NO_SELF,
1186                     impl_item.span,
1187                     "methods called `new` usually return `Self`",
1188                 );
1189             }
1190         }
1191     }
1192 }
1193
1194 /// Checks for the `OR_FUN_CALL` lint.
1195 #[allow(clippy::too_many_lines)]
1196 fn lint_or_fun_call<'a, 'tcx>(
1197     cx: &LateContext<'a, 'tcx>,
1198     expr: &hir::Expr,
1199     method_span: Span,
1200     name: &str,
1201     args: &'tcx [hir::Expr],
1202 ) {
1203     // Searches an expression for method calls or function calls that aren't ctors
1204     struct FunCallFinder<'a, 'tcx> {
1205         cx: &'a LateContext<'a, 'tcx>,
1206         found: bool,
1207     }
1208
1209     impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
1210         fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
1211             let call_found = match &expr.node {
1212                 // ignore enum and struct constructors
1213                 hir::ExprKind::Call(..) => !is_ctor_function(self.cx, expr),
1214                 hir::ExprKind::MethodCall(..) => true,
1215                 _ => false,
1216             };
1217
1218             if call_found {
1219                 // don't lint for constant values
1220                 let owner_def = self.cx.tcx.hir().get_parent_did(expr.hir_id);
1221                 let promotable = self
1222                     .cx
1223                     .tcx
1224                     .rvalue_promotable_map(owner_def)
1225                     .contains(&expr.hir_id.local_id);
1226                 if !promotable {
1227                     self.found |= true;
1228                 }
1229             }
1230
1231             if !self.found {
1232                 intravisit::walk_expr(self, expr);
1233             }
1234         }
1235
1236         fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
1237             intravisit::NestedVisitorMap::None
1238         }
1239     }
1240
1241     /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
1242     fn check_unwrap_or_default(
1243         cx: &LateContext<'_, '_>,
1244         name: &str,
1245         fun: &hir::Expr,
1246         self_expr: &hir::Expr,
1247         arg: &hir::Expr,
1248         or_has_args: bool,
1249         span: Span,
1250     ) -> bool {
1251         if_chain! {
1252             if !or_has_args;
1253             if name == "unwrap_or";
1254             if let hir::ExprKind::Path(ref qpath) = fun.node;
1255             let path = &*last_path_segment(qpath).ident.as_str();
1256             if ["default", "new"].contains(&path);
1257             let arg_ty = cx.tables.expr_ty(arg);
1258             if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
1259             if implements_trait(cx, arg_ty, default_trait_id, &[]);
1260
1261             then {
1262                 let mut applicability = Applicability::MachineApplicable;
1263                 span_lint_and_sugg(
1264                     cx,
1265                     OR_FUN_CALL,
1266                     span,
1267                     &format!("use of `{}` followed by a call to `{}`", name, path),
1268                     "try this",
1269                     format!(
1270                         "{}.unwrap_or_default()",
1271                         snippet_with_applicability(cx, self_expr.span, "_", &mut applicability)
1272                     ),
1273                     applicability,
1274                 );
1275
1276                 true
1277             } else {
1278                 false
1279             }
1280         }
1281     }
1282
1283     /// Checks for `*or(foo())`.
1284     #[allow(clippy::too_many_arguments)]
1285     fn check_general_case<'a, 'tcx>(
1286         cx: &LateContext<'a, 'tcx>,
1287         name: &str,
1288         method_span: Span,
1289         fun_span: Span,
1290         self_expr: &hir::Expr,
1291         arg: &'tcx hir::Expr,
1292         or_has_args: bool,
1293         span: Span,
1294     ) {
1295         // (path, fn_has_argument, methods, suffix)
1296         let know_types: &[(&[_], _, &[_], _)] = &[
1297             (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
1298             (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
1299             (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
1300             (&paths::RESULT, true, &["or", "unwrap_or"], "else"),
1301         ];
1302
1303         if_chain! {
1304             if know_types.iter().any(|k| k.2.contains(&name));
1305
1306             let mut finder = FunCallFinder { cx: &cx, found: false };
1307             if { finder.visit_expr(&arg); finder.found };
1308
1309             let self_ty = cx.tables.expr_ty(self_expr);
1310
1311             if let Some(&(_, fn_has_arguments, poss, suffix)) =
1312                    know_types.iter().find(|&&i| match_type(cx, self_ty, i.0));
1313
1314             if poss.contains(&name);
1315
1316             then {
1317                 let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) {
1318                     (true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
1319                     (false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
1320                     (false, true) => snippet_with_macro_callsite(cx, fun_span, ".."),
1321                 };
1322                 let span_replace_word = method_span.with_hi(span.hi());
1323                 span_lint_and_sugg(
1324                     cx,
1325                     OR_FUN_CALL,
1326                     span_replace_word,
1327                     &format!("use of `{}` followed by a function call", name),
1328                     "try this",
1329                     format!("{}_{}({})", name, suffix, sugg),
1330                     Applicability::HasPlaceholders,
1331                 );
1332             }
1333         }
1334     }
1335
1336     if args.len() == 2 {
1337         match args[1].node {
1338             hir::ExprKind::Call(ref fun, ref or_args) => {
1339                 let or_has_args = !or_args.is_empty();
1340                 if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
1341                     check_general_case(
1342                         cx,
1343                         name,
1344                         method_span,
1345                         fun.span,
1346                         &args[0],
1347                         &args[1],
1348                         or_has_args,
1349                         expr.span,
1350                     );
1351                 }
1352             },
1353             hir::ExprKind::MethodCall(_, span, ref or_args) => check_general_case(
1354                 cx,
1355                 name,
1356                 method_span,
1357                 span,
1358                 &args[0],
1359                 &args[1],
1360                 !or_args.is_empty(),
1361                 expr.span,
1362             ),
1363             _ => {},
1364         }
1365     }
1366 }
1367
1368 /// Checks for the `EXPECT_FUN_CALL` lint.
1369 #[allow(clippy::too_many_lines)]
1370 fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) {
1371     // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
1372     // `&str`
1373     fn get_arg_root<'a>(cx: &LateContext<'_, '_>, arg: &'a hir::Expr) -> &'a hir::Expr {
1374         let mut arg_root = arg;
1375         loop {
1376             arg_root = match &arg_root.node {
1377                 hir::ExprKind::AddrOf(_, expr) => expr,
1378                 hir::ExprKind::MethodCall(method_name, _, call_args) => {
1379                     if call_args.len() == 1
1380                         && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref))
1381                         && {
1382                             let arg_type = cx.tables.expr_ty(&call_args[0]);
1383                             let base_type = walk_ptrs_ty(arg_type);
1384                             base_type.sty == ty::Str || match_type(cx, base_type, &paths::STRING)
1385                         }
1386                     {
1387                         &call_args[0]
1388                     } else {
1389                         break;
1390                     }
1391                 },
1392                 _ => break,
1393             };
1394         }
1395         arg_root
1396     }
1397
1398     // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be
1399     // converted to string.
1400     fn requires_to_string(cx: &LateContext<'_, '_>, arg: &hir::Expr) -> bool {
1401         let arg_ty = cx.tables.expr_ty(arg);
1402         if match_type(cx, arg_ty, &paths::STRING) {
1403             return false;
1404         }
1405         if let ty::Ref(ty::ReStatic, ty, ..) = arg_ty.sty {
1406             if ty.sty == ty::Str {
1407                 return false;
1408             }
1409         };
1410         true
1411     }
1412
1413     fn generate_format_arg_snippet(
1414         cx: &LateContext<'_, '_>,
1415         a: &hir::Expr,
1416         applicability: &mut Applicability,
1417     ) -> Vec<String> {
1418         if_chain! {
1419             if let hir::ExprKind::AddrOf(_, ref format_arg) = a.node;
1420             if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.node;
1421             if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.node;
1422
1423             then {
1424                 format_arg_expr_tup
1425                     .iter()
1426                     .map(|a| snippet_with_applicability(cx, a.span, "..", applicability).into_owned())
1427                     .collect()
1428             } else {
1429                 unreachable!()
1430             }
1431         }
1432     }
1433
1434     fn is_call(node: &hir::ExprKind) -> bool {
1435         match node {
1436             hir::ExprKind::AddrOf(_, expr) => {
1437                 is_call(&expr.node)
1438             },
1439             hir::ExprKind::Call(..)
1440             | hir::ExprKind::MethodCall(..)
1441             // These variants are debatable or require further examination
1442             | hir::ExprKind::Match(..)
1443             | hir::ExprKind::Block{ .. } => true,
1444             _ => false,
1445         }
1446     }
1447
1448     if args.len() != 2 || name != "expect" || !is_call(&args[1].node) {
1449         return;
1450     }
1451
1452     let receiver_type = cx.tables.expr_ty(&args[0]);
1453     let closure_args = if match_type(cx, receiver_type, &paths::OPTION) {
1454         "||"
1455     } else if match_type(cx, receiver_type, &paths::RESULT) {
1456         "|_|"
1457     } else {
1458         return;
1459     };
1460
1461     let arg_root = get_arg_root(cx, &args[1]);
1462
1463     let span_replace_word = method_span.with_hi(expr.span.hi());
1464
1465     let mut applicability = Applicability::MachineApplicable;
1466
1467     //Special handling for `format!` as arg_root
1468     if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = arg_root.node {
1469         if is_expn_of(inner_fun.span, "format").is_some() && inner_args.len() == 1 {
1470             if let hir::ExprKind::Call(_, format_args) = &inner_args[0].node {
1471                 let fmt_spec = &format_args[0];
1472                 let fmt_args = &format_args[1];
1473
1474                 let mut args = vec![snippet(cx, fmt_spec.span, "..").into_owned()];
1475
1476                 args.extend(generate_format_arg_snippet(cx, fmt_args, &mut applicability));
1477
1478                 let sugg = args.join(", ");
1479
1480                 span_lint_and_sugg(
1481                     cx,
1482                     EXPECT_FUN_CALL,
1483                     span_replace_word,
1484                     &format!("use of `{}` followed by a function call", name),
1485                     "try this",
1486                     format!("unwrap_or_else({} panic!({}))", closure_args, sugg),
1487                     applicability,
1488                 );
1489
1490                 return;
1491             }
1492         }
1493     }
1494
1495     let mut arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability);
1496     if requires_to_string(cx, arg_root) {
1497         arg_root_snippet.to_mut().push_str(".to_string()");
1498     }
1499
1500     span_lint_and_sugg(
1501         cx,
1502         EXPECT_FUN_CALL,
1503         span_replace_word,
1504         &format!("use of `{}` followed by a function call", name),
1505         "try this",
1506         format!("unwrap_or_else({} {{ panic!({}) }})", closure_args, arg_root_snippet),
1507         applicability,
1508     );
1509 }
1510
1511 /// Checks for the `CLONE_ON_COPY` lint.
1512 fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Expr, arg_ty: Ty<'_>) {
1513     let ty = cx.tables.expr_ty(expr);
1514     if let ty::Ref(_, inner, _) = arg_ty.sty {
1515         if let ty::Ref(_, innermost, _) = inner.sty {
1516             span_lint_and_then(
1517                 cx,
1518                 CLONE_DOUBLE_REF,
1519                 expr.span,
1520                 "using `clone` on a double-reference; \
1521                  this will copy the reference instead of cloning the inner type",
1522                 |db| {
1523                     if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
1524                         let mut ty = innermost;
1525                         let mut n = 0;
1526                         while let ty::Ref(_, inner, _) = ty.sty {
1527                             ty = inner;
1528                             n += 1;
1529                         }
1530                         let refs: String = iter::repeat('&').take(n + 1).collect();
1531                         let derefs: String = iter::repeat('*').take(n).collect();
1532                         let explicit = format!("{}{}::clone({})", refs, ty, snip);
1533                         db.span_suggestion(
1534                             expr.span,
1535                             "try dereferencing it",
1536                             format!("{}({}{}).clone()", refs, derefs, snip.deref()),
1537                             Applicability::MaybeIncorrect,
1538                         );
1539                         db.span_suggestion(
1540                             expr.span,
1541                             "or try being explicit about what type to clone",
1542                             explicit,
1543                             Applicability::MaybeIncorrect,
1544                         );
1545                     }
1546                 },
1547             );
1548             return; // don't report clone_on_copy
1549         }
1550     }
1551
1552     if is_copy(cx, ty) {
1553         let snip;
1554         if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) {
1555             let parent = cx.tcx.hir().get_parent_node(expr.hir_id);
1556             match &cx.tcx.hir().get(parent) {
1557                 hir::Node::Expr(parent) => match parent.node {
1558                     // &*x is a nop, &x.clone() is not
1559                     hir::ExprKind::AddrOf(..) |
1560                     // (*x).func() is useless, x.clone().func() can work in case func borrows mutably
1561                     hir::ExprKind::MethodCall(..) => return,
1562                     _ => {},
1563                 },
1564                 hir::Node::Stmt(stmt) => {
1565                     if let hir::StmtKind::Local(ref loc) = stmt.node {
1566                         if let hir::PatKind::Ref(..) = loc.pat.node {
1567                             // let ref y = *x borrows x, let ref y = x.clone() does not
1568                             return;
1569                         }
1570                     }
1571                 },
1572                 _ => {},
1573             }
1574
1575             // x.clone() might have dereferenced x, possibly through Deref impls
1576             if cx.tables.expr_ty(arg) == ty {
1577                 snip = Some(("try removing the `clone` call", format!("{}", snippet)));
1578             } else {
1579                 let deref_count = cx
1580                     .tables
1581                     .expr_adjustments(arg)
1582                     .iter()
1583                     .filter(|adj| {
1584                         if let ty::adjustment::Adjust::Deref(_) = adj.kind {
1585                             true
1586                         } else {
1587                             false
1588                         }
1589                     })
1590                     .count();
1591                 let derefs: String = iter::repeat('*').take(deref_count).collect();
1592                 snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
1593             }
1594         } else {
1595             snip = None;
1596         }
1597         span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |db| {
1598             if let Some((text, snip)) = snip {
1599                 db.span_suggestion(expr.span, text, snip, Applicability::Unspecified);
1600             }
1601         });
1602     }
1603 }
1604
1605 fn lint_clone_on_ref_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Expr) {
1606     let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(arg));
1607
1608     if let ty::Adt(_, subst) = obj_ty.sty {
1609         let caller_type = if match_type(cx, obj_ty, &paths::RC) {
1610             "Rc"
1611         } else if match_type(cx, obj_ty, &paths::ARC) {
1612             "Arc"
1613         } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) {
1614             "Weak"
1615         } else {
1616             return;
1617         };
1618
1619         span_lint_and_sugg(
1620             cx,
1621             CLONE_ON_REF_PTR,
1622             expr.span,
1623             "using '.clone()' on a ref-counted pointer",
1624             "try this",
1625             format!(
1626                 "{}::<{}>::clone(&{})",
1627                 caller_type,
1628                 subst.type_at(0),
1629                 snippet(cx, arg.span, "_")
1630             ),
1631             Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak
1632         );
1633     }
1634 }
1635
1636 fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
1637     let arg = &args[1];
1638     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
1639         let target = &arglists[0][0];
1640         let self_ty = walk_ptrs_ty(cx.tables.expr_ty(target));
1641         let ref_str = if self_ty.sty == ty::Str {
1642             ""
1643         } else if match_type(cx, self_ty, &paths::STRING) {
1644             "&"
1645         } else {
1646             return;
1647         };
1648
1649         let mut applicability = Applicability::MachineApplicable;
1650         span_lint_and_sugg(
1651             cx,
1652             STRING_EXTEND_CHARS,
1653             expr.span,
1654             "calling `.extend(_.chars())`",
1655             "try this",
1656             format!(
1657                 "{}.push_str({}{})",
1658                 snippet_with_applicability(cx, args[0].span, "_", &mut applicability),
1659                 ref_str,
1660                 snippet_with_applicability(cx, target.span, "_", &mut applicability)
1661             ),
1662             applicability,
1663         );
1664     }
1665 }
1666
1667 fn lint_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
1668     let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
1669     if match_type(cx, obj_ty, &paths::STRING) {
1670         lint_string_extend(cx, expr, args);
1671     }
1672 }
1673
1674 fn lint_cstring_as_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, source: &hir::Expr, unwrap: &hir::Expr) {
1675     if_chain! {
1676         let source_type = cx.tables.expr_ty(source);
1677         if let ty::Adt(def, substs) = source_type.sty;
1678         if match_def_path(cx, def.did, &paths::RESULT);
1679         if match_type(cx, substs.type_at(0), &paths::CSTRING);
1680         then {
1681             span_lint_and_then(
1682                 cx,
1683                 TEMPORARY_CSTRING_AS_PTR,
1684                 expr.span,
1685                 "you are getting the inner pointer of a temporary `CString`",
1686                 |db| {
1687                     db.note("that pointer will be invalid outside this expression");
1688                     db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime");
1689                 });
1690         }
1691     }
1692 }
1693
1694 fn lint_iter_cloned_collect<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, iter_args: &'tcx [hir::Expr]) {
1695     if_chain! {
1696         if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC);
1697         if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0]));
1698         if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
1699
1700         then {
1701             span_lint_and_sugg(
1702                 cx,
1703                 ITER_CLONED_COLLECT,
1704                 to_replace,
1705                 "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
1706                  more readable",
1707                 "try",
1708                 ".to_vec()".to_string(),
1709                 Applicability::MachineApplicable,
1710             );
1711         }
1712     }
1713 }
1714
1715 fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args: &[hir::Expr]) {
1716     fn check_fold_with_op(
1717         cx: &LateContext<'_, '_>,
1718         expr: &hir::Expr,
1719         fold_args: &[hir::Expr],
1720         op: hir::BinOpKind,
1721         replacement_method_name: &str,
1722         replacement_has_args: bool,
1723     ) {
1724         if_chain! {
1725             // Extract the body of the closure passed to fold
1726             if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].node;
1727             let closure_body = cx.tcx.hir().body(body_id);
1728             let closure_expr = remove_blocks(&closure_body.value);
1729
1730             // Check if the closure body is of the form `acc <op> some_expr(x)`
1731             if let hir::ExprKind::Binary(ref bin_op, ref left_expr, ref right_expr) = closure_expr.node;
1732             if bin_op.node == op;
1733
1734             // Extract the names of the two arguments to the closure
1735             if let Some(first_arg_ident) = get_arg_name(&closure_body.arguments[0].pat);
1736             if let Some(second_arg_ident) = get_arg_name(&closure_body.arguments[1].pat);
1737
1738             if match_var(&*left_expr, first_arg_ident);
1739             if replacement_has_args || match_var(&*right_expr, second_arg_ident);
1740
1741             if let hir::ExprKind::MethodCall(_, span, _) = &expr.node;
1742
1743             then {
1744                 let mut applicability = Applicability::MachineApplicable;
1745                 let sugg = if replacement_has_args {
1746                     format!(
1747                         "{replacement}(|{s}| {r})",
1748                         replacement = replacement_method_name,
1749                         s = second_arg_ident,
1750                         r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
1751                     )
1752                 } else {
1753                     format!(
1754                         "{replacement}()",
1755                         replacement = replacement_method_name,
1756                     )
1757                 };
1758
1759                 span_lint_and_sugg(
1760                     cx,
1761                     UNNECESSARY_FOLD,
1762                     span.with_hi(expr.span.hi()),
1763                     // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
1764                     "this `.fold` can be written more succinctly using another method",
1765                     "try",
1766                     sugg,
1767                     applicability,
1768                 );
1769             }
1770         }
1771     }
1772
1773     // Check that this is a call to Iterator::fold rather than just some function called fold
1774     if !match_trait_method(cx, expr, &paths::ITERATOR) {
1775         return;
1776     }
1777
1778     assert!(
1779         fold_args.len() == 3,
1780         "Expected fold_args to have three entries - the receiver, the initial value and the closure"
1781     );
1782
1783     // Check if the first argument to .fold is a suitable literal
1784     if let hir::ExprKind::Lit(ref lit) = fold_args[1].node {
1785         match lit.node {
1786             ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, fold_args, hir::BinOpKind::Or, "any", true),
1787             ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, fold_args, hir::BinOpKind::And, "all", true),
1788             ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, fold_args, hir::BinOpKind::Add, "sum", false),
1789             ast::LitKind::Int(1, _) => check_fold_with_op(cx, expr, fold_args, hir::BinOpKind::Mul, "product", false),
1790             _ => (),
1791         }
1792     }
1793 }
1794
1795 fn lint_iter_nth<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, iter_args: &'tcx [hir::Expr], is_mut: bool) {
1796     let mut_str = if is_mut { "_mut" } else { "" };
1797     let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {
1798         "slice"
1799     } else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &paths::VEC) {
1800         "Vec"
1801     } else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &paths::VEC_DEQUE) {
1802         "VecDeque"
1803     } else {
1804         return; // caller is not a type that we want to lint
1805     };
1806
1807     span_lint(
1808         cx,
1809         ITER_NTH,
1810         expr.span,
1811         &format!(
1812             "called `.iter{0}().nth()` on a {1}. Calling `.get{0}()` is both faster and more readable",
1813             mut_str, caller_type
1814         ),
1815     );
1816 }
1817
1818 fn lint_get_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, get_args: &'tcx [hir::Expr], is_mut: bool) {
1819     // Note: we don't want to lint `get_mut().unwrap` for HashMap or BTreeMap,
1820     // because they do not implement `IndexMut`
1821     let mut applicability = Applicability::MachineApplicable;
1822     let expr_ty = cx.tables.expr_ty(&get_args[0]);
1823     let get_args_str = if get_args.len() > 1 {
1824         snippet_with_applicability(cx, get_args[1].span, "_", &mut applicability)
1825     } else {
1826         return; // not linting on a .get().unwrap() chain or variant
1827     };
1828     let mut needs_ref;
1829     let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
1830         needs_ref = get_args_str.parse::<usize>().is_ok();
1831         "slice"
1832     } else if match_type(cx, expr_ty, &paths::VEC) {
1833         needs_ref = get_args_str.parse::<usize>().is_ok();
1834         "Vec"
1835     } else if match_type(cx, expr_ty, &paths::VEC_DEQUE) {
1836         needs_ref = get_args_str.parse::<usize>().is_ok();
1837         "VecDeque"
1838     } else if !is_mut && match_type(cx, expr_ty, &paths::HASHMAP) {
1839         needs_ref = true;
1840         "HashMap"
1841     } else if !is_mut && match_type(cx, expr_ty, &paths::BTREEMAP) {
1842         needs_ref = true;
1843         "BTreeMap"
1844     } else {
1845         return; // caller is not a type that we want to lint
1846     };
1847
1848     let mut span = expr.span;
1849
1850     // Handle the case where the result is immediately dereferenced
1851     // by not requiring ref and pulling the dereference into the
1852     // suggestion.
1853     if_chain! {
1854         if needs_ref;
1855         if let Some(parent) = get_parent_expr(cx, expr);
1856         if let hir::ExprKind::Unary(hir::UnOp::UnDeref, _) = parent.node;
1857         then {
1858             needs_ref = false;
1859             span = parent.span;
1860         }
1861     }
1862
1863     let mut_str = if is_mut { "_mut" } else { "" };
1864     let borrow_str = if !needs_ref {
1865         ""
1866     } else if is_mut {
1867         "&mut "
1868     } else {
1869         "&"
1870     };
1871
1872     span_lint_and_sugg(
1873         cx,
1874         GET_UNWRAP,
1875         span,
1876         &format!(
1877             "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
1878             mut_str, caller_type
1879         ),
1880         "try this",
1881         format!(
1882             "{}{}[{}]",
1883             borrow_str,
1884             snippet_with_applicability(cx, get_args[0].span, "_", &mut applicability),
1885             get_args_str
1886         ),
1887         applicability,
1888     );
1889 }
1890
1891 fn lint_iter_skip_next(cx: &LateContext<'_, '_>, expr: &hir::Expr) {
1892     // lint if caller of skip is an Iterator
1893     if match_trait_method(cx, expr, &paths::ITERATOR) {
1894         span_lint(
1895             cx,
1896             ITER_SKIP_NEXT,
1897             expr.span,
1898             "called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`",
1899         );
1900     }
1901 }
1902
1903 fn derefs_to_slice<'a, 'tcx>(
1904     cx: &LateContext<'a, 'tcx>,
1905     expr: &'tcx hir::Expr,
1906     ty: Ty<'tcx>,
1907 ) -> Option<&'tcx hir::Expr> {
1908     fn may_slice<'a>(cx: &LateContext<'_, 'a>, ty: Ty<'a>) -> bool {
1909         match ty.sty {
1910             ty::Slice(_) => true,
1911             ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
1912             ty::Adt(..) => match_type(cx, ty, &paths::VEC),
1913             ty::Array(_, size) => size.eval_usize(cx.tcx, cx.param_env) < 32,
1914             ty::Ref(_, inner, _) => may_slice(cx, inner),
1915             _ => false,
1916         }
1917     }
1918
1919     if let hir::ExprKind::MethodCall(ref path, _, ref args) = expr.node {
1920         if path.ident.name == sym!(iter) && may_slice(cx, cx.tables.expr_ty(&args[0])) {
1921             Some(&args[0])
1922         } else {
1923             None
1924         }
1925     } else {
1926         match ty.sty {
1927             ty::Slice(_) => Some(expr),
1928             ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
1929             ty::Ref(_, inner, _) => {
1930                 if may_slice(cx, inner) {
1931                     Some(expr)
1932                 } else {
1933                     None
1934                 }
1935             },
1936             _ => None,
1937         }
1938     }
1939 }
1940
1941 /// lint use of `unwrap()` for `Option`s and `Result`s
1942 fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, unwrap_args: &[hir::Expr]) {
1943     let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&unwrap_args[0]));
1944
1945     let mess = if match_type(cx, obj_ty, &paths::OPTION) {
1946         Some((OPTION_UNWRAP_USED, "an Option", "None"))
1947     } else if match_type(cx, obj_ty, &paths::RESULT) {
1948         Some((RESULT_UNWRAP_USED, "a Result", "Err"))
1949     } else {
1950         None
1951     };
1952
1953     if let Some((lint, kind, none_value)) = mess {
1954         span_lint(
1955             cx,
1956             lint,
1957             expr.span,
1958             &format!(
1959                 "used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \
1960                  using expect() to provide a better panic \
1961                  message",
1962                 kind, none_value
1963             ),
1964         );
1965     }
1966 }
1967
1968 /// lint use of `ok().expect()` for `Result`s
1969 fn lint_ok_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr, ok_args: &[hir::Expr]) {
1970     if_chain! {
1971         // lint if the caller of `ok()` is a `Result`
1972         if match_type(cx, cx.tables.expr_ty(&ok_args[0]), &paths::RESULT);
1973         let result_type = cx.tables.expr_ty(&ok_args[0]);
1974         if let Some(error_type) = get_error_type(cx, result_type);
1975         if has_debug_impl(error_type, cx);
1976
1977         then {
1978             span_lint(
1979                 cx,
1980                 OK_EXPECT,
1981                 expr.span,
1982                 "called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`",
1983             );
1984         }
1985     }
1986 }
1987
1988 /// lint use of `map().flatten()` for `Iterators`
1989 fn lint_map_flatten<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_args: &'tcx [hir::Expr]) {
1990     // lint if caller of `.map().flatten()` is an Iterator
1991     if match_trait_method(cx, expr, &paths::ITERATOR) {
1992         let msg = "called `map(..).flatten()` on an `Iterator`. \
1993                    This is more succinctly expressed by calling `.flat_map(..)`";
1994         let self_snippet = snippet(cx, map_args[0].span, "..");
1995         let func_snippet = snippet(cx, map_args[1].span, "..");
1996         let hint = format!("{0}.flat_map({1})", self_snippet, func_snippet);
1997         span_lint_and_then(cx, MAP_FLATTEN, expr.span, msg, |db| {
1998             db.span_suggestion(
1999                 expr.span,
2000                 "try using flat_map instead",
2001                 hint,
2002                 Applicability::MachineApplicable,
2003             );
2004         });
2005     }
2006 }
2007
2008 /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
2009 fn lint_map_unwrap_or_else<'a, 'tcx>(
2010     cx: &LateContext<'a, 'tcx>,
2011     expr: &'tcx hir::Expr,
2012     map_args: &'tcx [hir::Expr],
2013     unwrap_args: &'tcx [hir::Expr],
2014 ) {
2015     // lint if the caller of `map()` is an `Option`
2016     let is_option = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION);
2017     let is_result = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::RESULT);
2018
2019     if is_option || is_result {
2020         // Don't make a suggestion that may fail to compile due to mutably borrowing
2021         // the same variable twice.
2022         let map_mutated_vars = mutated_variables(&map_args[0], cx);
2023         let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx);
2024         if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) {
2025             if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() {
2026                 return;
2027             }
2028         } else {
2029             return;
2030         }
2031
2032         // lint message
2033         let msg = if is_option {
2034             "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \
2035              `map_or_else(g, f)` instead"
2036         } else {
2037             "called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling \
2038              `ok().map_or_else(g, f)` instead"
2039         };
2040         // get snippets for args to map() and unwrap_or_else()
2041         let map_snippet = snippet(cx, map_args[1].span, "..");
2042         let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
2043         // lint, with note if neither arg is > 1 line and both map() and
2044         // unwrap_or_else() have the same span
2045         let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
2046         let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt();
2047         if same_span && !multiline {
2048             span_note_and_lint(
2049                 cx,
2050                 if is_option {
2051                     OPTION_MAP_UNWRAP_OR_ELSE
2052                 } else {
2053                     RESULT_MAP_UNWRAP_OR_ELSE
2054                 },
2055                 expr.span,
2056                 msg,
2057                 expr.span,
2058                 &format!(
2059                     "replace `map({0}).unwrap_or_else({1})` with `{2}map_or_else({1}, {0})`",
2060                     map_snippet,
2061                     unwrap_snippet,
2062                     if is_result { "ok()." } else { "" }
2063                 ),
2064             );
2065         } else if same_span && multiline {
2066             span_lint(
2067                 cx,
2068                 if is_option {
2069                     OPTION_MAP_UNWRAP_OR_ELSE
2070                 } else {
2071                     RESULT_MAP_UNWRAP_OR_ELSE
2072                 },
2073                 expr.span,
2074                 msg,
2075             );
2076         };
2077     }
2078 }
2079
2080 /// lint use of `_.map_or(None, _)` for `Option`s
2081 fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_or_args: &'tcx [hir::Expr]) {
2082     if match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::OPTION) {
2083         // check if the first non-self argument to map_or() is None
2084         let map_or_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].node {
2085             match_qpath(qpath, &paths::OPTION_NONE)
2086         } else {
2087             false
2088         };
2089
2090         if map_or_arg_is_none {
2091             // lint message
2092             let msg = "called `map_or(None, f)` on an Option value. This can be done more directly by calling \
2093                        `and_then(f)` instead";
2094             let map_or_self_snippet = snippet(cx, map_or_args[0].span, "..");
2095             let map_or_func_snippet = snippet(cx, map_or_args[2].span, "..");
2096             let hint = format!("{0}.and_then({1})", map_or_self_snippet, map_or_func_snippet);
2097             span_lint_and_then(cx, OPTION_MAP_OR_NONE, expr.span, msg, |db| {
2098                 db.span_suggestion(
2099                     expr.span,
2100                     "try using and_then instead",
2101                     hint,
2102                     Applicability::MachineApplicable, // snippet
2103                 );
2104             });
2105         }
2106     }
2107 }
2108
2109 /// Lint use of `_.and_then(|x| Some(y))` for `Option`s
2110 fn lint_option_and_then_some(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
2111     const LINT_MSG: &str = "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`";
2112     const NO_OP_MSG: &str = "using `Option.and_then(Some)`, which is a no-op";
2113
2114     // Searches an return expressions in `y` in `_.and_then(|x| Some(y))`, which we don't lint
2115     struct RetCallFinder {
2116         found: bool,
2117     }
2118
2119     impl<'tcx> intravisit::Visitor<'tcx> for RetCallFinder {
2120         fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
2121             if self.found {
2122                 return;
2123             }
2124             if let hir::ExprKind::Ret(..) = &expr.node {
2125                 self.found = true;
2126             } else {
2127                 intravisit::walk_expr(self, expr);
2128             }
2129         }
2130
2131         fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
2132             intravisit::NestedVisitorMap::None
2133         }
2134     }
2135
2136     let ty = cx.tables.expr_ty(&args[0]);
2137     if !match_type(cx, ty, &paths::OPTION) {
2138         return;
2139     }
2140
2141     match args[1].node {
2142         hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => {
2143             let closure_body = cx.tcx.hir().body(body_id);
2144             let closure_expr = remove_blocks(&closure_body.value);
2145             if_chain! {
2146                 if let hir::ExprKind::Call(ref some_expr, ref some_args) = closure_expr.node;
2147                 if let hir::ExprKind::Path(ref qpath) = some_expr.node;
2148                 if match_qpath(qpath, &paths::OPTION_SOME);
2149                 if some_args.len() == 1;
2150                 then {
2151                     let inner_expr = &some_args[0];
2152
2153                     let mut finder = RetCallFinder { found: false };
2154                     finder.visit_expr(inner_expr);
2155                     if finder.found {
2156                         return;
2157                     }
2158
2159                     let some_inner_snip = if inner_expr.span.from_expansion() {
2160                         snippet_with_macro_callsite(cx, inner_expr.span, "_")
2161                     } else {
2162                         snippet(cx, inner_expr.span, "_")
2163                     };
2164
2165                     let closure_args_snip = snippet(cx, closure_args_span, "..");
2166                     let option_snip = snippet(cx, args[0].span, "..");
2167                     let note = format!("{}.map({} {})", option_snip, closure_args_snip, some_inner_snip);
2168                     span_lint_and_sugg(
2169                         cx,
2170                         OPTION_AND_THEN_SOME,
2171                         expr.span,
2172                         LINT_MSG,
2173                         "try this",
2174                         note,
2175                         Applicability::MachineApplicable,
2176                     );
2177                 }
2178             }
2179         },
2180         // `_.and_then(Some)` case, which is no-op.
2181         hir::ExprKind::Path(ref qpath) => {
2182             if match_qpath(qpath, &paths::OPTION_SOME) {
2183                 let option_snip = snippet(cx, args[0].span, "..");
2184                 let note = format!("{}", option_snip);
2185                 span_lint_and_sugg(
2186                     cx,
2187                     OPTION_AND_THEN_SOME,
2188                     expr.span,
2189                     NO_OP_MSG,
2190                     "use the expression directly",
2191                     note,
2192                     Applicability::MachineApplicable,
2193                 );
2194             }
2195         },
2196         _ => {},
2197     }
2198 }
2199
2200 /// lint use of `filter().next()` for `Iterators`
2201 fn lint_filter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, filter_args: &'tcx [hir::Expr]) {
2202     // lint if caller of `.filter().next()` is an Iterator
2203     if match_trait_method(cx, expr, &paths::ITERATOR) {
2204         let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
2205                    `.find(p)` instead.";
2206         let filter_snippet = snippet(cx, filter_args[1].span, "..");
2207         if filter_snippet.lines().count() <= 1 {
2208             // add note if not multi-line
2209             span_note_and_lint(
2210                 cx,
2211                 FILTER_NEXT,
2212                 expr.span,
2213                 msg,
2214                 expr.span,
2215                 &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet),
2216             );
2217         } else {
2218             span_lint(cx, FILTER_NEXT, expr.span, msg);
2219         }
2220     }
2221 }
2222
2223 /// lint use of `filter().map()` for `Iterators`
2224 fn lint_filter_map<'a, 'tcx>(
2225     cx: &LateContext<'a, 'tcx>,
2226     expr: &'tcx hir::Expr,
2227     _filter_args: &'tcx [hir::Expr],
2228     _map_args: &'tcx [hir::Expr],
2229 ) {
2230     // lint if caller of `.filter().map()` is an Iterator
2231     if match_trait_method(cx, expr, &paths::ITERATOR) {
2232         let msg = "called `filter(p).map(q)` on an `Iterator`. \
2233                    This is more succinctly expressed by calling `.filter_map(..)` instead.";
2234         span_lint(cx, FILTER_MAP, expr.span, msg);
2235     }
2236 }
2237
2238 /// lint use of `filter_map().next()` for `Iterators`
2239 fn lint_filter_map_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, filter_args: &'tcx [hir::Expr]) {
2240     if match_trait_method(cx, expr, &paths::ITERATOR) {
2241         let msg = "called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
2242                    `.find_map(p)` instead.";
2243         let filter_snippet = snippet(cx, filter_args[1].span, "..");
2244         if filter_snippet.lines().count() <= 1 {
2245             span_note_and_lint(
2246                 cx,
2247                 FILTER_MAP_NEXT,
2248                 expr.span,
2249                 msg,
2250                 expr.span,
2251                 &format!("replace `filter_map({0}).next()` with `find_map({0})`", filter_snippet),
2252             );
2253         } else {
2254             span_lint(cx, FILTER_MAP_NEXT, expr.span, msg);
2255         }
2256     }
2257 }
2258
2259 /// lint use of `find().map()` for `Iterators`
2260 fn lint_find_map<'a, 'tcx>(
2261     cx: &LateContext<'a, 'tcx>,
2262     expr: &'tcx hir::Expr,
2263     _find_args: &'tcx [hir::Expr],
2264     map_args: &'tcx [hir::Expr],
2265 ) {
2266     // lint if caller of `.filter().map()` is an Iterator
2267     if match_trait_method(cx, &map_args[0], &paths::ITERATOR) {
2268         let msg = "called `find(p).map(q)` on an `Iterator`. \
2269                    This is more succinctly expressed by calling `.find_map(..)` instead.";
2270         span_lint(cx, FIND_MAP, expr.span, msg);
2271     }
2272 }
2273
2274 /// lint use of `filter().map()` for `Iterators`
2275 fn lint_filter_map_map<'a, 'tcx>(
2276     cx: &LateContext<'a, 'tcx>,
2277     expr: &'tcx hir::Expr,
2278     _filter_args: &'tcx [hir::Expr],
2279     _map_args: &'tcx [hir::Expr],
2280 ) {
2281     // lint if caller of `.filter().map()` is an Iterator
2282     if match_trait_method(cx, expr, &paths::ITERATOR) {
2283         let msg = "called `filter_map(p).map(q)` on an `Iterator`. \
2284                    This is more succinctly expressed by only calling `.filter_map(..)` instead.";
2285         span_lint(cx, FILTER_MAP, expr.span, msg);
2286     }
2287 }
2288
2289 /// lint use of `filter().flat_map()` for `Iterators`
2290 fn lint_filter_flat_map<'a, 'tcx>(
2291     cx: &LateContext<'a, 'tcx>,
2292     expr: &'tcx hir::Expr,
2293     _filter_args: &'tcx [hir::Expr],
2294     _map_args: &'tcx [hir::Expr],
2295 ) {
2296     // lint if caller of `.filter().flat_map()` is an Iterator
2297     if match_trait_method(cx, expr, &paths::ITERATOR) {
2298         let msg = "called `filter(p).flat_map(q)` on an `Iterator`. \
2299                    This is more succinctly expressed by calling `.flat_map(..)` \
2300                    and filtering by returning an empty Iterator.";
2301         span_lint(cx, FILTER_MAP, expr.span, msg);
2302     }
2303 }
2304
2305 /// lint use of `filter_map().flat_map()` for `Iterators`
2306 fn lint_filter_map_flat_map<'a, 'tcx>(
2307     cx: &LateContext<'a, 'tcx>,
2308     expr: &'tcx hir::Expr,
2309     _filter_args: &'tcx [hir::Expr],
2310     _map_args: &'tcx [hir::Expr],
2311 ) {
2312     // lint if caller of `.filter_map().flat_map()` is an Iterator
2313     if match_trait_method(cx, expr, &paths::ITERATOR) {
2314         let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`. \
2315                    This is more succinctly expressed by calling `.flat_map(..)` \
2316                    and filtering by returning an empty Iterator.";
2317         span_lint(cx, FILTER_MAP, expr.span, msg);
2318     }
2319 }
2320
2321 /// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient
2322 fn lint_flat_map_identity<'a, 'tcx>(
2323     cx: &LateContext<'a, 'tcx>,
2324     expr: &'tcx hir::Expr,
2325     flat_map_args: &'tcx [hir::Expr],
2326 ) {
2327     if match_trait_method(cx, expr, &paths::ITERATOR) {
2328         let arg_node = &flat_map_args[1].node;
2329
2330         let apply_lint = |message: &str| {
2331             if let hir::ExprKind::MethodCall(_, span, _) = &expr.node {
2332                 span_lint_and_sugg(
2333                     cx,
2334                     FLAT_MAP_IDENTITY,
2335                     span.with_hi(expr.span.hi()),
2336                     message,
2337                     "try",
2338                     "flatten()".to_string(),
2339                     Applicability::MachineApplicable,
2340                 );
2341             }
2342         };
2343
2344         if_chain! {
2345             if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node;
2346             let body = cx.tcx.hir().body(*body_id);
2347
2348             if let hir::PatKind::Binding(_, _, binding_ident, _) = body.arguments[0].pat.node;
2349             if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.node;
2350
2351             if path.segments.len() == 1;
2352             if path.segments[0].ident.as_str() == binding_ident.as_str();
2353
2354             then {
2355                 apply_lint("called `flat_map(|x| x)` on an `Iterator`");
2356             }
2357         }
2358
2359         if_chain! {
2360             if let hir::ExprKind::Path(ref qpath) = arg_node;
2361
2362             if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY);
2363
2364             then {
2365                 apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`");
2366             }
2367         }
2368     }
2369 }
2370
2371 /// lint searching an Iterator followed by `is_some()`
2372 fn lint_search_is_some<'a, 'tcx>(
2373     cx: &LateContext<'a, 'tcx>,
2374     expr: &'tcx hir::Expr,
2375     search_method: &str,
2376     search_args: &'tcx [hir::Expr],
2377     is_some_args: &'tcx [hir::Expr],
2378 ) {
2379     // lint if caller of search is an Iterator
2380     if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) {
2381         let msg = format!(
2382             "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \
2383              expressed by calling `any()`.",
2384             search_method
2385         );
2386         let search_snippet = snippet(cx, search_args[1].span, "..");
2387         if search_snippet.lines().count() <= 1 {
2388             // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
2389             let any_search_snippet = if_chain! {
2390                 if search_method == "find";
2391                 if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].node;
2392                 let closure_body = cx.tcx.hir().body(body_id);
2393                 if let Some(closure_arg) = closure_body.arguments.get(0);
2394                 if let hir::PatKind::Ref(..) = closure_arg.pat.node;
2395                 then {
2396                     Some(search_snippet.replacen('&', "", 1))
2397                 } else {
2398                     None
2399                 }
2400             };
2401             // add note if not multi-line
2402             span_note_and_lint(
2403                 cx,
2404                 SEARCH_IS_SOME,
2405                 expr.span,
2406                 &msg,
2407                 expr.span,
2408                 &format!(
2409                     "replace `{0}({1}).is_some()` with `any({2})`",
2410                     search_method,
2411                     search_snippet,
2412                     any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
2413                 ),
2414             );
2415         } else {
2416             span_lint(cx, SEARCH_IS_SOME, expr.span, &msg);
2417         }
2418     }
2419 }
2420
2421 /// Used for `lint_binary_expr_with_method_call`.
2422 #[derive(Copy, Clone)]
2423 struct BinaryExprInfo<'a> {
2424     expr: &'a hir::Expr,
2425     chain: &'a hir::Expr,
2426     other: &'a hir::Expr,
2427     eq: bool,
2428 }
2429
2430 /// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
2431 fn lint_binary_expr_with_method_call(cx: &LateContext<'_, '_>, info: &mut BinaryExprInfo<'_>) {
2432     macro_rules! lint_with_both_lhs_and_rhs {
2433         ($func:ident, $cx:expr, $info:ident) => {
2434             if !$func($cx, $info) {
2435                 ::std::mem::swap(&mut $info.chain, &mut $info.other);
2436                 if $func($cx, $info) {
2437                     return;
2438                 }
2439             }
2440         };
2441     }
2442
2443     lint_with_both_lhs_and_rhs!(lint_chars_next_cmp, cx, info);
2444     lint_with_both_lhs_and_rhs!(lint_chars_last_cmp, cx, info);
2445     lint_with_both_lhs_and_rhs!(lint_chars_next_cmp_with_unwrap, cx, info);
2446     lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info);
2447 }
2448
2449 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
2450 fn lint_chars_cmp(
2451     cx: &LateContext<'_, '_>,
2452     info: &BinaryExprInfo<'_>,
2453     chain_methods: &[&str],
2454     lint: &'static Lint,
2455     suggest: &str,
2456 ) -> bool {
2457     if_chain! {
2458         if let Some(args) = method_chain_args(info.chain, chain_methods);
2459         if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.node;
2460         if arg_char.len() == 1;
2461         if let hir::ExprKind::Path(ref qpath) = fun.node;
2462         if let Some(segment) = single_segment_path(qpath);
2463         if segment.ident.name == sym!(Some);
2464         then {
2465             let mut applicability = Applicability::MachineApplicable;
2466             let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0]));
2467
2468             if self_ty.sty != ty::Str {
2469                 return false;
2470             }
2471
2472             span_lint_and_sugg(
2473                 cx,
2474                 lint,
2475                 info.expr.span,
2476                 &format!("you should use the `{}` method", suggest),
2477                 "like this",
2478                 format!("{}{}.{}({})",
2479                         if info.eq { "" } else { "!" },
2480                         snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
2481                         suggest,
2482                         snippet_with_applicability(cx, arg_char[0].span, "_", &mut applicability)),
2483                 applicability,
2484             );
2485
2486             return true;
2487         }
2488     }
2489
2490     false
2491 }
2492
2493 /// Checks for the `CHARS_NEXT_CMP` lint.
2494 fn lint_chars_next_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
2495     lint_chars_cmp(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
2496 }
2497
2498 /// Checks for the `CHARS_LAST_CMP` lint.
2499 fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
2500     if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
2501         true
2502     } else {
2503         lint_chars_cmp(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with")
2504     }
2505 }
2506
2507 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
2508 fn lint_chars_cmp_with_unwrap<'a, 'tcx>(
2509     cx: &LateContext<'a, 'tcx>,
2510     info: &BinaryExprInfo<'_>,
2511     chain_methods: &[&str],
2512     lint: &'static Lint,
2513     suggest: &str,
2514 ) -> bool {
2515     if_chain! {
2516         if let Some(args) = method_chain_args(info.chain, chain_methods);
2517         if let hir::ExprKind::Lit(ref lit) = info.other.node;
2518         if let ast::LitKind::Char(c) = lit.node;
2519         then {
2520             let mut applicability = Applicability::MachineApplicable;
2521             span_lint_and_sugg(
2522                 cx,
2523                 lint,
2524                 info.expr.span,
2525                 &format!("you should use the `{}` method", suggest),
2526                 "like this",
2527                 format!("{}{}.{}('{}')",
2528                         if info.eq { "" } else { "!" },
2529                         snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
2530                         suggest,
2531                         c),
2532                 applicability,
2533             );
2534
2535             true
2536         } else {
2537             false
2538         }
2539     }
2540 }
2541
2542 /// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
2543 fn lint_chars_next_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
2544     lint_chars_cmp_with_unwrap(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
2545 }
2546
2547 /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
2548 fn lint_chars_last_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
2549     if lint_chars_cmp_with_unwrap(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
2550         true
2551     } else {
2552         lint_chars_cmp_with_unwrap(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with")
2553     }
2554 }
2555
2556 /// lint for length-1 `str`s for methods in `PATTERN_METHODS`
2557 fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, _expr: &'tcx hir::Expr, arg: &'tcx hir::Expr) {
2558     if_chain! {
2559         if let hir::ExprKind::Lit(lit) = &arg.node;
2560         if let ast::LitKind::Str(r, style) = lit.node;
2561         if r.as_str().len() == 1;
2562         then {
2563             let mut applicability = Applicability::MachineApplicable;
2564             let snip = snippet_with_applicability(cx, arg.span, "..", &mut applicability);
2565             let ch = if let ast::StrStyle::Raw(nhash) = style {
2566                 let nhash = nhash as usize;
2567                 // for raw string: r##"a"##
2568                 &snip[(nhash + 2)..(snip.len() - 1 - nhash)]
2569             } else {
2570                 // for regular string: "a"
2571                 &snip[1..(snip.len() - 1)]
2572             };
2573             let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch });
2574             span_lint_and_sugg(
2575                 cx,
2576                 SINGLE_CHAR_PATTERN,
2577                 arg.span,
2578                 "single-character string constant used as pattern",
2579                 "try using a char instead",
2580                 hint,
2581                 applicability,
2582             );
2583         }
2584     }
2585 }
2586
2587 /// Checks for the `USELESS_ASREF` lint.
2588 fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr, call_name: &str, as_ref_args: &[hir::Expr]) {
2589     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
2590     // check if the call is to the actual `AsRef` or `AsMut` trait
2591     if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
2592         // check if the type after `as_ref` or `as_mut` is the same as before
2593         let recvr = &as_ref_args[0];
2594         let rcv_ty = cx.tables.expr_ty(recvr);
2595         let res_ty = cx.tables.expr_ty(expr);
2596         let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
2597         let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
2598         if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
2599             // allow the `as_ref` or `as_mut` if it is followed by another method call
2600             if_chain! {
2601                 if let Some(parent) = get_parent_expr(cx, expr);
2602                 if let hir::ExprKind::MethodCall(_, ref span, _) = parent.node;
2603                 if span != &expr.span;
2604                 then {
2605                     return;
2606                 }
2607             }
2608
2609             let mut applicability = Applicability::MachineApplicable;
2610             span_lint_and_sugg(
2611                 cx,
2612                 USELESS_ASREF,
2613                 expr.span,
2614                 &format!("this call to `{}` does nothing", call_name),
2615                 "try this",
2616                 snippet_with_applicability(cx, recvr.span, "_", &mut applicability).to_string(),
2617                 applicability,
2618             );
2619         }
2620     }
2621 }
2622
2623 fn ty_has_iter_method(
2624     cx: &LateContext<'_, '_>,
2625     self_ref_ty: Ty<'_>,
2626 ) -> Option<(&'static Lint, &'static str, &'static str)> {
2627     has_iter_method(cx, self_ref_ty).map(|ty_name| {
2628         let lint = if ty_name == "array" || ty_name == "PathBuf" {
2629             INTO_ITER_ON_ARRAY
2630         } else {
2631             INTO_ITER_ON_REF
2632         };
2633         let mutbl = match self_ref_ty.sty {
2634             ty::Ref(_, _, mutbl) => mutbl,
2635             _ => unreachable!(),
2636         };
2637         let method_name = match mutbl {
2638             hir::MutImmutable => "iter",
2639             hir::MutMutable => "iter_mut",
2640         };
2641         (lint, ty_name, method_name)
2642     })
2643 }
2644
2645 fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: Ty<'_>, method_span: Span) {
2646     if !match_trait_method(cx, expr, &paths::INTO_ITERATOR) {
2647         return;
2648     }
2649     if let Some((lint, kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) {
2650         span_lint_and_sugg(
2651             cx,
2652             lint,
2653             method_span,
2654             &format!(
2655                 "this .into_iter() call is equivalent to .{}() and will not move the {}",
2656                 method_name, kind,
2657             ),
2658             "call directly",
2659             method_name.to_string(),
2660             Applicability::MachineApplicable,
2661         );
2662     }
2663 }
2664
2665 fn lint_suspicious_map(cx: &LateContext<'_, '_>, expr: &hir::Expr) {
2666     span_help_and_lint(
2667         cx,
2668         SUSPICIOUS_MAP,
2669         expr.span,
2670         "this call to `map()` won't have an effect on the call to `count()`",
2671         "make sure you did not confuse `map` with `filter`",
2672     );
2673 }
2674
2675 /// Given a `Result<T, E>` type, return its error type (`E`).
2676 fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> {
2677     match ty.sty {
2678         ty::Adt(_, substs) if match_type(cx, ty, &paths::RESULT) => substs.types().nth(1),
2679         _ => None,
2680     }
2681 }
2682
2683 /// This checks whether a given type is known to implement Debug.
2684 fn has_debug_impl<'a, 'b>(ty: Ty<'a>, cx: &LateContext<'b, 'a>) -> bool {
2685     match cx.tcx.lang_items().debug_trait() {
2686         Some(debug) => implements_trait(cx, ty, debug, &[]),
2687         None => false,
2688     }
2689 }
2690
2691 enum Convention {
2692     Eq(&'static str),
2693     StartsWith(&'static str),
2694 }
2695
2696 #[rustfmt::skip]
2697 const CONVENTIONS: [(Convention, &[SelfKind]); 7] = [
2698     (Convention::Eq("new"), &[SelfKind::No]),
2699     (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]),
2700     (Convention::StartsWith("from_"), &[SelfKind::No]),
2701     (Convention::StartsWith("into_"), &[SelfKind::Value]),
2702     (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]),
2703     (Convention::Eq("to_mut"), &[SelfKind::RefMut]),
2704     (Convention::StartsWith("to_"), &[SelfKind::Ref]),
2705 ];
2706
2707 #[rustfmt::skip]
2708 const TRAIT_METHODS: [(&str, usize, SelfKind, OutType, &str); 30] = [
2709     ("add", 2, SelfKind::Value, OutType::Any, "std::ops::Add"),
2710     ("as_mut", 1, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"),
2711     ("as_ref", 1, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"),
2712     ("bitand", 2, SelfKind::Value, OutType::Any, "std::ops::BitAnd"),
2713     ("bitor", 2, SelfKind::Value, OutType::Any, "std::ops::BitOr"),
2714     ("bitxor", 2, SelfKind::Value, OutType::Any, "std::ops::BitXor"),
2715     ("borrow", 1, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"),
2716     ("borrow_mut", 1, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"),
2717     ("clone", 1, SelfKind::Ref, OutType::Any, "std::clone::Clone"),
2718     ("cmp", 2, SelfKind::Ref, OutType::Any, "std::cmp::Ord"),
2719     ("default", 0, SelfKind::No, OutType::Any, "std::default::Default"),
2720     ("deref", 1, SelfKind::Ref, OutType::Ref, "std::ops::Deref"),
2721     ("deref_mut", 1, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"),
2722     ("div", 2, SelfKind::Value, OutType::Any, "std::ops::Div"),
2723     ("drop", 1, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"),
2724     ("eq", 2, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"),
2725     ("from_iter", 1, SelfKind::No, OutType::Any, "std::iter::FromIterator"),
2726     ("from_str", 1, SelfKind::No, OutType::Any, "std::str::FromStr"),
2727     ("hash", 2, SelfKind::Ref, OutType::Unit, "std::hash::Hash"),
2728     ("index", 2, SelfKind::Ref, OutType::Ref, "std::ops::Index"),
2729     ("index_mut", 2, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"),
2730     ("into_iter", 1, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"),
2731     ("mul", 2, SelfKind::Value, OutType::Any, "std::ops::Mul"),
2732     ("neg", 1, SelfKind::Value, OutType::Any, "std::ops::Neg"),
2733     ("next", 1, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"),
2734     ("not", 1, SelfKind::Value, OutType::Any, "std::ops::Not"),
2735     ("rem", 2, SelfKind::Value, OutType::Any, "std::ops::Rem"),
2736     ("shl", 2, SelfKind::Value, OutType::Any, "std::ops::Shl"),
2737     ("shr", 2, SelfKind::Value, OutType::Any, "std::ops::Shr"),
2738     ("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"),
2739 ];
2740
2741 #[rustfmt::skip]
2742 const PATTERN_METHODS: [(&str, usize); 17] = [
2743     ("contains", 1),
2744     ("starts_with", 1),
2745     ("ends_with", 1),
2746     ("find", 1),
2747     ("rfind", 1),
2748     ("split", 1),
2749     ("rsplit", 1),
2750     ("split_terminator", 1),
2751     ("rsplit_terminator", 1),
2752     ("splitn", 2),
2753     ("rsplitn", 2),
2754     ("matches", 1),
2755     ("rmatches", 1),
2756     ("match_indices", 1),
2757     ("rmatch_indices", 1),
2758     ("trim_start_matches", 1),
2759     ("trim_end_matches", 1),
2760 ];
2761
2762 #[derive(Clone, Copy, PartialEq, Debug)]
2763 enum SelfKind {
2764     Value,
2765     Ref,
2766     RefMut,
2767     No,
2768 }
2769
2770 impl SelfKind {
2771     fn matches<'a>(self, cx: &LateContext<'_, 'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
2772         fn matches_value(parent_ty: Ty<'_>, ty: Ty<'_>) -> bool {
2773             if ty == parent_ty {
2774                 true
2775             } else if ty.is_box() {
2776                 ty.boxed_ty() == parent_ty
2777             } else if ty.is_rc() || ty.is_arc() {
2778                 if let ty::Adt(_, substs) = ty.sty {
2779                     substs.types().next().map_or(false, |t| t == parent_ty)
2780                 } else {
2781                     false
2782                 }
2783             } else {
2784                 false
2785             }
2786         }
2787
2788         fn matches_ref<'a>(
2789             cx: &LateContext<'_, 'a>,
2790             mutability: hir::Mutability,
2791             parent_ty: Ty<'a>,
2792             ty: Ty<'a>,
2793         ) -> bool {
2794             if let ty::Ref(_, t, m) = ty.sty {
2795                 return m == mutability && t == parent_ty;
2796             }
2797
2798             let trait_path = match mutability {
2799                 hir::Mutability::MutImmutable => &paths::ASREF_TRAIT,
2800                 hir::Mutability::MutMutable => &paths::ASMUT_TRAIT,
2801             };
2802
2803             let trait_def_id = match get_trait_def_id(cx, trait_path) {
2804                 Some(did) => did,
2805                 None => return false,
2806             };
2807             implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
2808         }
2809
2810         match self {
2811             Self::Value => matches_value(parent_ty, ty),
2812             Self::Ref => {
2813                 matches_ref(cx, hir::Mutability::MutImmutable, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty)
2814             },
2815             Self::RefMut => matches_ref(cx, hir::Mutability::MutMutable, parent_ty, ty),
2816             Self::No => ty != parent_ty,
2817         }
2818     }
2819
2820     fn description(self) -> &'static str {
2821         match self {
2822             Self::Value => "self by value",
2823             Self::Ref => "self by reference",
2824             Self::RefMut => "self by mutable reference",
2825             Self::No => "no self",
2826         }
2827     }
2828 }
2829
2830 impl Convention {
2831     fn check(&self, other: &str) -> bool {
2832         match *self {
2833             Self::Eq(this) => this == other,
2834             Self::StartsWith(this) => other.starts_with(this) && this != other,
2835         }
2836     }
2837 }
2838
2839 impl fmt::Display for Convention {
2840     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
2841         match *self {
2842             Self::Eq(this) => this.fmt(f),
2843             Self::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)),
2844         }
2845     }
2846 }
2847
2848 #[derive(Clone, Copy)]
2849 enum OutType {
2850     Unit,
2851     Bool,
2852     Any,
2853     Ref,
2854 }
2855
2856 impl OutType {
2857     fn matches(self, cx: &LateContext<'_, '_>, ty: &hir::FunctionRetTy) -> bool {
2858         let is_unit = |ty: &hir::Ty| SpanlessEq::new(cx).eq_ty_kind(&ty.node, &hir::TyKind::Tup(vec![].into()));
2859         match (self, ty) {
2860             (Self::Unit, &hir::DefaultReturn(_)) => true,
2861             (Self::Unit, &hir::Return(ref ty)) if is_unit(ty) => true,
2862             (Self::Bool, &hir::Return(ref ty)) if is_bool(ty) => true,
2863             (Self::Any, &hir::Return(ref ty)) if !is_unit(ty) => true,
2864             (Self::Ref, &hir::Return(ref ty)) => matches!(ty.node, hir::TyKind::Rptr(_, _)),
2865             _ => false,
2866         }
2867     }
2868 }
2869
2870 fn is_bool(ty: &hir::Ty) -> bool {
2871     if let hir::TyKind::Path(ref p) = ty.node {
2872         match_qpath(p, &["bool"])
2873     } else {
2874         false
2875     }
2876 }