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