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