]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/methods/mod.rs
Use `summary_opts()` in another spot
[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::eager_or_lazy::is_lazyness_candidate;
29 use crate::utils::usage::mutated_variables;
30 use crate::utils::{
31     contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro,
32     is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath,
33     match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty,
34     single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
35     span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, 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
403     /// `_.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
427     /// `_.filter_map(_)`.
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
455     /// `_.find_map(_)`.
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
499     /// `_.find_map(_)`.
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 or string 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(_)` or `_.contains(_)`.
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 or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`"
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 calling `.step_by(0)` on iterators which panics.
802     ///
803     /// **Why is this bad?** This very much looks like an oversight. Use `panic!()` instead if you
804     /// actually intend to panic.
805     ///
806     /// **Known problems:** None.
807     ///
808     /// **Example:**
809     /// ```rust,should_panic
810     /// for x in (0..100).step_by(0) {
811     ///     //..
812     /// }
813     /// ```
814     pub ITERATOR_STEP_BY_ZERO,
815     correctness,
816     "using `Iterator::step_by(0)`, which will panic at runtime"
817 }
818
819 declare_clippy_lint! {
820     /// **What it does:** Checks for the use of `iter.nth(0)`.
821     ///
822     /// **Why is this bad?** `iter.next()` is equivalent to
823     /// `iter.nth(0)`, as they both consume the next element,
824     ///  but is more readable.
825     ///
826     /// **Known problems:** None.
827     ///
828     /// **Example:**
829     ///
830     /// ```rust
831     /// # use std::collections::HashSet;
832     /// // Bad
833     /// # let mut s = HashSet::new();
834     /// # s.insert(1);
835     /// let x = s.iter().nth(0);
836     ///
837     /// // Good
838     /// # let mut s = HashSet::new();
839     /// # s.insert(1);
840     /// let x = s.iter().next();
841     /// ```
842     pub ITER_NTH_ZERO,
843     style,
844     "replace `iter.nth(0)` with `iter.next()`"
845 }
846
847 declare_clippy_lint! {
848     /// **What it does:** Checks for use of `.iter().nth()` (and the related
849     /// `.iter_mut().nth()`) on standard library types with O(1) element access.
850     ///
851     /// **Why is this bad?** `.get()` and `.get_mut()` are more efficient and more
852     /// readable.
853     ///
854     /// **Known problems:** None.
855     ///
856     /// **Example:**
857     /// ```rust
858     /// let some_vec = vec![0, 1, 2, 3];
859     /// let bad_vec = some_vec.iter().nth(3);
860     /// let bad_slice = &some_vec[..].iter().nth(3);
861     /// ```
862     /// The correct use would be:
863     /// ```rust
864     /// let some_vec = vec![0, 1, 2, 3];
865     /// let bad_vec = some_vec.get(3);
866     /// let bad_slice = &some_vec[..].get(3);
867     /// ```
868     pub ITER_NTH,
869     perf,
870     "using `.iter().nth()` on a standard library type with O(1) element access"
871 }
872
873 declare_clippy_lint! {
874     /// **What it does:** Checks for use of `.skip(x).next()` on iterators.
875     ///
876     /// **Why is this bad?** `.nth(x)` is cleaner
877     ///
878     /// **Known problems:** None.
879     ///
880     /// **Example:**
881     /// ```rust
882     /// let some_vec = vec![0, 1, 2, 3];
883     /// let bad_vec = some_vec.iter().skip(3).next();
884     /// let bad_slice = &some_vec[..].iter().skip(3).next();
885     /// ```
886     /// The correct use would be:
887     /// ```rust
888     /// let some_vec = vec![0, 1, 2, 3];
889     /// let bad_vec = some_vec.iter().nth(3);
890     /// let bad_slice = &some_vec[..].iter().nth(3);
891     /// ```
892     pub ITER_SKIP_NEXT,
893     style,
894     "using `.skip(x).next()` on an iterator"
895 }
896
897 declare_clippy_lint! {
898     /// **What it does:** Checks for use of `.get().unwrap()` (or
899     /// `.get_mut().unwrap`) on a standard library type which implements `Index`
900     ///
901     /// **Why is this bad?** Using the Index trait (`[]`) is more clear and more
902     /// concise.
903     ///
904     /// **Known problems:** Not a replacement for error handling: Using either
905     /// `.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic`
906     /// if the value being accessed is `None`. If the use of `.get().unwrap()` is a
907     /// temporary placeholder for dealing with the `Option` type, then this does
908     /// not mitigate the need for error handling. If there is a chance that `.get()`
909     /// will be `None` in your program, then it is advisable that the `None` case
910     /// is handled in a future refactor instead of using `.unwrap()` or the Index
911     /// trait.
912     ///
913     /// **Example:**
914     /// ```rust
915     /// let mut some_vec = vec![0, 1, 2, 3];
916     /// let last = some_vec.get(3).unwrap();
917     /// *some_vec.get_mut(0).unwrap() = 1;
918     /// ```
919     /// The correct use would be:
920     /// ```rust
921     /// let mut some_vec = vec![0, 1, 2, 3];
922     /// let last = some_vec[3];
923     /// some_vec[0] = 1;
924     /// ```
925     pub GET_UNWRAP,
926     restriction,
927     "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
928 }
929
930 declare_clippy_lint! {
931     /// **What it does:** Checks for the use of `.extend(s.chars())` where s is a
932     /// `&str` or `String`.
933     ///
934     /// **Why is this bad?** `.push_str(s)` is clearer
935     ///
936     /// **Known problems:** None.
937     ///
938     /// **Example:**
939     /// ```rust
940     /// let abc = "abc";
941     /// let def = String::from("def");
942     /// let mut s = String::new();
943     /// s.extend(abc.chars());
944     /// s.extend(def.chars());
945     /// ```
946     /// The correct use would be:
947     /// ```rust
948     /// let abc = "abc";
949     /// let def = String::from("def");
950     /// let mut s = String::new();
951     /// s.push_str(abc);
952     /// s.push_str(&def);
953     /// ```
954     pub STRING_EXTEND_CHARS,
955     style,
956     "using `x.extend(s.chars())` where s is a `&str` or `String`"
957 }
958
959 declare_clippy_lint! {
960     /// **What it does:** Checks for the use of `.cloned().collect()` on slice to
961     /// create a `Vec`.
962     ///
963     /// **Why is this bad?** `.to_vec()` is clearer
964     ///
965     /// **Known problems:** None.
966     ///
967     /// **Example:**
968     /// ```rust
969     /// let s = [1, 2, 3, 4, 5];
970     /// let s2: Vec<isize> = s[..].iter().cloned().collect();
971     /// ```
972     /// The better use would be:
973     /// ```rust
974     /// let s = [1, 2, 3, 4, 5];
975     /// let s2: Vec<isize> = s.to_vec();
976     /// ```
977     pub ITER_CLONED_COLLECT,
978     style,
979     "using `.cloned().collect()` on slice to create a `Vec`"
980 }
981
982 declare_clippy_lint! {
983     /// **What it does:** Checks for usage of `_.chars().last()` or
984     /// `_.chars().next_back()` on a `str` to check if it ends with a given char.
985     ///
986     /// **Why is this bad?** Readability, this can be written more concisely as
987     /// `_.ends_with(_)`.
988     ///
989     /// **Known problems:** None.
990     ///
991     /// **Example:**
992     /// ```rust
993     /// # let name = "_";
994     ///
995     /// // Bad
996     /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
997     ///
998     /// // Good
999     /// name.ends_with('_') || name.ends_with('-');
1000     /// ```
1001     pub CHARS_LAST_CMP,
1002     style,
1003     "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char"
1004 }
1005
1006 declare_clippy_lint! {
1007     /// **What it does:** Checks for usage of `.as_ref()` or `.as_mut()` where the
1008     /// types before and after the call are the same.
1009     ///
1010     /// **Why is this bad?** The call is unnecessary.
1011     ///
1012     /// **Known problems:** None.
1013     ///
1014     /// **Example:**
1015     /// ```rust
1016     /// # fn do_stuff(x: &[i32]) {}
1017     /// let x: &[i32] = &[1, 2, 3, 4, 5];
1018     /// do_stuff(x.as_ref());
1019     /// ```
1020     /// The correct use would be:
1021     /// ```rust
1022     /// # fn do_stuff(x: &[i32]) {}
1023     /// let x: &[i32] = &[1, 2, 3, 4, 5];
1024     /// do_stuff(x);
1025     /// ```
1026     pub USELESS_ASREF,
1027     complexity,
1028     "using `as_ref` where the types before and after the call are the same"
1029 }
1030
1031 declare_clippy_lint! {
1032     /// **What it does:** Checks for using `fold` when a more succinct alternative exists.
1033     /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
1034     /// `sum` or `product`.
1035     ///
1036     /// **Why is this bad?** Readability.
1037     ///
1038     /// **Known problems:** None.
1039     ///
1040     /// **Example:**
1041     /// ```rust
1042     /// let _ = (0..3).fold(false, |acc, x| acc || x > 2);
1043     /// ```
1044     /// This could be written as:
1045     /// ```rust
1046     /// let _ = (0..3).any(|x| x > 2);
1047     /// ```
1048     pub UNNECESSARY_FOLD,
1049     style,
1050     "using `fold` when a more succinct alternative exists"
1051 }
1052
1053 declare_clippy_lint! {
1054     /// **What it does:** Checks for `filter_map` calls which could be replaced by `filter` or `map`.
1055     /// More specifically it checks if the closure provided is only performing one of the
1056     /// filter or map operations and suggests the appropriate option.
1057     ///
1058     /// **Why is this bad?** Complexity. The intent is also clearer if only a single
1059     /// operation is being performed.
1060     ///
1061     /// **Known problems:** None
1062     ///
1063     /// **Example:**
1064     /// ```rust
1065     /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
1066     ///
1067     /// // As there is no transformation of the argument this could be written as:
1068     /// let _ = (0..3).filter(|&x| x > 2);
1069     /// ```
1070     ///
1071     /// ```rust
1072     /// let _ = (0..4).filter_map(|x| Some(x + 1));
1073     ///
1074     /// // As there is no conditional check on the argument this could be written as:
1075     /// let _ = (0..4).map(|x| x + 1);
1076     /// ```
1077     pub UNNECESSARY_FILTER_MAP,
1078     complexity,
1079     "using `filter_map` when a more succinct alternative exists"
1080 }
1081
1082 declare_clippy_lint! {
1083     /// **What it does:** Checks for `into_iter` calls on references which should be replaced by `iter`
1084     /// or `iter_mut`.
1085     ///
1086     /// **Why is this bad?** Readability. Calling `into_iter` on a reference will not move out its
1087     /// content into the resulting iterator, which is confusing. It is better just call `iter` or
1088     /// `iter_mut` directly.
1089     ///
1090     /// **Known problems:** None
1091     ///
1092     /// **Example:**
1093     ///
1094     /// ```rust
1095     /// // Bad
1096     /// let _ = (&vec![3, 4, 5]).into_iter();
1097     ///
1098     /// // Good
1099     /// let _ = (&vec![3, 4, 5]).iter();
1100     /// ```
1101     pub INTO_ITER_ON_REF,
1102     style,
1103     "using `.into_iter()` on a reference"
1104 }
1105
1106 declare_clippy_lint! {
1107     /// **What it does:** Checks for calls to `map` followed by a `count`.
1108     ///
1109     /// **Why is this bad?** It looks suspicious. Maybe `map` was confused with `filter`.
1110     /// If the `map` call is intentional, this should be rewritten. Or, if you intend to
1111     /// drive the iterator to completion, you can just use `for_each` instead.
1112     ///
1113     /// **Known problems:** None
1114     ///
1115     /// **Example:**
1116     ///
1117     /// ```rust
1118     /// let _ = (0..3).map(|x| x + 2).count();
1119     /// ```
1120     pub SUSPICIOUS_MAP,
1121     complexity,
1122     "suspicious usage of map"
1123 }
1124
1125 declare_clippy_lint! {
1126     /// **What it does:** Checks for `MaybeUninit::uninit().assume_init()`.
1127     ///
1128     /// **Why is this bad?** For most types, this is undefined behavior.
1129     ///
1130     /// **Known problems:** For now, we accept empty tuples and tuples / arrays
1131     /// of `MaybeUninit`. There may be other types that allow uninitialized
1132     /// data, but those are not yet rigorously defined.
1133     ///
1134     /// **Example:**
1135     ///
1136     /// ```rust
1137     /// // Beware the UB
1138     /// use std::mem::MaybeUninit;
1139     ///
1140     /// let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
1141     /// ```
1142     ///
1143     /// Note that the following is OK:
1144     ///
1145     /// ```rust
1146     /// use std::mem::MaybeUninit;
1147     ///
1148     /// let _: [MaybeUninit<bool>; 5] = unsafe {
1149     ///     MaybeUninit::uninit().assume_init()
1150     /// };
1151     /// ```
1152     pub UNINIT_ASSUMED_INIT,
1153     correctness,
1154     "`MaybeUninit::uninit().assume_init()`"
1155 }
1156
1157 declare_clippy_lint! {
1158     /// **What it does:** Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`.
1159     ///
1160     /// **Why is this bad?** These can be written simply with `saturating_add/sub` methods.
1161     ///
1162     /// **Example:**
1163     ///
1164     /// ```rust
1165     /// # let y: u32 = 0;
1166     /// # let x: u32 = 100;
1167     /// let add = x.checked_add(y).unwrap_or(u32::MAX);
1168     /// let sub = x.checked_sub(y).unwrap_or(u32::MIN);
1169     /// ```
1170     ///
1171     /// can be written using dedicated methods for saturating addition/subtraction as:
1172     ///
1173     /// ```rust
1174     /// # let y: u32 = 0;
1175     /// # let x: u32 = 100;
1176     /// let add = x.saturating_add(y);
1177     /// let sub = x.saturating_sub(y);
1178     /// ```
1179     pub MANUAL_SATURATING_ARITHMETIC,
1180     style,
1181     "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`"
1182 }
1183
1184 declare_clippy_lint! {
1185     /// **What it does:** Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to
1186     /// zero-sized types
1187     ///
1188     /// **Why is this bad?** This is a no-op, and likely unintended
1189     ///
1190     /// **Known problems:** None
1191     ///
1192     /// **Example:**
1193     /// ```rust
1194     /// unsafe { (&() as *const ()).offset(1) };
1195     /// ```
1196     pub ZST_OFFSET,
1197     correctness,
1198     "Check for offset calculations on raw pointers to zero-sized types"
1199 }
1200
1201 declare_clippy_lint! {
1202     /// **What it does:** Checks for `FileType::is_file()`.
1203     ///
1204     /// **Why is this bad?** When people testing a file type with `FileType::is_file`
1205     /// they are testing whether a path is something they can get bytes from. But
1206     /// `is_file` doesn't cover special file types in unix-like systems, and doesn't cover
1207     /// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention.
1208     ///
1209     /// **Example:**
1210     ///
1211     /// ```rust
1212     /// # || {
1213     /// let metadata = std::fs::metadata("foo.txt")?;
1214     /// let filetype = metadata.file_type();
1215     ///
1216     /// if filetype.is_file() {
1217     ///     // read file
1218     /// }
1219     /// # Ok::<_, std::io::Error>(())
1220     /// # };
1221     /// ```
1222     ///
1223     /// should be written as:
1224     ///
1225     /// ```rust
1226     /// # || {
1227     /// let metadata = std::fs::metadata("foo.txt")?;
1228     /// let filetype = metadata.file_type();
1229     ///
1230     /// if !filetype.is_dir() {
1231     ///     // read file
1232     /// }
1233     /// # Ok::<_, std::io::Error>(())
1234     /// # };
1235     /// ```
1236     pub FILETYPE_IS_FILE,
1237     restriction,
1238     "`FileType::is_file` is not recommended to test for readable file type"
1239 }
1240
1241 declare_clippy_lint! {
1242     /// **What it does:** Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
1243     ///
1244     /// **Why is this bad?** Readability, this can be written more concisely as
1245     /// `_.as_deref()`.
1246     ///
1247     /// **Known problems:** None.
1248     ///
1249     /// **Example:**
1250     /// ```rust
1251     /// # let opt = Some("".to_string());
1252     /// opt.as_ref().map(String::as_str)
1253     /// # ;
1254     /// ```
1255     /// Can be written as
1256     /// ```rust
1257     /// # let opt = Some("".to_string());
1258     /// opt.as_deref()
1259     /// # ;
1260     /// ```
1261     pub OPTION_AS_REF_DEREF,
1262     complexity,
1263     "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`"
1264 }
1265
1266 declare_clippy_lint! {
1267     /// **What it does:** Checks for usage of `iter().next()` on a Slice or an Array
1268     ///
1269     /// **Why is this bad?** These can be shortened into `.get()`
1270     ///
1271     /// **Known problems:** None.
1272     ///
1273     /// **Example:**
1274     /// ```rust
1275     /// # let a = [1, 2, 3];
1276     /// # let b = vec![1, 2, 3];
1277     /// a[2..].iter().next();
1278     /// b.iter().next();
1279     /// ```
1280     /// should be written as:
1281     /// ```rust
1282     /// # let a = [1, 2, 3];
1283     /// # let b = vec![1, 2, 3];
1284     /// a.get(2);
1285     /// b.get(0);
1286     /// ```
1287     pub ITER_NEXT_SLICE,
1288     style,
1289     "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
1290 }
1291
1292 declare_clippy_lint! {
1293     /// **What it does:** Warns when using `push_str`/`insert_str` with a single-character string literal
1294     /// where `push`/`insert` with a `char` would work fine.
1295     ///
1296     /// **Why is this bad?** It's less clear that we are pushing a single character.
1297     ///
1298     /// **Known problems:** None
1299     ///
1300     /// **Example:**
1301     /// ```rust
1302     /// let mut string = String::new();
1303     /// string.insert_str(0, "R");
1304     /// string.push_str("R");
1305     /// ```
1306     /// Could be written as
1307     /// ```rust
1308     /// let mut string = String::new();
1309     /// string.insert(0, 'R');
1310     /// string.push('R');
1311     /// ```
1312     pub SINGLE_CHAR_ADD_STR,
1313     style,
1314     "`push_str()` or `insert_str()` used with a single-character string literal as parameter"
1315 }
1316
1317 declare_clippy_lint! {
1318     /// **What it does:** As the counterpart to `or_fun_call`, this lint looks for unnecessary
1319     /// lazily evaluated closures on `Option` and `Result`.
1320     ///
1321     /// This lint suggests changing the following functions, when eager evaluation results in
1322     /// simpler code:
1323     ///  - `unwrap_or_else` to `unwrap_or`
1324     ///  - `and_then` to `and`
1325     ///  - `or_else` to `or`
1326     ///  - `get_or_insert_with` to `get_or_insert`
1327     ///  - `ok_or_else` to `ok_or`
1328     ///
1329     /// **Why is this bad?** Using eager evaluation is shorter and simpler in some cases.
1330     ///
1331     /// **Known problems:** It is possible, but not recommended for `Deref` and `Index` to have
1332     /// side effects. Eagerly evaluating them can change the semantics of the program.
1333     ///
1334     /// **Example:**
1335     ///
1336     /// ```rust
1337     /// // example code where clippy issues a warning
1338     /// let opt: Option<u32> = None;
1339     ///
1340     /// opt.unwrap_or_else(|| 42);
1341     /// ```
1342     /// Use instead:
1343     /// ```rust
1344     /// let opt: Option<u32> = None;
1345     ///
1346     /// opt.unwrap_or(42);
1347     /// ```
1348     pub UNNECESSARY_LAZY_EVALUATIONS,
1349     style,
1350     "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
1351 }
1352
1353 declare_clippy_lint! {
1354     /// **What it does:** Checks for usage of `_.map(_).collect::<Result<(), _>()`.
1355     ///
1356     /// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic.
1357     ///
1358     /// **Known problems:** None
1359     ///
1360     /// **Example:**
1361     ///
1362     /// ```rust
1363     /// (0..3).map(|t| Err(t)).collect::<Result<(), _>>();
1364     /// ```
1365     /// Use instead:
1366     /// ```rust
1367     /// (0..3).try_for_each(|t| Err(t));
1368     /// ```
1369     pub MAP_COLLECT_RESULT_UNIT,
1370     style,
1371     "using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
1372 }
1373
1374 declare_clippy_lint! {
1375     /// **What it does:** Checks for `from_iter()` function calls on types that implement the `FromIterator`
1376     /// trait.
1377     ///
1378     /// **Why is this bad?** It is recommended style to use collect. See
1379     /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
1380     ///
1381     /// **Known problems:** None.
1382     ///
1383     /// **Example:**
1384     ///
1385     /// ```rust
1386     /// use std::iter::FromIterator;
1387     ///
1388     /// let five_fives = std::iter::repeat(5).take(5);
1389     ///
1390     /// let v = Vec::from_iter(five_fives);
1391     ///
1392     /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
1393     /// ```
1394     /// Use instead:
1395     /// ```rust
1396     /// let five_fives = std::iter::repeat(5).take(5);
1397     ///
1398     /// let v: Vec<i32> = five_fives.collect();
1399     ///
1400     /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
1401     /// ```
1402     pub FROM_ITER_INSTEAD_OF_COLLECT,
1403     style,
1404     "use `.collect()` instead of `::from_iter()`"
1405 }
1406
1407 declare_lint_pass!(Methods => [
1408     UNWRAP_USED,
1409     EXPECT_USED,
1410     SHOULD_IMPLEMENT_TRAIT,
1411     WRONG_SELF_CONVENTION,
1412     WRONG_PUB_SELF_CONVENTION,
1413     OK_EXPECT,
1414     MAP_UNWRAP_OR,
1415     RESULT_MAP_OR_INTO_OPTION,
1416     OPTION_MAP_OR_NONE,
1417     BIND_INSTEAD_OF_MAP,
1418     OR_FUN_CALL,
1419     EXPECT_FUN_CALL,
1420     CHARS_NEXT_CMP,
1421     CHARS_LAST_CMP,
1422     CLONE_ON_COPY,
1423     CLONE_ON_REF_PTR,
1424     CLONE_DOUBLE_REF,
1425     INEFFICIENT_TO_STRING,
1426     NEW_RET_NO_SELF,
1427     SINGLE_CHAR_PATTERN,
1428     SINGLE_CHAR_ADD_STR,
1429     SEARCH_IS_SOME,
1430     FILTER_NEXT,
1431     SKIP_WHILE_NEXT,
1432     FILTER_MAP,
1433     FILTER_MAP_NEXT,
1434     FLAT_MAP_IDENTITY,
1435     FIND_MAP,
1436     MAP_FLATTEN,
1437     ITERATOR_STEP_BY_ZERO,
1438     ITER_NEXT_SLICE,
1439     ITER_NTH,
1440     ITER_NTH_ZERO,
1441     ITER_SKIP_NEXT,
1442     GET_UNWRAP,
1443     STRING_EXTEND_CHARS,
1444     ITER_CLONED_COLLECT,
1445     USELESS_ASREF,
1446     UNNECESSARY_FOLD,
1447     UNNECESSARY_FILTER_MAP,
1448     INTO_ITER_ON_REF,
1449     SUSPICIOUS_MAP,
1450     UNINIT_ASSUMED_INIT,
1451     MANUAL_SATURATING_ARITHMETIC,
1452     ZST_OFFSET,
1453     FILETYPE_IS_FILE,
1454     OPTION_AS_REF_DEREF,
1455     UNNECESSARY_LAZY_EVALUATIONS,
1456     MAP_COLLECT_RESULT_UNIT,
1457     FROM_ITER_INSTEAD_OF_COLLECT,
1458 ]);
1459
1460 impl<'tcx> LateLintPass<'tcx> for Methods {
1461     #[allow(clippy::too_many_lines)]
1462     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
1463         if in_macro(expr.span) {
1464             return;
1465         }
1466
1467         let (method_names, arg_lists, method_spans) = method_calls(expr, 2);
1468         let method_names: Vec<SymbolStr> = method_names.iter().map(|s| s.as_str()).collect();
1469         let method_names: Vec<&str> = method_names.iter().map(|s| &**s).collect();
1470
1471         match method_names.as_slice() {
1472             ["unwrap", "get"] => lint_get_unwrap(cx, expr, arg_lists[1], false),
1473             ["unwrap", "get_mut"] => lint_get_unwrap(cx, expr, arg_lists[1], true),
1474             ["unwrap", ..] => lint_unwrap(cx, expr, arg_lists[0]),
1475             ["expect", "ok"] => lint_ok_expect(cx, expr, arg_lists[1]),
1476             ["expect", ..] => lint_expect(cx, expr, arg_lists[0]),
1477             ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]),
1478             ["unwrap_or_else", "map"] => {
1479                 if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) {
1480                     unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or");
1481                 }
1482             },
1483             ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]),
1484             ["and_then", ..] => {
1485                 let biom_option_linted = bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]);
1486                 let biom_result_linted = bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]);
1487                 if !biom_option_linted && !biom_result_linted {
1488                     unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "and");
1489                 }
1490             },
1491             ["or_else", ..] => {
1492                 if !bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]) {
1493                     unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "or");
1494                 }
1495             },
1496             ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
1497             ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]),
1498             ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]),
1499             ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]),
1500             ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]),
1501             ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]),
1502             ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]),
1503             ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
1504             ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
1505             ["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0], method_spans[0]),
1506             ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]),
1507             ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]),
1508             ["is_some", "position"] => {
1509                 lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1])
1510             },
1511             ["is_some", "rposition"] => {
1512                 lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1])
1513             },
1514             ["extend", ..] => lint_extend(cx, expr, arg_lists[0]),
1515             ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false),
1516             ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true),
1517             ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]),
1518             ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]),
1519             ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]),
1520             ["collect", "cloned"] => lint_iter_cloned_collect(cx, expr, arg_lists[1]),
1521             ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]),
1522             ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]),
1523             ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0], method_spans[0]),
1524             ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]),
1525             ["count", "map"] => lint_suspicious_map(cx, expr),
1526             ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr),
1527             ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => {
1528                 manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..])
1529             },
1530             ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => {
1531                 check_pointer_offset(cx, expr, arg_lists[0])
1532             },
1533             ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
1534             ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false),
1535             ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true),
1536             ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"),
1537             ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"),
1538             ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"),
1539             ["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]),
1540             _ => {},
1541         }
1542
1543         match expr.kind {
1544             hir::ExprKind::Call(ref func, ref args) => {
1545                 if let hir::ExprKind::Path(path) = &func.kind {
1546                     if match_qpath(path, &["from_iter"]) {
1547                         lint_from_iter(cx, expr, args);
1548                     }
1549                 }
1550             },
1551             hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => {
1552                 lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
1553                 lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
1554
1555                 let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
1556                 if args.len() == 1 && method_call.ident.name == sym!(clone) {
1557                     lint_clone_on_copy(cx, expr, &args[0], self_ty);
1558                     lint_clone_on_ref_ptr(cx, expr, &args[0]);
1559                 }
1560                 if args.len() == 1 && method_call.ident.name == sym!(to_string) {
1561                     inefficient_to_string::lint(cx, expr, &args[0], self_ty);
1562                 }
1563
1564                 if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
1565                     if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
1566                         lint_single_char_push_string(cx, expr, args);
1567                     } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
1568                         lint_single_char_insert_string(cx, expr, args);
1569                     }
1570                 }
1571
1572                 match self_ty.kind() {
1573                     ty::Ref(_, ty, _) if *ty.kind() == ty::Str => {
1574                         for &(method, pos) in &PATTERN_METHODS {
1575                             if method_call.ident.name.as_str() == method && args.len() > pos {
1576                                 lint_single_char_pattern(cx, expr, &args[pos]);
1577                             }
1578                         }
1579                     },
1580                     ty::Ref(..) if method_call.ident.name == sym!(into_iter) => {
1581                         lint_into_iter(cx, expr, self_ty, *method_span);
1582                     },
1583                     _ => (),
1584                 }
1585             },
1586             hir::ExprKind::Binary(op, ref lhs, ref rhs)
1587                 if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne =>
1588             {
1589                 let mut info = BinaryExprInfo {
1590                     expr,
1591                     chain: lhs,
1592                     other: rhs,
1593                     eq: op.node == hir::BinOpKind::Eq,
1594                 };
1595                 lint_binary_expr_with_method_call(cx, &mut info);
1596             }
1597             _ => (),
1598         }
1599     }
1600
1601     #[allow(clippy::too_many_lines)]
1602     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
1603         if in_external_macro(cx.sess(), impl_item.span) {
1604             return;
1605         }
1606         let name = impl_item.ident.name.as_str();
1607         let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id);
1608         let item = cx.tcx.hir().expect_item(parent);
1609         let def_id = cx.tcx.hir().local_def_id(item.hir_id);
1610         let self_ty = cx.tcx.type_of(def_id);
1611         if_chain! {
1612             if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
1613             if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next();
1614             if let hir::ItemKind::Impl{ of_trait: None, .. } = item.kind;
1615
1616             let method_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
1617             let method_sig = cx.tcx.fn_sig(method_def_id);
1618             let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
1619
1620             let first_arg_ty = &method_sig.inputs().iter().next();
1621
1622             // check conventions w.r.t. conversion method names and predicates
1623             if let Some(first_arg_ty) = first_arg_ty;
1624
1625             then {
1626                 if cx.access_levels.is_exported(impl_item.hir_id) {
1627                     // check missing trait implementations
1628                     for method_config in &TRAIT_METHODS {
1629                         if name == method_config.method_name &&
1630                             sig.decl.inputs.len() == method_config.param_count &&
1631                             method_config.output_type.matches(cx, &sig.decl.output) &&
1632                             method_config.self_kind.matches(cx, self_ty, first_arg_ty) &&
1633                             fn_header_equals(method_config.fn_header, sig.header) &&
1634                             method_config.lifetime_param_cond(&impl_item)
1635                         {
1636                             span_lint_and_help(
1637                                 cx,
1638                                 SHOULD_IMPLEMENT_TRAIT,
1639                                 impl_item.span,
1640                                 &format!(
1641                                     "method `{}` can be confused for the standard trait method `{}::{}`",
1642                                     method_config.method_name,
1643                                     method_config.trait_name,
1644                                     method_config.method_name
1645                                 ),
1646                                 None,
1647                                 &format!(
1648                                     "consider implementing the trait `{}` or choosing a less ambiguous method name",
1649                                     method_config.trait_name
1650                                 )
1651                             );
1652                         }
1653                     }
1654                 }
1655
1656                 if let Some((ref conv, self_kinds)) = &CONVENTIONS
1657                     .iter()
1658                     .find(|(ref conv, _)| conv.check(&name))
1659                 {
1660                     if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) {
1661                         let lint = if item.vis.node.is_pub() {
1662                             WRONG_PUB_SELF_CONVENTION
1663                         } else {
1664                             WRONG_SELF_CONVENTION
1665                         };
1666
1667                         span_lint(
1668                             cx,
1669                             lint,
1670                             first_arg.pat.span,
1671                             &format!("methods called `{}` usually take {}; consider choosing a less ambiguous name",
1672                                 conv,
1673                                 &self_kinds
1674                                     .iter()
1675                                     .map(|k| k.description())
1676                                     .collect::<Vec<_>>()
1677                                     .join(" or ")
1678                             ),
1679                         );
1680                     }
1681                 }
1682             }
1683         }
1684
1685         // if this impl block implements a trait, lint in trait definition instead
1686         if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind {
1687             return;
1688         }
1689
1690         if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
1691             let ret_ty = return_ty(cx, impl_item.hir_id);
1692
1693             // walk the return type and check for Self (this does not check associated types)
1694             if contains_ty(ret_ty, self_ty) {
1695                 return;
1696             }
1697
1698             // if return type is impl trait, check the associated types
1699             if let ty::Opaque(def_id, _) = *ret_ty.kind() {
1700                 // one of the associated types must be Self
1701                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
1702                     if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
1703                         // walk the associated type and check for Self
1704                         if contains_ty(projection_predicate.ty, self_ty) {
1705                             return;
1706                         }
1707                     }
1708                 }
1709             }
1710
1711             if name == "new" && !TyS::same_type(ret_ty, self_ty) {
1712                 span_lint(
1713                     cx,
1714                     NEW_RET_NO_SELF,
1715                     impl_item.span,
1716                     "methods called `new` usually return `Self`",
1717                 );
1718             }
1719         }
1720     }
1721
1722     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
1723         if_chain! {
1724             if !in_external_macro(cx.tcx.sess, item.span);
1725             if item.ident.name == sym::new;
1726             if let TraitItemKind::Fn(_, _) = item.kind;
1727             let ret_ty = return_ty(cx, item.hir_id);
1728             let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty();
1729             if !contains_ty(ret_ty, self_ty);
1730
1731             then {
1732                 span_lint(
1733                     cx,
1734                     NEW_RET_NO_SELF,
1735                     item.span,
1736                     "methods called `new` usually return `Self`",
1737                 );
1738             }
1739         }
1740     }
1741 }
1742
1743 /// Checks for the `OR_FUN_CALL` lint.
1744 #[allow(clippy::too_many_lines)]
1745 fn lint_or_fun_call<'tcx>(
1746     cx: &LateContext<'tcx>,
1747     expr: &hir::Expr<'_>,
1748     method_span: Span,
1749     name: &str,
1750     args: &'tcx [hir::Expr<'_>],
1751 ) {
1752     /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
1753     fn check_unwrap_or_default(
1754         cx: &LateContext<'_>,
1755         name: &str,
1756         fun: &hir::Expr<'_>,
1757         self_expr: &hir::Expr<'_>,
1758         arg: &hir::Expr<'_>,
1759         or_has_args: bool,
1760         span: Span,
1761     ) -> bool {
1762         if_chain! {
1763             if !or_has_args;
1764             if name == "unwrap_or";
1765             if let hir::ExprKind::Path(ref qpath) = fun.kind;
1766             let path = &*last_path_segment(qpath).ident.as_str();
1767             if ["default", "new"].contains(&path);
1768             let arg_ty = cx.typeck_results().expr_ty(arg);
1769             if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
1770             if implements_trait(cx, arg_ty, default_trait_id, &[]);
1771
1772             then {
1773                 let mut applicability = Applicability::MachineApplicable;
1774                 span_lint_and_sugg(
1775                     cx,
1776                     OR_FUN_CALL,
1777                     span,
1778                     &format!("use of `{}` followed by a call to `{}`", name, path),
1779                     "try this",
1780                     format!(
1781                         "{}.unwrap_or_default()",
1782                         snippet_with_applicability(cx, self_expr.span, "..", &mut applicability)
1783                     ),
1784                     applicability,
1785                 );
1786
1787                 true
1788             } else {
1789                 false
1790             }
1791         }
1792     }
1793
1794     /// Checks for `*or(foo())`.
1795     #[allow(clippy::too_many_arguments)]
1796     fn check_general_case<'tcx>(
1797         cx: &LateContext<'tcx>,
1798         name: &str,
1799         method_span: Span,
1800         self_expr: &hir::Expr<'_>,
1801         arg: &'tcx hir::Expr<'_>,
1802         span: Span,
1803         // None if lambda is required
1804         fun_span: Option<Span>,
1805     ) {
1806         // (path, fn_has_argument, methods, suffix)
1807         static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
1808             (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
1809             (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
1810             (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
1811             (&paths::RESULT, true, &["or", "unwrap_or"], "else"),
1812         ];
1813
1814         if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
1815             if path.ident.as_str() == "len" {
1816                 let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
1817
1818                 match ty.kind() {
1819                     ty::Slice(_) | ty::Array(_, _) => return,
1820                     _ => (),
1821                 }
1822
1823                 if is_type_diagnostic_item(cx, ty, sym::vec_type) {
1824                     return;
1825                 }
1826             }
1827         }
1828
1829         if_chain! {
1830             if KNOW_TYPES.iter().any(|k| k.2.contains(&name));
1831
1832             if is_lazyness_candidate(cx, arg);
1833             if !contains_return(&arg);
1834
1835             let self_ty = cx.typeck_results().expr_ty(self_expr);
1836
1837             if let Some(&(_, fn_has_arguments, poss, suffix)) =
1838                 KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0));
1839
1840             if poss.contains(&name);
1841
1842             then {
1843                 let sugg: Cow<'_, str> = {
1844                     let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
1845                         (false, Some(fun_span)) => (fun_span, false),
1846                         _ => (arg.span, true),
1847                     };
1848                     let snippet = snippet_with_macro_callsite(cx, snippet_span, "..");
1849                     if use_lambda {
1850                         let l_arg = if fn_has_arguments { "_" } else { "" };
1851                         format!("|{}| {}", l_arg, snippet).into()
1852                     } else {
1853                         snippet
1854                     }
1855                 };
1856                 let span_replace_word = method_span.with_hi(span.hi());
1857                 span_lint_and_sugg(
1858                     cx,
1859                     OR_FUN_CALL,
1860                     span_replace_word,
1861                     &format!("use of `{}` followed by a function call", name),
1862                     "try this",
1863                     format!("{}_{}({})", name, suffix, sugg),
1864                     Applicability::HasPlaceholders,
1865                 );
1866             }
1867         }
1868     }
1869
1870     if args.len() == 2 {
1871         match args[1].kind {
1872             hir::ExprKind::Call(ref fun, ref or_args) => {
1873                 let or_has_args = !or_args.is_empty();
1874                 if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
1875                     let fun_span = if or_has_args { None } else { Some(fun.span) };
1876                     check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span);
1877                 }
1878             },
1879             hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
1880                 check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
1881             },
1882             _ => {},
1883         }
1884     }
1885 }
1886
1887 /// Checks for the `EXPECT_FUN_CALL` lint.
1888 #[allow(clippy::too_many_lines)]
1889 fn lint_expect_fun_call(
1890     cx: &LateContext<'_>,
1891     expr: &hir::Expr<'_>,
1892     method_span: Span,
1893     name: &str,
1894     args: &[hir::Expr<'_>],
1895 ) {
1896     // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
1897     // `&str`
1898     fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
1899         let mut arg_root = arg;
1900         loop {
1901             arg_root = match &arg_root.kind {
1902                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
1903                 hir::ExprKind::MethodCall(method_name, _, call_args, _) => {
1904                     if call_args.len() == 1
1905                         && (method_name.ident.name == sym::as_str || method_name.ident.name == sym!(as_ref))
1906                         && {
1907                             let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
1908                             let base_type = arg_type.peel_refs();
1909                             *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::string_type)
1910                         }
1911                     {
1912                         &call_args[0]
1913                     } else {
1914                         break;
1915                     }
1916                 },
1917                 _ => break,
1918             };
1919         }
1920         arg_root
1921     }
1922
1923     // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be
1924     // converted to string.
1925     fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
1926         let arg_ty = cx.typeck_results().expr_ty(arg);
1927         if is_type_diagnostic_item(cx, arg_ty, sym::string_type) {
1928             return false;
1929         }
1930         if let ty::Ref(_, ty, ..) = arg_ty.kind() {
1931             if *ty.kind() == ty::Str && can_be_static_str(cx, arg) {
1932                 return false;
1933             }
1934         };
1935         true
1936     }
1937
1938     // Check if an expression could have type `&'static str`, knowing that it
1939     // has type `&str` for some lifetime.
1940     fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
1941         match arg.kind {
1942             hir::ExprKind::Lit(_) => true,
1943             hir::ExprKind::Call(fun, _) => {
1944                 if let hir::ExprKind::Path(ref p) = fun.kind {
1945                     match cx.qpath_res(p, fun.hir_id) {
1946                         hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
1947                             cx.tcx.fn_sig(def_id).output().skip_binder().kind(),
1948                             ty::Ref(ty::ReStatic, ..)
1949                         ),
1950                         _ => false,
1951                     }
1952                 } else {
1953                     false
1954                 }
1955             },
1956             hir::ExprKind::MethodCall(..) => {
1957                 cx.typeck_results()
1958                     .type_dependent_def_id(arg.hir_id)
1959                     .map_or(false, |method_id| {
1960                         matches!(
1961                             cx.tcx.fn_sig(method_id).output().skip_binder().kind(),
1962                             ty::Ref(ty::ReStatic, ..)
1963                         )
1964                     })
1965             },
1966             hir::ExprKind::Path(ref p) => matches!(
1967                 cx.qpath_res(p, arg.hir_id),
1968                 hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _)
1969             ),
1970             _ => false,
1971         }
1972     }
1973
1974     fn generate_format_arg_snippet(
1975         cx: &LateContext<'_>,
1976         a: &hir::Expr<'_>,
1977         applicability: &mut Applicability,
1978     ) -> Vec<String> {
1979         if_chain! {
1980             if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref format_arg) = a.kind;
1981             if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.kind;
1982             if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.kind;
1983
1984             then {
1985                 format_arg_expr_tup
1986                     .iter()
1987                     .map(|a| snippet_with_applicability(cx, a.span, "..", applicability).into_owned())
1988                     .collect()
1989             } else {
1990                 unreachable!()
1991             }
1992         }
1993     }
1994
1995     fn is_call(node: &hir::ExprKind<'_>) -> bool {
1996         match node {
1997             hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => {
1998                 is_call(&expr.kind)
1999             },
2000             hir::ExprKind::Call(..)
2001             | hir::ExprKind::MethodCall(..)
2002             // These variants are debatable or require further examination
2003             | hir::ExprKind::Match(..)
2004             | hir::ExprKind::Block{ .. } => true,
2005             _ => false,
2006         }
2007     }
2008
2009     if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) {
2010         return;
2011     }
2012
2013     let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]);
2014     let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::option_type) {
2015         "||"
2016     } else if is_type_diagnostic_item(cx, receiver_type, sym::result_type) {
2017         "|_|"
2018     } else {
2019         return;
2020     };
2021
2022     let arg_root = get_arg_root(cx, &args[1]);
2023
2024     let span_replace_word = method_span.with_hi(expr.span.hi());
2025
2026     let mut applicability = Applicability::MachineApplicable;
2027
2028     //Special handling for `format!` as arg_root
2029     if_chain! {
2030         if let hir::ExprKind::Block(block, None) = &arg_root.kind;
2031         if block.stmts.len() == 1;
2032         if let hir::StmtKind::Local(local) = &block.stmts[0].kind;
2033         if let Some(arg_root) = &local.init;
2034         if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = arg_root.kind;
2035         if is_expn_of(inner_fun.span, "format").is_some() && inner_args.len() == 1;
2036         if let hir::ExprKind::Call(_, format_args) = &inner_args[0].kind;
2037         then {
2038             let fmt_spec = &format_args[0];
2039             let fmt_args = &format_args[1];
2040
2041             let mut args = vec![snippet(cx, fmt_spec.span, "..").into_owned()];
2042
2043             args.extend(generate_format_arg_snippet(cx, fmt_args, &mut applicability));
2044
2045             let sugg = args.join(", ");
2046
2047             span_lint_and_sugg(
2048                 cx,
2049                 EXPECT_FUN_CALL,
2050                 span_replace_word,
2051                 &format!("use of `{}` followed by a function call", name),
2052                 "try this",
2053                 format!("unwrap_or_else({} panic!({}))", closure_args, sugg),
2054                 applicability,
2055             );
2056
2057             return;
2058         }
2059     }
2060
2061     let mut arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability);
2062     if requires_to_string(cx, arg_root) {
2063         arg_root_snippet.to_mut().push_str(".to_string()");
2064     }
2065
2066     span_lint_and_sugg(
2067         cx,
2068         EXPECT_FUN_CALL,
2069         span_replace_word,
2070         &format!("use of `{}` followed by a function call", name),
2071         "try this",
2072         format!("unwrap_or_else({} {{ panic!({}) }})", closure_args, arg_root_snippet),
2073         applicability,
2074     );
2075 }
2076
2077 /// Checks for the `CLONE_ON_COPY` lint.
2078 fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) {
2079     let ty = cx.typeck_results().expr_ty(expr);
2080     if let ty::Ref(_, inner, _) = arg_ty.kind() {
2081         if let ty::Ref(_, innermost, _) = inner.kind() {
2082             span_lint_and_then(
2083                 cx,
2084                 CLONE_DOUBLE_REF,
2085                 expr.span,
2086                 "using `clone` on a double-reference; \
2087                 this will copy the reference instead of cloning the inner type",
2088                 |diag| {
2089                     if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
2090                         let mut ty = innermost;
2091                         let mut n = 0;
2092                         while let ty::Ref(_, inner, _) = ty.kind() {
2093                             ty = inner;
2094                             n += 1;
2095                         }
2096                         let refs: String = iter::repeat('&').take(n + 1).collect();
2097                         let derefs: String = iter::repeat('*').take(n).collect();
2098                         let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
2099                         diag.span_suggestion(
2100                             expr.span,
2101                             "try dereferencing it",
2102                             format!("{}({}{}).clone()", refs, derefs, snip.deref()),
2103                             Applicability::MaybeIncorrect,
2104                         );
2105                         diag.span_suggestion(
2106                             expr.span,
2107                             "or try being explicit if you are sure, that you want to clone a reference",
2108                             explicit,
2109                             Applicability::MaybeIncorrect,
2110                         );
2111                     }
2112                 },
2113             );
2114             return; // don't report clone_on_copy
2115         }
2116     }
2117
2118     if is_copy(cx, ty) {
2119         let snip;
2120         if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) {
2121             let parent = cx.tcx.hir().get_parent_node(expr.hir_id);
2122             match &cx.tcx.hir().get(parent) {
2123                 hir::Node::Expr(parent) => match parent.kind {
2124                     // &*x is a nop, &x.clone() is not
2125                     hir::ExprKind::AddrOf(..) => return,
2126                     // (*x).func() is useless, x.clone().func() can work in case func borrows mutably
2127                     hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => {
2128                         return;
2129                     },
2130
2131                     _ => {},
2132                 },
2133                 hir::Node::Stmt(stmt) => {
2134                     if let hir::StmtKind::Local(ref loc) = stmt.kind {
2135                         if let hir::PatKind::Ref(..) = loc.pat.kind {
2136                             // let ref y = *x borrows x, let ref y = x.clone() does not
2137                             return;
2138                         }
2139                     }
2140                 },
2141                 _ => {},
2142             }
2143
2144             // x.clone() might have dereferenced x, possibly through Deref impls
2145             if cx.typeck_results().expr_ty(arg) == ty {
2146                 snip = Some(("try removing the `clone` call", format!("{}", snippet)));
2147             } else {
2148                 let deref_count = cx
2149                     .typeck_results()
2150                     .expr_adjustments(arg)
2151                     .iter()
2152                     .filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_)))
2153                     .count();
2154                 let derefs: String = iter::repeat('*').take(deref_count).collect();
2155                 snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
2156             }
2157         } else {
2158             snip = None;
2159         }
2160         span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |diag| {
2161             if let Some((text, snip)) = snip {
2162                 diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable);
2163             }
2164         });
2165     }
2166 }
2167
2168 fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
2169     let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs();
2170
2171     if let ty::Adt(_, subst) = obj_ty.kind() {
2172         let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
2173             "Rc"
2174         } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) {
2175             "Arc"
2176         } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) {
2177             "Weak"
2178         } else {
2179             return;
2180         };
2181
2182         let snippet = snippet_with_macro_callsite(cx, arg.span, "..");
2183
2184         span_lint_and_sugg(
2185             cx,
2186             CLONE_ON_REF_PTR,
2187             expr.span,
2188             "using `.clone()` on a ref-counted pointer",
2189             "try this",
2190             format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet),
2191             Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak
2192         );
2193     }
2194 }
2195
2196 fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
2197     let arg = &args[1];
2198     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
2199         let target = &arglists[0][0];
2200         let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
2201         let ref_str = if *self_ty.kind() == ty::Str {
2202             ""
2203         } else if is_type_diagnostic_item(cx, self_ty, sym::string_type) {
2204             "&"
2205         } else {
2206             return;
2207         };
2208
2209         let mut applicability = Applicability::MachineApplicable;
2210         span_lint_and_sugg(
2211             cx,
2212             STRING_EXTEND_CHARS,
2213             expr.span,
2214             "calling `.extend(_.chars())`",
2215             "try this",
2216             format!(
2217                 "{}.push_str({}{})",
2218                 snippet_with_applicability(cx, args[0].span, "..", &mut applicability),
2219                 ref_str,
2220                 snippet_with_applicability(cx, target.span, "..", &mut applicability)
2221             ),
2222             applicability,
2223         );
2224     }
2225 }
2226
2227 fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
2228     let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
2229     if is_type_diagnostic_item(cx, obj_ty, sym::string_type) {
2230         lint_string_extend(cx, expr, args);
2231     }
2232 }
2233
2234 fn lint_iter_cloned_collect<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
2235     if_chain! {
2236         if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type);
2237         if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0]));
2238         if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
2239
2240         then {
2241             span_lint_and_sugg(
2242                 cx,
2243                 ITER_CLONED_COLLECT,
2244                 to_replace,
2245                 "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
2246                 more readable",
2247                 "try",
2248                 ".to_vec()".to_string(),
2249                 Applicability::MachineApplicable,
2250             );
2251         }
2252     }
2253 }
2254
2255 fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) {
2256     fn check_fold_with_op(
2257         cx: &LateContext<'_>,
2258         expr: &hir::Expr<'_>,
2259         fold_args: &[hir::Expr<'_>],
2260         fold_span: Span,
2261         op: hir::BinOpKind,
2262         replacement_method_name: &str,
2263         replacement_has_args: bool,
2264     ) {
2265         if_chain! {
2266             // Extract the body of the closure passed to fold
2267             if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].kind;
2268             let closure_body = cx.tcx.hir().body(body_id);
2269             let closure_expr = remove_blocks(&closure_body.value);
2270
2271             // Check if the closure body is of the form `acc <op> some_expr(x)`
2272             if let hir::ExprKind::Binary(ref bin_op, ref left_expr, ref right_expr) = closure_expr.kind;
2273             if bin_op.node == op;
2274
2275             // Extract the names of the two arguments to the closure
2276             if let Some(first_arg_ident) = get_arg_name(&closure_body.params[0].pat);
2277             if let Some(second_arg_ident) = get_arg_name(&closure_body.params[1].pat);
2278
2279             if match_var(&*left_expr, first_arg_ident);
2280             if replacement_has_args || match_var(&*right_expr, second_arg_ident);
2281
2282             then {
2283                 let mut applicability = Applicability::MachineApplicable;
2284                 let sugg = if replacement_has_args {
2285                     format!(
2286                         "{replacement}(|{s}| {r})",
2287                         replacement = replacement_method_name,
2288                         s = second_arg_ident,
2289                         r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
2290                     )
2291                 } else {
2292                     format!(
2293                         "{replacement}()",
2294                         replacement = replacement_method_name,
2295                     )
2296                 };
2297
2298                 span_lint_and_sugg(
2299                     cx,
2300                     UNNECESSARY_FOLD,
2301                     fold_span.with_hi(expr.span.hi()),
2302                     // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
2303                     "this `.fold` can be written more succinctly using another method",
2304                     "try",
2305                     sugg,
2306                     applicability,
2307                 );
2308             }
2309         }
2310     }
2311
2312     // Check that this is a call to Iterator::fold rather than just some function called fold
2313     if !match_trait_method(cx, expr, &paths::ITERATOR) {
2314         return;
2315     }
2316
2317     assert!(
2318         fold_args.len() == 3,
2319         "Expected fold_args to have three entries - the receiver, the initial value and the closure"
2320     );
2321
2322     // Check if the first argument to .fold is a suitable literal
2323     if let hir::ExprKind::Lit(ref lit) = fold_args[1].kind {
2324         match lit.node {
2325             ast::LitKind::Bool(false) => {
2326                 check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true)
2327             },
2328             ast::LitKind::Bool(true) => {
2329                 check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true)
2330             },
2331             ast::LitKind::Int(0, _) => {
2332                 check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false)
2333             },
2334             ast::LitKind::Int(1, _) => {
2335                 check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false)
2336             },
2337             _ => (),
2338         }
2339     }
2340 }
2341
2342 fn lint_step_by<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) {
2343     if match_trait_method(cx, expr, &paths::ITERATOR) {
2344         if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) {
2345             span_lint(
2346                 cx,
2347                 ITERATOR_STEP_BY_ZERO,
2348                 expr.span,
2349                 "Iterator::step_by(0) will panic at runtime",
2350             );
2351         }
2352     }
2353 }
2354
2355 fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
2356     let caller_expr = &iter_args[0];
2357
2358     // Skip lint if the `iter().next()` expression is a for loop argument,
2359     // since it is already covered by `&loops::ITER_NEXT_LOOP`
2360     let mut parent_expr_opt = get_parent_expr(cx, expr);
2361     while let Some(parent_expr) = parent_expr_opt {
2362         if higher::for_loop(parent_expr).is_some() {
2363             return;
2364         }
2365         parent_expr_opt = get_parent_expr(cx, parent_expr);
2366     }
2367
2368     if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() {
2369         // caller is a Slice
2370         if_chain! {
2371             if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
2372             if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
2373                 = higher::range(index_expr);
2374             if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
2375             if let ast::LitKind::Int(start_idx, _) = start_lit.node;
2376             then {
2377                 let mut applicability = Applicability::MachineApplicable;
2378                 span_lint_and_sugg(
2379                     cx,
2380                     ITER_NEXT_SLICE,
2381                     expr.span,
2382                     "using `.iter().next()` on a Slice without end index",
2383                     "try calling",
2384                     format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx),
2385                     applicability,
2386                 );
2387             }
2388         }
2389     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type)
2390         || matches!(
2391             &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(),
2392             ty::Array(_, _)
2393         )
2394     {
2395         // caller is a Vec or an Array
2396         let mut applicability = Applicability::MachineApplicable;
2397         span_lint_and_sugg(
2398             cx,
2399             ITER_NEXT_SLICE,
2400             expr.span,
2401             "using `.iter().next()` on an array",
2402             "try calling",
2403             format!(
2404                 "{}.get(0)",
2405                 snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability)
2406             ),
2407             applicability,
2408         );
2409     }
2410 }
2411
2412 fn lint_iter_nth<'tcx>(
2413     cx: &LateContext<'tcx>,
2414     expr: &hir::Expr<'_>,
2415     nth_and_iter_args: &[&'tcx [hir::Expr<'tcx>]],
2416     is_mut: bool,
2417 ) {
2418     let iter_args = nth_and_iter_args[1];
2419     let mut_str = if is_mut { "_mut" } else { "" };
2420     let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() {
2421         "slice"
2422     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) {
2423         "Vec"
2424     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) {
2425         "VecDeque"
2426     } else {
2427         let nth_args = nth_and_iter_args[0];
2428         lint_iter_nth_zero(cx, expr, &nth_args);
2429         return; // caller is not a type that we want to lint
2430     };
2431
2432     span_lint_and_help(
2433         cx,
2434         ITER_NTH,
2435         expr.span,
2436         &format!("called `.iter{0}().nth()` on a {1}", mut_str, caller_type),
2437         None,
2438         &format!("calling `.get{}()` is both faster and more readable", mut_str),
2439     );
2440 }
2441
2442 fn lint_iter_nth_zero<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) {
2443     if_chain! {
2444         if match_trait_method(cx, expr, &paths::ITERATOR);
2445         if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]);
2446         then {
2447             let mut applicability = Applicability::MachineApplicable;
2448             span_lint_and_sugg(
2449                 cx,
2450                 ITER_NTH_ZERO,
2451                 expr.span,
2452                 "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent",
2453                 "try calling `.next()` instead of `.nth(0)`",
2454                 format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)),
2455                 applicability,
2456             );
2457         }
2458     }
2459 }
2460
2461 fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: &'tcx [hir::Expr<'_>], is_mut: bool) {
2462     // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
2463     // because they do not implement `IndexMut`
2464     let mut applicability = Applicability::MachineApplicable;
2465     let expr_ty = cx.typeck_results().expr_ty(&get_args[0]);
2466     let get_args_str = if get_args.len() > 1 {
2467         snippet_with_applicability(cx, get_args[1].span, "..", &mut applicability)
2468     } else {
2469         return; // not linting on a .get().unwrap() chain or variant
2470     };
2471     let mut needs_ref;
2472     let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
2473         needs_ref = get_args_str.parse::<usize>().is_ok();
2474         "slice"
2475     } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) {
2476         needs_ref = get_args_str.parse::<usize>().is_ok();
2477         "Vec"
2478     } else if is_type_diagnostic_item(cx, expr_ty, sym!(vecdeque_type)) {
2479         needs_ref = get_args_str.parse::<usize>().is_ok();
2480         "VecDeque"
2481     } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym!(hashmap_type)) {
2482         needs_ref = true;
2483         "HashMap"
2484     } else if !is_mut && match_type(cx, expr_ty, &paths::BTREEMAP) {
2485         needs_ref = true;
2486         "BTreeMap"
2487     } else {
2488         return; // caller is not a type that we want to lint
2489     };
2490
2491     let mut span = expr.span;
2492
2493     // Handle the case where the result is immediately dereferenced
2494     // by not requiring ref and pulling the dereference into the
2495     // suggestion.
2496     if_chain! {
2497         if needs_ref;
2498         if let Some(parent) = get_parent_expr(cx, expr);
2499         if let hir::ExprKind::Unary(hir::UnOp::UnDeref, _) = parent.kind;
2500         then {
2501             needs_ref = false;
2502             span = parent.span;
2503         }
2504     }
2505
2506     let mut_str = if is_mut { "_mut" } else { "" };
2507     let borrow_str = if !needs_ref {
2508         ""
2509     } else if is_mut {
2510         "&mut "
2511     } else {
2512         "&"
2513     };
2514
2515     span_lint_and_sugg(
2516         cx,
2517         GET_UNWRAP,
2518         span,
2519         &format!(
2520             "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
2521             mut_str, caller_type
2522         ),
2523         "try this",
2524         format!(
2525             "{}{}[{}]",
2526             borrow_str,
2527             snippet_with_applicability(cx, get_args[0].span, "..", &mut applicability),
2528             get_args_str
2529         ),
2530         applicability,
2531     );
2532 }
2533
2534 fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) {
2535     // lint if caller of skip is an Iterator
2536     if match_trait_method(cx, expr, &paths::ITERATOR) {
2537         if let [caller, n] = skip_args {
2538             let hint = format!(".nth({})", snippet(cx, n.span, ".."));
2539             span_lint_and_sugg(
2540                 cx,
2541                 ITER_SKIP_NEXT,
2542                 expr.span.trim_start(caller.span).unwrap(),
2543                 "called `skip(..).next()` on an iterator",
2544                 "use `nth` instead",
2545                 hint,
2546                 Applicability::MachineApplicable,
2547             );
2548         }
2549     }
2550 }
2551
2552 fn derefs_to_slice<'tcx>(
2553     cx: &LateContext<'tcx>,
2554     expr: &'tcx hir::Expr<'tcx>,
2555     ty: Ty<'tcx>,
2556 ) -> Option<&'tcx hir::Expr<'tcx>> {
2557     fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
2558         match ty.kind() {
2559             ty::Slice(_) => true,
2560             ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
2561             ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type),
2562             ty::Array(_, size) => size
2563                 .try_eval_usize(cx.tcx, cx.param_env)
2564                 .map_or(false, |size| size < 32),
2565             ty::Ref(_, inner, _) => may_slice(cx, inner),
2566             _ => false,
2567         }
2568     }
2569
2570     if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind {
2571         if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) {
2572             Some(&args[0])
2573         } else {
2574             None
2575         }
2576     } else {
2577         match ty.kind() {
2578             ty::Slice(_) => Some(expr),
2579             ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
2580             ty::Ref(_, inner, _) => {
2581                 if may_slice(cx, inner) {
2582                     Some(expr)
2583                 } else {
2584                     None
2585                 }
2586             },
2587             _ => None,
2588         }
2589     }
2590 }
2591
2592 /// lint use of `unwrap()` for `Option`s and `Result`s
2593 fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
2594     let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs();
2595
2596     let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) {
2597         Some((UNWRAP_USED, "an Option", "None"))
2598     } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) {
2599         Some((UNWRAP_USED, "a Result", "Err"))
2600     } else {
2601         None
2602     };
2603
2604     if let Some((lint, kind, none_value)) = mess {
2605         span_lint_and_help(
2606             cx,
2607             lint,
2608             expr.span,
2609             &format!("used `unwrap()` on `{}` value", kind,),
2610             None,
2611             &format!(
2612                 "if you don't want to handle the `{}` case gracefully, consider \
2613                 using `expect()` to provide a better panic message",
2614                 none_value,
2615             ),
2616         );
2617     }
2618 }
2619
2620 /// lint use of `expect()` for `Option`s and `Result`s
2621 fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
2622     let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs();
2623
2624     let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
2625         Some((EXPECT_USED, "an Option", "None"))
2626     } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) {
2627         Some((EXPECT_USED, "a Result", "Err"))
2628     } else {
2629         None
2630     };
2631
2632     if let Some((lint, kind, none_value)) = mess {
2633         span_lint_and_help(
2634             cx,
2635             lint,
2636             expr.span,
2637             &format!("used `expect()` on `{}` value", kind,),
2638             None,
2639             &format!("if this value is an `{}`, it will panic", none_value,),
2640         );
2641     }
2642 }
2643
2644 /// lint use of `ok().expect()` for `Result`s
2645 fn lint_ok_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) {
2646     if_chain! {
2647         // lint if the caller of `ok()` is a `Result`
2648         if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym::result_type);
2649         let result_type = cx.typeck_results().expr_ty(&ok_args[0]);
2650         if let Some(error_type) = get_error_type(cx, result_type);
2651         if has_debug_impl(error_type, cx);
2652
2653         then {
2654             span_lint_and_help(
2655                 cx,
2656                 OK_EXPECT,
2657                 expr.span,
2658                 "called `ok().expect()` on a `Result` value",
2659                 None,
2660                 "you can call `expect()` directly on the `Result`",
2661             );
2662         }
2663     }
2664 }
2665
2666 /// lint use of `map().flatten()` for `Iterators` and 'Options'
2667 fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) {
2668     // lint if caller of `.map().flatten()` is an Iterator
2669     if match_trait_method(cx, expr, &paths::ITERATOR) {
2670         let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]);
2671         let is_map_to_option = match map_closure_ty.kind() {
2672             ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => {
2673                 let map_closure_sig = match map_closure_ty.kind() {
2674                     ty::Closure(_, substs) => substs.as_closure().sig(),
2675                     _ => map_closure_ty.fn_sig(cx.tcx),
2676                 };
2677                 let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output());
2678                 is_type_diagnostic_item(cx, map_closure_return_ty, sym::option_type)
2679             },
2680             _ => false,
2681         };
2682
2683         let method_to_use = if is_map_to_option {
2684             // `(...).map(...)` has type `impl Iterator<Item=Option<...>>
2685             "filter_map"
2686         } else {
2687             // `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
2688             "flat_map"
2689         };
2690         let func_snippet = snippet(cx, map_args[1].span, "..");
2691         let hint = format!(".{0}({1})", method_to_use, func_snippet);
2692         span_lint_and_sugg(
2693             cx,
2694             MAP_FLATTEN,
2695             expr.span.with_lo(map_args[0].span.hi()),
2696             "called `map(..).flatten()` on an `Iterator`",
2697             &format!("try using `{}` instead", method_to_use),
2698             hint,
2699             Applicability::MachineApplicable,
2700         );
2701     }
2702
2703     // lint if caller of `.map().flatten()` is an Option
2704     if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) {
2705         let func_snippet = snippet(cx, map_args[1].span, "..");
2706         let hint = format!(".and_then({})", func_snippet);
2707         span_lint_and_sugg(
2708             cx,
2709             MAP_FLATTEN,
2710             expr.span.with_lo(map_args[0].span.hi()),
2711             "called `map(..).flatten()` on an `Option`",
2712             "try using `and_then` instead",
2713             hint,
2714             Applicability::MachineApplicable,
2715         );
2716     }
2717 }
2718
2719 /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
2720 /// Return true if lint triggered
2721 fn lint_map_unwrap_or_else<'tcx>(
2722     cx: &LateContext<'tcx>,
2723     expr: &'tcx hir::Expr<'_>,
2724     map_args: &'tcx [hir::Expr<'_>],
2725     unwrap_args: &'tcx [hir::Expr<'_>],
2726 ) -> bool {
2727     // lint if the caller of `map()` is an `Option`
2728     let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type);
2729     let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type);
2730
2731     if is_option || is_result {
2732         // Don't make a suggestion that may fail to compile due to mutably borrowing
2733         // the same variable twice.
2734         let map_mutated_vars = mutated_variables(&map_args[0], cx);
2735         let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx);
2736         if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) {
2737             if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() {
2738                 return false;
2739             }
2740         } else {
2741             return false;
2742         }
2743
2744         // lint message
2745         let msg = if is_option {
2746             "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling \
2747             `map_or_else(<g>, <f>)` instead"
2748         } else {
2749             "called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling \
2750             `.map_or_else(<g>, <f>)` instead"
2751         };
2752         // get snippets for args to map() and unwrap_or_else()
2753         let map_snippet = snippet(cx, map_args[1].span, "..");
2754         let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
2755         // lint, with note if neither arg is > 1 line and both map() and
2756         // unwrap_or_else() have the same span
2757         let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
2758         let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt();
2759         if same_span && !multiline {
2760             let var_snippet = snippet(cx, map_args[0].span, "..");
2761             span_lint_and_sugg(
2762                 cx,
2763                 MAP_UNWRAP_OR,
2764                 expr.span,
2765                 msg,
2766                 "try this",
2767                 format!("{}.map_or_else({}, {})", var_snippet, unwrap_snippet, map_snippet),
2768                 Applicability::MachineApplicable,
2769             );
2770             return true;
2771         } else if same_span && multiline {
2772             span_lint(cx, MAP_UNWRAP_OR, expr.span, msg);
2773             return true;
2774         }
2775     }
2776
2777     false
2778 }
2779
2780 /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
2781 fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) {
2782     let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::option_type);
2783     let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::result_type);
2784
2785     // There are two variants of this `map_or` lint:
2786     // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
2787     // (2) using `map_or` as a combinator instead of `and_then`
2788     //
2789     // (For this lint) we don't care if any other type calls `map_or`
2790     if !is_option && !is_result {
2791         return;
2792     }
2793
2794     let (lint_name, msg, instead, hint) = {
2795         let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind {
2796             match_qpath(qpath, &paths::OPTION_NONE)
2797         } else {
2798             return;
2799         };
2800
2801         if !default_arg_is_none {
2802             // nothing to lint!
2803             return;
2804         }
2805
2806         let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_or_args[2].kind {
2807             match_qpath(qpath, &paths::OPTION_SOME)
2808         } else {
2809             false
2810         };
2811
2812         if is_option {
2813             let self_snippet = snippet(cx, map_or_args[0].span, "..");
2814             let func_snippet = snippet(cx, map_or_args[2].span, "..");
2815             let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
2816                        `and_then(..)` instead";
2817             (
2818                 OPTION_MAP_OR_NONE,
2819                 msg,
2820                 "try using `and_then` instead",
2821                 format!("{0}.and_then({1})", self_snippet, func_snippet),
2822             )
2823         } else if f_arg_is_some {
2824             let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
2825                        `ok()` instead";
2826             let self_snippet = snippet(cx, map_or_args[0].span, "..");
2827             (
2828                 RESULT_MAP_OR_INTO_OPTION,
2829                 msg,
2830                 "try using `ok` instead",
2831                 format!("{0}.ok()", self_snippet),
2832             )
2833         } else {
2834             // nothing to lint!
2835             return;
2836         }
2837     };
2838
2839     span_lint_and_sugg(
2840         cx,
2841         lint_name,
2842         expr.span,
2843         msg,
2844         instead,
2845         hint,
2846         Applicability::MachineApplicable,
2847     );
2848 }
2849
2850 /// lint use of `filter().next()` for `Iterators`
2851 fn lint_filter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) {
2852     // lint if caller of `.filter().next()` is an Iterator
2853     if match_trait_method(cx, expr, &paths::ITERATOR) {
2854         let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
2855                    `.find(..)` instead.";
2856         let filter_snippet = snippet(cx, filter_args[1].span, "..");
2857         if filter_snippet.lines().count() <= 1 {
2858             let iter_snippet = snippet(cx, filter_args[0].span, "..");
2859             // add note if not multi-line
2860             span_lint_and_sugg(
2861                 cx,
2862                 FILTER_NEXT,
2863                 expr.span,
2864                 msg,
2865                 "try this",
2866                 format!("{}.find({})", iter_snippet, filter_snippet),
2867                 Applicability::MachineApplicable,
2868             );
2869         } else {
2870             span_lint(cx, FILTER_NEXT, expr.span, msg);
2871         }
2872     }
2873 }
2874
2875 /// lint use of `skip_while().next()` for `Iterators`
2876 fn lint_skip_while_next<'tcx>(
2877     cx: &LateContext<'tcx>,
2878     expr: &'tcx hir::Expr<'_>,
2879     _skip_while_args: &'tcx [hir::Expr<'_>],
2880 ) {
2881     // lint if caller of `.skip_while().next()` is an Iterator
2882     if match_trait_method(cx, expr, &paths::ITERATOR) {
2883         span_lint_and_help(
2884             cx,
2885             SKIP_WHILE_NEXT,
2886             expr.span,
2887             "called `skip_while(<p>).next()` on an `Iterator`",
2888             None,
2889             "this is more succinctly expressed by calling `.find(!<p>)` instead",
2890         );
2891     }
2892 }
2893
2894 /// lint use of `filter().map()` for `Iterators`
2895 fn lint_filter_map<'tcx>(
2896     cx: &LateContext<'tcx>,
2897     expr: &'tcx hir::Expr<'_>,
2898     _filter_args: &'tcx [hir::Expr<'_>],
2899     _map_args: &'tcx [hir::Expr<'_>],
2900 ) {
2901     // lint if caller of `.filter().map()` is an Iterator
2902     if match_trait_method(cx, expr, &paths::ITERATOR) {
2903         let msg = "called `filter(..).map(..)` on an `Iterator`";
2904         let hint = "this is more succinctly expressed by calling `.filter_map(..)` instead";
2905         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
2906     }
2907 }
2908
2909 /// lint use of `filter_map().next()` for `Iterators`
2910 fn lint_filter_map_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) {
2911     if match_trait_method(cx, expr, &paths::ITERATOR) {
2912         let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
2913                    `.find_map(..)` instead.";
2914         let filter_snippet = snippet(cx, filter_args[1].span, "..");
2915         if filter_snippet.lines().count() <= 1 {
2916             let iter_snippet = snippet(cx, filter_args[0].span, "..");
2917             span_lint_and_sugg(
2918                 cx,
2919                 FILTER_MAP_NEXT,
2920                 expr.span,
2921                 msg,
2922                 "try this",
2923                 format!("{}.find_map({})", iter_snippet, filter_snippet),
2924                 Applicability::MachineApplicable,
2925             );
2926         } else {
2927             span_lint(cx, FILTER_MAP_NEXT, expr.span, msg);
2928         }
2929     }
2930 }
2931
2932 /// lint use of `find().map()` for `Iterators`
2933 fn lint_find_map<'tcx>(
2934     cx: &LateContext<'tcx>,
2935     expr: &'tcx hir::Expr<'_>,
2936     _find_args: &'tcx [hir::Expr<'_>],
2937     map_args: &'tcx [hir::Expr<'_>],
2938 ) {
2939     // lint if caller of `.filter().map()` is an Iterator
2940     if match_trait_method(cx, &map_args[0], &paths::ITERATOR) {
2941         let msg = "called `find(..).map(..)` on an `Iterator`";
2942         let hint = "this is more succinctly expressed by calling `.find_map(..)` instead";
2943         span_lint_and_help(cx, FIND_MAP, expr.span, msg, None, hint);
2944     }
2945 }
2946
2947 /// lint use of `filter_map().map()` for `Iterators`
2948 fn lint_filter_map_map<'tcx>(
2949     cx: &LateContext<'tcx>,
2950     expr: &'tcx hir::Expr<'_>,
2951     _filter_args: &'tcx [hir::Expr<'_>],
2952     _map_args: &'tcx [hir::Expr<'_>],
2953 ) {
2954     // lint if caller of `.filter().map()` is an Iterator
2955     if match_trait_method(cx, expr, &paths::ITERATOR) {
2956         let msg = "called `filter_map(..).map(..)` on an `Iterator`";
2957         let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead";
2958         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
2959     }
2960 }
2961
2962 /// lint use of `filter().flat_map()` for `Iterators`
2963 fn lint_filter_flat_map<'tcx>(
2964     cx: &LateContext<'tcx>,
2965     expr: &'tcx hir::Expr<'_>,
2966     _filter_args: &'tcx [hir::Expr<'_>],
2967     _map_args: &'tcx [hir::Expr<'_>],
2968 ) {
2969     // lint if caller of `.filter().flat_map()` is an Iterator
2970     if match_trait_method(cx, expr, &paths::ITERATOR) {
2971         let msg = "called `filter(..).flat_map(..)` on an `Iterator`";
2972         let hint = "this is more succinctly expressed by calling `.flat_map(..)` \
2973                     and filtering by returning `iter::empty()`";
2974         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
2975     }
2976 }
2977
2978 /// lint use of `filter_map().flat_map()` for `Iterators`
2979 fn lint_filter_map_flat_map<'tcx>(
2980     cx: &LateContext<'tcx>,
2981     expr: &'tcx hir::Expr<'_>,
2982     _filter_args: &'tcx [hir::Expr<'_>],
2983     _map_args: &'tcx [hir::Expr<'_>],
2984 ) {
2985     // lint if caller of `.filter_map().flat_map()` is an Iterator
2986     if match_trait_method(cx, expr, &paths::ITERATOR) {
2987         let msg = "called `filter_map(..).flat_map(..)` on an `Iterator`";
2988         let hint = "this is more succinctly expressed by calling `.flat_map(..)` \
2989                     and filtering by returning `iter::empty()`";
2990         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
2991     }
2992 }
2993
2994 /// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient
2995 fn lint_flat_map_identity<'tcx>(
2996     cx: &LateContext<'tcx>,
2997     expr: &'tcx hir::Expr<'_>,
2998     flat_map_args: &'tcx [hir::Expr<'_>],
2999     flat_map_span: Span,
3000 ) {
3001     if match_trait_method(cx, expr, &paths::ITERATOR) {
3002         let arg_node = &flat_map_args[1].kind;
3003
3004         let apply_lint = |message: &str| {
3005             span_lint_and_sugg(
3006                 cx,
3007                 FLAT_MAP_IDENTITY,
3008                 flat_map_span.with_hi(expr.span.hi()),
3009                 message,
3010                 "try",
3011                 "flatten()".to_string(),
3012                 Applicability::MachineApplicable,
3013             );
3014         };
3015
3016         if_chain! {
3017             if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node;
3018             let body = cx.tcx.hir().body(*body_id);
3019
3020             if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind;
3021             if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind;
3022
3023             if path.segments.len() == 1;
3024             if path.segments[0].ident.as_str() == binding_ident.as_str();
3025
3026             then {
3027                 apply_lint("called `flat_map(|x| x)` on an `Iterator`");
3028             }
3029         }
3030
3031         if_chain! {
3032             if let hir::ExprKind::Path(ref qpath) = arg_node;
3033
3034             if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY);
3035
3036             then {
3037                 apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`");
3038             }
3039         }
3040     }
3041 }
3042
3043 /// lint searching an Iterator followed by `is_some()`
3044 /// or calling `find()` on a string followed by `is_some()`
3045 fn lint_search_is_some<'tcx>(
3046     cx: &LateContext<'tcx>,
3047     expr: &'tcx hir::Expr<'_>,
3048     search_method: &str,
3049     search_args: &'tcx [hir::Expr<'_>],
3050     is_some_args: &'tcx [hir::Expr<'_>],
3051     method_span: Span,
3052 ) {
3053     // lint if caller of search is an Iterator
3054     if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) {
3055         let msg = format!(
3056             "called `is_some()` after searching an `Iterator` with `{}`",
3057             search_method
3058         );
3059         let hint = "this is more succinctly expressed by calling `any()`";
3060         let search_snippet = snippet(cx, search_args[1].span, "..");
3061         if search_snippet.lines().count() <= 1 {
3062             // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
3063             // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
3064             let any_search_snippet = if_chain! {
3065                 if search_method == "find";
3066                 if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].kind;
3067                 let closure_body = cx.tcx.hir().body(body_id);
3068                 if let Some(closure_arg) = closure_body.params.get(0);
3069                 then {
3070                     if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
3071                         Some(search_snippet.replacen('&', "", 1))
3072                     } else if let Some(name) = get_arg_name(&closure_arg.pat) {
3073                         Some(search_snippet.replace(&format!("*{}", name), &name.as_str()))
3074                     } else {
3075                         None
3076                     }
3077                 } else {
3078                     None
3079                 }
3080             };
3081             // add note if not multi-line
3082             span_lint_and_sugg(
3083                 cx,
3084                 SEARCH_IS_SOME,
3085                 method_span.with_hi(expr.span.hi()),
3086                 &msg,
3087                 "use `any()` instead",
3088                 format!(
3089                     "any({})",
3090                     any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
3091                 ),
3092                 Applicability::MachineApplicable,
3093             );
3094         } else {
3095             span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, hint);
3096         }
3097     }
3098     // lint if `find()` is called by `String` or `&str`
3099     else if search_method == "find" {
3100         let is_string_or_str_slice = |e| {
3101             let self_ty = cx.typeck_results().expr_ty(e).peel_refs();
3102             if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
3103                 true
3104             } else {
3105                 *self_ty.kind() == ty::Str
3106             }
3107         };
3108         if_chain! {
3109             if is_string_or_str_slice(&search_args[0]);
3110             if is_string_or_str_slice(&search_args[1]);
3111             then {
3112                 let msg = "called `is_some()` after calling `find()` on a string";
3113                 let mut applicability = Applicability::MachineApplicable;
3114                 let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability);
3115                 span_lint_and_sugg(
3116                     cx,
3117                     SEARCH_IS_SOME,
3118                     method_span.with_hi(expr.span.hi()),
3119                     msg,
3120                     "use `contains()` instead",
3121                     format!("contains({})", find_arg),
3122                     applicability,
3123                 );
3124             }
3125         }
3126     }
3127 }
3128
3129 /// Used for `lint_binary_expr_with_method_call`.
3130 #[derive(Copy, Clone)]
3131 struct BinaryExprInfo<'a> {
3132     expr: &'a hir::Expr<'a>,
3133     chain: &'a hir::Expr<'a>,
3134     other: &'a hir::Expr<'a>,
3135     eq: bool,
3136 }
3137
3138 /// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
3139 fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExprInfo<'_>) {
3140     macro_rules! lint_with_both_lhs_and_rhs {
3141         ($func:ident, $cx:expr, $info:ident) => {
3142             if !$func($cx, $info) {
3143                 ::std::mem::swap(&mut $info.chain, &mut $info.other);
3144                 if $func($cx, $info) {
3145                     return;
3146                 }
3147             }
3148         };
3149     }
3150
3151     lint_with_both_lhs_and_rhs!(lint_chars_next_cmp, cx, info);
3152     lint_with_both_lhs_and_rhs!(lint_chars_last_cmp, cx, info);
3153     lint_with_both_lhs_and_rhs!(lint_chars_next_cmp_with_unwrap, cx, info);
3154     lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info);
3155 }
3156
3157 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
3158 fn lint_chars_cmp(
3159     cx: &LateContext<'_>,
3160     info: &BinaryExprInfo<'_>,
3161     chain_methods: &[&str],
3162     lint: &'static Lint,
3163     suggest: &str,
3164 ) -> bool {
3165     if_chain! {
3166         if let Some(args) = method_chain_args(info.chain, chain_methods);
3167         if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.kind;
3168         if arg_char.len() == 1;
3169         if let hir::ExprKind::Path(ref qpath) = fun.kind;
3170         if let Some(segment) = single_segment_path(qpath);
3171         if segment.ident.name == sym::Some;
3172         then {
3173             let mut applicability = Applicability::MachineApplicable;
3174             let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
3175
3176             if *self_ty.kind() != ty::Str {
3177                 return false;
3178             }
3179
3180             span_lint_and_sugg(
3181                 cx,
3182                 lint,
3183                 info.expr.span,
3184                 &format!("you should use the `{}` method", suggest),
3185                 "like this",
3186                 format!("{}{}.{}({})",
3187                         if info.eq { "" } else { "!" },
3188                         snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
3189                         suggest,
3190                         snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)),
3191                 applicability,
3192             );
3193
3194             return true;
3195         }
3196     }
3197
3198     false
3199 }
3200
3201 /// Checks for the `CHARS_NEXT_CMP` lint.
3202 fn lint_chars_next_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
3203     lint_chars_cmp(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
3204 }
3205
3206 /// Checks for the `CHARS_LAST_CMP` lint.
3207 fn lint_chars_last_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
3208     if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
3209         true
3210     } else {
3211         lint_chars_cmp(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with")
3212     }
3213 }
3214
3215 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
3216 fn lint_chars_cmp_with_unwrap<'tcx>(
3217     cx: &LateContext<'tcx>,
3218     info: &BinaryExprInfo<'_>,
3219     chain_methods: &[&str],
3220     lint: &'static Lint,
3221     suggest: &str,
3222 ) -> bool {
3223     if_chain! {
3224         if let Some(args) = method_chain_args(info.chain, chain_methods);
3225         if let hir::ExprKind::Lit(ref lit) = info.other.kind;
3226         if let ast::LitKind::Char(c) = lit.node;
3227         then {
3228             let mut applicability = Applicability::MachineApplicable;
3229             span_lint_and_sugg(
3230                 cx,
3231                 lint,
3232                 info.expr.span,
3233                 &format!("you should use the `{}` method", suggest),
3234                 "like this",
3235                 format!("{}{}.{}('{}')",
3236                         if info.eq { "" } else { "!" },
3237                         snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
3238                         suggest,
3239                         c),
3240                 applicability,
3241             );
3242
3243             true
3244         } else {
3245             false
3246         }
3247     }
3248 }
3249
3250 /// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
3251 fn lint_chars_next_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
3252     lint_chars_cmp_with_unwrap(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
3253 }
3254
3255 /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
3256 fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
3257     if lint_chars_cmp_with_unwrap(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
3258         true
3259     } else {
3260         lint_chars_cmp_with_unwrap(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with")
3261     }
3262 }
3263
3264 fn get_hint_if_single_char_arg(
3265     cx: &LateContext<'_>,
3266     arg: &hir::Expr<'_>,
3267     applicability: &mut Applicability,
3268 ) -> Option<String> {
3269     if_chain! {
3270         if let hir::ExprKind::Lit(lit) = &arg.kind;
3271         if let ast::LitKind::Str(r, style) = lit.node;
3272         let string = r.as_str();
3273         if string.chars().count() == 1;
3274         then {
3275             let snip = snippet_with_applicability(cx, arg.span, &string, applicability);
3276             let ch = if let ast::StrStyle::Raw(nhash) = style {
3277                 let nhash = nhash as usize;
3278                 // for raw string: r##"a"##
3279                 &snip[(nhash + 2)..(snip.len() - 1 - nhash)]
3280             } else {
3281                 // for regular string: "a"
3282                 &snip[1..(snip.len() - 1)]
3283             };
3284             let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch });
3285             Some(hint)
3286         } else {
3287             None
3288         }
3289     }
3290 }
3291
3292 /// lint for length-1 `str`s for methods in `PATTERN_METHODS`
3293 fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
3294     let mut applicability = Applicability::MachineApplicable;
3295     if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) {
3296         span_lint_and_sugg(
3297             cx,
3298             SINGLE_CHAR_PATTERN,
3299             arg.span,
3300             "single-character string constant used as pattern",
3301             "try using a `char` instead",
3302             hint,
3303             applicability,
3304         );
3305     }
3306 }
3307
3308 /// lint for length-1 `str`s as argument for `push_str`
3309 fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
3310     let mut applicability = Applicability::MachineApplicable;
3311     if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
3312         let base_string_snippet =
3313             snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability);
3314         let sugg = format!("{}.push({})", base_string_snippet, extension_string);
3315         span_lint_and_sugg(
3316             cx,
3317             SINGLE_CHAR_ADD_STR,
3318             expr.span,
3319             "calling `push_str()` using a single-character string literal",
3320             "consider using `push` with a character literal",
3321             sugg,
3322             applicability,
3323         );
3324     }
3325 }
3326
3327 /// lint for length-1 `str`s as argument for `insert_str`
3328 fn lint_single_char_insert_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
3329     let mut applicability = Applicability::MachineApplicable;
3330     if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) {
3331         let base_string_snippet =
3332             snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability);
3333         let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability);
3334         let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string);
3335         span_lint_and_sugg(
3336             cx,
3337             SINGLE_CHAR_ADD_STR,
3338             expr.span,
3339             "calling `insert_str()` using a single-character string literal",
3340             "consider using `insert` with a character literal",
3341             sugg,
3342             applicability,
3343         );
3344     }
3345 }
3346
3347 /// Checks for the `USELESS_ASREF` lint.
3348 fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) {
3349     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
3350     // check if the call is to the actual `AsRef` or `AsMut` trait
3351     if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
3352         // check if the type after `as_ref` or `as_mut` is the same as before
3353         let recvr = &as_ref_args[0];
3354         let rcv_ty = cx.typeck_results().expr_ty(recvr);
3355         let res_ty = cx.typeck_results().expr_ty(expr);
3356         let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
3357         let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
3358         if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
3359             // allow the `as_ref` or `as_mut` if it is followed by another method call
3360             if_chain! {
3361                 if let Some(parent) = get_parent_expr(cx, expr);
3362                 if let hir::ExprKind::MethodCall(_, ref span, _, _) = parent.kind;
3363                 if span != &expr.span;
3364                 then {
3365                     return;
3366                 }
3367             }
3368
3369             let mut applicability = Applicability::MachineApplicable;
3370             span_lint_and_sugg(
3371                 cx,
3372                 USELESS_ASREF,
3373                 expr.span,
3374                 &format!("this call to `{}` does nothing", call_name),
3375                 "try this",
3376                 snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(),
3377                 applicability,
3378             );
3379         }
3380     }
3381 }
3382
3383 fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(&'static str, &'static str)> {
3384     has_iter_method(cx, self_ref_ty).map(|ty_name| {
3385         let mutbl = match self_ref_ty.kind() {
3386             ty::Ref(_, _, mutbl) => mutbl,
3387             _ => unreachable!(),
3388         };
3389         let method_name = match mutbl {
3390             hir::Mutability::Not => "iter",
3391             hir::Mutability::Mut => "iter_mut",
3392         };
3393         (ty_name, method_name)
3394     })
3395 }
3396
3397 fn lint_into_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_>, method_span: Span) {
3398     if !match_trait_method(cx, expr, &paths::INTO_ITERATOR) {
3399         return;
3400     }
3401     if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) {
3402         span_lint_and_sugg(
3403             cx,
3404             INTO_ITER_ON_REF,
3405             method_span,
3406             &format!(
3407                 "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`",
3408                 method_name, kind,
3409             ),
3410             "call directly",
3411             method_name.to_string(),
3412             Applicability::MachineApplicable,
3413         );
3414     }
3415 }
3416
3417 /// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter)
3418 fn lint_maybe_uninit(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Expr<'_>) {
3419     if_chain! {
3420         if let hir::ExprKind::Call(ref callee, ref args) = expr.kind;
3421         if args.is_empty();
3422         if let hir::ExprKind::Path(ref path) = callee.kind;
3423         if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT);
3424         if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(outer));
3425         then {
3426             span_lint(
3427                 cx,
3428                 UNINIT_ASSUMED_INIT,
3429                 outer.span,
3430                 "this call for this type may be undefined behavior"
3431             );
3432         }
3433     }
3434 }
3435
3436 fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
3437     match ty.kind() {
3438         ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component),
3439         ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)),
3440         ty::Adt(ref adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT),
3441         _ => false,
3442     }
3443 }
3444
3445 fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
3446     span_lint_and_help(
3447         cx,
3448         SUSPICIOUS_MAP,
3449         expr.span,
3450         "this call to `map()` won't have an effect on the call to `count()`",
3451         None,
3452         "make sure you did not confuse `map` with `filter` or `for_each`",
3453     );
3454 }
3455
3456 /// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
3457 fn lint_option_as_ref_deref<'tcx>(
3458     cx: &LateContext<'tcx>,
3459     expr: &hir::Expr<'_>,
3460     as_ref_args: &[hir::Expr<'_>],
3461     map_args: &[hir::Expr<'_>],
3462     is_mut: bool,
3463 ) {
3464     let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
3465
3466     let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
3467     if !is_type_diagnostic_item(cx, option_ty, sym::option_type) {
3468         return;
3469     }
3470
3471     let deref_aliases: [&[&str]; 9] = [
3472         &paths::DEREF_TRAIT_METHOD,
3473         &paths::DEREF_MUT_TRAIT_METHOD,
3474         &paths::CSTRING_AS_C_STR,
3475         &paths::OS_STRING_AS_OS_STR,
3476         &paths::PATH_BUF_AS_PATH,
3477         &paths::STRING_AS_STR,
3478         &paths::STRING_AS_MUT_STR,
3479         &paths::VEC_AS_SLICE,
3480         &paths::VEC_AS_MUT_SLICE,
3481     ];
3482
3483     let is_deref = match map_args[1].kind {
3484         hir::ExprKind::Path(ref expr_qpath) => cx
3485             .qpath_res(expr_qpath, map_args[1].hir_id)
3486             .opt_def_id()
3487             .map_or(false, |fun_def_id| {
3488                 deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
3489             }),
3490         hir::ExprKind::Closure(_, _, body_id, _, _) => {
3491             let closure_body = cx.tcx.hir().body(body_id);
3492             let closure_expr = remove_blocks(&closure_body.value);
3493
3494             match &closure_expr.kind {
3495                 hir::ExprKind::MethodCall(_, _, args, _) => {
3496                     if_chain! {
3497                         if args.len() == 1;
3498                         if let hir::ExprKind::Path(qpath) = &args[0].kind;
3499                         if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, args[0].hir_id);
3500                         if closure_body.params[0].pat.hir_id == local_id;
3501                         let adj = cx
3502                             .typeck_results()
3503                             .expr_adjustments(&args[0])
3504                             .iter()
3505                             .map(|x| &x.kind)
3506                             .collect::<Box<[_]>>();
3507                         if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
3508                         then {
3509                             let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
3510                             deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
3511                         } else {
3512                             false
3513                         }
3514                     }
3515                 },
3516                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => {
3517                     if_chain! {
3518                         if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner1) = inner.kind;
3519                         if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner2) = inner1.kind;
3520                         if let hir::ExprKind::Path(ref qpath) = inner2.kind;
3521                         if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, inner2.hir_id);
3522                         then {
3523                             closure_body.params[0].pat.hir_id == local_id
3524                         } else {
3525                             false
3526                         }
3527                     }
3528                 },
3529                 _ => false,
3530             }
3531         },
3532         _ => false,
3533     };
3534
3535     if is_deref {
3536         let current_method = if is_mut {
3537             format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
3538         } else {
3539             format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
3540         };
3541         let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
3542         let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
3543         let suggestion = format!("try using {} instead", method_hint);
3544
3545         let msg = format!(
3546             "called `{0}` on an Option value. This can be done more directly \
3547             by calling `{1}` instead",
3548             current_method, hint
3549         );
3550         span_lint_and_sugg(
3551             cx,
3552             OPTION_AS_REF_DEREF,
3553             expr.span,
3554             &msg,
3555             &suggestion,
3556             hint,
3557             Applicability::MachineApplicable,
3558         );
3559     }
3560 }
3561
3562 fn lint_map_collect(
3563     cx: &LateContext<'_>,
3564     expr: &hir::Expr<'_>,
3565     map_args: &[hir::Expr<'_>],
3566     collect_args: &[hir::Expr<'_>],
3567 ) {
3568     if_chain! {
3569         // called on Iterator
3570         if let [map_expr] = collect_args;
3571         if match_trait_method(cx, map_expr, &paths::ITERATOR);
3572         // return of collect `Result<(),_>`
3573         let collect_ret_ty = cx.typeck_results().expr_ty(expr);
3574         if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type);
3575         if let ty::Adt(_, substs) = collect_ret_ty.kind();
3576         if let Some(result_t) = substs.types().next();
3577         if result_t.is_unit();
3578         // get parts for snippet
3579         if let [iter, map_fn] = map_args;
3580         then {
3581             span_lint_and_sugg(
3582                 cx,
3583                 MAP_COLLECT_RESULT_UNIT,
3584                 expr.span,
3585                 "`.map().collect()` can be replaced with `.try_for_each()`",
3586                 "try this",
3587                 format!(
3588                     "{}.try_for_each({})",
3589                     snippet(cx, iter.span, ".."),
3590                     snippet(cx, map_fn.span, "..")
3591                 ),
3592                 Applicability::MachineApplicable,
3593             );
3594         }
3595     }
3596 }
3597
3598 /// Given a `Result<T, E>` type, return its error type (`E`).
3599 fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
3600     match ty.kind() {
3601         ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::result_type) => substs.types().nth(1),
3602         _ => None,
3603     }
3604 }
3605
3606 /// This checks whether a given type is known to implement Debug.
3607 fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
3608     cx.tcx
3609         .get_diagnostic_item(sym::debug_trait)
3610         .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
3611 }
3612
3613 enum Convention {
3614     Eq(&'static str),
3615     StartsWith(&'static str),
3616 }
3617
3618 #[rustfmt::skip]
3619 const CONVENTIONS: [(Convention, &[SelfKind]); 7] = [
3620     (Convention::Eq("new"), &[SelfKind::No]),
3621     (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]),
3622     (Convention::StartsWith("from_"), &[SelfKind::No]),
3623     (Convention::StartsWith("into_"), &[SelfKind::Value]),
3624     (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]),
3625     (Convention::Eq("to_mut"), &[SelfKind::RefMut]),
3626     (Convention::StartsWith("to_"), &[SelfKind::Ref]),
3627 ];
3628
3629 const FN_HEADER: hir::FnHeader = hir::FnHeader {
3630     unsafety: hir::Unsafety::Normal,
3631     constness: hir::Constness::NotConst,
3632     asyncness: hir::IsAsync::NotAsync,
3633     abi: rustc_target::spec::abi::Abi::Rust,
3634 };
3635
3636 struct ShouldImplTraitCase {
3637     trait_name: &'static str,
3638     method_name: &'static str,
3639     param_count: usize,
3640     fn_header: hir::FnHeader,
3641     // implicit self kind expected (none, self, &self, ...)
3642     self_kind: SelfKind,
3643     // checks against the output type
3644     output_type: OutType,
3645     // certain methods with explicit lifetimes can't implement the equivalent trait method
3646     lint_explicit_lifetime: bool,
3647 }
3648 impl ShouldImplTraitCase {
3649     const fn new(
3650         trait_name: &'static str,
3651         method_name: &'static str,
3652         param_count: usize,
3653         fn_header: hir::FnHeader,
3654         self_kind: SelfKind,
3655         output_type: OutType,
3656         lint_explicit_lifetime: bool,
3657     ) -> ShouldImplTraitCase {
3658         ShouldImplTraitCase {
3659             trait_name,
3660             method_name,
3661             param_count,
3662             fn_header,
3663             self_kind,
3664             output_type,
3665             lint_explicit_lifetime,
3666         }
3667     }
3668
3669     fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
3670         self.lint_explicit_lifetime
3671             || !impl_item.generics.params.iter().any(|p| {
3672                 matches!(
3673                     p.kind,
3674                     hir::GenericParamKind::Lifetime {
3675                         kind: hir::LifetimeParamKind::Explicit
3676                     }
3677                 )
3678             })
3679     }
3680 }
3681
3682 #[rustfmt::skip]
3683 const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
3684     ShouldImplTraitCase::new("std::ops::Add", "add",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3685     ShouldImplTraitCase::new("std::convert::AsMut", "as_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
3686     ShouldImplTraitCase::new("std::convert::AsRef", "as_ref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
3687     ShouldImplTraitCase::new("std::ops::BitAnd", "bitand",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3688     ShouldImplTraitCase::new("std::ops::BitOr", "bitor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3689     ShouldImplTraitCase::new("std::ops::BitXor", "bitxor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3690     ShouldImplTraitCase::new("std::borrow::Borrow", "borrow",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
3691     ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
3692     ShouldImplTraitCase::new("std::clone::Clone", "clone",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
3693     ShouldImplTraitCase::new("std::cmp::Ord", "cmp",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
3694     // FIXME: default doesn't work
3695     ShouldImplTraitCase::new("std::default::Default", "default",  0,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
3696     ShouldImplTraitCase::new("std::ops::Deref", "deref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
3697     ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
3698     ShouldImplTraitCase::new("std::ops::Div", "div",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3699     ShouldImplTraitCase::new("std::ops::Drop", "drop",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Unit, true),
3700     ShouldImplTraitCase::new("std::cmp::PartialEq", "eq",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Bool, true),
3701     ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
3702     ShouldImplTraitCase::new("std::str::FromStr", "from_str",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
3703     ShouldImplTraitCase::new("std::hash::Hash", "hash",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Unit, true),
3704     ShouldImplTraitCase::new("std::ops::Index", "index",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
3705     ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut",  2,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
3706     ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3707     ShouldImplTraitCase::new("std::ops::Mul", "mul",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3708     ShouldImplTraitCase::new("std::ops::Neg", "neg",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3709     ShouldImplTraitCase::new("std::iter::Iterator", "next",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Any, false),
3710     ShouldImplTraitCase::new("std::ops::Not", "not",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3711     ShouldImplTraitCase::new("std::ops::Rem", "rem",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3712     ShouldImplTraitCase::new("std::ops::Shl", "shl",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3713     ShouldImplTraitCase::new("std::ops::Shr", "shr",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3714     ShouldImplTraitCase::new("std::ops::Sub", "sub",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
3715 ];
3716
3717 #[rustfmt::skip]
3718 const PATTERN_METHODS: [(&str, usize); 17] = [
3719     ("contains", 1),
3720     ("starts_with", 1),
3721     ("ends_with", 1),
3722     ("find", 1),
3723     ("rfind", 1),
3724     ("split", 1),
3725     ("rsplit", 1),
3726     ("split_terminator", 1),
3727     ("rsplit_terminator", 1),
3728     ("splitn", 2),
3729     ("rsplitn", 2),
3730     ("matches", 1),
3731     ("rmatches", 1),
3732     ("match_indices", 1),
3733     ("rmatch_indices", 1),
3734     ("trim_start_matches", 1),
3735     ("trim_end_matches", 1),
3736 ];
3737
3738 #[derive(Clone, Copy, PartialEq, Debug)]
3739 enum SelfKind {
3740     Value,
3741     Ref,
3742     RefMut,
3743     No,
3744 }
3745
3746 impl SelfKind {
3747     fn matches<'a>(self, cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
3748         fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'_>, ty: Ty<'_>) -> bool {
3749             if ty == parent_ty {
3750                 true
3751             } else if ty.is_box() {
3752                 ty.boxed_ty() == parent_ty
3753             } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
3754                 if let ty::Adt(_, substs) = ty.kind() {
3755                     substs.types().next().map_or(false, |t| t == parent_ty)
3756                 } else {
3757                     false
3758                 }
3759             } else {
3760                 false
3761             }
3762         }
3763
3764         fn matches_ref<'a>(cx: &LateContext<'a>, mutability: hir::Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
3765             if let ty::Ref(_, t, m) = *ty.kind() {
3766                 return m == mutability && t == parent_ty;
3767             }
3768
3769             let trait_path = match mutability {
3770                 hir::Mutability::Not => &paths::ASREF_TRAIT,
3771                 hir::Mutability::Mut => &paths::ASMUT_TRAIT,
3772             };
3773
3774             let trait_def_id = match get_trait_def_id(cx, trait_path) {
3775                 Some(did) => did,
3776                 None => return false,
3777             };
3778             implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
3779         }
3780
3781         match self {
3782             Self::Value => matches_value(cx, parent_ty, ty),
3783             Self::Ref => matches_ref(cx, hir::Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
3784             Self::RefMut => matches_ref(cx, hir::Mutability::Mut, parent_ty, ty),
3785             Self::No => ty != parent_ty,
3786         }
3787     }
3788
3789     #[must_use]
3790     fn description(self) -> &'static str {
3791         match self {
3792             Self::Value => "self by value",
3793             Self::Ref => "self by reference",
3794             Self::RefMut => "self by mutable reference",
3795             Self::No => "no self",
3796         }
3797     }
3798 }
3799
3800 impl Convention {
3801     #[must_use]
3802     fn check(&self, other: &str) -> bool {
3803         match *self {
3804             Self::Eq(this) => this == other,
3805             Self::StartsWith(this) => other.starts_with(this) && this != other,
3806         }
3807     }
3808 }
3809
3810 impl fmt::Display for Convention {
3811     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
3812         match *self {
3813             Self::Eq(this) => this.fmt(f),
3814             Self::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)),
3815         }
3816     }
3817 }
3818
3819 #[derive(Clone, Copy)]
3820 enum OutType {
3821     Unit,
3822     Bool,
3823     Any,
3824     Ref,
3825 }
3826
3827 impl OutType {
3828     fn matches(self, cx: &LateContext<'_>, ty: &hir::FnRetTy<'_>) -> bool {
3829         let is_unit = |ty: &hir::Ty<'_>| SpanlessEq::new(cx).eq_ty_kind(&ty.kind, &hir::TyKind::Tup(&[]));
3830         match (self, ty) {
3831             (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true,
3832             (Self::Unit, &hir::FnRetTy::Return(ref ty)) if is_unit(ty) => true,
3833             (Self::Bool, &hir::FnRetTy::Return(ref ty)) if is_bool(ty) => true,
3834             (Self::Any, &hir::FnRetTy::Return(ref ty)) if !is_unit(ty) => true,
3835             (Self::Ref, &hir::FnRetTy::Return(ref ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)),
3836             _ => false,
3837         }
3838     }
3839 }
3840
3841 fn is_bool(ty: &hir::Ty<'_>) -> bool {
3842     if let hir::TyKind::Path(ref p) = ty.kind {
3843         match_qpath(p, &["bool"])
3844     } else {
3845         false
3846     }
3847 }
3848
3849 // Returns `true` if `expr` contains a return expression
3850 fn contains_return(expr: &hir::Expr<'_>) -> bool {
3851     struct RetCallFinder {
3852         found: bool,
3853     }
3854
3855     impl<'tcx> intravisit::Visitor<'tcx> for RetCallFinder {
3856         type Map = Map<'tcx>;
3857
3858         fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
3859             if self.found {
3860                 return;
3861             }
3862             if let hir::ExprKind::Ret(..) = &expr.kind {
3863                 self.found = true;
3864             } else {
3865                 intravisit::walk_expr(self, expr);
3866             }
3867         }
3868
3869         fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
3870             intravisit::NestedVisitorMap::None
3871         }
3872     }
3873
3874     let mut visitor = RetCallFinder { found: false };
3875     visitor.visit_expr(expr);
3876     visitor.found
3877 }
3878
3879 fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
3880     if_chain! {
3881         if args.len() == 2;
3882         if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind();
3883         if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
3884         if layout.is_zst();
3885         then {
3886             span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value");
3887         }
3888     }
3889 }
3890
3891 fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
3892     let ty = cx.typeck_results().expr_ty(&args[0]);
3893
3894     if !match_type(cx, ty, &paths::FILE_TYPE) {
3895         return;
3896     }
3897
3898     let span: Span;
3899     let verb: &str;
3900     let lint_unary: &str;
3901     let help_unary: &str;
3902     if_chain! {
3903         if let Some(parent) = get_parent_expr(cx, expr);
3904         if let hir::ExprKind::Unary(op, _) = parent.kind;
3905         if op == hir::UnOp::UnNot;
3906         then {
3907             lint_unary = "!";
3908             verb = "denies";
3909             help_unary = "";
3910             span = parent.span;
3911         } else {
3912             lint_unary = "";
3913             verb = "covers";
3914             help_unary = "!";
3915             span = expr.span;
3916         }
3917     }
3918     let lint_msg = format!("`{}FileType::is_file()` only {} regular files", lint_unary, verb);
3919     let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary);
3920     span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg);
3921 }
3922
3923 fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
3924     let ty = cx.typeck_results().expr_ty(expr);
3925     let arg_ty = cx.typeck_results().expr_ty(&args[0]);
3926
3927     if_chain! {
3928         if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR);
3929         if let Some(iter_id) = get_trait_def_id(cx, &paths::ITERATOR);
3930
3931         if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]);
3932         then {
3933             // `expr` implements `FromIterator` trait
3934             let iter_expr = snippet(cx, args[0].span, "..");
3935             span_lint_and_sugg(
3936                 cx,
3937                 FROM_ITER_INSTEAD_OF_COLLECT,
3938                 expr.span,
3939                 "usage of `FromIterator::from_iter`",
3940                 "use `.collect()` instead of `::from_iter()`",
3941                 format!("{}.collect()", iter_expr),
3942                 Applicability::MaybeIncorrect,
3943             );
3944         }
3945     }
3946 }
3947
3948 fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
3949     expected.constness == actual.constness
3950         && expected.unsafety == actual.unsafety
3951         && expected.asyncness == actual.asyncness
3952 }