]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/methods/mod.rs
Rollup merge of #75892 - ArekPiekarz:unstable_book_tls_model_typo, r=petrochenkov
[rust.git] / src / tools / clippy / clippy_lints / src / methods / mod.rs
1 mod bind_instead_of_map;
2 mod inefficient_to_string;
3 mod manual_saturating_arithmetic;
4 mod option_map_unwrap_or;
5 mod unnecessary_filter_map;
6 mod unnecessary_lazy_eval;
7
8 use std::borrow::Cow;
9 use std::fmt;
10 use std::iter;
11
12 use bind_instead_of_map::BindInsteadOfMap;
13 use if_chain::if_chain;
14 use rustc_ast::ast;
15 use rustc_errors::Applicability;
16 use rustc_hir as hir;
17 use rustc_hir::intravisit::{self, Visitor};
18 use rustc_hir::{TraitItem, TraitItemKind};
19 use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
20 use rustc_middle::hir::map::Map;
21 use rustc_middle::lint::in_external_macro;
22 use rustc_middle::ty::{self, TraitRef, Ty, TyS};
23 use rustc_session::{declare_lint_pass, declare_tool_lint};
24 use rustc_span::source_map::Span;
25 use rustc_span::symbol::{sym, SymbolStr};
26
27 use crate::consts::{constant, Constant};
28 use crate::utils::usage::mutated_variables;
29 use crate::utils::{
30     contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro,
31     is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats,
32     last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls,
33     method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability,
34     snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
35     span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
36 };
37
38 declare_clippy_lint! {
39     /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s.
40     ///
41     /// **Why is this bad?** It is better to handle the `None` or `Err` case,
42     /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of
43     /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
44     /// `Allow` by default.
45     ///
46     /// `result.unwrap()` will let the thread panic on `Err` values.
47     /// Normally, you want to implement more sophisticated error handling,
48     /// and propagate errors upwards with `?` operator.
49     ///
50     /// Even if you want to panic on errors, not all `Error`s implement good
51     /// messages on display. Therefore, it may be beneficial to look at the places
52     /// where they may get displayed. Activate this lint to do just that.
53     ///
54     /// **Known problems:** None.
55     ///
56     /// **Examples:**
57     /// ```rust
58     /// # let opt = Some(1);
59     ///
60     /// // Bad
61     /// opt.unwrap();
62     ///
63     /// // Good
64     /// opt.expect("more helpful message");
65     /// ```
66     ///
67     /// // or
68     ///
69     /// ```rust
70     /// # let res: Result<usize, ()> = Ok(1);
71     ///
72     /// // Bad
73     /// res.unwrap();
74     ///
75     /// // Good
76     /// res.expect("more helpful message");
77     /// ```
78     pub UNWRAP_USED,
79     restriction,
80     "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`"
81 }
82
83 declare_clippy_lint! {
84     /// **What it does:** Checks for `.expect()` calls on `Option`s and `Result`s.
85     ///
86     /// **Why is this bad?** Usually it is better to handle the `None` or `Err` case.
87     /// Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why
88     /// this lint is `Allow` by default.
89     ///
90     /// `result.expect()` will let the thread panic on `Err`
91     /// values. Normally, you want to implement more sophisticated error handling,
92     /// and propagate errors upwards with `?` operator.
93     ///
94     /// **Known problems:** None.
95     ///
96     /// **Examples:**
97     /// ```rust,ignore
98     /// # let opt = Some(1);
99     ///
100     /// // Bad
101     /// opt.expect("one");
102     ///
103     /// // Good
104     /// let opt = Some(1);
105     /// opt?;
106     /// ```
107     ///
108     /// // or
109     ///
110     /// ```rust
111     /// # let res: Result<usize, ()> = Ok(1);
112     ///
113     /// // Bad
114     /// res.expect("one");
115     ///
116     /// // Good
117     /// res?;
118     /// # Ok::<(), ()>(())
119     /// ```
120     pub EXPECT_USED,
121     restriction,
122     "using `.expect()` on `Result` or `Option`, which might be better handled"
123 }
124
125 declare_clippy_lint! {
126     /// **What it does:** Checks for methods that should live in a trait
127     /// implementation of a `std` trait (see [llogiq's blog
128     /// post](http://llogiq.github.io/2015/07/30/traits.html) for further
129     /// information) instead of an inherent implementation.
130     ///
131     /// **Why is this bad?** Implementing the traits improve ergonomics for users of
132     /// the code, often with very little cost. Also people seeing a `mul(...)`
133     /// method
134     /// may expect `*` to work equally, so you should have good reason to disappoint
135     /// them.
136     ///
137     /// **Known problems:** None.
138     ///
139     /// **Example:**
140     /// ```rust
141     /// struct X;
142     /// impl X {
143     ///     fn add(&self, other: &X) -> X {
144     ///         // ..
145     /// # X
146     ///     }
147     /// }
148     /// ```
149     pub SHOULD_IMPLEMENT_TRAIT,
150     style,
151     "defining a method that should be implementing a std trait"
152 }
153
154 declare_clippy_lint! {
155     /// **What it does:** Checks for methods with certain name prefixes and which
156     /// doesn't match how self is taken. The actual rules are:
157     ///
158     /// |Prefix |`self` taken          |
159     /// |-------|----------------------|
160     /// |`as_`  |`&self` or `&mut self`|
161     /// |`from_`| none                 |
162     /// |`into_`|`self`                |
163     /// |`is_`  |`&self` or none       |
164     /// |`to_`  |`&self`               |
165     ///
166     /// **Why is this bad?** Consistency breeds readability. If you follow the
167     /// conventions, your users won't be surprised that they, e.g., need to supply a
168     /// mutable reference to a `as_..` function.
169     ///
170     /// **Known problems:** None.
171     ///
172     /// **Example:**
173     /// ```rust
174     /// # struct X;
175     /// impl X {
176     ///     fn as_str(self) -> &'static str {
177     ///         // ..
178     /// # ""
179     ///     }
180     /// }
181     /// ```
182     pub WRONG_SELF_CONVENTION,
183     style,
184     "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
185 }
186
187 declare_clippy_lint! {
188     /// **What it does:** This is the same as
189     /// [`wrong_self_convention`](#wrong_self_convention), but for public items.
190     ///
191     /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention).
192     ///
193     /// **Known problems:** Actually *renaming* the function may break clients if
194     /// the function is part of the public interface. In that case, be mindful of
195     /// the stability guarantees you've given your users.
196     ///
197     /// **Example:**
198     /// ```rust
199     /// # struct X;
200     /// impl<'a> X {
201     ///     pub fn as_str(self) -> &'a str {
202     ///         "foo"
203     ///     }
204     /// }
205     /// ```
206     pub WRONG_PUB_SELF_CONVENTION,
207     restriction,
208     "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
209 }
210
211 declare_clippy_lint! {
212     /// **What it does:** Checks for usage of `ok().expect(..)`.
213     ///
214     /// **Why is this bad?** Because you usually call `expect()` on the `Result`
215     /// directly to get a better error message.
216     ///
217     /// **Known problems:** The error type needs to implement `Debug`
218     ///
219     /// **Example:**
220     /// ```rust
221     /// # let x = Ok::<_, ()>(());
222     ///
223     /// // Bad
224     /// x.ok().expect("why did I do this again?");
225     ///
226     /// // Good
227     /// x.expect("why did I do this again?");
228     /// ```
229     pub OK_EXPECT,
230     style,
231     "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
232 }
233
234 declare_clippy_lint! {
235     /// **What it does:** Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
236     /// `result.map(_).unwrap_or_else(_)`.
237     ///
238     /// **Why is this bad?** Readability, these can be written more concisely (resp.) as
239     /// `option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`.
240     ///
241     /// **Known problems:** The order of the arguments is not in execution order
242     ///
243     /// **Examples:**
244     /// ```rust
245     /// # let x = Some(1);
246     ///
247     /// // Bad
248     /// x.map(|a| a + 1).unwrap_or(0);
249     ///
250     /// // Good
251     /// x.map_or(0, |a| a + 1);
252     /// ```
253     ///
254     /// // or
255     ///
256     /// ```rust
257     /// # let x: Result<usize, ()> = Ok(1);
258     /// # fn some_function(foo: ()) -> usize { 1 }
259     ///
260     /// // Bad
261     /// x.map(|a| a + 1).unwrap_or_else(some_function);
262     ///
263     /// // Good
264     /// x.map_or_else(some_function, |a| a + 1);
265     /// ```
266     pub MAP_UNWRAP_OR,
267     pedantic,
268     "using `.map(f).unwrap_or(a)` or `.map(f).unwrap_or_else(func)`, which are more succinctly expressed as `map_or(a, f)` or `map_or_else(a, f)`"
269 }
270
271 declare_clippy_lint! {
272     /// **What it does:** Checks for usage of `_.map_or(None, _)`.
273     ///
274     /// **Why is this bad?** Readability, this can be written more concisely as
275     /// `_.and_then(_)`.
276     ///
277     /// **Known problems:** The order of the arguments is not in execution order.
278     ///
279     /// **Example:**
280     /// ```rust
281     /// # let opt = Some(1);
282     ///
283     /// // Bad
284     /// opt.map_or(None, |a| Some(a + 1));
285     ///
286     /// // Good
287     /// opt.and_then(|a| Some(a + 1));
288     /// ```
289     pub OPTION_MAP_OR_NONE,
290     style,
291     "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
292 }
293
294 declare_clippy_lint! {
295     /// **What it does:** Checks for usage of `_.map_or(None, Some)`.
296     ///
297     /// **Why is this bad?** Readability, this can be written more concisely as
298     /// `_.ok()`.
299     ///
300     /// **Known problems:** None.
301     ///
302     /// **Example:**
303     ///
304     /// Bad:
305     /// ```rust
306     /// # let r: Result<u32, &str> = Ok(1);
307     /// assert_eq!(Some(1), r.map_or(None, Some));
308     /// ```
309     ///
310     /// Good:
311     /// ```rust
312     /// # let r: Result<u32, &str> = Ok(1);
313     /// assert_eq!(Some(1), r.ok());
314     /// ```
315     pub RESULT_MAP_OR_INTO_OPTION,
316     style,
317     "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`"
318 }
319
320 declare_clippy_lint! {
321     /// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
322     /// `_.or_else(|x| Err(y))`.
323     ///
324     /// **Why is this bad?** Readability, this can be written more concisely as
325     /// `_.map(|x| y)` or `_.map_err(|x| y)`.
326     ///
327     /// **Known problems:** None
328     ///
329     /// **Example:**
330     ///
331     /// ```rust
332     /// # fn opt() -> Option<&'static str> { Some("42") }
333     /// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
334     /// let _ = opt().and_then(|s| Some(s.len()));
335     /// let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) });
336     /// let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) });
337     /// ```
338     ///
339     /// The correct use would be:
340     ///
341     /// ```rust
342     /// # fn opt() -> Option<&'static str> { Some("42") }
343     /// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
344     /// let _ = opt().map(|s| s.len());
345     /// let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });
346     /// let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });
347     /// ```
348     pub BIND_INSTEAD_OF_MAP,
349     complexity,
350     "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`"
351 }
352
353 declare_clippy_lint! {
354     /// **What it does:** Checks for usage of `_.filter(_).next()`.
355     ///
356     /// **Why is this bad?** Readability, this can be written more concisely as
357     /// `_.find(_)`.
358     ///
359     /// **Known problems:** None.
360     ///
361     /// **Example:**
362     /// ```rust
363     /// # let vec = vec![1];
364     /// vec.iter().filter(|x| **x == 0).next();
365     /// ```
366     /// Could be written as
367     /// ```rust
368     /// # let vec = vec![1];
369     /// vec.iter().find(|x| **x == 0);
370     /// ```
371     pub FILTER_NEXT,
372     complexity,
373     "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"
374 }
375
376 declare_clippy_lint! {
377     /// **What it does:** Checks for usage of `_.skip_while(condition).next()`.
378     ///
379     /// **Why is this bad?** Readability, this can be written more concisely as
380     /// `_.find(!condition)`.
381     ///
382     /// **Known problems:** None.
383     ///
384     /// **Example:**
385     /// ```rust
386     /// # let vec = vec![1];
387     /// vec.iter().skip_while(|x| **x == 0).next();
388     /// ```
389     /// Could be written as
390     /// ```rust
391     /// # let vec = vec![1];
392     /// vec.iter().find(|x| **x != 0);
393     /// ```
394     pub SKIP_WHILE_NEXT,
395     complexity,
396     "using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`"
397 }
398
399 declare_clippy_lint! {
400     /// **What it does:** Checks for usage of `_.map(_).flatten(_)`,
401     ///
402     /// **Why is this bad?** Readability, this can be written more concisely as a
403     /// single method call using `_.flat_map(_)`
404     ///
405     /// **Known problems:**
406     ///
407     /// **Example:**
408     /// ```rust
409     /// let vec = vec![vec![1]];
410     ///
411     /// // Bad
412     /// vec.iter().map(|x| x.iter()).flatten();
413     ///
414     /// // Good
415     /// vec.iter().flat_map(|x| x.iter());
416     /// ```
417     pub MAP_FLATTEN,
418     pedantic,
419     "using combinations of `flatten` and `map` which can usually be written as a single method call"
420 }
421
422 declare_clippy_lint! {
423     /// **What it does:** Checks for usage of `_.filter(_).map(_)`,
424     /// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar.
425     ///
426     /// **Why is this bad?** Readability, this can be written more concisely as a
427     /// single method call.
428     ///
429     /// **Known problems:** Often requires a condition + Option/Iterator creation
430     /// inside the closure.
431     ///
432     /// **Example:**
433     /// ```rust
434     /// let vec = vec![1];
435     ///
436     /// // Bad
437     /// vec.iter().filter(|x| **x == 0).map(|x| *x * 2);
438     ///
439     /// // Good
440     /// vec.iter().filter_map(|x| if *x == 0 {
441     ///     Some(*x * 2)
442     /// } else {
443     ///     None
444     /// });
445     /// ```
446     pub FILTER_MAP,
447     pedantic,
448     "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call"
449 }
450
451 declare_clippy_lint! {
452     /// **What it does:** Checks for usage of `_.filter_map(_).next()`.
453     ///
454     /// **Why is this bad?** Readability, this can be written more concisely as a
455     /// single method call.
456     ///
457     /// **Known problems:** None
458     ///
459     /// **Example:**
460     /// ```rust
461     ///  (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
462     /// ```
463     /// Can be written as
464     ///
465     /// ```rust
466     ///  (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
467     /// ```
468     pub FILTER_MAP_NEXT,
469     pedantic,
470     "using combination of `filter_map` and `next` which can usually be written as a single method call"
471 }
472
473 declare_clippy_lint! {
474     /// **What it does:** Checks for usage of `flat_map(|x| x)`.
475     ///
476     /// **Why is this bad?** Readability, this can be written more concisely by using `flatten`.
477     ///
478     /// **Known problems:** None
479     ///
480     /// **Example:**
481     /// ```rust
482     /// # let iter = vec![vec![0]].into_iter();
483     /// iter.flat_map(|x| x);
484     /// ```
485     /// Can be written as
486     /// ```rust
487     /// # let iter = vec![vec![0]].into_iter();
488     /// iter.flatten();
489     /// ```
490     pub FLAT_MAP_IDENTITY,
491     complexity,
492     "call to `flat_map` where `flatten` is sufficient"
493 }
494
495 declare_clippy_lint! {
496     /// **What it does:** Checks for usage of `_.find(_).map(_)`.
497     ///
498     /// **Why is this bad?** Readability, this can be written more concisely as a
499     /// single method call.
500     ///
501     /// **Known problems:** Often requires a condition + Option/Iterator creation
502     /// inside the closure.
503     ///
504     /// **Example:**
505     /// ```rust
506     ///  (0..3).find(|x| *x == 2).map(|x| x * 2);
507     /// ```
508     /// Can be written as
509     /// ```rust
510     ///  (0..3).find_map(|x| if x == 2 { Some(x * 2) } else { None });
511     /// ```
512     pub FIND_MAP,
513     pedantic,
514     "using a combination of `find` and `map` can usually be written as a single method call"
515 }
516
517 declare_clippy_lint! {
518     /// **What it does:** Checks for an iterator search (such as `find()`,
519     /// `position()`, or `rposition()`) followed by a call to `is_some()`.
520     ///
521     /// **Why is this bad?** Readability, this can be written more concisely as
522     /// `_.any(_)`.
523     ///
524     /// **Known problems:** None.
525     ///
526     /// **Example:**
527     /// ```rust
528     /// # let vec = vec![1];
529     /// vec.iter().find(|x| **x == 0).is_some();
530     /// ```
531     /// Could be written as
532     /// ```rust
533     /// # let vec = vec![1];
534     /// vec.iter().any(|x| *x == 0);
535     /// ```
536     pub SEARCH_IS_SOME,
537     complexity,
538     "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`"
539 }
540
541 declare_clippy_lint! {
542     /// **What it does:** Checks for usage of `.chars().next()` on a `str` to check
543     /// if it starts with a given char.
544     ///
545     /// **Why is this bad?** Readability, this can be written more concisely as
546     /// `_.starts_with(_)`.
547     ///
548     /// **Known problems:** None.
549     ///
550     /// **Example:**
551     /// ```rust
552     /// let name = "foo";
553     /// if name.chars().next() == Some('_') {};
554     /// ```
555     /// Could be written as
556     /// ```rust
557     /// let name = "foo";
558     /// if name.starts_with('_') {};
559     /// ```
560     pub CHARS_NEXT_CMP,
561     style,
562     "using `.chars().next()` to check if a string starts with a char"
563 }
564
565 declare_clippy_lint! {
566     /// **What it does:** Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
567     /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
568     /// `unwrap_or_default` instead.
569     ///
570     /// **Why is this bad?** The function will always be called and potentially
571     /// allocate an object acting as the default.
572     ///
573     /// **Known problems:** If the function has side-effects, not calling it will
574     /// change the semantic of the program, but you shouldn't rely on that anyway.
575     ///
576     /// **Example:**
577     /// ```rust
578     /// # let foo = Some(String::new());
579     /// foo.unwrap_or(String::new());
580     /// ```
581     /// this can instead be written:
582     /// ```rust
583     /// # let foo = Some(String::new());
584     /// foo.unwrap_or_else(String::new);
585     /// ```
586     /// or
587     /// ```rust
588     /// # let foo = Some(String::new());
589     /// foo.unwrap_or_default();
590     /// ```
591     pub OR_FUN_CALL,
592     perf,
593     "using any `*or` method with a function call, which suggests `*or_else`"
594 }
595
596 declare_clippy_lint! {
597     /// **What it does:** Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
598     /// etc., and suggests to use `unwrap_or_else` instead
599     ///
600     /// **Why is this bad?** The function will always be called.
601     ///
602     /// **Known problems:** If the function has side-effects, not calling it will
603     /// change the semantics of the program, but you shouldn't rely on that anyway.
604     ///
605     /// **Example:**
606     /// ```rust
607     /// # let foo = Some(String::new());
608     /// # let err_code = "418";
609     /// # let err_msg = "I'm a teapot";
610     /// foo.expect(&format!("Err {}: {}", err_code, err_msg));
611     /// ```
612     /// or
613     /// ```rust
614     /// # let foo = Some(String::new());
615     /// # let err_code = "418";
616     /// # let err_msg = "I'm a teapot";
617     /// foo.expect(format!("Err {}: {}", err_code, err_msg).as_str());
618     /// ```
619     /// this can instead be written:
620     /// ```rust
621     /// # let foo = Some(String::new());
622     /// # let err_code = "418";
623     /// # let err_msg = "I'm a teapot";
624     /// foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg));
625     /// ```
626     pub EXPECT_FUN_CALL,
627     perf,
628     "using any `expect` method with a function call"
629 }
630
631 declare_clippy_lint! {
632     /// **What it does:** Checks for usage of `.clone()` on a `Copy` type.
633     ///
634     /// **Why is this bad?** The only reason `Copy` types implement `Clone` is for
635     /// generics, not for using the `clone` method on a concrete type.
636     ///
637     /// **Known problems:** None.
638     ///
639     /// **Example:**
640     /// ```rust
641     /// 42u64.clone();
642     /// ```
643     pub CLONE_ON_COPY,
644     complexity,
645     "using `clone` on a `Copy` type"
646 }
647
648 declare_clippy_lint! {
649     /// **What it does:** Checks for usage of `.clone()` on a ref-counted pointer,
650     /// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
651     /// function syntax instead (e.g., `Rc::clone(foo)`).
652     ///
653     /// **Why is this bad?** Calling '.clone()' on an Rc, Arc, or Weak
654     /// can obscure the fact that only the pointer is being cloned, not the underlying
655     /// data.
656     ///
657     /// **Example:**
658     /// ```rust
659     /// # use std::rc::Rc;
660     /// let x = Rc::new(1);
661     ///
662     /// // Bad
663     /// x.clone();
664     ///
665     /// // Good
666     /// Rc::clone(&x);
667     /// ```
668     pub CLONE_ON_REF_PTR,
669     restriction,
670     "using 'clone' on a ref-counted pointer"
671 }
672
673 declare_clippy_lint! {
674     /// **What it does:** Checks for usage of `.clone()` on an `&&T`.
675     ///
676     /// **Why is this bad?** Cloning an `&&T` copies the inner `&T`, instead of
677     /// cloning the underlying `T`.
678     ///
679     /// **Known problems:** None.
680     ///
681     /// **Example:**
682     /// ```rust
683     /// fn main() {
684     ///     let x = vec![1];
685     ///     let y = &&x;
686     ///     let z = y.clone();
687     ///     println!("{:p} {:p}", *y, z); // prints out the same pointer
688     /// }
689     /// ```
690     pub CLONE_DOUBLE_REF,
691     correctness,
692     "using `clone` on `&&T`"
693 }
694
695 declare_clippy_lint! {
696     /// **What it does:** Checks for usage of `.to_string()` on an `&&T` where
697     /// `T` implements `ToString` directly (like `&&str` or `&&String`).
698     ///
699     /// **Why is this bad?** This bypasses the specialized implementation of
700     /// `ToString` and instead goes through the more expensive string formatting
701     /// facilities.
702     ///
703     /// **Known problems:** None.
704     ///
705     /// **Example:**
706     /// ```rust
707     /// // Generic implementation for `T: Display` is used (slow)
708     /// ["foo", "bar"].iter().map(|s| s.to_string());
709     ///
710     /// // OK, the specialized impl is used
711     /// ["foo", "bar"].iter().map(|&s| s.to_string());
712     /// ```
713     pub INEFFICIENT_TO_STRING,
714     pedantic,
715     "using `to_string` on `&&T` where `T: ToString`"
716 }
717
718 declare_clippy_lint! {
719     /// **What it does:** Checks for `new` not returning a type that contains `Self`.
720     ///
721     /// **Why is this bad?** As a convention, `new` methods are used to make a new
722     /// instance of a type.
723     ///
724     /// **Known problems:** None.
725     ///
726     /// **Example:**
727     /// In an impl block:
728     /// ```rust
729     /// # struct Foo;
730     /// # struct NotAFoo;
731     /// impl Foo {
732     ///     fn new() -> NotAFoo {
733     /// # NotAFoo
734     ///     }
735     /// }
736     /// ```
737     ///
738     /// ```rust
739     /// # struct Foo;
740     /// struct Bar(Foo);
741     /// impl Foo {
742     ///     // Bad. The type name must contain `Self`
743     ///     fn new() -> Bar {
744     /// # Bar(Foo)
745     ///     }
746     /// }
747     /// ```
748     ///
749     /// ```rust
750     /// # struct Foo;
751     /// # struct FooError;
752     /// impl Foo {
753     ///     // Good. Return type contains `Self`
754     ///     fn new() -> Result<Foo, FooError> {
755     /// # Ok(Foo)
756     ///     }
757     /// }
758     /// ```
759     ///
760     /// Or in a trait definition:
761     /// ```rust
762     /// pub trait Trait {
763     ///     // Bad. The type name must contain `Self`
764     ///     fn new();
765     /// }
766     /// ```
767     ///
768     /// ```rust
769     /// pub trait Trait {
770     ///     // Good. Return type contains `Self`
771     ///     fn new() -> Self;
772     /// }
773     /// ```
774     pub NEW_RET_NO_SELF,
775     style,
776     "not returning type containing `Self` in a `new` method"
777 }
778
779 declare_clippy_lint! {
780     /// **What it does:** Checks for string methods that receive a single-character
781     /// `str` as an argument, e.g., `_.split("x")`.
782     ///
783     /// **Why is this bad?** Performing these methods using a `char` is faster than
784     /// using a `str`.
785     ///
786     /// **Known problems:** Does not catch multi-byte unicode characters.
787     ///
788     /// **Example:**
789     /// ```rust,ignore
790     /// // Bad
791     /// _.split("x");
792     ///
793     /// // Good
794     /// _.split('x');
795     pub SINGLE_CHAR_PATTERN,
796     perf,
797     "using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
798 }
799
800 declare_clippy_lint! {
801     /// **What it does:** Checks for getting the inner pointer of a temporary
802     /// `CString`.
803     ///
804     /// **Why is this bad?** The inner pointer of a `CString` is only valid as long
805     /// as the `CString` is alive.
806     ///
807     /// **Known problems:** None.
808     ///
809     /// **Example:**
810     /// ```rust
811     /// # use std::ffi::CString;
812     /// # fn call_some_ffi_func(_: *const i8) {}
813     /// #
814     /// let c_str = CString::new("foo").unwrap().as_ptr();
815     /// unsafe {
816     ///     call_some_ffi_func(c_str);
817     /// }
818     /// ```
819     /// Here `c_str` points to a freed address. The correct use would be:
820     /// ```rust
821     /// # use std::ffi::CString;
822     /// # fn call_some_ffi_func(_: *const i8) {}
823     /// #
824     /// let c_str = CString::new("foo").unwrap();
825     /// unsafe {
826     ///     call_some_ffi_func(c_str.as_ptr());
827     /// }
828     /// ```
829     pub TEMPORARY_CSTRING_AS_PTR,
830     correctness,
831     "getting the inner pointer of a temporary `CString`"
832 }
833
834 declare_clippy_lint! {
835     /// **What it does:** Checks for calling `.step_by(0)` on iterators which panics.
836     ///
837     /// **Why is this bad?** This very much looks like an oversight. Use `panic!()` instead if you
838     /// actually intend to panic.
839     ///
840     /// **Known problems:** None.
841     ///
842     /// **Example:**
843     /// ```rust,should_panic
844     /// for x in (0..100).step_by(0) {
845     ///     //..
846     /// }
847     /// ```
848     pub ITERATOR_STEP_BY_ZERO,
849     correctness,
850     "using `Iterator::step_by(0)`, which will panic at runtime"
851 }
852
853 declare_clippy_lint! {
854     /// **What it does:** Checks for the use of `iter.nth(0)`.
855     ///
856     /// **Why is this bad?** `iter.next()` is equivalent to
857     /// `iter.nth(0)`, as they both consume the next element,
858     ///  but is more readable.
859     ///
860     /// **Known problems:** None.
861     ///
862     /// **Example:**
863     ///
864     /// ```rust
865     /// # use std::collections::HashSet;
866     /// // Bad
867     /// # let mut s = HashSet::new();
868     /// # s.insert(1);
869     /// let x = s.iter().nth(0);
870     ///
871     /// // Good
872     /// # let mut s = HashSet::new();
873     /// # s.insert(1);
874     /// let x = s.iter().next();
875     /// ```
876     pub ITER_NTH_ZERO,
877     style,
878     "replace `iter.nth(0)` with `iter.next()`"
879 }
880
881 declare_clippy_lint! {
882     /// **What it does:** Checks for use of `.iter().nth()` (and the related
883     /// `.iter_mut().nth()`) on standard library types with O(1) element access.
884     ///
885     /// **Why is this bad?** `.get()` and `.get_mut()` are more efficient and more
886     /// readable.
887     ///
888     /// **Known problems:** None.
889     ///
890     /// **Example:**
891     /// ```rust
892     /// let some_vec = vec![0, 1, 2, 3];
893     /// let bad_vec = some_vec.iter().nth(3);
894     /// let bad_slice = &some_vec[..].iter().nth(3);
895     /// ```
896     /// The correct use would be:
897     /// ```rust
898     /// let some_vec = vec![0, 1, 2, 3];
899     /// let bad_vec = some_vec.get(3);
900     /// let bad_slice = &some_vec[..].get(3);
901     /// ```
902     pub ITER_NTH,
903     perf,
904     "using `.iter().nth()` on a standard library type with O(1) element access"
905 }
906
907 declare_clippy_lint! {
908     /// **What it does:** Checks for use of `.skip(x).next()` on iterators.
909     ///
910     /// **Why is this bad?** `.nth(x)` is cleaner
911     ///
912     /// **Known problems:** None.
913     ///
914     /// **Example:**
915     /// ```rust
916     /// let some_vec = vec![0, 1, 2, 3];
917     /// let bad_vec = some_vec.iter().skip(3).next();
918     /// let bad_slice = &some_vec[..].iter().skip(3).next();
919     /// ```
920     /// The correct use would be:
921     /// ```rust
922     /// let some_vec = vec![0, 1, 2, 3];
923     /// let bad_vec = some_vec.iter().nth(3);
924     /// let bad_slice = &some_vec[..].iter().nth(3);
925     /// ```
926     pub ITER_SKIP_NEXT,
927     style,
928     "using `.skip(x).next()` on an iterator"
929 }
930
931 declare_clippy_lint! {
932     /// **What it does:** Checks for use of `.get().unwrap()` (or
933     /// `.get_mut().unwrap`) on a standard library type which implements `Index`
934     ///
935     /// **Why is this bad?** Using the Index trait (`[]`) is more clear and more
936     /// concise.
937     ///
938     /// **Known problems:** Not a replacement for error handling: Using either
939     /// `.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic`
940     /// if the value being accessed is `None`. If the use of `.get().unwrap()` is a
941     /// temporary placeholder for dealing with the `Option` type, then this does
942     /// not mitigate the need for error handling. If there is a chance that `.get()`
943     /// will be `None` in your program, then it is advisable that the `None` case
944     /// is handled in a future refactor instead of using `.unwrap()` or the Index
945     /// trait.
946     ///
947     /// **Example:**
948     /// ```rust
949     /// let mut some_vec = vec![0, 1, 2, 3];
950     /// let last = some_vec.get(3).unwrap();
951     /// *some_vec.get_mut(0).unwrap() = 1;
952     /// ```
953     /// The correct use would be:
954     /// ```rust
955     /// let mut some_vec = vec![0, 1, 2, 3];
956     /// let last = some_vec[3];
957     /// some_vec[0] = 1;
958     /// ```
959     pub GET_UNWRAP,
960     restriction,
961     "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
962 }
963
964 declare_clippy_lint! {
965     /// **What it does:** Checks for the use of `.extend(s.chars())` where s is a
966     /// `&str` or `String`.
967     ///
968     /// **Why is this bad?** `.push_str(s)` is clearer
969     ///
970     /// **Known problems:** None.
971     ///
972     /// **Example:**
973     /// ```rust
974     /// let abc = "abc";
975     /// let def = String::from("def");
976     /// let mut s = String::new();
977     /// s.extend(abc.chars());
978     /// s.extend(def.chars());
979     /// ```
980     /// The correct use would be:
981     /// ```rust
982     /// let abc = "abc";
983     /// let def = String::from("def");
984     /// let mut s = String::new();
985     /// s.push_str(abc);
986     /// s.push_str(&def);
987     /// ```
988     pub STRING_EXTEND_CHARS,
989     style,
990     "using `x.extend(s.chars())` where s is a `&str` or `String`"
991 }
992
993 declare_clippy_lint! {
994     /// **What it does:** Checks for the use of `.cloned().collect()` on slice to
995     /// create a `Vec`.
996     ///
997     /// **Why is this bad?** `.to_vec()` is clearer
998     ///
999     /// **Known problems:** None.
1000     ///
1001     /// **Example:**
1002     /// ```rust
1003     /// let s = [1, 2, 3, 4, 5];
1004     /// let s2: Vec<isize> = s[..].iter().cloned().collect();
1005     /// ```
1006     /// The better use would be:
1007     /// ```rust
1008     /// let s = [1, 2, 3, 4, 5];
1009     /// let s2: Vec<isize> = s.to_vec();
1010     /// ```
1011     pub ITER_CLONED_COLLECT,
1012     style,
1013     "using `.cloned().collect()` on slice to create a `Vec`"
1014 }
1015
1016 declare_clippy_lint! {
1017     /// **What it does:** Checks for usage of `_.chars().last()` or
1018     /// `_.chars().next_back()` on a `str` to check if it ends with a given char.
1019     ///
1020     /// **Why is this bad?** Readability, this can be written more concisely as
1021     /// `_.ends_with(_)`.
1022     ///
1023     /// **Known problems:** None.
1024     ///
1025     /// **Example:**
1026     /// ```rust
1027     /// # let name = "_";
1028     ///
1029     /// // Bad
1030     /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
1031     ///
1032     /// // Good
1033     /// name.ends_with('_') || name.ends_with('-');
1034     /// ```
1035     pub CHARS_LAST_CMP,
1036     style,
1037     "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char"
1038 }
1039
1040 declare_clippy_lint! {
1041     /// **What it does:** Checks for usage of `.as_ref()` or `.as_mut()` where the
1042     /// types before and after the call are the same.
1043     ///
1044     /// **Why is this bad?** The call is unnecessary.
1045     ///
1046     /// **Known problems:** None.
1047     ///
1048     /// **Example:**
1049     /// ```rust
1050     /// # fn do_stuff(x: &[i32]) {}
1051     /// let x: &[i32] = &[1, 2, 3, 4, 5];
1052     /// do_stuff(x.as_ref());
1053     /// ```
1054     /// The correct use would be:
1055     /// ```rust
1056     /// # fn do_stuff(x: &[i32]) {}
1057     /// let x: &[i32] = &[1, 2, 3, 4, 5];
1058     /// do_stuff(x);
1059     /// ```
1060     pub USELESS_ASREF,
1061     complexity,
1062     "using `as_ref` where the types before and after the call are the same"
1063 }
1064
1065 declare_clippy_lint! {
1066     /// **What it does:** Checks for using `fold` when a more succinct alternative exists.
1067     /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
1068     /// `sum` or `product`.
1069     ///
1070     /// **Why is this bad?** Readability.
1071     ///
1072     /// **Known problems:** None.
1073     ///
1074     /// **Example:**
1075     /// ```rust
1076     /// let _ = (0..3).fold(false, |acc, x| acc || x > 2);
1077     /// ```
1078     /// This could be written as:
1079     /// ```rust
1080     /// let _ = (0..3).any(|x| x > 2);
1081     /// ```
1082     pub UNNECESSARY_FOLD,
1083     style,
1084     "using `fold` when a more succinct alternative exists"
1085 }
1086
1087 declare_clippy_lint! {
1088     /// **What it does:** Checks for `filter_map` calls which could be replaced by `filter` or `map`.
1089     /// More specifically it checks if the closure provided is only performing one of the
1090     /// filter or map operations and suggests the appropriate option.
1091     ///
1092     /// **Why is this bad?** Complexity. The intent is also clearer if only a single
1093     /// operation is being performed.
1094     ///
1095     /// **Known problems:** None
1096     ///
1097     /// **Example:**
1098     /// ```rust
1099     /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
1100     ///
1101     /// // As there is no transformation of the argument this could be written as:
1102     /// let _ = (0..3).filter(|&x| x > 2);
1103     /// ```
1104     ///
1105     /// ```rust
1106     /// let _ = (0..4).filter_map(|x| Some(x + 1));
1107     ///
1108     /// // As there is no conditional check on the argument this could be written as:
1109     /// let _ = (0..4).map(|x| x + 1);
1110     /// ```
1111     pub UNNECESSARY_FILTER_MAP,
1112     complexity,
1113     "using `filter_map` when a more succinct alternative exists"
1114 }
1115
1116 declare_clippy_lint! {
1117     /// **What it does:** Checks for `into_iter` calls on references which should be replaced by `iter`
1118     /// or `iter_mut`.
1119     ///
1120     /// **Why is this bad?** Readability. Calling `into_iter` on a reference will not move out its
1121     /// content into the resulting iterator, which is confusing. It is better just call `iter` or
1122     /// `iter_mut` directly.
1123     ///
1124     /// **Known problems:** None
1125     ///
1126     /// **Example:**
1127     ///
1128     /// ```rust
1129     /// // Bad
1130     /// let _ = (&vec![3, 4, 5]).into_iter();
1131     ///
1132     /// // Good
1133     /// let _ = (&vec![3, 4, 5]).iter();
1134     /// ```
1135     pub INTO_ITER_ON_REF,
1136     style,
1137     "using `.into_iter()` on a reference"
1138 }
1139
1140 declare_clippy_lint! {
1141     /// **What it does:** Checks for calls to `map` followed by a `count`.
1142     ///
1143     /// **Why is this bad?** It looks suspicious. Maybe `map` was confused with `filter`.
1144     /// If the `map` call is intentional, this should be rewritten. Or, if you intend to
1145     /// drive the iterator to completion, you can just use `for_each` instead.
1146     ///
1147     /// **Known problems:** None
1148     ///
1149     /// **Example:**
1150     ///
1151     /// ```rust
1152     /// let _ = (0..3).map(|x| x + 2).count();
1153     /// ```
1154     pub SUSPICIOUS_MAP,
1155     complexity,
1156     "suspicious usage of map"
1157 }
1158
1159 declare_clippy_lint! {
1160     /// **What it does:** Checks for `MaybeUninit::uninit().assume_init()`.
1161     ///
1162     /// **Why is this bad?** For most types, this is undefined behavior.
1163     ///
1164     /// **Known problems:** For now, we accept empty tuples and tuples / arrays
1165     /// of `MaybeUninit`. There may be other types that allow uninitialized
1166     /// data, but those are not yet rigorously defined.
1167     ///
1168     /// **Example:**
1169     ///
1170     /// ```rust
1171     /// // Beware the UB
1172     /// use std::mem::MaybeUninit;
1173     ///
1174     /// let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
1175     /// ```
1176     ///
1177     /// Note that the following is OK:
1178     ///
1179     /// ```rust
1180     /// use std::mem::MaybeUninit;
1181     ///
1182     /// let _: [MaybeUninit<bool>; 5] = unsafe {
1183     ///     MaybeUninit::uninit().assume_init()
1184     /// };
1185     /// ```
1186     pub UNINIT_ASSUMED_INIT,
1187     correctness,
1188     "`MaybeUninit::uninit().assume_init()`"
1189 }
1190
1191 declare_clippy_lint! {
1192     /// **What it does:** Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`.
1193     ///
1194     /// **Why is this bad?** These can be written simply with `saturating_add/sub` methods.
1195     ///
1196     /// **Example:**
1197     ///
1198     /// ```rust
1199     /// # let y: u32 = 0;
1200     /// # let x: u32 = 100;
1201     /// let add = x.checked_add(y).unwrap_or(u32::MAX);
1202     /// let sub = x.checked_sub(y).unwrap_or(u32::MIN);
1203     /// ```
1204     ///
1205     /// can be written using dedicated methods for saturating addition/subtraction as:
1206     ///
1207     /// ```rust
1208     /// # let y: u32 = 0;
1209     /// # let x: u32 = 100;
1210     /// let add = x.saturating_add(y);
1211     /// let sub = x.saturating_sub(y);
1212     /// ```
1213     pub MANUAL_SATURATING_ARITHMETIC,
1214     style,
1215     "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`"
1216 }
1217
1218 declare_clippy_lint! {
1219     /// **What it does:** Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to
1220     /// zero-sized types
1221     ///
1222     /// **Why is this bad?** This is a no-op, and likely unintended
1223     ///
1224     /// **Known problems:** None
1225     ///
1226     /// **Example:**
1227     /// ```rust
1228     /// unsafe { (&() as *const ()).offset(1) };
1229     /// ```
1230     pub ZST_OFFSET,
1231     correctness,
1232     "Check for offset calculations on raw pointers to zero-sized types"
1233 }
1234
1235 declare_clippy_lint! {
1236     /// **What it does:** Checks for `FileType::is_file()`.
1237     ///
1238     /// **Why is this bad?** When people testing a file type with `FileType::is_file`
1239     /// they are testing whether a path is something they can get bytes from. But
1240     /// `is_file` doesn't cover special file types in unix-like systems, and doesn't cover
1241     /// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention.
1242     ///
1243     /// **Example:**
1244     ///
1245     /// ```rust
1246     /// # || {
1247     /// let metadata = std::fs::metadata("foo.txt")?;
1248     /// let filetype = metadata.file_type();
1249     ///
1250     /// if filetype.is_file() {
1251     ///     // read file
1252     /// }
1253     /// # Ok::<_, std::io::Error>(())
1254     /// # };
1255     /// ```
1256     ///
1257     /// should be written as:
1258     ///
1259     /// ```rust
1260     /// # || {
1261     /// let metadata = std::fs::metadata("foo.txt")?;
1262     /// let filetype = metadata.file_type();
1263     ///
1264     /// if !filetype.is_dir() {
1265     ///     // read file
1266     /// }
1267     /// # Ok::<_, std::io::Error>(())
1268     /// # };
1269     /// ```
1270     pub FILETYPE_IS_FILE,
1271     restriction,
1272     "`FileType::is_file` is not recommended to test for readable file type"
1273 }
1274
1275 declare_clippy_lint! {
1276     /// **What it does:** Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
1277     ///
1278     /// **Why is this bad?** Readability, this can be written more concisely as a
1279     /// single method call.
1280     ///
1281     /// **Known problems:** None.
1282     ///
1283     /// **Example:**
1284     /// ```rust
1285     /// # let opt = Some("".to_string());
1286     /// opt.as_ref().map(String::as_str)
1287     /// # ;
1288     /// ```
1289     /// Can be written as
1290     /// ```rust
1291     /// # let opt = Some("".to_string());
1292     /// opt.as_deref()
1293     /// # ;
1294     /// ```
1295     pub OPTION_AS_REF_DEREF,
1296     complexity,
1297     "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`"
1298 }
1299
1300 declare_clippy_lint! {
1301     /// **What it does:** Checks for usage of `iter().next()` on a Slice or an Array
1302     ///
1303     /// **Why is this bad?** These can be shortened into `.get()`
1304     ///
1305     /// **Known problems:** None.
1306     ///
1307     /// **Example:**
1308     /// ```rust
1309     /// # let a = [1, 2, 3];
1310     /// # let b = vec![1, 2, 3];
1311     /// a[2..].iter().next();
1312     /// b.iter().next();
1313     /// ```
1314     /// should be written as:
1315     /// ```rust
1316     /// # let a = [1, 2, 3];
1317     /// # let b = vec![1, 2, 3];
1318     /// a.get(2);
1319     /// b.get(0);
1320     /// ```
1321     pub ITER_NEXT_SLICE,
1322     style,
1323     "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
1324 }
1325
1326 declare_clippy_lint! {
1327     /// **What it does:** Warns when using push_str with a single-character string literal,
1328     /// and push with a char would work fine.
1329     ///
1330     /// **Why is this bad?** It's less clear that we are pushing a single character
1331     ///
1332     /// **Known problems:** None
1333     ///
1334     /// **Example:**
1335     /// ```
1336     /// let mut string = String::new();
1337     /// string.push_str("R");
1338     /// ```
1339     /// Could be written as
1340     /// ```
1341     /// let mut string = String::new();
1342     /// string.push('R');
1343     /// ```
1344     pub SINGLE_CHAR_PUSH_STR,
1345     style,
1346     "`push_str()` used with a single-character string literal as parameter"
1347 }
1348
1349 declare_clippy_lint! {
1350     /// **What it does:** As the counterpart to `or_fun_call`, this lint looks for unnecessary
1351     /// lazily evaluated closures on `Option` and `Result`.
1352     ///
1353     /// This lint suggests changing the following functions, when eager evaluation results in
1354     /// simpler code:
1355     ///  - `unwrap_or_else` to `unwrap_or`
1356     ///  - `and_then` to `and`
1357     ///  - `or_else` to `or`
1358     ///  - `get_or_insert_with` to `get_or_insert`
1359     ///  - `ok_or_else` to `ok_or`
1360     ///
1361     /// **Why is this bad?** Using eager evaluation is shorter and simpler in some cases.
1362     ///
1363     /// **Known problems:** It is possible, but not recommended for `Deref` and `Index` to have
1364     /// side effects. Eagerly evaluating them can change the semantics of the program.
1365     ///
1366     /// **Example:**
1367     ///
1368     /// ```rust
1369     /// // example code where clippy issues a warning
1370     /// let opt: Option<u32> = None;
1371     ///
1372     /// opt.unwrap_or_else(|| 42);
1373     /// ```
1374     /// Use instead:
1375     /// ```rust
1376     /// let opt: Option<u32> = None;
1377     ///
1378     /// opt.unwrap_or(42);
1379     /// ```
1380     pub UNNECESSARY_LAZY_EVALUATIONS,
1381     style,
1382     "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
1383 }
1384
1385 declare_lint_pass!(Methods => [
1386     UNWRAP_USED,
1387     EXPECT_USED,
1388     SHOULD_IMPLEMENT_TRAIT,
1389     WRONG_SELF_CONVENTION,
1390     WRONG_PUB_SELF_CONVENTION,
1391     OK_EXPECT,
1392     MAP_UNWRAP_OR,
1393     RESULT_MAP_OR_INTO_OPTION,
1394     OPTION_MAP_OR_NONE,
1395     BIND_INSTEAD_OF_MAP,
1396     OR_FUN_CALL,
1397     EXPECT_FUN_CALL,
1398     CHARS_NEXT_CMP,
1399     CHARS_LAST_CMP,
1400     CLONE_ON_COPY,
1401     CLONE_ON_REF_PTR,
1402     CLONE_DOUBLE_REF,
1403     INEFFICIENT_TO_STRING,
1404     NEW_RET_NO_SELF,
1405     SINGLE_CHAR_PATTERN,
1406     SINGLE_CHAR_PUSH_STR,
1407     SEARCH_IS_SOME,
1408     TEMPORARY_CSTRING_AS_PTR,
1409     FILTER_NEXT,
1410     SKIP_WHILE_NEXT,
1411     FILTER_MAP,
1412     FILTER_MAP_NEXT,
1413     FLAT_MAP_IDENTITY,
1414     FIND_MAP,
1415     MAP_FLATTEN,
1416     ITERATOR_STEP_BY_ZERO,
1417     ITER_NEXT_SLICE,
1418     ITER_NTH,
1419     ITER_NTH_ZERO,
1420     ITER_SKIP_NEXT,
1421     GET_UNWRAP,
1422     STRING_EXTEND_CHARS,
1423     ITER_CLONED_COLLECT,
1424     USELESS_ASREF,
1425     UNNECESSARY_FOLD,
1426     UNNECESSARY_FILTER_MAP,
1427     INTO_ITER_ON_REF,
1428     SUSPICIOUS_MAP,
1429     UNINIT_ASSUMED_INIT,
1430     MANUAL_SATURATING_ARITHMETIC,
1431     ZST_OFFSET,
1432     FILETYPE_IS_FILE,
1433     OPTION_AS_REF_DEREF,
1434     UNNECESSARY_LAZY_EVALUATIONS,
1435 ]);
1436
1437 impl<'tcx> LateLintPass<'tcx> for Methods {
1438     #[allow(clippy::too_many_lines)]
1439     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
1440         if in_macro(expr.span) {
1441             return;
1442         }
1443
1444         let (method_names, arg_lists, method_spans) = method_calls(expr, 2);
1445         let method_names: Vec<SymbolStr> = method_names.iter().map(|s| s.as_str()).collect();
1446         let method_names: Vec<&str> = method_names.iter().map(|s| &**s).collect();
1447
1448         match method_names.as_slice() {
1449             ["unwrap", "get"] => lint_get_unwrap(cx, expr, arg_lists[1], false),
1450             ["unwrap", "get_mut"] => lint_get_unwrap(cx, expr, arg_lists[1], true),
1451             ["unwrap", ..] => lint_unwrap(cx, expr, arg_lists[0]),
1452             ["expect", "ok"] => lint_ok_expect(cx, expr, arg_lists[1]),
1453             ["expect", ..] => lint_expect(cx, expr, arg_lists[0]),
1454             ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]),
1455             ["unwrap_or_else", "map"] => {
1456                 if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) {
1457                     unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or");
1458                 }
1459             },
1460             ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]),
1461             ["and_then", ..] => {
1462                 unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "and");
1463                 bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]);
1464                 bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]);
1465             },
1466             ["or_else", ..] => {
1467                 unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "or");
1468                 bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]);
1469             },
1470             ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
1471             ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]),
1472             ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]),
1473             ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]),
1474             ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]),
1475             ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]),
1476             ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]),
1477             ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
1478             ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
1479             ["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0], method_spans[0]),
1480             ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]),
1481             ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]),
1482             ["is_some", "position"] => {
1483                 lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1])
1484             },
1485             ["is_some", "rposition"] => {
1486                 lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1])
1487             },
1488             ["extend", ..] => lint_extend(cx, expr, arg_lists[0]),
1489             ["as_ptr", "unwrap" | "expect"] => lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0]),
1490             ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false),
1491             ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true),
1492             ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]),
1493             ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]),
1494             ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]),
1495             ["collect", "cloned"] => lint_iter_cloned_collect(cx, expr, arg_lists[1]),
1496             ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]),
1497             ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]),
1498             ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0], method_spans[0]),
1499             ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]),
1500             ["count", "map"] => lint_suspicious_map(cx, expr),
1501             ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr),
1502             ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => {
1503                 manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..])
1504             },
1505             ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => {
1506                 check_pointer_offset(cx, expr, arg_lists[0])
1507             },
1508             ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
1509             ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false),
1510             ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true),
1511             ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"),
1512             ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "get_or_insert"),
1513             ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "ok_or"),
1514             _ => {},
1515         }
1516
1517         match expr.kind {
1518             hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => {
1519                 lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
1520                 lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
1521
1522                 let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
1523                 if args.len() == 1 && method_call.ident.name == sym!(clone) {
1524                     lint_clone_on_copy(cx, expr, &args[0], self_ty);
1525                     lint_clone_on_ref_ptr(cx, expr, &args[0]);
1526                 }
1527                 if args.len() == 1 && method_call.ident.name == sym!(to_string) {
1528                     inefficient_to_string::lint(cx, expr, &args[0], self_ty);
1529                 }
1530
1531                 if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
1532                     if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
1533                         lint_single_char_push_string(cx, expr, args);
1534                     }
1535                 }
1536
1537                 match self_ty.kind {
1538                     ty::Ref(_, ty, _) if ty.kind == ty::Str => {
1539                         for &(method, pos) in &PATTERN_METHODS {
1540                             if method_call.ident.name.as_str() == method && args.len() > pos {
1541                                 lint_single_char_pattern(cx, expr, &args[pos]);
1542                             }
1543                         }
1544                     },
1545                     ty::Ref(..) if method_call.ident.name == sym!(into_iter) => {
1546                         lint_into_iter(cx, expr, self_ty, *method_span);
1547                     },
1548                     _ => (),
1549                 }
1550             },
1551             hir::ExprKind::Binary(op, ref lhs, ref rhs)
1552                 if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne =>
1553             {
1554                 let mut info = BinaryExprInfo {
1555                     expr,
1556                     chain: lhs,
1557                     other: rhs,
1558                     eq: op.node == hir::BinOpKind::Eq,
1559                 };
1560                 lint_binary_expr_with_method_call(cx, &mut info);
1561             }
1562             _ => (),
1563         }
1564     }
1565
1566     #[allow(clippy::too_many_lines)]
1567     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
1568         if in_external_macro(cx.sess(), impl_item.span) {
1569             return;
1570         }
1571         let name = impl_item.ident.name.as_str();
1572         let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id);
1573         let item = cx.tcx.hir().expect_item(parent);
1574         let def_id = cx.tcx.hir().local_def_id(item.hir_id);
1575         let self_ty = cx.tcx.type_of(def_id);
1576         if_chain! {
1577             if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
1578             if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next();
1579             if let hir::ItemKind::Impl{ of_trait: None, .. } = item.kind;
1580
1581             let method_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
1582             let method_sig = cx.tcx.fn_sig(method_def_id);
1583             let method_sig = cx.tcx.erase_late_bound_regions(&method_sig);
1584
1585             let first_arg_ty = &method_sig.inputs().iter().next();
1586
1587             // check conventions w.r.t. conversion method names and predicates
1588             if let Some(first_arg_ty) = first_arg_ty;
1589
1590             then {
1591                 if cx.access_levels.is_exported(impl_item.hir_id) {
1592                     // check missing trait implementations
1593                     for method_config in &TRAIT_METHODS {
1594                         if name == method_config.method_name &&
1595                             sig.decl.inputs.len() == method_config.param_count &&
1596                             method_config.output_type.matches(cx, &sig.decl.output) &&
1597                             method_config.self_kind.matches(cx, self_ty, first_arg_ty) &&
1598                             fn_header_equals(method_config.fn_header, sig.header) &&
1599                             method_config.lifetime_param_cond(&impl_item)
1600                         {
1601                             span_lint_and_help(
1602                                 cx,
1603                                 SHOULD_IMPLEMENT_TRAIT,
1604                                 impl_item.span,
1605                                 &format!(
1606                                     "method `{}` can be confused for the standard trait method `{}::{}`",
1607                                     method_config.method_name,
1608                                     method_config.trait_name,
1609                                     method_config.method_name
1610                                 ),
1611                                 None,
1612                                 &format!(
1613                                     "consider implementing the trait `{}` or choosing a less ambiguous method name",
1614                                     method_config.trait_name
1615                                 )
1616                             );
1617                         }
1618                     }
1619                 }
1620
1621                 if let Some((ref conv, self_kinds)) = &CONVENTIONS
1622                     .iter()
1623                     .find(|(ref conv, _)| conv.check(&name))
1624                 {
1625                     if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) {
1626                         let lint = if item.vis.node.is_pub() {
1627                             WRONG_PUB_SELF_CONVENTION
1628                         } else {
1629                             WRONG_SELF_CONVENTION
1630                         };
1631
1632                         span_lint(
1633                             cx,
1634                             lint,
1635                             first_arg.pat.span,
1636                             &format!("methods called `{}` usually take {}; consider choosing a less ambiguous name",
1637                                 conv,
1638                                 &self_kinds
1639                                     .iter()
1640                                     .map(|k| k.description())
1641                                     .collect::<Vec<_>>()
1642                                     .join(" or ")
1643                             ),
1644                         );
1645                     }
1646                 }
1647             }
1648         }
1649
1650         // if this impl block implements a trait, lint in trait definition instead
1651         if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind {
1652             return;
1653         }
1654
1655         if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
1656             let ret_ty = return_ty(cx, impl_item.hir_id);
1657
1658             // walk the return type and check for Self (this does not check associated types)
1659             if contains_ty(ret_ty, self_ty) {
1660                 return;
1661             }
1662
1663             // if return type is impl trait, check the associated types
1664             if let ty::Opaque(def_id, _) = ret_ty.kind {
1665                 // one of the associated types must be Self
1666                 for &(predicate, _span) in cx.tcx.predicates_of(def_id).predicates {
1667                     if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
1668                         // walk the associated type and check for Self
1669                         if contains_ty(projection_predicate.ty, self_ty) {
1670                             return;
1671                         }
1672                     }
1673                 }
1674             }
1675
1676             if name == "new" && !TyS::same_type(ret_ty, self_ty) {
1677                 span_lint(
1678                     cx,
1679                     NEW_RET_NO_SELF,
1680                     impl_item.span,
1681                     "methods called `new` usually return `Self`",
1682                 );
1683             }
1684         }
1685     }
1686
1687     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
1688         if_chain! {
1689             if !in_external_macro(cx.tcx.sess, item.span);
1690             if item.ident.name == sym!(new);
1691             if let TraitItemKind::Fn(_, _) = item.kind;
1692             let ret_ty = return_ty(cx, item.hir_id);
1693             let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty();
1694             if !contains_ty(ret_ty, self_ty);
1695
1696             then {
1697                 span_lint(
1698                     cx,
1699                     NEW_RET_NO_SELF,
1700                     item.span,
1701                     "methods called `new` usually return `Self`",
1702                 );
1703             }
1704         }
1705     }
1706 }
1707
1708 /// Checks for the `OR_FUN_CALL` lint.
1709 #[allow(clippy::too_many_lines)]
1710 fn lint_or_fun_call<'tcx>(
1711     cx: &LateContext<'tcx>,
1712     expr: &hir::Expr<'_>,
1713     method_span: Span,
1714     name: &str,
1715     args: &'tcx [hir::Expr<'_>],
1716 ) {
1717     // Searches an expression for method calls or function calls that aren't ctors
1718     struct FunCallFinder<'a, 'tcx> {
1719         cx: &'a LateContext<'tcx>,
1720         found: bool,
1721     }
1722
1723     impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
1724         type Map = Map<'tcx>;
1725
1726         fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
1727             let call_found = match &expr.kind {
1728                 // ignore enum and struct constructors
1729                 hir::ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
1730                 hir::ExprKind::MethodCall(..) => true,
1731                 _ => false,
1732             };
1733
1734             if call_found {
1735                 self.found |= true;
1736             }
1737
1738             if !self.found {
1739                 intravisit::walk_expr(self, expr);
1740             }
1741         }
1742
1743         fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
1744             intravisit::NestedVisitorMap::None
1745         }
1746     }
1747
1748     /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
1749     fn check_unwrap_or_default(
1750         cx: &LateContext<'_>,
1751         name: &str,
1752         fun: &hir::Expr<'_>,
1753         self_expr: &hir::Expr<'_>,
1754         arg: &hir::Expr<'_>,
1755         or_has_args: bool,
1756         span: Span,
1757     ) -> bool {
1758         if_chain! {
1759             if !or_has_args;
1760             if name == "unwrap_or";
1761             if let hir::ExprKind::Path(ref qpath) = fun.kind;
1762             let path = &*last_path_segment(qpath).ident.as_str();
1763             if ["default", "new"].contains(&path);
1764             let arg_ty = cx.typeck_results().expr_ty(arg);
1765             if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
1766             if implements_trait(cx, arg_ty, default_trait_id, &[]);
1767
1768             then {
1769                 let mut applicability = Applicability::MachineApplicable;
1770                 span_lint_and_sugg(
1771                     cx,
1772                     OR_FUN_CALL,
1773                     span,
1774                     &format!("use of `{}` followed by a call to `{}`", name, path),
1775                     "try this",
1776                     format!(
1777                         "{}.unwrap_or_default()",
1778                         snippet_with_applicability(cx, self_expr.span, "_", &mut applicability)
1779                     ),
1780                     applicability,
1781                 );
1782
1783                 true
1784             } else {
1785                 false
1786             }
1787         }
1788     }
1789
1790     /// Checks for `*or(foo())`.
1791     #[allow(clippy::too_many_arguments)]
1792     fn check_general_case<'tcx>(
1793         cx: &LateContext<'tcx>,
1794         name: &str,
1795         method_span: Span,
1796         fun_span: Span,
1797         self_expr: &hir::Expr<'_>,
1798         arg: &'tcx hir::Expr<'_>,
1799         or_has_args: bool,
1800         span: Span,
1801     ) {
1802         if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
1803             if path.ident.as_str() == "len" {
1804                 let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
1805
1806                 match ty.kind {
1807                     ty::Slice(_) | ty::Array(_, _) => return,
1808                     _ => (),
1809                 }
1810
1811                 if match_type(cx, ty, &paths::VEC) {
1812                     return;
1813                 }
1814             }
1815         }
1816
1817         // (path, fn_has_argument, methods, suffix)
1818         let know_types: &[(&[_], _, &[_], _)] = &[
1819             (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
1820             (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
1821             (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
1822             (&paths::RESULT, true, &["or", "unwrap_or"], "else"),
1823         ];
1824
1825         if_chain! {
1826             if know_types.iter().any(|k| k.2.contains(&name));
1827
1828             let mut finder = FunCallFinder { cx: &cx, found: false };
1829             if { finder.visit_expr(&arg); finder.found };
1830             if !contains_return(&arg);
1831
1832             let self_ty = cx.typeck_results().expr_ty(self_expr);
1833
1834             if let Some(&(_, fn_has_arguments, poss, suffix)) =
1835                 know_types.iter().find(|&&i| match_type(cx, self_ty, i.0));
1836
1837             if poss.contains(&name);
1838
1839             then {
1840                 let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) {
1841                     (true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
1842                     (false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
1843                     (false, true) => snippet_with_macro_callsite(cx, fun_span, ".."),
1844                 };
1845                 let span_replace_word = method_span.with_hi(span.hi());
1846                 span_lint_and_sugg(
1847                     cx,
1848                     OR_FUN_CALL,
1849                     span_replace_word,
1850                     &format!("use of `{}` followed by a function call", name),
1851                     "try this",
1852                     format!("{}_{}({})", name, suffix, sugg),
1853                     Applicability::HasPlaceholders,
1854                 );
1855             }
1856         }
1857     }
1858
1859     if args.len() == 2 {
1860         match args[1].kind {
1861             hir::ExprKind::Call(ref fun, ref or_args) => {
1862                 let or_has_args = !or_args.is_empty();
1863                 if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
1864                     check_general_case(
1865                         cx,
1866                         name,
1867                         method_span,
1868                         fun.span,
1869                         &args[0],
1870                         &args[1],
1871                         or_has_args,
1872                         expr.span,
1873                     );
1874                 }
1875             },
1876             hir::ExprKind::MethodCall(_, span, ref or_args, _) => check_general_case(
1877                 cx,
1878                 name,
1879                 method_span,
1880                 span,
1881                 &args[0],
1882                 &args[1],
1883                 !or_args.is_empty(),
1884                 expr.span,
1885             ),
1886             _ => {},
1887         }
1888     }
1889 }
1890
1891 /// Checks for the `EXPECT_FUN_CALL` lint.
1892 #[allow(clippy::too_many_lines)]
1893 fn lint_expect_fun_call(
1894     cx: &LateContext<'_>,
1895     expr: &hir::Expr<'_>,
1896     method_span: Span,
1897     name: &str,
1898     args: &[hir::Expr<'_>],
1899 ) {
1900     // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
1901     // `&str`
1902     fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
1903         let mut arg_root = arg;
1904         loop {
1905             arg_root = match &arg_root.kind {
1906                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
1907                 hir::ExprKind::MethodCall(method_name, _, call_args, _) => {
1908                     if call_args.len() == 1
1909                         && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref))
1910                         && {
1911                             let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
1912                             let base_type = walk_ptrs_ty(arg_type);
1913                             base_type.kind == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type))
1914                         }
1915                     {
1916                         &call_args[0]
1917                     } else {
1918                         break;
1919                     }
1920                 },
1921                 _ => break,
1922             };
1923         }
1924         arg_root
1925     }
1926
1927     // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be
1928     // converted to string.
1929     fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
1930         let arg_ty = cx.typeck_results().expr_ty(arg);
1931         if is_type_diagnostic_item(cx, arg_ty, sym!(string_type)) {
1932             return false;
1933         }
1934         if let ty::Ref(_, ty, ..) = arg_ty.kind {
1935             if ty.kind == ty::Str && can_be_static_str(cx, arg) {
1936                 return false;
1937             }
1938         };
1939         true
1940     }
1941
1942     // Check if an expression could have type `&'static str`, knowing that it
1943     // has type `&str` for some lifetime.
1944     fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
1945         match arg.kind {
1946             hir::ExprKind::Lit(_) => true,
1947             hir::ExprKind::Call(fun, _) => {
1948                 if let hir::ExprKind::Path(ref p) = fun.kind {
1949                     match cx.qpath_res(p, fun.hir_id) {
1950                         hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
1951                             cx.tcx.fn_sig(def_id).output().skip_binder().kind,
1952                             ty::Ref(ty::ReStatic, ..)
1953                         ),
1954                         _ => false,
1955                     }
1956                 } else {
1957                     false
1958                 }
1959             },
1960             hir::ExprKind::MethodCall(..) => {
1961                 cx.typeck_results()
1962                     .type_dependent_def_id(arg.hir_id)
1963                     .map_or(false, |method_id| {
1964                         matches!(
1965                             cx.tcx.fn_sig(method_id).output().skip_binder().kind,
1966                             ty::Ref(ty::ReStatic, ..)
1967                         )
1968                     })
1969             },
1970             hir::ExprKind::Path(ref p) => matches!(
1971                 cx.qpath_res(p, arg.hir_id),
1972                 hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _)
1973             ),
1974             _ => false,
1975         }
1976     }
1977
1978     fn generate_format_arg_snippet(
1979         cx: &LateContext<'_>,
1980         a: &hir::Expr<'_>,
1981         applicability: &mut Applicability,
1982     ) -> Vec<String> {
1983         if_chain! {
1984             if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref format_arg) = a.kind;
1985             if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.kind;
1986             if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.kind;
1987
1988             then {
1989                 format_arg_expr_tup
1990                     .iter()
1991                     .map(|a| snippet_with_applicability(cx, a.span, "..", applicability).into_owned())
1992                     .collect()
1993             } else {
1994                 unreachable!()
1995             }
1996         }
1997     }
1998
1999     fn is_call(node: &hir::ExprKind<'_>) -> bool {
2000         match node {
2001             hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => {
2002                 is_call(&expr.kind)
2003             },
2004             hir::ExprKind::Call(..)
2005             | hir::ExprKind::MethodCall(..)
2006             // These variants are debatable or require further examination
2007             | hir::ExprKind::Match(..)
2008             | hir::ExprKind::Block{ .. } => true,
2009             _ => false,
2010         }
2011     }
2012
2013     if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) {
2014         return;
2015     }
2016
2017     let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]);
2018     let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym!(option_type)) {
2019         "||"
2020     } else if is_type_diagnostic_item(cx, receiver_type, sym!(result_type)) {
2021         "|_|"
2022     } else {
2023         return;
2024     };
2025
2026     let arg_root = get_arg_root(cx, &args[1]);
2027
2028     let span_replace_word = method_span.with_hi(expr.span.hi());
2029
2030     let mut applicability = Applicability::MachineApplicable;
2031
2032     //Special handling for `format!` as arg_root
2033     if_chain! {
2034         if let hir::ExprKind::Block(block, None) = &arg_root.kind;
2035         if block.stmts.len() == 1;
2036         if let hir::StmtKind::Local(local) = &block.stmts[0].kind;
2037         if let Some(arg_root) = &local.init;
2038         if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = arg_root.kind;
2039         if is_expn_of(inner_fun.span, "format").is_some() && inner_args.len() == 1;
2040         if let hir::ExprKind::Call(_, format_args) = &inner_args[0].kind;
2041         then {
2042             let fmt_spec = &format_args[0];
2043             let fmt_args = &format_args[1];
2044
2045             let mut args = vec![snippet(cx, fmt_spec.span, "..").into_owned()];
2046
2047             args.extend(generate_format_arg_snippet(cx, fmt_args, &mut applicability));
2048
2049             let sugg = args.join(", ");
2050
2051             span_lint_and_sugg(
2052                 cx,
2053                 EXPECT_FUN_CALL,
2054                 span_replace_word,
2055                 &format!("use of `{}` followed by a function call", name),
2056                 "try this",
2057                 format!("unwrap_or_else({} panic!({}))", closure_args, sugg),
2058                 applicability,
2059             );
2060
2061             return;
2062         }
2063     }
2064
2065     let mut arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability);
2066     if requires_to_string(cx, arg_root) {
2067         arg_root_snippet.to_mut().push_str(".to_string()");
2068     }
2069
2070     span_lint_and_sugg(
2071         cx,
2072         EXPECT_FUN_CALL,
2073         span_replace_word,
2074         &format!("use of `{}` followed by a function call", name),
2075         "try this",
2076         format!("unwrap_or_else({} {{ panic!({}) }})", closure_args, arg_root_snippet),
2077         applicability,
2078     );
2079 }
2080
2081 /// Checks for the `CLONE_ON_COPY` lint.
2082 fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) {
2083     let ty = cx.typeck_results().expr_ty(expr);
2084     if let ty::Ref(_, inner, _) = arg_ty.kind {
2085         if let ty::Ref(_, innermost, _) = inner.kind {
2086             span_lint_and_then(
2087                 cx,
2088                 CLONE_DOUBLE_REF,
2089                 expr.span,
2090                 "using `clone` on a double-reference; \
2091                 this will copy the reference instead of cloning the inner type",
2092                 |diag| {
2093                     if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
2094                         let mut ty = innermost;
2095                         let mut n = 0;
2096                         while let ty::Ref(_, inner, _) = ty.kind {
2097                             ty = inner;
2098                             n += 1;
2099                         }
2100                         let refs: String = iter::repeat('&').take(n + 1).collect();
2101                         let derefs: String = iter::repeat('*').take(n).collect();
2102                         let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
2103                         diag.span_suggestion(
2104                             expr.span,
2105                             "try dereferencing it",
2106                             format!("{}({}{}).clone()", refs, derefs, snip.deref()),
2107                             Applicability::MaybeIncorrect,
2108                         );
2109                         diag.span_suggestion(
2110                             expr.span,
2111                             "or try being explicit if you are sure, that you want to clone a reference",
2112                             explicit,
2113                             Applicability::MaybeIncorrect,
2114                         );
2115                     }
2116                 },
2117             );
2118             return; // don't report clone_on_copy
2119         }
2120     }
2121
2122     if is_copy(cx, ty) {
2123         let snip;
2124         if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) {
2125             let parent = cx.tcx.hir().get_parent_node(expr.hir_id);
2126             match &cx.tcx.hir().get(parent) {
2127                 hir::Node::Expr(parent) => match parent.kind {
2128                     // &*x is a nop, &x.clone() is not
2129                     hir::ExprKind::AddrOf(..) => return,
2130                     // (*x).func() is useless, x.clone().func() can work in case func borrows mutably
2131                     hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => {
2132                         return;
2133                     },
2134
2135                     _ => {},
2136                 },
2137                 hir::Node::Stmt(stmt) => {
2138                     if let hir::StmtKind::Local(ref loc) = stmt.kind {
2139                         if let hir::PatKind::Ref(..) = loc.pat.kind {
2140                             // let ref y = *x borrows x, let ref y = x.clone() does not
2141                             return;
2142                         }
2143                     }
2144                 },
2145                 _ => {},
2146             }
2147
2148             // x.clone() might have dereferenced x, possibly through Deref impls
2149             if cx.typeck_results().expr_ty(arg) == ty {
2150                 snip = Some(("try removing the `clone` call", format!("{}", snippet)));
2151             } else {
2152                 let deref_count = cx
2153                     .typeck_results()
2154                     .expr_adjustments(arg)
2155                     .iter()
2156                     .filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_)))
2157                     .count();
2158                 let derefs: String = iter::repeat('*').take(deref_count).collect();
2159                 snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
2160             }
2161         } else {
2162             snip = None;
2163         }
2164         span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |diag| {
2165             if let Some((text, snip)) = snip {
2166                 diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable);
2167             }
2168         });
2169     }
2170 }
2171
2172 fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
2173     let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(arg));
2174
2175     if let ty::Adt(_, subst) = obj_ty.kind {
2176         let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
2177             "Rc"
2178         } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) {
2179             "Arc"
2180         } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) {
2181             "Weak"
2182         } else {
2183             return;
2184         };
2185
2186         let snippet = snippet_with_macro_callsite(cx, arg.span, "_");
2187
2188         span_lint_and_sugg(
2189             cx,
2190             CLONE_ON_REF_PTR,
2191             expr.span,
2192             "using `.clone()` on a ref-counted pointer",
2193             "try this",
2194             format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet),
2195             Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak
2196         );
2197     }
2198 }
2199
2200 fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
2201     let arg = &args[1];
2202     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
2203         let target = &arglists[0][0];
2204         let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(target));
2205         let ref_str = if self_ty.kind == ty::Str {
2206             ""
2207         } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
2208             "&"
2209         } else {
2210             return;
2211         };
2212
2213         let mut applicability = Applicability::MachineApplicable;
2214         span_lint_and_sugg(
2215             cx,
2216             STRING_EXTEND_CHARS,
2217             expr.span,
2218             "calling `.extend(_.chars())`",
2219             "try this",
2220             format!(
2221                 "{}.push_str({}{})",
2222                 snippet_with_applicability(cx, args[0].span, "_", &mut applicability),
2223                 ref_str,
2224                 snippet_with_applicability(cx, target.span, "_", &mut applicability)
2225             ),
2226             applicability,
2227         );
2228     }
2229 }
2230
2231 fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
2232     let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
2233     if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) {
2234         lint_string_extend(cx, expr, args);
2235     }
2236 }
2237
2238 fn lint_cstring_as_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, source: &hir::Expr<'_>, unwrap: &hir::Expr<'_>) {
2239     if_chain! {
2240         let source_type = cx.typeck_results().expr_ty(source);
2241         if let ty::Adt(def, substs) = source_type.kind;
2242         if cx.tcx.is_diagnostic_item(sym!(result_type), def.did);
2243         if match_type(cx, substs.type_at(0), &paths::CSTRING);
2244         then {
2245             span_lint_and_then(
2246                 cx,
2247                 TEMPORARY_CSTRING_AS_PTR,
2248                 expr.span,
2249                 "you are getting the inner pointer of a temporary `CString`",
2250                 |diag| {
2251                     diag.note("that pointer will be invalid outside this expression");
2252                     diag.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime");
2253                 });
2254         }
2255     }
2256 }
2257
2258 fn lint_iter_cloned_collect<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
2259     if_chain! {
2260         if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym!(vec_type));
2261         if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0]));
2262         if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
2263
2264         then {
2265             span_lint_and_sugg(
2266                 cx,
2267                 ITER_CLONED_COLLECT,
2268                 to_replace,
2269                 "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
2270                 more readable",
2271                 "try",
2272                 ".to_vec()".to_string(),
2273                 Applicability::MachineApplicable,
2274             );
2275         }
2276     }
2277 }
2278
2279 fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) {
2280     fn check_fold_with_op(
2281         cx: &LateContext<'_>,
2282         expr: &hir::Expr<'_>,
2283         fold_args: &[hir::Expr<'_>],
2284         fold_span: Span,
2285         op: hir::BinOpKind,
2286         replacement_method_name: &str,
2287         replacement_has_args: bool,
2288     ) {
2289         if_chain! {
2290             // Extract the body of the closure passed to fold
2291             if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].kind;
2292             let closure_body = cx.tcx.hir().body(body_id);
2293             let closure_expr = remove_blocks(&closure_body.value);
2294
2295             // Check if the closure body is of the form `acc <op> some_expr(x)`
2296             if let hir::ExprKind::Binary(ref bin_op, ref left_expr, ref right_expr) = closure_expr.kind;
2297             if bin_op.node == op;
2298
2299             // Extract the names of the two arguments to the closure
2300             if let Some(first_arg_ident) = get_arg_name(&closure_body.params[0].pat);
2301             if let Some(second_arg_ident) = get_arg_name(&closure_body.params[1].pat);
2302
2303             if match_var(&*left_expr, first_arg_ident);
2304             if replacement_has_args || match_var(&*right_expr, second_arg_ident);
2305
2306             then {
2307                 let mut applicability = Applicability::MachineApplicable;
2308                 let sugg = if replacement_has_args {
2309                     format!(
2310                         "{replacement}(|{s}| {r})",
2311                         replacement = replacement_method_name,
2312                         s = second_arg_ident,
2313                         r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
2314                     )
2315                 } else {
2316                     format!(
2317                         "{replacement}()",
2318                         replacement = replacement_method_name,
2319                     )
2320                 };
2321
2322                 span_lint_and_sugg(
2323                     cx,
2324                     UNNECESSARY_FOLD,
2325                     fold_span.with_hi(expr.span.hi()),
2326                     // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
2327                     "this `.fold` can be written more succinctly using another method",
2328                     "try",
2329                     sugg,
2330                     applicability,
2331                 );
2332             }
2333         }
2334     }
2335
2336     // Check that this is a call to Iterator::fold rather than just some function called fold
2337     if !match_trait_method(cx, expr, &paths::ITERATOR) {
2338         return;
2339     }
2340
2341     assert!(
2342         fold_args.len() == 3,
2343         "Expected fold_args to have three entries - the receiver, the initial value and the closure"
2344     );
2345
2346     // Check if the first argument to .fold is a suitable literal
2347     if let hir::ExprKind::Lit(ref lit) = fold_args[1].kind {
2348         match lit.node {
2349             ast::LitKind::Bool(false) => {
2350                 check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true)
2351             },
2352             ast::LitKind::Bool(true) => {
2353                 check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true)
2354             },
2355             ast::LitKind::Int(0, _) => {
2356                 check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false)
2357             },
2358             ast::LitKind::Int(1, _) => {
2359                 check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false)
2360             },
2361             _ => (),
2362         }
2363     }
2364 }
2365
2366 fn lint_step_by<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) {
2367     if match_trait_method(cx, expr, &paths::ITERATOR) {
2368         if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) {
2369             span_lint(
2370                 cx,
2371                 ITERATOR_STEP_BY_ZERO,
2372                 expr.span,
2373                 "Iterator::step_by(0) will panic at runtime",
2374             );
2375         }
2376     }
2377 }
2378
2379 fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
2380     let caller_expr = &iter_args[0];
2381
2382     // Skip lint if the `iter().next()` expression is a for loop argument,
2383     // since it is already covered by `&loops::ITER_NEXT_LOOP`
2384     let mut parent_expr_opt = get_parent_expr(cx, expr);
2385     while let Some(parent_expr) = parent_expr_opt {
2386         if higher::for_loop(parent_expr).is_some() {
2387             return;
2388         }
2389         parent_expr_opt = get_parent_expr(cx, parent_expr);
2390     }
2391
2392     if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() {
2393         // caller is a Slice
2394         if_chain! {
2395             if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
2396             if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
2397                 = higher::range(index_expr);
2398             if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
2399             if let ast::LitKind::Int(start_idx, _) = start_lit.node;
2400             then {
2401                 let mut applicability = Applicability::MachineApplicable;
2402                 span_lint_and_sugg(
2403                     cx,
2404                     ITER_NEXT_SLICE,
2405                     expr.span,
2406                     "using `.iter().next()` on a Slice without end index",
2407                     "try calling",
2408                     format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx),
2409                     applicability,
2410                 );
2411             }
2412         }
2413     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type))
2414         || matches!(
2415             &walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind,
2416             ty::Array(_, _)
2417         )
2418     {
2419         // caller is a Vec or an Array
2420         let mut applicability = Applicability::MachineApplicable;
2421         span_lint_and_sugg(
2422             cx,
2423             ITER_NEXT_SLICE,
2424             expr.span,
2425             "using `.iter().next()` on an array",
2426             "try calling",
2427             format!(
2428                 "{}.get(0)",
2429                 snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability)
2430             ),
2431             applicability,
2432         );
2433     }
2434 }
2435
2436 fn lint_iter_nth<'tcx>(
2437     cx: &LateContext<'tcx>,
2438     expr: &hir::Expr<'_>,
2439     nth_and_iter_args: &[&'tcx [hir::Expr<'tcx>]],
2440     is_mut: bool,
2441 ) {
2442     let iter_args = nth_and_iter_args[1];
2443     let mut_str = if is_mut { "_mut" } else { "" };
2444     let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() {
2445         "slice"
2446     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vec_type)) {
2447         "Vec"
2448     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) {
2449         "VecDeque"
2450     } else {
2451         let nth_args = nth_and_iter_args[0];
2452         lint_iter_nth_zero(cx, expr, &nth_args);
2453         return; // caller is not a type that we want to lint
2454     };
2455
2456     span_lint_and_help(
2457         cx,
2458         ITER_NTH,
2459         expr.span,
2460         &format!("called `.iter{0}().nth()` on a {1}", mut_str, caller_type),
2461         None,
2462         &format!("calling `.get{}()` is both faster and more readable", mut_str),
2463     );
2464 }
2465
2466 fn lint_iter_nth_zero<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) {
2467     if_chain! {
2468         if match_trait_method(cx, expr, &paths::ITERATOR);
2469         if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]);
2470         then {
2471             let mut applicability = Applicability::MachineApplicable;
2472             span_lint_and_sugg(
2473                 cx,
2474                 ITER_NTH_ZERO,
2475                 expr.span,
2476                 "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent",
2477                 "try calling `.next()` instead of `.nth(0)`",
2478                 format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)),
2479                 applicability,
2480             );
2481         }
2482     }
2483 }
2484
2485 fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: &'tcx [hir::Expr<'_>], is_mut: bool) {
2486     // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
2487     // because they do not implement `IndexMut`
2488     let mut applicability = Applicability::MachineApplicable;
2489     let expr_ty = cx.typeck_results().expr_ty(&get_args[0]);
2490     let get_args_str = if get_args.len() > 1 {
2491         snippet_with_applicability(cx, get_args[1].span, "_", &mut applicability)
2492     } else {
2493         return; // not linting on a .get().unwrap() chain or variant
2494     };
2495     let mut needs_ref;
2496     let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
2497         needs_ref = get_args_str.parse::<usize>().is_ok();
2498         "slice"
2499     } else if is_type_diagnostic_item(cx, expr_ty, sym!(vec_type)) {
2500         needs_ref = get_args_str.parse::<usize>().is_ok();
2501         "Vec"
2502     } else if is_type_diagnostic_item(cx, expr_ty, sym!(vecdeque_type)) {
2503         needs_ref = get_args_str.parse::<usize>().is_ok();
2504         "VecDeque"
2505     } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym!(hashmap_type)) {
2506         needs_ref = true;
2507         "HashMap"
2508     } else if !is_mut && match_type(cx, expr_ty, &paths::BTREEMAP) {
2509         needs_ref = true;
2510         "BTreeMap"
2511     } else {
2512         return; // caller is not a type that we want to lint
2513     };
2514
2515     let mut span = expr.span;
2516
2517     // Handle the case where the result is immediately dereferenced
2518     // by not requiring ref and pulling the dereference into the
2519     // suggestion.
2520     if_chain! {
2521         if needs_ref;
2522         if let Some(parent) = get_parent_expr(cx, expr);
2523         if let hir::ExprKind::Unary(hir::UnOp::UnDeref, _) = parent.kind;
2524         then {
2525             needs_ref = false;
2526             span = parent.span;
2527         }
2528     }
2529
2530     let mut_str = if is_mut { "_mut" } else { "" };
2531     let borrow_str = if !needs_ref {
2532         ""
2533     } else if is_mut {
2534         "&mut "
2535     } else {
2536         "&"
2537     };
2538
2539     span_lint_and_sugg(
2540         cx,
2541         GET_UNWRAP,
2542         span,
2543         &format!(
2544             "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
2545             mut_str, caller_type
2546         ),
2547         "try this",
2548         format!(
2549             "{}{}[{}]",
2550             borrow_str,
2551             snippet_with_applicability(cx, get_args[0].span, "_", &mut applicability),
2552             get_args_str
2553         ),
2554         applicability,
2555     );
2556 }
2557
2558 fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) {
2559     // lint if caller of skip is an Iterator
2560     if match_trait_method(cx, expr, &paths::ITERATOR) {
2561         if let [caller, n] = skip_args {
2562             let hint = format!(".nth({})", snippet(cx, n.span, ".."));
2563             span_lint_and_sugg(
2564                 cx,
2565                 ITER_SKIP_NEXT,
2566                 expr.span.trim_start(caller.span).unwrap(),
2567                 "called `skip(x).next()` on an iterator",
2568                 "use `nth` instead",
2569                 hint,
2570                 Applicability::MachineApplicable,
2571             );
2572         }
2573     }
2574 }
2575
2576 fn derefs_to_slice<'tcx>(
2577     cx: &LateContext<'tcx>,
2578     expr: &'tcx hir::Expr<'tcx>,
2579     ty: Ty<'tcx>,
2580 ) -> Option<&'tcx hir::Expr<'tcx>> {
2581     fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
2582         match ty.kind {
2583             ty::Slice(_) => true,
2584             ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
2585             ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym!(vec_type)),
2586             ty::Array(_, size) => size
2587                 .try_eval_usize(cx.tcx, cx.param_env)
2588                 .map_or(false, |size| size < 32),
2589             ty::Ref(_, inner, _) => may_slice(cx, inner),
2590             _ => false,
2591         }
2592     }
2593
2594     if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind {
2595         if path.ident.name == sym!(iter) && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) {
2596             Some(&args[0])
2597         } else {
2598             None
2599         }
2600     } else {
2601         match ty.kind {
2602             ty::Slice(_) => Some(expr),
2603             ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
2604             ty::Ref(_, inner, _) => {
2605                 if may_slice(cx, inner) {
2606                     Some(expr)
2607                 } else {
2608                     None
2609                 }
2610             },
2611             _ => None,
2612         }
2613     }
2614 }
2615
2616 /// lint use of `unwrap()` for `Option`s and `Result`s
2617 fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
2618     let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&unwrap_args[0]));
2619
2620     let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
2621         Some((UNWRAP_USED, "an Option", "None"))
2622     } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) {
2623         Some((UNWRAP_USED, "a Result", "Err"))
2624     } else {
2625         None
2626     };
2627
2628     if let Some((lint, kind, none_value)) = mess {
2629         span_lint_and_help(
2630             cx,
2631             lint,
2632             expr.span,
2633             &format!("used `unwrap()` on `{}` value", kind,),
2634             None,
2635             &format!(
2636                 "if you don't want to handle the `{}` case gracefully, consider \
2637                 using `expect()` to provide a better panic message",
2638                 none_value,
2639             ),
2640         );
2641     }
2642 }
2643
2644 /// lint use of `expect()` for `Option`s and `Result`s
2645 fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
2646     let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&expect_args[0]));
2647
2648     let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
2649         Some((EXPECT_USED, "an Option", "None"))
2650     } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) {
2651         Some((EXPECT_USED, "a Result", "Err"))
2652     } else {
2653         None
2654     };
2655
2656     if let Some((lint, kind, none_value)) = mess {
2657         span_lint_and_help(
2658             cx,
2659             lint,
2660             expr.span,
2661             &format!("used `expect()` on `{}` value", kind,),
2662             None,
2663             &format!("if this value is an `{}`, it will panic", none_value,),
2664         );
2665     }
2666 }
2667
2668 /// lint use of `ok().expect()` for `Result`s
2669 fn lint_ok_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) {
2670     if_chain! {
2671         // lint if the caller of `ok()` is a `Result`
2672         if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym!(result_type));
2673         let result_type = cx.typeck_results().expr_ty(&ok_args[0]);
2674         if let Some(error_type) = get_error_type(cx, result_type);
2675         if has_debug_impl(error_type, cx);
2676
2677         then {
2678             span_lint_and_help(
2679                 cx,
2680                 OK_EXPECT,
2681                 expr.span,
2682                 "called `ok().expect()` on a `Result` value",
2683                 None,
2684                 "you can call `expect()` directly on the `Result`",
2685             );
2686         }
2687     }
2688 }
2689
2690 /// lint use of `map().flatten()` for `Iterators` and 'Options'
2691 fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) {
2692     // lint if caller of `.map().flatten()` is an Iterator
2693     if match_trait_method(cx, expr, &paths::ITERATOR) {
2694         let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]);
2695         let is_map_to_option = match map_closure_ty.kind {
2696             ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => {
2697                 let map_closure_sig = match map_closure_ty.kind {
2698                     ty::Closure(_, substs) => substs.as_closure().sig(),
2699                     _ => map_closure_ty.fn_sig(cx.tcx),
2700                 };
2701                 let map_closure_return_ty = cx.tcx.erase_late_bound_regions(&map_closure_sig.output());
2702                 is_type_diagnostic_item(cx, map_closure_return_ty, sym!(option_type))
2703             },
2704             _ => false,
2705         };
2706
2707         let method_to_use = if is_map_to_option {
2708             // `(...).map(...)` has type `impl Iterator<Item=Option<...>>
2709             "filter_map"
2710         } else {
2711             // `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
2712             "flat_map"
2713         };
2714         let func_snippet = snippet(cx, map_args[1].span, "..");
2715         let hint = format!(".{0}({1})", method_to_use, func_snippet);
2716         span_lint_and_sugg(
2717             cx,
2718             MAP_FLATTEN,
2719             expr.span.with_lo(map_args[0].span.hi()),
2720             "called `map(..).flatten()` on an `Iterator`",
2721             &format!("try using `{}` instead", method_to_use),
2722             hint,
2723             Applicability::MachineApplicable,
2724         );
2725     }
2726
2727     // lint if caller of `.map().flatten()` is an Option
2728     if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)) {
2729         let func_snippet = snippet(cx, map_args[1].span, "..");
2730         let hint = format!(".and_then({})", func_snippet);
2731         span_lint_and_sugg(
2732             cx,
2733             MAP_FLATTEN,
2734             expr.span.with_lo(map_args[0].span.hi()),
2735             "called `map(..).flatten()` on an `Option`",
2736             "try using `and_then` instead",
2737             hint,
2738             Applicability::MachineApplicable,
2739         );
2740     }
2741 }
2742
2743 /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
2744 /// Return true if lint triggered
2745 fn lint_map_unwrap_or_else<'tcx>(
2746     cx: &LateContext<'tcx>,
2747     expr: &'tcx hir::Expr<'_>,
2748     map_args: &'tcx [hir::Expr<'_>],
2749     unwrap_args: &'tcx [hir::Expr<'_>],
2750 ) -> bool {
2751     // lint if the caller of `map()` is an `Option`
2752     let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type));
2753     let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(result_type));
2754
2755     if is_option || is_result {
2756         // Don't make a suggestion that may fail to compile due to mutably borrowing
2757         // the same variable twice.
2758         let map_mutated_vars = mutated_variables(&map_args[0], cx);
2759         let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx);
2760         if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) {
2761             if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() {
2762                 return false;
2763             }
2764         } else {
2765             return false;
2766         }
2767
2768         // lint message
2769         let msg = if is_option {
2770             "called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling \
2771             `map_or_else(g, f)` instead"
2772         } else {
2773             "called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling \
2774             `.map_or_else(g, f)` instead"
2775         };
2776         // get snippets for args to map() and unwrap_or_else()
2777         let map_snippet = snippet(cx, map_args[1].span, "..");
2778         let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
2779         // lint, with note if neither arg is > 1 line and both map() and
2780         // unwrap_or_else() have the same span
2781         let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
2782         let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt();
2783         if same_span && !multiline {
2784             span_lint_and_note(
2785                 cx,
2786                 MAP_UNWRAP_OR,
2787                 expr.span,
2788                 msg,
2789                 None,
2790                 &format!(
2791                     "replace `map({0}).unwrap_or_else({1})` with `map_or_else({1}, {0})`",
2792                     map_snippet, unwrap_snippet,
2793                 ),
2794             );
2795             return true;
2796         } else if same_span && multiline {
2797             span_lint(cx, MAP_UNWRAP_OR, expr.span, msg);
2798             return true;
2799         }
2800     }
2801
2802     false
2803 }
2804
2805 /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
2806 fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) {
2807     let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(option_type));
2808     let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(result_type));
2809
2810     // There are two variants of this `map_or` lint:
2811     // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
2812     // (2) using `map_or` as a combinator instead of `and_then`
2813     //
2814     // (For this lint) we don't care if any other type calls `map_or`
2815     if !is_option && !is_result {
2816         return;
2817     }
2818
2819     let (lint_name, msg, instead, hint) = {
2820         let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind {
2821             match_qpath(qpath, &paths::OPTION_NONE)
2822         } else {
2823             return;
2824         };
2825
2826         if !default_arg_is_none {
2827             // nothing to lint!
2828             return;
2829         }
2830
2831         let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_or_args[2].kind {
2832             match_qpath(qpath, &paths::OPTION_SOME)
2833         } else {
2834             false
2835         };
2836
2837         if is_option {
2838             let self_snippet = snippet(cx, map_or_args[0].span, "..");
2839             let func_snippet = snippet(cx, map_or_args[2].span, "..");
2840             let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \
2841                        `and_then(f)` instead";
2842             (
2843                 OPTION_MAP_OR_NONE,
2844                 msg,
2845                 "try using `and_then` instead",
2846                 format!("{0}.and_then({1})", self_snippet, func_snippet),
2847             )
2848         } else if f_arg_is_some {
2849             let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
2850                        `ok()` instead";
2851             let self_snippet = snippet(cx, map_or_args[0].span, "..");
2852             (
2853                 RESULT_MAP_OR_INTO_OPTION,
2854                 msg,
2855                 "try using `ok` instead",
2856                 format!("{0}.ok()", self_snippet),
2857             )
2858         } else {
2859             // nothing to lint!
2860             return;
2861         }
2862     };
2863
2864     span_lint_and_sugg(
2865         cx,
2866         lint_name,
2867         expr.span,
2868         msg,
2869         instead,
2870         hint,
2871         Applicability::MachineApplicable,
2872     );
2873 }
2874
2875 /// lint use of `filter().next()` for `Iterators`
2876 fn lint_filter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) {
2877     // lint if caller of `.filter().next()` is an Iterator
2878     if match_trait_method(cx, expr, &paths::ITERATOR) {
2879         let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
2880                    `.find(p)` instead.";
2881         let filter_snippet = snippet(cx, filter_args[1].span, "..");
2882         if filter_snippet.lines().count() <= 1 {
2883             // add note if not multi-line
2884             span_lint_and_note(
2885                 cx,
2886                 FILTER_NEXT,
2887                 expr.span,
2888                 msg,
2889                 None,
2890                 &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet),
2891             );
2892         } else {
2893             span_lint(cx, FILTER_NEXT, expr.span, msg);
2894         }
2895     }
2896 }
2897
2898 /// lint use of `skip_while().next()` for `Iterators`
2899 fn lint_skip_while_next<'tcx>(
2900     cx: &LateContext<'tcx>,
2901     expr: &'tcx hir::Expr<'_>,
2902     _skip_while_args: &'tcx [hir::Expr<'_>],
2903 ) {
2904     // lint if caller of `.skip_while().next()` is an Iterator
2905     if match_trait_method(cx, expr, &paths::ITERATOR) {
2906         span_lint_and_help(
2907             cx,
2908             SKIP_WHILE_NEXT,
2909             expr.span,
2910             "called `skip_while(p).next()` on an `Iterator`",
2911             None,
2912             "this is more succinctly expressed by calling `.find(!p)` instead",
2913         );
2914     }
2915 }
2916
2917 /// lint use of `filter().map()` for `Iterators`
2918 fn lint_filter_map<'tcx>(
2919     cx: &LateContext<'tcx>,
2920     expr: &'tcx hir::Expr<'_>,
2921     _filter_args: &'tcx [hir::Expr<'_>],
2922     _map_args: &'tcx [hir::Expr<'_>],
2923 ) {
2924     // lint if caller of `.filter().map()` is an Iterator
2925     if match_trait_method(cx, expr, &paths::ITERATOR) {
2926         let msg = "called `filter(p).map(q)` on an `Iterator`";
2927         let hint = "this is more succinctly expressed by calling `.filter_map(..)` instead";
2928         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
2929     }
2930 }
2931
2932 /// lint use of `filter_map().next()` for `Iterators`
2933 fn lint_filter_map_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) {
2934     if match_trait_method(cx, expr, &paths::ITERATOR) {
2935         let msg = "called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
2936                    `.find_map(p)` instead.";
2937         let filter_snippet = snippet(cx, filter_args[1].span, "..");
2938         if filter_snippet.lines().count() <= 1 {
2939             span_lint_and_note(
2940                 cx,
2941                 FILTER_MAP_NEXT,
2942                 expr.span,
2943                 msg,
2944                 None,
2945                 &format!("replace `filter_map({0}).next()` with `find_map({0})`", filter_snippet),
2946             );
2947         } else {
2948             span_lint(cx, FILTER_MAP_NEXT, expr.span, msg);
2949         }
2950     }
2951 }
2952
2953 /// lint use of `find().map()` for `Iterators`
2954 fn lint_find_map<'tcx>(
2955     cx: &LateContext<'tcx>,
2956     expr: &'tcx hir::Expr<'_>,
2957     _find_args: &'tcx [hir::Expr<'_>],
2958     map_args: &'tcx [hir::Expr<'_>],
2959 ) {
2960     // lint if caller of `.filter().map()` is an Iterator
2961     if match_trait_method(cx, &map_args[0], &paths::ITERATOR) {
2962         let msg = "called `find(p).map(q)` on an `Iterator`";
2963         let hint = "this is more succinctly expressed by calling `.find_map(..)` instead";
2964         span_lint_and_help(cx, FIND_MAP, expr.span, msg, None, hint);
2965     }
2966 }
2967
2968 /// lint use of `filter_map().map()` for `Iterators`
2969 fn lint_filter_map_map<'tcx>(
2970     cx: &LateContext<'tcx>,
2971     expr: &'tcx hir::Expr<'_>,
2972     _filter_args: &'tcx [hir::Expr<'_>],
2973     _map_args: &'tcx [hir::Expr<'_>],
2974 ) {
2975     // lint if caller of `.filter().map()` is an Iterator
2976     if match_trait_method(cx, expr, &paths::ITERATOR) {
2977         let msg = "called `filter_map(p).map(q)` on an `Iterator`";
2978         let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead";
2979         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
2980     }
2981 }
2982
2983 /// lint use of `filter().flat_map()` for `Iterators`
2984 fn lint_filter_flat_map<'tcx>(
2985     cx: &LateContext<'tcx>,
2986     expr: &'tcx hir::Expr<'_>,
2987     _filter_args: &'tcx [hir::Expr<'_>],
2988     _map_args: &'tcx [hir::Expr<'_>],
2989 ) {
2990     // lint if caller of `.filter().flat_map()` is an Iterator
2991     if match_trait_method(cx, expr, &paths::ITERATOR) {
2992         let msg = "called `filter(p).flat_map(q)` on an `Iterator`";
2993         let hint = "this is more succinctly expressed by calling `.flat_map(..)` \
2994                     and filtering by returning `iter::empty()`";
2995         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
2996     }
2997 }
2998
2999 /// lint use of `filter_map().flat_map()` for `Iterators`
3000 fn lint_filter_map_flat_map<'tcx>(
3001     cx: &LateContext<'tcx>,
3002     expr: &'tcx hir::Expr<'_>,
3003     _filter_args: &'tcx [hir::Expr<'_>],
3004     _map_args: &'tcx [hir::Expr<'_>],
3005 ) {
3006     // lint if caller of `.filter_map().flat_map()` is an Iterator
3007     if match_trait_method(cx, expr, &paths::ITERATOR) {
3008         let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`";
3009         let hint = "this is more succinctly expressed by calling `.flat_map(..)` \
3010                     and filtering by returning `iter::empty()`";
3011         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
3012     }
3013 }
3014
3015 /// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient
3016 fn lint_flat_map_identity<'tcx>(
3017     cx: &LateContext<'tcx>,
3018     expr: &'tcx hir::Expr<'_>,
3019     flat_map_args: &'tcx [hir::Expr<'_>],
3020     flat_map_span: Span,
3021 ) {
3022     if match_trait_method(cx, expr, &paths::ITERATOR) {
3023         let arg_node = &flat_map_args[1].kind;
3024
3025         let apply_lint = |message: &str| {
3026             span_lint_and_sugg(
3027                 cx,
3028                 FLAT_MAP_IDENTITY,
3029                 flat_map_span.with_hi(expr.span.hi()),
3030                 message,
3031                 "try",
3032                 "flatten()".to_string(),
3033                 Applicability::MachineApplicable,
3034             );
3035         };
3036
3037         if_chain! {
3038             if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node;
3039             let body = cx.tcx.hir().body(*body_id);
3040
3041             if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind;
3042             if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind;
3043
3044             if path.segments.len() == 1;
3045             if path.segments[0].ident.as_str() == binding_ident.as_str();
3046
3047             then {
3048                 apply_lint("called `flat_map(|x| x)` on an `Iterator`");
3049             }
3050         }
3051
3052         if_chain! {
3053             if let hir::ExprKind::Path(ref qpath) = arg_node;
3054
3055             if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY);
3056
3057             then {
3058                 apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`");
3059             }
3060         }
3061     }
3062 }
3063
3064 /// lint searching an Iterator followed by `is_some()`
3065 fn lint_search_is_some<'tcx>(
3066     cx: &LateContext<'tcx>,
3067     expr: &'tcx hir::Expr<'_>,
3068     search_method: &str,
3069     search_args: &'tcx [hir::Expr<'_>],
3070     is_some_args: &'tcx [hir::Expr<'_>],
3071     method_span: Span,
3072 ) {
3073     // lint if caller of search is an Iterator
3074     if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) {
3075         let msg = format!(
3076             "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \
3077              expressed by calling `any()`.",
3078             search_method
3079         );
3080         let search_snippet = snippet(cx, search_args[1].span, "..");
3081         if search_snippet.lines().count() <= 1 {
3082             // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
3083             // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
3084             let any_search_snippet = if_chain! {
3085                 if search_method == "find";
3086                 if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].kind;
3087                 let closure_body = cx.tcx.hir().body(body_id);
3088                 if let Some(closure_arg) = closure_body.params.get(0);
3089                 then {
3090                     if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
3091                         Some(search_snippet.replacen('&', "", 1))
3092                     } else if let Some(name) = get_arg_name(&closure_arg.pat) {
3093                         Some(search_snippet.replace(&format!("*{}", name), &name.as_str()))
3094                     } else {
3095                         None
3096                     }
3097                 } else {
3098                     None
3099                 }
3100             };
3101             // add note if not multi-line
3102             span_lint_and_sugg(
3103                 cx,
3104                 SEARCH_IS_SOME,
3105                 method_span.with_hi(expr.span.hi()),
3106                 &msg,
3107                 "try this",
3108                 format!(
3109                     "any({})",
3110                     any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
3111                 ),
3112                 Applicability::MachineApplicable,
3113             );
3114         } else {
3115             span_lint(cx, SEARCH_IS_SOME, expr.span, &msg);
3116         }
3117     }
3118 }
3119
3120 /// Used for `lint_binary_expr_with_method_call`.
3121 #[derive(Copy, Clone)]
3122 struct BinaryExprInfo<'a> {
3123     expr: &'a hir::Expr<'a>,
3124     chain: &'a hir::Expr<'a>,
3125     other: &'a hir::Expr<'a>,
3126     eq: bool,
3127 }
3128
3129 /// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
3130 fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExprInfo<'_>) {
3131     macro_rules! lint_with_both_lhs_and_rhs {
3132         ($func:ident, $cx:expr, $info:ident) => {
3133             if !$func($cx, $info) {
3134                 ::std::mem::swap(&mut $info.chain, &mut $info.other);
3135                 if $func($cx, $info) {
3136                     return;
3137                 }
3138             }
3139         };
3140     }
3141
3142     lint_with_both_lhs_and_rhs!(lint_chars_next_cmp, cx, info);
3143     lint_with_both_lhs_and_rhs!(lint_chars_last_cmp, cx, info);
3144     lint_with_both_lhs_and_rhs!(lint_chars_next_cmp_with_unwrap, cx, info);
3145     lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info);
3146 }
3147
3148 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
3149 fn lint_chars_cmp(
3150     cx: &LateContext<'_>,
3151     info: &BinaryExprInfo<'_>,
3152     chain_methods: &[&str],
3153     lint: &'static Lint,
3154     suggest: &str,
3155 ) -> bool {
3156     if_chain! {
3157         if let Some(args) = method_chain_args(info.chain, chain_methods);
3158         if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.kind;
3159         if arg_char.len() == 1;
3160         if let hir::ExprKind::Path(ref qpath) = fun.kind;
3161         if let Some(segment) = single_segment_path(qpath);
3162         if segment.ident.name == sym!(Some);
3163         then {
3164             let mut applicability = Applicability::MachineApplicable;
3165             let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty_adjusted(&args[0][0]));
3166
3167             if self_ty.kind != ty::Str {
3168                 return false;
3169             }
3170
3171             span_lint_and_sugg(
3172                 cx,
3173                 lint,
3174                 info.expr.span,
3175                 &format!("you should use the `{}` method", suggest),
3176                 "like this",
3177                 format!("{}{}.{}({})",
3178                         if info.eq { "" } else { "!" },
3179                         snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
3180                         suggest,
3181                         snippet_with_applicability(cx, arg_char[0].span, "_", &mut applicability)),
3182                 applicability,
3183             );
3184
3185             return true;
3186         }
3187     }
3188
3189     false
3190 }
3191
3192 /// Checks for the `CHARS_NEXT_CMP` lint.
3193 fn lint_chars_next_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
3194     lint_chars_cmp(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
3195 }
3196
3197 /// Checks for the `CHARS_LAST_CMP` lint.
3198 fn lint_chars_last_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
3199     if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
3200         true
3201     } else {
3202         lint_chars_cmp(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with")
3203     }
3204 }
3205
3206 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
3207 fn lint_chars_cmp_with_unwrap<'tcx>(
3208     cx: &LateContext<'tcx>,
3209     info: &BinaryExprInfo<'_>,
3210     chain_methods: &[&str],
3211     lint: &'static Lint,
3212     suggest: &str,
3213 ) -> bool {
3214     if_chain! {
3215         if let Some(args) = method_chain_args(info.chain, chain_methods);
3216         if let hir::ExprKind::Lit(ref lit) = info.other.kind;
3217         if let ast::LitKind::Char(c) = lit.node;
3218         then {
3219             let mut applicability = Applicability::MachineApplicable;
3220             span_lint_and_sugg(
3221                 cx,
3222                 lint,
3223                 info.expr.span,
3224                 &format!("you should use the `{}` method", suggest),
3225                 "like this",
3226                 format!("{}{}.{}('{}')",
3227                         if info.eq { "" } else { "!" },
3228                         snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
3229                         suggest,
3230                         c),
3231                 applicability,
3232             );
3233
3234             true
3235         } else {
3236             false
3237         }
3238     }
3239 }
3240
3241 /// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
3242 fn lint_chars_next_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
3243     lint_chars_cmp_with_unwrap(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
3244 }
3245
3246 /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
3247 fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
3248     if lint_chars_cmp_with_unwrap(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
3249         true
3250     } else {
3251         lint_chars_cmp_with_unwrap(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with")
3252     }
3253 }
3254
3255 fn get_hint_if_single_char_arg(
3256     cx: &LateContext<'_>,
3257     arg: &hir::Expr<'_>,
3258     applicability: &mut Applicability,
3259 ) -> Option<String> {
3260     if_chain! {
3261         if let hir::ExprKind::Lit(lit) = &arg.kind;
3262         if let ast::LitKind::Str(r, style) = lit.node;
3263         let string = r.as_str();
3264         if string.len() == 1;
3265         then {
3266             let snip = snippet_with_applicability(cx, arg.span, &string, applicability);
3267             let ch = if let ast::StrStyle::Raw(nhash) = style {
3268                 let nhash = nhash as usize;
3269                 // for raw string: r##"a"##
3270                 &snip[(nhash + 2)..(snip.len() - 1 - nhash)]
3271             } else {
3272                 // for regular string: "a"
3273                 &snip[1..(snip.len() - 1)]
3274             };
3275             let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch });
3276             Some(hint)
3277         } else {
3278             None
3279         }
3280     }
3281 }
3282
3283 /// lint for length-1 `str`s for methods in `PATTERN_METHODS`
3284 fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
3285     let mut applicability = Applicability::MachineApplicable;
3286     if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) {
3287         span_lint_and_sugg(
3288             cx,
3289             SINGLE_CHAR_PATTERN,
3290             arg.span,
3291             "single-character string constant used as pattern",
3292             "try using a `char` instead",
3293             hint,
3294             applicability,
3295         );
3296     }
3297 }
3298
3299 /// lint for length-1 `str`s as argument for `push_str`
3300 fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
3301     let mut applicability = Applicability::MachineApplicable;
3302     if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
3303         let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
3304         let sugg = format!("{}.push({})", base_string_snippet, extension_string);
3305         span_lint_and_sugg(
3306             cx,
3307             SINGLE_CHAR_PUSH_STR,
3308             expr.span,
3309             "calling `push_str()` using a single-character string literal",
3310             "consider using `push` with a character literal",
3311             sugg,
3312             applicability,
3313         );
3314     }
3315 }
3316
3317 /// Checks for the `USELESS_ASREF` lint.
3318 fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) {
3319     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
3320     // check if the call is to the actual `AsRef` or `AsMut` trait
3321     if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
3322         // check if the type after `as_ref` or `as_mut` is the same as before
3323         let recvr = &as_ref_args[0];
3324         let rcv_ty = cx.typeck_results().expr_ty(recvr);
3325         let res_ty = cx.typeck_results().expr_ty(expr);
3326         let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
3327         let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
3328         if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
3329             // allow the `as_ref` or `as_mut` if it is followed by another method call
3330             if_chain! {
3331                 if let Some(parent) = get_parent_expr(cx, expr);
3332                 if let hir::ExprKind::MethodCall(_, ref span, _, _) = parent.kind;
3333                 if span != &expr.span;
3334                 then {
3335                     return;
3336                 }
3337             }
3338
3339             let mut applicability = Applicability::MachineApplicable;
3340             span_lint_and_sugg(
3341                 cx,
3342                 USELESS_ASREF,
3343                 expr.span,
3344                 &format!("this call to `{}` does nothing", call_name),
3345                 "try this",
3346                 snippet_with_applicability(cx, recvr.span, "_", &mut applicability).to_string(),
3347                 applicability,
3348             );
3349         }
3350     }
3351 }
3352
3353 fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(&'static str, &'static str)> {
3354     has_iter_method(cx, self_ref_ty).map(|ty_name| {
3355         let mutbl = match self_ref_ty.kind {
3356             ty::Ref(_, _, mutbl) => mutbl,
3357             _ => unreachable!(),
3358         };
3359         let method_name = match mutbl {
3360             hir::Mutability::Not => "iter",
3361             hir::Mutability::Mut => "iter_mut",
3362         };
3363         (ty_name, method_name)
3364     })
3365 }
3366
3367 fn lint_into_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_>, method_span: Span) {
3368     if !match_trait_method(cx, expr, &paths::INTO_ITERATOR) {
3369         return;
3370     }
3371     if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) {
3372         span_lint_and_sugg(
3373             cx,
3374             INTO_ITER_ON_REF,
3375             method_span,
3376             &format!(
3377                 "this `.into_iter()` call is equivalent to `.{}()` and will not move the `{}`",
3378                 method_name, kind,
3379             ),
3380             "call directly",
3381             method_name.to_string(),
3382             Applicability::MachineApplicable,
3383         );
3384     }
3385 }
3386
3387 /// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter)
3388 fn lint_maybe_uninit(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Expr<'_>) {
3389     if_chain! {
3390         if let hir::ExprKind::Call(ref callee, ref args) = expr.kind;
3391         if args.is_empty();
3392         if let hir::ExprKind::Path(ref path) = callee.kind;
3393         if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT);
3394         if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(outer));
3395         then {
3396             span_lint(
3397                 cx,
3398                 UNINIT_ASSUMED_INIT,
3399                 outer.span,
3400                 "this call for this type may be undefined behavior"
3401             );
3402         }
3403     }
3404 }
3405
3406 fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
3407     match ty.kind {
3408         ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component),
3409         ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)),
3410         ty::Adt(ref adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT),
3411         _ => false,
3412     }
3413 }
3414
3415 fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
3416     span_lint_and_help(
3417         cx,
3418         SUSPICIOUS_MAP,
3419         expr.span,
3420         "this call to `map()` won't have an effect on the call to `count()`",
3421         None,
3422         "make sure you did not confuse `map` with `filter` or `for_each`",
3423     );
3424 }
3425
3426 /// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
3427 fn lint_option_as_ref_deref<'tcx>(
3428     cx: &LateContext<'tcx>,
3429     expr: &hir::Expr<'_>,
3430     as_ref_args: &[hir::Expr<'_>],
3431     map_args: &[hir::Expr<'_>],
3432     is_mut: bool,
3433 ) {
3434     let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
3435
3436     let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
3437     if !is_type_diagnostic_item(cx, option_ty, sym!(option_type)) {
3438         return;
3439     }
3440
3441     let deref_aliases: [&[&str]; 9] = [
3442         &paths::DEREF_TRAIT_METHOD,
3443         &paths::DEREF_MUT_TRAIT_METHOD,
3444         &paths::CSTRING_AS_C_STR,
3445         &paths::OS_STRING_AS_OS_STR,
3446         &paths::PATH_BUF_AS_PATH,
3447         &paths::STRING_AS_STR,
3448         &paths::STRING_AS_MUT_STR,
3449         &paths::VEC_AS_SLICE,
3450         &paths::VEC_AS_MUT_SLICE,
3451     ];
3452
3453     let is_deref = match map_args[1].kind {
3454         hir::ExprKind::Path(ref expr_qpath) => cx
3455             .qpath_res(expr_qpath, map_args[1].hir_id)
3456             .opt_def_id()
3457             .map_or(false, |fun_def_id| {
3458                 deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
3459             }),
3460         hir::ExprKind::Closure(_, _, body_id, _, _) => {
3461             let closure_body = cx.tcx.hir().body(body_id);
3462             let closure_expr = remove_blocks(&closure_body.value);
3463
3464             match &closure_expr.kind {
3465                 hir::ExprKind::MethodCall(_, _, args, _) => {
3466                     if_chain! {
3467                         if args.len() == 1;
3468                         if let hir::ExprKind::Path(qpath) = &args[0].kind;
3469                         if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, args[0].hir_id);
3470                         if closure_body.params[0].pat.hir_id == local_id;
3471                         let adj = cx
3472                             .typeck_results()
3473                             .expr_adjustments(&args[0])
3474                             .iter()
3475                             .map(|x| &x.kind)
3476                             .collect::<Box<[_]>>();
3477                         if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
3478                         then {
3479                             let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
3480                             deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
3481                         } else {
3482                             false
3483                         }
3484                     }
3485                 },
3486                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => {
3487                     if_chain! {
3488                         if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner1) = inner.kind;
3489                         if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner2) = inner1.kind;
3490                         if let hir::ExprKind::Path(ref qpath) = inner2.kind;
3491                         if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, inner2.hir_id);
3492                         then {
3493                             closure_body.params[0].pat.hir_id == local_id
3494                         } else {
3495                             false
3496                         }
3497                     }
3498                 },
3499                 _ => false,
3500             }
3501         },
3502         _ => false,
3503     };
3504
3505     if is_deref {
3506         let current_method = if is_mut {
3507             format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
3508         } else {
3509             format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
3510         };
3511         let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
3512         let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
3513         let suggestion = format!("try using {} instead", method_hint);
3514
3515         let msg = format!(
3516             "called `{0}` on an Option value. This can be done more directly \
3517             by calling `{1}` instead",
3518             current_method, hint
3519         );
3520         span_lint_and_sugg(
3521             cx,
3522             OPTION_AS_REF_DEREF,
3523             expr.span,
3524             &msg,
3525             &suggestion,
3526             hint,
3527             Applicability::MachineApplicable,
3528         );
3529     }
3530 }
3531
3532 /// Given a `Result<T, E>` type, return its error type (`E`).
3533 fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
3534     match ty.kind {
3535         ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym!(result_type)) => substs.types().nth(1),
3536         _ => None,
3537     }
3538 }
3539
3540 /// This checks whether a given type is known to implement Debug.
3541 fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
3542     cx.tcx
3543         .get_diagnostic_item(sym::debug_trait)
3544         .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
3545 }
3546
3547 enum Convention {
3548     Eq(&'static str),
3549     StartsWith(&'static str),
3550 }
3551
3552 #[rustfmt::skip]
3553 const CONVENTIONS: [(Convention, &[SelfKind]); 7] = [
3554     (Convention::Eq("new"), &[SelfKind::No]),
3555     (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]),
3556     (Convention::StartsWith("from_"), &[SelfKind::No]),
3557     (Convention::StartsWith("into_"), &[SelfKind::Value]),
3558     (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]),
3559     (Convention::Eq("to_mut"), &[SelfKind::RefMut]),
3560     (Convention::StartsWith("to_"), &[SelfKind::Ref]),
3561 ];
3562
3563 const FN_HEADER: hir::FnHeader = hir::FnHeader {
3564     unsafety: hir::Unsafety::Normal,
3565     constness: hir::Constness::NotConst,
3566     asyncness: hir::IsAsync::NotAsync,
3567     abi: rustc_target::spec::abi::Abi::Rust,
3568 };
3569
3570 struct ShouldImplTraitCase {
3571     trait_name: &'static str,
3572     method_name: &'static str,
3573     param_count: usize,
3574     fn_header: hir::FnHeader,
3575     // implicit self kind expected (none, self, &self, ...)
3576     self_kind: SelfKind,
3577     // checks against the output type
3578     output_type: OutType,
3579     // certain methods with explicit lifetimes can't implement the equivalent trait method
3580     lint_explicit_lifetime: bool,
3581 }
3582 impl ShouldImplTraitCase {
3583     const fn new(
3584         trait_name: &'static str,
3585         method_name: &'static str,
3586         param_count: usize,
3587         fn_header: hir::FnHeader,
3588         self_kind: SelfKind,
3589         output_type: OutType,
3590         lint_explicit_lifetime: bool,
3591     ) -> ShouldImplTraitCase {
3592         ShouldImplTraitCase {
3593             trait_name,
3594             method_name,
3595             param_count,
3596             fn_header,
3597             self_kind,
3598             output_type,
3599             lint_explicit_lifetime,
3600         }
3601     }
3602
3603     fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
3604         self.lint_explicit_lifetime
3605             || !impl_item.generics.params.iter().any(|p| {
3606                 matches!(
3607                     p.kind,
3608                     hir::GenericParamKind::Lifetime {
3609                         kind: hir::LifetimeParamKind::Explicit
3610                     }
3611                 )
3612             })
3613     }
3614 }
3615
3616 #[rustfmt::skip]
3617 const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
3618     ShouldImplTraitCase::new("std::ops::Add", "add",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3619     ShouldImplTraitCase::new("std::convert::AsMut", "as_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
3620     ShouldImplTraitCase::new("std::convert::AsRef", "as_ref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
3621     ShouldImplTraitCase::new("std::ops::BitAnd", "bitand",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3622     ShouldImplTraitCase::new("std::ops::BitOr", "bitor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3623     ShouldImplTraitCase::new("std::ops::BitXor", "bitxor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3624     ShouldImplTraitCase::new("std::borrow::Borrow", "borrow",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
3625     ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
3626     ShouldImplTraitCase::new("std::clone::Clone", "clone",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
3627     ShouldImplTraitCase::new("std::cmp::Ord", "cmp",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
3628     // FIXME: default doesn't work
3629     ShouldImplTraitCase::new("std::default::Default", "default",  0,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
3630     ShouldImplTraitCase::new("std::ops::Deref", "deref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
3631     ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
3632     ShouldImplTraitCase::new("std::ops::Div", "div",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3633     ShouldImplTraitCase::new("std::ops::Drop", "drop",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Unit, true),
3634     ShouldImplTraitCase::new("std::cmp::PartialEq", "eq",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Bool, true),
3635     ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
3636     ShouldImplTraitCase::new("std::str::FromStr", "from_str",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
3637     ShouldImplTraitCase::new("std::hash::Hash", "hash",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Unit, true),
3638     ShouldImplTraitCase::new("std::ops::Index", "index",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
3639     ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut",  2,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
3640     ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3641     ShouldImplTraitCase::new("std::ops::Mul", "mul",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3642     ShouldImplTraitCase::new("std::ops::Neg", "neg",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3643     ShouldImplTraitCase::new("std::iter::Iterator", "next",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Any, false),
3644     ShouldImplTraitCase::new("std::ops::Not", "not",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3645     ShouldImplTraitCase::new("std::ops::Rem", "rem",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3646     ShouldImplTraitCase::new("std::ops::Shl", "shl",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3647     ShouldImplTraitCase::new("std::ops::Shr", "shr",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3648     ShouldImplTraitCase::new("std::ops::Sub", "sub",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3649 ];
3650
3651 #[rustfmt::skip]
3652 const PATTERN_METHODS: [(&str, usize); 17] = [
3653     ("contains", 1),
3654     ("starts_with", 1),
3655     ("ends_with", 1),
3656     ("find", 1),
3657     ("rfind", 1),
3658     ("split", 1),
3659     ("rsplit", 1),
3660     ("split_terminator", 1),
3661     ("rsplit_terminator", 1),
3662     ("splitn", 2),
3663     ("rsplitn", 2),
3664     ("matches", 1),
3665     ("rmatches", 1),
3666     ("match_indices", 1),
3667     ("rmatch_indices", 1),
3668     ("trim_start_matches", 1),
3669     ("trim_end_matches", 1),
3670 ];
3671
3672 #[derive(Clone, Copy, PartialEq, Debug)]
3673 enum SelfKind {
3674     Value,
3675     Ref,
3676     RefMut,
3677     No,
3678 }
3679
3680 impl SelfKind {
3681     fn matches<'a>(self, cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
3682         fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'_>, ty: Ty<'_>) -> bool {
3683             if ty == parent_ty {
3684                 true
3685             } else if ty.is_box() {
3686                 ty.boxed_ty() == parent_ty
3687             } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
3688                 if let ty::Adt(_, substs) = ty.kind {
3689                     substs.types().next().map_or(false, |t| t == parent_ty)
3690                 } else {
3691                     false
3692                 }
3693             } else {
3694                 false
3695             }
3696         }
3697
3698         fn matches_ref<'a>(cx: &LateContext<'a>, mutability: hir::Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
3699             if let ty::Ref(_, t, m) = ty.kind {
3700                 return m == mutability && t == parent_ty;
3701             }
3702
3703             let trait_path = match mutability {
3704                 hir::Mutability::Not => &paths::ASREF_TRAIT,
3705                 hir::Mutability::Mut => &paths::ASMUT_TRAIT,
3706             };
3707
3708             let trait_def_id = match get_trait_def_id(cx, trait_path) {
3709                 Some(did) => did,
3710                 None => return false,
3711             };
3712             implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
3713         }
3714
3715         match self {
3716             Self::Value => matches_value(cx, parent_ty, ty),
3717             Self::Ref => matches_ref(cx, hir::Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
3718             Self::RefMut => matches_ref(cx, hir::Mutability::Mut, parent_ty, ty),
3719             Self::No => ty != parent_ty,
3720         }
3721     }
3722
3723     #[must_use]
3724     fn description(self) -> &'static str {
3725         match self {
3726             Self::Value => "self by value",
3727             Self::Ref => "self by reference",
3728             Self::RefMut => "self by mutable reference",
3729             Self::No => "no self",
3730         }
3731     }
3732 }
3733
3734 impl Convention {
3735     #[must_use]
3736     fn check(&self, other: &str) -> bool {
3737         match *self {
3738             Self::Eq(this) => this == other,
3739             Self::StartsWith(this) => other.starts_with(this) && this != other,
3740         }
3741     }
3742 }
3743
3744 impl fmt::Display for Convention {
3745     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
3746         match *self {
3747             Self::Eq(this) => this.fmt(f),
3748             Self::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)),
3749         }
3750     }
3751 }
3752
3753 #[derive(Clone, Copy)]
3754 enum OutType {
3755     Unit,
3756     Bool,
3757     Any,
3758     Ref,
3759 }
3760
3761 impl OutType {
3762     fn matches(self, cx: &LateContext<'_>, ty: &hir::FnRetTy<'_>) -> bool {
3763         let is_unit = |ty: &hir::Ty<'_>| SpanlessEq::new(cx).eq_ty_kind(&ty.kind, &hir::TyKind::Tup(&[]));
3764         match (self, ty) {
3765             (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true,
3766             (Self::Unit, &hir::FnRetTy::Return(ref ty)) if is_unit(ty) => true,
3767             (Self::Bool, &hir::FnRetTy::Return(ref ty)) if is_bool(ty) => true,
3768             (Self::Any, &hir::FnRetTy::Return(ref ty)) if !is_unit(ty) => true,
3769             (Self::Ref, &hir::FnRetTy::Return(ref ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)),
3770             _ => false,
3771         }
3772     }
3773 }
3774
3775 fn is_bool(ty: &hir::Ty<'_>) -> bool {
3776     if let hir::TyKind::Path(ref p) = ty.kind {
3777         match_qpath(p, &["bool"])
3778     } else {
3779         false
3780     }
3781 }
3782
3783 // Returns `true` if `expr` contains a return expression
3784 fn contains_return(expr: &hir::Expr<'_>) -> bool {
3785     struct RetCallFinder {
3786         found: bool,
3787     }
3788
3789     impl<'tcx> intravisit::Visitor<'tcx> for RetCallFinder {
3790         type Map = Map<'tcx>;
3791
3792         fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
3793             if self.found {
3794                 return;
3795             }
3796             if let hir::ExprKind::Ret(..) = &expr.kind {
3797                 self.found = true;
3798             } else {
3799                 intravisit::walk_expr(self, expr);
3800             }
3801         }
3802
3803         fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
3804             intravisit::NestedVisitorMap::None
3805         }
3806     }
3807
3808     let mut visitor = RetCallFinder { found: false };
3809     visitor.visit_expr(expr);
3810     visitor.found
3811 }
3812
3813 fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
3814     if_chain! {
3815         if args.len() == 2;
3816         if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind;
3817         if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
3818         if layout.is_zst();
3819         then {
3820             span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value");
3821         }
3822     }
3823 }
3824
3825 fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
3826     let ty = cx.typeck_results().expr_ty(&args[0]);
3827
3828     if !match_type(cx, ty, &paths::FILE_TYPE) {
3829         return;
3830     }
3831
3832     let span: Span;
3833     let verb: &str;
3834     let lint_unary: &str;
3835     let help_unary: &str;
3836     if_chain! {
3837         if let Some(parent) = get_parent_expr(cx, expr);
3838         if let hir::ExprKind::Unary(op, _) = parent.kind;
3839         if op == hir::UnOp::UnNot;
3840         then {
3841             lint_unary = "!";
3842             verb = "denies";
3843             help_unary = "";
3844             span = parent.span;
3845         } else {
3846             lint_unary = "";
3847             verb = "covers";
3848             help_unary = "!";
3849             span = expr.span;
3850         }
3851     }
3852     let lint_msg = format!("`{}FileType::is_file()` only {} regular files", lint_unary, verb);
3853     let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary);
3854     span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg);
3855 }
3856
3857 fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
3858     expected.constness == actual.constness
3859         && expected.unsafety == actual.unsafety
3860         && expected.asyncness == actual.asyncness
3861 }