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