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