]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/matches.rs
Merge remote-tracking branch 'upstream/master' into rustup
[rust.git] / clippy_lints / src / matches.rs
1 use clippy_utils::consts::{constant, miri_to_const, Constant};
2 use clippy_utils::diagnostics::{
3     multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
4 };
5 use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability};
6 use clippy_utils::sugg::Sugg;
7 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs};
8 use clippy_utils::visitors::LocalUsedVisitor;
9 use clippy_utils::{
10     get_parent_expr, in_macro, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_wild, meets_msrv, msrvs,
11     path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks,
12     strip_pat_refs,
13 };
14 use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
15 use if_chain::if_chain;
16 use rustc_ast::ast::LitKind;
17 use rustc_errors::Applicability;
18 use rustc_hir::def::{CtorKind, DefKind, Res};
19 use rustc_hir::LangItem::{OptionNone, OptionSome};
20 use rustc_hir::{
21     self as hir, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, HirId, Local, MatchSource,
22     Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind,
23 };
24 use rustc_hir::{HirIdMap, HirIdSet};
25 use rustc_lint::{LateContext, LateLintPass, LintContext};
26 use rustc_middle::lint::in_external_macro;
27 use rustc_middle::ty::{self, Ty, TyS, VariantDef};
28 use rustc_semver::RustcVersion;
29 use rustc_session::{declare_tool_lint, impl_lint_pass};
30 use rustc_span::source_map::{Span, Spanned};
31 use rustc_span::sym;
32 use std::cmp::Ordering;
33 use std::collections::hash_map::Entry;
34 use std::iter;
35 use std::ops::Bound;
36
37 declare_clippy_lint! {
38     /// ### What it does
39     /// Checks for matches with a single arm where an `if let`
40     /// will usually suffice.
41     ///
42     /// ### Why is this bad?
43     /// Just readability – `if let` nests less than a `match`.
44     ///
45     /// ### Example
46     /// ```rust
47     /// # fn bar(stool: &str) {}
48     /// # let x = Some("abc");
49     /// // Bad
50     /// match x {
51     ///     Some(ref foo) => bar(foo),
52     ///     _ => (),
53     /// }
54     ///
55     /// // Good
56     /// if let Some(ref foo) = x {
57     ///     bar(foo);
58     /// }
59     /// ```
60     pub SINGLE_MATCH,
61     style,
62     "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`"
63 }
64
65 declare_clippy_lint! {
66     /// ### What it does
67     /// Checks for matches with two arms where an `if let else` will
68     /// usually suffice.
69     ///
70     /// ### Why is this bad?
71     /// Just readability – `if let` nests less than a `match`.
72     ///
73     /// ### Known problems
74     /// Personal style preferences may differ.
75     ///
76     /// ### Example
77     /// Using `match`:
78     ///
79     /// ```rust
80     /// # fn bar(foo: &usize) {}
81     /// # let other_ref: usize = 1;
82     /// # let x: Option<&usize> = Some(&1);
83     /// match x {
84     ///     Some(ref foo) => bar(foo),
85     ///     _ => bar(&other_ref),
86     /// }
87     /// ```
88     ///
89     /// Using `if let` with `else`:
90     ///
91     /// ```rust
92     /// # fn bar(foo: &usize) {}
93     /// # let other_ref: usize = 1;
94     /// # let x: Option<&usize> = Some(&1);
95     /// if let Some(ref foo) = x {
96     ///     bar(foo);
97     /// } else {
98     ///     bar(&other_ref);
99     /// }
100     /// ```
101     pub SINGLE_MATCH_ELSE,
102     pedantic,
103     "a `match` statement with two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
104 }
105
106 declare_clippy_lint! {
107     /// ### What it does
108     /// Checks for matches where all arms match a reference,
109     /// suggesting to remove the reference and deref the matched expression
110     /// instead. It also checks for `if let &foo = bar` blocks.
111     ///
112     /// ### Why is this bad?
113     /// It just makes the code less readable. That reference
114     /// destructuring adds nothing to the code.
115     ///
116     /// ### Example
117     /// ```rust,ignore
118     /// // Bad
119     /// match x {
120     ///     &A(ref y) => foo(y),
121     ///     &B => bar(),
122     ///     _ => frob(&x),
123     /// }
124     ///
125     /// // Good
126     /// match *x {
127     ///     A(ref y) => foo(y),
128     ///     B => bar(),
129     ///     _ => frob(x),
130     /// }
131     /// ```
132     pub MATCH_REF_PATS,
133     style,
134     "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression"
135 }
136
137 declare_clippy_lint! {
138     /// ### What it does
139     /// Checks for matches where match expression is a `bool`. It
140     /// suggests to replace the expression with an `if...else` block.
141     ///
142     /// ### Why is this bad?
143     /// It makes the code less readable.
144     ///
145     /// ### Example
146     /// ```rust
147     /// # fn foo() {}
148     /// # fn bar() {}
149     /// let condition: bool = true;
150     /// match condition {
151     ///     true => foo(),
152     ///     false => bar(),
153     /// }
154     /// ```
155     /// Use if/else instead:
156     /// ```rust
157     /// # fn foo() {}
158     /// # fn bar() {}
159     /// let condition: bool = true;
160     /// if condition {
161     ///     foo();
162     /// } else {
163     ///     bar();
164     /// }
165     /// ```
166     pub MATCH_BOOL,
167     pedantic,
168     "a `match` on a boolean expression instead of an `if..else` block"
169 }
170
171 declare_clippy_lint! {
172     /// ### What it does
173     /// Checks for overlapping match arms.
174     ///
175     /// ### Why is this bad?
176     /// It is likely to be an error and if not, makes the code
177     /// less obvious.
178     ///
179     /// ### Example
180     /// ```rust
181     /// let x = 5;
182     /// match x {
183     ///     1...10 => println!("1 ... 10"),
184     ///     5...15 => println!("5 ... 15"),
185     ///     _ => (),
186     /// }
187     /// ```
188     pub MATCH_OVERLAPPING_ARM,
189     style,
190     "a `match` with overlapping arms"
191 }
192
193 declare_clippy_lint! {
194     /// ### What it does
195     /// Checks for arm which matches all errors with `Err(_)`
196     /// and take drastic actions like `panic!`.
197     ///
198     /// ### Why is this bad?
199     /// It is generally a bad practice, similar to
200     /// catching all exceptions in java with `catch(Exception)`
201     ///
202     /// ### Example
203     /// ```rust
204     /// let x: Result<i32, &str> = Ok(3);
205     /// match x {
206     ///     Ok(_) => println!("ok"),
207     ///     Err(_) => panic!("err"),
208     /// }
209     /// ```
210     pub MATCH_WILD_ERR_ARM,
211     pedantic,
212     "a `match` with `Err(_)` arm and take drastic actions"
213 }
214
215 declare_clippy_lint! {
216     /// ### What it does
217     /// Checks for match which is used to add a reference to an
218     /// `Option` value.
219     ///
220     /// ### Why is this bad?
221     /// Using `as_ref()` or `as_mut()` instead is shorter.
222     ///
223     /// ### Example
224     /// ```rust
225     /// let x: Option<()> = None;
226     ///
227     /// // Bad
228     /// let r: Option<&()> = match x {
229     ///     None => None,
230     ///     Some(ref v) => Some(v),
231     /// };
232     ///
233     /// // Good
234     /// let r: Option<&()> = x.as_ref();
235     /// ```
236     pub MATCH_AS_REF,
237     complexity,
238     "a `match` on an Option value instead of using `as_ref()` or `as_mut`"
239 }
240
241 declare_clippy_lint! {
242     /// ### What it does
243     /// Checks for wildcard enum matches using `_`.
244     ///
245     /// ### Why is this bad?
246     /// New enum variants added by library updates can be missed.
247     ///
248     /// ### Known problems
249     /// Suggested replacements may be incorrect if guards exhaustively cover some
250     /// variants, and also may not use correct path to enum if it's not present in the current scope.
251     ///
252     /// ### Example
253     /// ```rust
254     /// # enum Foo { A(usize), B(usize) }
255     /// # let x = Foo::B(1);
256     /// // Bad
257     /// match x {
258     ///     Foo::A(_) => {},
259     ///     _ => {},
260     /// }
261     ///
262     /// // Good
263     /// match x {
264     ///     Foo::A(_) => {},
265     ///     Foo::B(_) => {},
266     /// }
267     /// ```
268     pub WILDCARD_ENUM_MATCH_ARM,
269     restriction,
270     "a wildcard enum match arm using `_`"
271 }
272
273 declare_clippy_lint! {
274     /// ### What it does
275     /// Checks for wildcard enum matches for a single variant.
276     ///
277     /// ### Why is this bad?
278     /// New enum variants added by library updates can be missed.
279     ///
280     /// ### Known problems
281     /// Suggested replacements may not use correct path to enum
282     /// if it's not present in the current scope.
283     ///
284     /// ### Example
285     /// ```rust
286     /// # enum Foo { A, B, C }
287     /// # let x = Foo::B;
288     /// // Bad
289     /// match x {
290     ///     Foo::A => {},
291     ///     Foo::B => {},
292     ///     _ => {},
293     /// }
294     ///
295     /// // Good
296     /// match x {
297     ///     Foo::A => {},
298     ///     Foo::B => {},
299     ///     Foo::C => {},
300     /// }
301     /// ```
302     pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
303     pedantic,
304     "a wildcard enum match for a single variant"
305 }
306
307 declare_clippy_lint! {
308     /// ### What it does
309     /// Checks for wildcard pattern used with others patterns in same match arm.
310     ///
311     /// ### Why is this bad?
312     /// Wildcard pattern already covers any other pattern as it will match anyway.
313     /// It makes the code less readable, especially to spot wildcard pattern use in match arm.
314     ///
315     /// ### Example
316     /// ```rust
317     /// // Bad
318     /// match "foo" {
319     ///     "a" => {},
320     ///     "bar" | _ => {},
321     /// }
322     ///
323     /// // Good
324     /// match "foo" {
325     ///     "a" => {},
326     ///     _ => {},
327     /// }
328     /// ```
329     pub WILDCARD_IN_OR_PATTERNS,
330     complexity,
331     "a wildcard pattern used with others patterns in same match arm"
332 }
333
334 declare_clippy_lint! {
335     /// ### What it does
336     /// Checks for matches being used to destructure a single-variant enum
337     /// or tuple struct where a `let` will suffice.
338     ///
339     /// ### Why is this bad?
340     /// Just readability – `let` doesn't nest, whereas a `match` does.
341     ///
342     /// ### Example
343     /// ```rust
344     /// enum Wrapper {
345     ///     Data(i32),
346     /// }
347     ///
348     /// let wrapper = Wrapper::Data(42);
349     ///
350     /// let data = match wrapper {
351     ///     Wrapper::Data(i) => i,
352     /// };
353     /// ```
354     ///
355     /// The correct use would be:
356     /// ```rust
357     /// enum Wrapper {
358     ///     Data(i32),
359     /// }
360     ///
361     /// let wrapper = Wrapper::Data(42);
362     /// let Wrapper::Data(data) = wrapper;
363     /// ```
364     pub INFALLIBLE_DESTRUCTURING_MATCH,
365     style,
366     "a `match` statement with a single infallible arm instead of a `let`"
367 }
368
369 declare_clippy_lint! {
370     /// ### What it does
371     /// Checks for useless match that binds to only one value.
372     ///
373     /// ### Why is this bad?
374     /// Readability and needless complexity.
375     ///
376     /// ### Known problems
377     ///  Suggested replacements may be incorrect when `match`
378     /// is actually binding temporary value, bringing a 'dropped while borrowed' error.
379     ///
380     /// ### Example
381     /// ```rust
382     /// # let a = 1;
383     /// # let b = 2;
384     ///
385     /// // Bad
386     /// match (a, b) {
387     ///     (c, d) => {
388     ///         // useless match
389     ///     }
390     /// }
391     ///
392     /// // Good
393     /// let (c, d) = (a, b);
394     /// ```
395     pub MATCH_SINGLE_BINDING,
396     complexity,
397     "a match with a single binding instead of using `let` statement"
398 }
399
400 declare_clippy_lint! {
401     /// ### What it does
402     /// Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched.
403     ///
404     /// ### Why is this bad?
405     /// Correctness and readability. It's like having a wildcard pattern after
406     /// matching all enum variants explicitly.
407     ///
408     /// ### Example
409     /// ```rust
410     /// # struct A { a: i32 }
411     /// let a = A { a: 5 };
412     ///
413     /// // Bad
414     /// match a {
415     ///     A { a: 5, .. } => {},
416     ///     _ => {},
417     /// }
418     ///
419     /// // Good
420     /// match a {
421     ///     A { a: 5 } => {},
422     ///     _ => {},
423     /// }
424     /// ```
425     pub REST_PAT_IN_FULLY_BOUND_STRUCTS,
426     restriction,
427     "a match on a struct that binds all fields but still uses the wildcard pattern"
428 }
429
430 declare_clippy_lint! {
431     /// ### What it does
432     /// Lint for redundant pattern matching over `Result`, `Option`,
433     /// `std::task::Poll` or `std::net::IpAddr`
434     ///
435     /// ### Why is this bad?
436     /// It's more concise and clear to just use the proper
437     /// utility function
438     ///
439     /// ### Known problems
440     /// This will change the drop order for the matched type. Both `if let` and
441     /// `while let` will drop the value at the end of the block, both `if` and `while` will drop the
442     /// value before entering the block. For most types this change will not matter, but for a few
443     /// types this will not be an acceptable change (e.g. locks). See the
444     /// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
445     /// drop order.
446     ///
447     /// ### Example
448     /// ```rust
449     /// # use std::task::Poll;
450     /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
451     /// if let Ok(_) = Ok::<i32, i32>(42) {}
452     /// if let Err(_) = Err::<i32, i32>(42) {}
453     /// if let None = None::<()> {}
454     /// if let Some(_) = Some(42) {}
455     /// if let Poll::Pending = Poll::Pending::<()> {}
456     /// if let Poll::Ready(_) = Poll::Ready(42) {}
457     /// if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {}
458     /// if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {}
459     /// match Ok::<i32, i32>(42) {
460     ///     Ok(_) => true,
461     ///     Err(_) => false,
462     /// };
463     /// ```
464     ///
465     /// The more idiomatic use would be:
466     ///
467     /// ```rust
468     /// # use std::task::Poll;
469     /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
470     /// if Ok::<i32, i32>(42).is_ok() {}
471     /// if Err::<i32, i32>(42).is_err() {}
472     /// if None::<()>.is_none() {}
473     /// if Some(42).is_some() {}
474     /// if Poll::Pending::<()>.is_pending() {}
475     /// if Poll::Ready(42).is_ready() {}
476     /// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
477     /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
478     /// Ok::<i32, i32>(42).is_ok();
479     /// ```
480     pub REDUNDANT_PATTERN_MATCHING,
481     style,
482     "use the proper utility function avoiding an `if let`"
483 }
484
485 declare_clippy_lint! {
486     /// ### What it does
487     /// Checks for `match`  or `if let` expressions producing a
488     /// `bool` that could be written using `matches!`
489     ///
490     /// ### Why is this bad?
491     /// Readability and needless complexity.
492     ///
493     /// ### Known problems
494     /// This lint falsely triggers, if there are arms with
495     /// `cfg` attributes that remove an arm evaluating to `false`.
496     ///
497     /// ### Example
498     /// ```rust
499     /// let x = Some(5);
500     ///
501     /// // Bad
502     /// let a = match x {
503     ///     Some(0) => true,
504     ///     _ => false,
505     /// };
506     ///
507     /// let a = if let Some(0) = x {
508     ///     true
509     /// } else {
510     ///     false
511     /// };
512     ///
513     /// // Good
514     /// let a = matches!(x, Some(0));
515     /// ```
516     pub MATCH_LIKE_MATCHES_MACRO,
517     style,
518     "a match that could be written with the matches! macro"
519 }
520
521 declare_clippy_lint! {
522     /// ### What it does
523     /// Checks for `match` with identical arm bodies.
524     ///
525     /// ### Why is this bad?
526     /// This is probably a copy & paste error. If arm bodies
527     /// are the same on purpose, you can factor them
528     /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
529     ///
530     /// ### Known problems
531     /// False positive possible with order dependent `match`
532     /// (see issue
533     /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
534     ///
535     /// ### Example
536     /// ```rust,ignore
537     /// match foo {
538     ///     Bar => bar(),
539     ///     Quz => quz(),
540     ///     Baz => bar(), // <= oops
541     /// }
542     /// ```
543     ///
544     /// This should probably be
545     /// ```rust,ignore
546     /// match foo {
547     ///     Bar => bar(),
548     ///     Quz => quz(),
549     ///     Baz => baz(), // <= fixed
550     /// }
551     /// ```
552     ///
553     /// or if the original code was not a typo:
554     /// ```rust,ignore
555     /// match foo {
556     ///     Bar | Baz => bar(), // <= shows the intent better
557     ///     Quz => quz(),
558     /// }
559     /// ```
560     pub MATCH_SAME_ARMS,
561     pedantic,
562     "`match` with identical arm bodies"
563 }
564
565 #[derive(Default)]
566 pub struct Matches {
567     msrv: Option<RustcVersion>,
568     infallible_destructuring_match_linted: bool,
569 }
570
571 impl Matches {
572     #[must_use]
573     pub fn new(msrv: Option<RustcVersion>) -> Self {
574         Self {
575             msrv,
576             ..Matches::default()
577         }
578     }
579 }
580
581 impl_lint_pass!(Matches => [
582     SINGLE_MATCH,
583     MATCH_REF_PATS,
584     MATCH_BOOL,
585     SINGLE_MATCH_ELSE,
586     MATCH_OVERLAPPING_ARM,
587     MATCH_WILD_ERR_ARM,
588     MATCH_AS_REF,
589     WILDCARD_ENUM_MATCH_ARM,
590     MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
591     WILDCARD_IN_OR_PATTERNS,
592     MATCH_SINGLE_BINDING,
593     INFALLIBLE_DESTRUCTURING_MATCH,
594     REST_PAT_IN_FULLY_BOUND_STRUCTS,
595     REDUNDANT_PATTERN_MATCHING,
596     MATCH_LIKE_MATCHES_MACRO,
597     MATCH_SAME_ARMS,
598 ]);
599
600 impl<'tcx> LateLintPass<'tcx> for Matches {
601     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
602         if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) {
603             return;
604         }
605
606         redundant_pattern_match::check(cx, expr);
607
608         if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) {
609             if !check_match_like_matches(cx, expr) {
610                 lint_match_arms(cx, expr);
611             }
612         } else {
613             lint_match_arms(cx, expr);
614         }
615
616         if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
617             check_single_match(cx, ex, arms, expr);
618             check_match_bool(cx, ex, arms, expr);
619             check_overlapping_arms(cx, ex, arms);
620             check_wild_err_arm(cx, ex, arms);
621             check_wild_enum_match(cx, ex, arms);
622             check_match_as_ref(cx, ex, arms, expr);
623             check_wild_in_or_pats(cx, arms);
624
625             if self.infallible_destructuring_match_linted {
626                 self.infallible_destructuring_match_linted = false;
627             } else {
628                 check_match_single_binding(cx, ex, arms, expr);
629             }
630         }
631         if let ExprKind::Match(ex, arms, _) = expr.kind {
632             check_match_ref_pats(cx, ex, arms, expr);
633         }
634     }
635
636     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
637         if_chain! {
638             if !in_external_macro(cx.sess(), local.span);
639             if !in_macro(local.span);
640             if let Some(expr) = local.init;
641             if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind;
642             if arms.len() == 1 && arms[0].guard.is_none();
643             if let PatKind::TupleStruct(
644                 QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
645             if args.len() == 1;
646             if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
647             let body = remove_blocks(arms[0].body);
648             if path_to_local_id(body, arg);
649
650             then {
651                 let mut applicability = Applicability::MachineApplicable;
652                 self.infallible_destructuring_match_linted = true;
653                 span_lint_and_sugg(
654                     cx,
655                     INFALLIBLE_DESTRUCTURING_MATCH,
656                     local.span,
657                     "you seem to be trying to use `match` to destructure a single infallible pattern. \
658                     Consider using `let`",
659                     "try this",
660                     format!(
661                         "let {}({}) = {};",
662                         snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
663                         snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
664                         snippet_with_applicability(cx, target.span, "..", &mut applicability),
665                     ),
666                     applicability,
667                 );
668             }
669         }
670     }
671
672     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
673         if_chain! {
674             if !in_external_macro(cx.sess(), pat.span);
675             if !in_macro(pat.span);
676             if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
677             if let Some(def_id) = path.res.opt_def_id();
678             let ty = cx.tcx.type_of(def_id);
679             if let ty::Adt(def, _) = ty.kind();
680             if def.is_struct() || def.is_union();
681             if fields.len() == def.non_enum_variant().fields.len();
682
683             then {
684                 span_lint_and_help(
685                     cx,
686                     REST_PAT_IN_FULLY_BOUND_STRUCTS,
687                     pat.span,
688                     "unnecessary use of `..` pattern in struct binding. All fields were already bound",
689                     None,
690                     "consider removing `..` from this binding",
691                 );
692             }
693         }
694     }
695
696     extract_msrv_attr!(LateContext);
697 }
698
699 #[rustfmt::skip]
700 fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
701     if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
702         if in_macro(expr.span) {
703             // Don't lint match expressions present in
704             // macro_rules! block
705             return;
706         }
707         if let PatKind::Or(..) = arms[0].pat.kind {
708             // don't lint for or patterns for now, this makes
709             // the lint noisy in unnecessary situations
710             return;
711         }
712         let els = arms[1].body;
713         let els = if is_unit_expr(remove_blocks(els)) {
714             None
715         } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
716             if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
717                 // single statement/expr "else" block, don't lint
718                 return;
719             }
720             // block with 2+ statements or 1 expr and 1+ statement
721             Some(els)
722         } else {
723             // not a block, don't lint
724             return;
725         };
726
727         let ty = cx.typeck_results().expr_ty(ex);
728         if *ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id) {
729             check_single_match_single_pattern(cx, ex, arms, expr, els);
730             check_single_match_opt_like(cx, ex, arms, expr, ty, els);
731         }
732     }
733 }
734
735 fn check_single_match_single_pattern(
736     cx: &LateContext<'_>,
737     ex: &Expr<'_>,
738     arms: &[Arm<'_>],
739     expr: &Expr<'_>,
740     els: Option<&Expr<'_>>,
741 ) {
742     if is_wild(arms[1].pat) {
743         report_single_match_single_pattern(cx, ex, arms, expr, els);
744     }
745 }
746
747 fn report_single_match_single_pattern(
748     cx: &LateContext<'_>,
749     ex: &Expr<'_>,
750     arms: &[Arm<'_>],
751     expr: &Expr<'_>,
752     els: Option<&Expr<'_>>,
753 ) {
754     let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
755     let els_str = els.map_or(String::new(), |els| {
756         format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
757     });
758
759     let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
760     let (msg, sugg) = if_chain! {
761         if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind;
762         let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex));
763         if let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait();
764         if let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait();
765         if ty.is_integral() || ty.is_char() || ty.is_str()
766             || (implements_trait(cx, ty, spe_trait_id, &[])
767                 && implements_trait(cx, ty, pe_trait_id, &[ty.into()]));
768         then {
769             // scrutinee derives PartialEq and the pattern is a constant.
770             let pat_ref_count = match pat.kind {
771                 // string literals are already a reference.
772                 PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1,
773                 _ => pat_ref_count,
774             };
775             // References are only implicitly added to the pattern, so no overflow here.
776             // e.g. will work: match &Some(_) { Some(_) => () }
777             // will not: match Some(_) { &Some(_) => () }
778             let ref_count_diff = ty_ref_count - pat_ref_count;
779
780             // Try to remove address of expressions first.
781             let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
782             let ref_count_diff = ref_count_diff - removed;
783
784             let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
785             let sugg = format!(
786                 "if {} == {}{} {}{}",
787                 snippet(cx, ex.span, ".."),
788                 // PartialEq for different reference counts may not exist.
789                 "&".repeat(ref_count_diff),
790                 snippet(cx, arms[0].pat.span, ".."),
791                 expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
792                 els_str,
793             );
794             (msg, sugg)
795         } else {
796             let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
797             let sugg = format!(
798                 "if let {} = {} {}{}",
799                 snippet(cx, arms[0].pat.span, ".."),
800                 snippet(cx, ex.span, ".."),
801                 expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
802                 els_str,
803             );
804             (msg, sugg)
805         }
806     };
807
808     span_lint_and_sugg(
809         cx,
810         lint,
811         expr.span,
812         msg,
813         "try this",
814         sugg,
815         Applicability::HasPlaceholders,
816     );
817 }
818
819 fn check_single_match_opt_like(
820     cx: &LateContext<'_>,
821     ex: &Expr<'_>,
822     arms: &[Arm<'_>],
823     expr: &Expr<'_>,
824     ty: Ty<'_>,
825     els: Option<&Expr<'_>>,
826 ) {
827     // list of candidate `Enum`s we know will never get any more members
828     let candidates = &[
829         (&paths::COW, "Borrowed"),
830         (&paths::COW, "Cow::Borrowed"),
831         (&paths::COW, "Cow::Owned"),
832         (&paths::COW, "Owned"),
833         (&paths::OPTION, "None"),
834         (&paths::RESULT, "Err"),
835         (&paths::RESULT, "Ok"),
836     ];
837
838     let path = match arms[1].pat.kind {
839         PatKind::TupleStruct(ref path, inner, _) => {
840             // Contains any non wildcard patterns (e.g., `Err(err)`)?
841             if !inner.iter().all(is_wild) {
842                 return;
843             }
844             rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
845         },
846         PatKind::Binding(BindingAnnotation::Unannotated, .., ident, None) => ident.to_string(),
847         PatKind::Path(ref path) => {
848             rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
849         },
850         _ => return,
851     };
852
853     for &(ty_path, pat_path) in candidates {
854         if path == *pat_path && match_type(cx, ty, ty_path) {
855             report_single_match_single_pattern(cx, ex, arms, expr, els);
856         }
857     }
858 }
859
860 fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
861     // Type of expression is `bool`.
862     if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool {
863         span_lint_and_then(
864             cx,
865             MATCH_BOOL,
866             expr.span,
867             "you seem to be trying to match on a boolean expression",
868             move |diag| {
869                 if arms.len() == 2 {
870                     // no guards
871                     let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
872                         if let ExprKind::Lit(ref lit) = arm_bool.kind {
873                             match lit.node {
874                                 LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)),
875                                 LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)),
876                                 _ => None,
877                             }
878                         } else {
879                             None
880                         }
881                     } else {
882                         None
883                     };
884
885                     if let Some((true_expr, false_expr)) = exprs {
886                         let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) {
887                             (false, false) => Some(format!(
888                                 "if {} {} else {}",
889                                 snippet(cx, ex.span, "b"),
890                                 expr_block(cx, true_expr, None, "..", Some(expr.span)),
891                                 expr_block(cx, false_expr, None, "..", Some(expr.span))
892                             )),
893                             (false, true) => Some(format!(
894                                 "if {} {}",
895                                 snippet(cx, ex.span, "b"),
896                                 expr_block(cx, true_expr, None, "..", Some(expr.span))
897                             )),
898                             (true, false) => {
899                                 let test = Sugg::hir(cx, ex, "..");
900                                 Some(format!(
901                                     "if {} {}",
902                                     !test,
903                                     expr_block(cx, false_expr, None, "..", Some(expr.span))
904                                 ))
905                             },
906                             (true, true) => None,
907                         };
908
909                         if let Some(sugg) = sugg {
910                             diag.span_suggestion(
911                                 expr.span,
912                                 "consider using an `if`/`else` expression",
913                                 sugg,
914                                 Applicability::HasPlaceholders,
915                             );
916                         }
917                     }
918                 }
919             },
920         );
921     }
922 }
923
924 fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
925     if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
926         let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
927         let type_ranges = type_ranges(&ranges);
928         if !type_ranges.is_empty() {
929             if let Some((start, end)) = overlapping(&type_ranges) {
930                 span_lint_and_note(
931                     cx,
932                     MATCH_OVERLAPPING_ARM,
933                     start.span,
934                     "some ranges overlap",
935                     Some(end.span),
936                     "overlaps with this",
937                 );
938             }
939         }
940     }
941 }
942
943 fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
944     let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
945     if is_type_diagnostic_item(cx, ex_ty, sym::result_type) {
946         for arm in arms {
947             if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
948                 let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
949                 if path_str == "Err" {
950                     let mut matching_wild = inner.iter().any(is_wild);
951                     let mut ident_bind_name = String::from("_");
952                     if !matching_wild {
953                         // Looking for unused bindings (i.e.: `_e`)
954                         for pat in inner.iter() {
955                             if let PatKind::Binding(_, id, ident, None) = pat.kind {
956                                 if ident.as_str().starts_with('_')
957                                     && !LocalUsedVisitor::new(cx, id).check_expr(arm.body)
958                                 {
959                                     ident_bind_name = (&ident.name.as_str()).to_string();
960                                     matching_wild = true;
961                                 }
962                             }
963                         }
964                     }
965                     if_chain! {
966                         if matching_wild;
967                         if let ExprKind::Block(block, _) = arm.body.kind;
968                         if is_panic_block(block);
969                         then {
970                             // `Err(_)` or `Err(_e)` arm with `panic!` found
971                             span_lint_and_note(cx,
972                                 MATCH_WILD_ERR_ARM,
973                                 arm.pat.span,
974                                 &format!("`Err({})` matches all errors", &ident_bind_name),
975                                 None,
976                                 "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
977                             );
978                         }
979                     }
980                 }
981             }
982         }
983     }
984 }
985
986 enum CommonPrefixSearcher<'a> {
987     None,
988     Path(&'a [PathSegment<'a>]),
989     Mixed,
990 }
991 impl CommonPrefixSearcher<'a> {
992     fn with_path(&mut self, path: &'a [PathSegment<'a>]) {
993         match path {
994             [path @ .., _] => self.with_prefix(path),
995             [] => (),
996         }
997     }
998
999     fn with_prefix(&mut self, path: &'a [PathSegment<'a>]) {
1000         match self {
1001             Self::None => *self = Self::Path(path),
1002             Self::Path(self_path)
1003                 if path
1004                     .iter()
1005                     .map(|p| p.ident.name)
1006                     .eq(self_path.iter().map(|p| p.ident.name)) => {},
1007             Self::Path(_) => *self = Self::Mixed,
1008             Self::Mixed => (),
1009         }
1010     }
1011 }
1012
1013 fn is_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool {
1014     let attrs = cx.tcx.get_attrs(variant_def.def_id);
1015     clippy_utils::attrs::is_doc_hidden(attrs) || clippy_utils::attrs::is_unstable(attrs)
1016 }
1017
1018 #[allow(clippy::too_many_lines)]
1019 fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
1020     let ty = cx.typeck_results().expr_ty(ex).peel_refs();
1021     let adt_def = match ty.kind() {
1022         ty::Adt(adt_def, _)
1023             if adt_def.is_enum()
1024                 && !(is_type_diagnostic_item(cx, ty, sym::option_type)
1025                     || is_type_diagnostic_item(cx, ty, sym::result_type)) =>
1026         {
1027             adt_def
1028         },
1029         _ => return,
1030     };
1031
1032     // First pass - check for violation, but don't do much book-keeping because this is hopefully
1033     // the uncommon case, and the book-keeping is slightly expensive.
1034     let mut wildcard_span = None;
1035     let mut wildcard_ident = None;
1036     let mut has_non_wild = false;
1037     for arm in arms {
1038         match peel_hir_pat_refs(arm.pat).0.kind {
1039             PatKind::Wild => wildcard_span = Some(arm.pat.span),
1040             PatKind::Binding(_, _, ident, None) => {
1041                 wildcard_span = Some(arm.pat.span);
1042                 wildcard_ident = Some(ident);
1043             },
1044             _ => has_non_wild = true,
1045         }
1046     }
1047     let wildcard_span = match wildcard_span {
1048         Some(x) if has_non_wild => x,
1049         _ => return,
1050     };
1051
1052     // Accumulate the variants which should be put in place of the wildcard because they're not
1053     // already covered.
1054     let has_hidden = adt_def.variants.iter().any(|x| is_hidden(cx, x));
1055     let mut missing_variants: Vec<_> = adt_def.variants.iter().filter(|x| !is_hidden(cx, x)).collect();
1056
1057     let mut path_prefix = CommonPrefixSearcher::None;
1058     for arm in arms {
1059         // Guards mean that this case probably isn't exhaustively covered. Technically
1060         // this is incorrect, as we should really check whether each variant is exhaustively
1061         // covered by the set of guards that cover it, but that's really hard to do.
1062         recurse_or_patterns(arm.pat, |pat| {
1063             let path = match &peel_hir_pat_refs(pat).0.kind {
1064                 PatKind::Path(path) => {
1065                     #[allow(clippy::match_same_arms)]
1066                     let id = match cx.qpath_res(path, pat.hir_id) {
1067                         Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return,
1068                         Res::Def(_, id) => id,
1069                         _ => return,
1070                     };
1071                     if arm.guard.is_none() {
1072                         missing_variants.retain(|e| e.ctor_def_id != Some(id));
1073                     }
1074                     path
1075                 },
1076                 PatKind::TupleStruct(path, patterns, ..) => {
1077                     if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
1078                         if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) {
1079                             missing_variants.retain(|e| e.ctor_def_id != Some(id));
1080                         }
1081                     }
1082                     path
1083                 },
1084                 PatKind::Struct(path, patterns, ..) => {
1085                     if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
1086                         if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p.pat)) {
1087                             missing_variants.retain(|e| e.def_id != id);
1088                         }
1089                     }
1090                     path
1091                 },
1092                 _ => return,
1093             };
1094             match path {
1095                 QPath::Resolved(_, path) => path_prefix.with_path(path.segments),
1096                 QPath::TypeRelative(
1097                     hir::Ty {
1098                         kind: TyKind::Path(QPath::Resolved(_, path)),
1099                         ..
1100                     },
1101                     _,
1102                 ) => path_prefix.with_prefix(path.segments),
1103                 _ => (),
1104             }
1105         });
1106     }
1107
1108     let format_suggestion = |variant: &VariantDef| {
1109         format!(
1110             "{}{}{}{}",
1111             if let Some(ident) = wildcard_ident {
1112                 format!("{} @ ", ident.name)
1113             } else {
1114                 String::new()
1115             },
1116             if let CommonPrefixSearcher::Path(path_prefix) = path_prefix {
1117                 let mut s = String::new();
1118                 for seg in path_prefix {
1119                     s.push_str(&seg.ident.as_str());
1120                     s.push_str("::");
1121                 }
1122                 s
1123             } else {
1124                 let mut s = cx.tcx.def_path_str(adt_def.did);
1125                 s.push_str("::");
1126                 s
1127             },
1128             variant.ident.name,
1129             match variant.ctor_kind {
1130                 CtorKind::Fn if variant.fields.len() == 1 => "(_)",
1131                 CtorKind::Fn => "(..)",
1132                 CtorKind::Const => "",
1133                 CtorKind::Fictive => "{ .. }",
1134             }
1135         )
1136     };
1137
1138     match missing_variants.as_slice() {
1139         [] => (),
1140         [x] if !adt_def.is_variant_list_non_exhaustive() && !has_hidden => span_lint_and_sugg(
1141             cx,
1142             MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
1143             wildcard_span,
1144             "wildcard matches only a single variant and will also match any future added variants",
1145             "try this",
1146             format_suggestion(x),
1147             Applicability::MaybeIncorrect,
1148         ),
1149         variants => {
1150             let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect();
1151             let message = if adt_def.is_variant_list_non_exhaustive() || has_hidden {
1152                 suggestions.push("_".into());
1153                 "wildcard matches known variants and will also match future added variants"
1154             } else {
1155                 "wildcard match will also match any future added variants"
1156             };
1157
1158             span_lint_and_sugg(
1159                 cx,
1160                 WILDCARD_ENUM_MATCH_ARM,
1161                 wildcard_span,
1162                 message,
1163                 "try this",
1164                 suggestions.join(" | "),
1165                 Applicability::MaybeIncorrect,
1166             );
1167         },
1168     };
1169 }
1170
1171 // If the block contains only a `panic!` macro (as expression or statement)
1172 fn is_panic_block(block: &Block<'_>) -> bool {
1173     match (&block.expr, block.stmts.len(), block.stmts.first()) {
1174         (&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(),
1175         (&None, 1, Some(stmt)) => {
1176             is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none()
1177         },
1178         _ => false,
1179     }
1180 }
1181
1182 fn check_match_ref_pats(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
1183     if has_only_ref_pats(arms) {
1184         let mut suggs = Vec::with_capacity(arms.len() + 1);
1185         let (title, msg) = if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
1186             let span = ex.span.source_callsite();
1187             suggs.push((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
1188             (
1189                 "you don't need to add `&` to both the expression and the patterns",
1190                 "try",
1191             )
1192         } else {
1193             let span = ex.span.source_callsite();
1194             suggs.push((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
1195             (
1196                 "you don't need to add `&` to all patterns",
1197                 "instead of prefixing all patterns with `&`, you can dereference the expression",
1198             )
1199         };
1200
1201         suggs.extend(arms.iter().filter_map(|a| {
1202             if let PatKind::Ref(refp, _) = a.pat.kind {
1203                 Some((a.pat.span, snippet(cx, refp.span, "..").to_string()))
1204             } else {
1205                 None
1206             }
1207         }));
1208
1209         span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
1210             if !expr.span.from_expansion() {
1211                 multispan_sugg(diag, msg, suggs);
1212             }
1213         });
1214     }
1215 }
1216
1217 fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
1218     if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
1219         let arm_ref: Option<BindingAnnotation> = if is_none_arm(cx, &arms[0]) {
1220             is_ref_some_arm(cx, &arms[1])
1221         } else if is_none_arm(cx, &arms[1]) {
1222             is_ref_some_arm(cx, &arms[0])
1223         } else {
1224             None
1225         };
1226         if let Some(rb) = arm_ref {
1227             let suggestion = if rb == BindingAnnotation::Ref {
1228                 "as_ref"
1229             } else {
1230                 "as_mut"
1231             };
1232
1233             let output_ty = cx.typeck_results().expr_ty(expr);
1234             let input_ty = cx.typeck_results().expr_ty(ex);
1235
1236             let cast = if_chain! {
1237                 if let ty::Adt(_, substs) = input_ty.kind();
1238                 let input_ty = substs.type_at(0);
1239                 if let ty::Adt(_, substs) = output_ty.kind();
1240                 let output_ty = substs.type_at(0);
1241                 if let ty::Ref(_, output_ty, _) = *output_ty.kind();
1242                 if input_ty != output_ty;
1243                 then {
1244                     ".map(|x| x as _)"
1245                 } else {
1246                     ""
1247                 }
1248             };
1249
1250             let mut applicability = Applicability::MachineApplicable;
1251             span_lint_and_sugg(
1252                 cx,
1253                 MATCH_AS_REF,
1254                 expr.span,
1255                 &format!("use `{}()` instead", suggestion),
1256                 "try this",
1257                 format!(
1258                     "{}.{}(){}",
1259                     snippet_with_applicability(cx, ex.span, "_", &mut applicability),
1260                     suggestion,
1261                     cast,
1262                 ),
1263                 applicability,
1264             );
1265         }
1266     }
1267 }
1268
1269 fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
1270     for arm in arms {
1271         if let PatKind::Or(fields) = arm.pat.kind {
1272             // look for multiple fields in this arm that contains at least one Wild pattern
1273             if fields.len() > 1 && fields.iter().any(is_wild) {
1274                 span_lint_and_help(
1275                     cx,
1276                     WILDCARD_IN_OR_PATTERNS,
1277                     arm.pat.span,
1278                     "wildcard pattern covers any other pattern as it will match anyway",
1279                     None,
1280                     "consider handling `_` separately",
1281                 );
1282             }
1283         }
1284     }
1285 }
1286
1287 /// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
1288 fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
1289     if let ExprKind::Match(ex, arms, ref match_source) = &expr.kind {
1290         match match_source {
1291             MatchSource::Normal => find_matches_sugg(cx, ex, arms, expr, false),
1292             MatchSource::IfLetDesugar { .. } => find_matches_sugg(cx, ex, arms, expr, true),
1293             _ => false,
1294         }
1295     } else {
1296         false
1297     }
1298 }
1299
1300 /// Lint a `match` or desugared `if let` for replacement by `matches!`
1301 fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>, desugared: bool) -> bool {
1302     if_chain! {
1303         if arms.len() >= 2;
1304         if cx.typeck_results().expr_ty(expr).is_bool();
1305         if let Some((b1_arm, b0_arms)) = arms.split_last();
1306         if let Some(b0) = find_bool_lit(&b0_arms[0].body.kind, desugared);
1307         if let Some(b1) = find_bool_lit(&b1_arm.body.kind, desugared);
1308         if is_wild(b1_arm.pat);
1309         if b0 != b1;
1310         let if_guard = &b0_arms[0].guard;
1311         if if_guard.is_none() || b0_arms.len() == 1;
1312         if cx.tcx.hir().attrs(b0_arms[0].hir_id).is_empty();
1313         if b0_arms[1..].iter()
1314             .all(|arm| {
1315                 find_bool_lit(&arm.body.kind, desugared).map_or(false, |b| b == b0) &&
1316                 arm.guard.is_none() && cx.tcx.hir().attrs(arm.hir_id).is_empty()
1317             });
1318         then {
1319             // The suggestion may be incorrect, because some arms can have `cfg` attributes
1320             // evaluated into `false` and so such arms will be stripped before.
1321             let mut applicability = Applicability::MaybeIncorrect;
1322             let pat = {
1323                 use itertools::Itertools as _;
1324                 b0_arms.iter()
1325                     .map(|arm| snippet_with_applicability(cx, arm.pat.span, "..", &mut applicability))
1326                     .join(" | ")
1327             };
1328             let pat_and_guard = if let Some(Guard::If(g)) = if_guard {
1329                 format!("{} if {}", pat, snippet_with_applicability(cx, g.span, "..", &mut applicability))
1330             } else {
1331                 pat
1332             };
1333
1334             // strip potential borrows (#6503), but only if the type is a reference
1335             let mut ex_new = ex;
1336             if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
1337                 if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() {
1338                     ex_new = ex_inner;
1339                 }
1340             };
1341             span_lint_and_sugg(
1342                 cx,
1343                 MATCH_LIKE_MATCHES_MACRO,
1344                 expr.span,
1345                 &format!("{} expression looks like `matches!` macro", if desugared { "if let .. else" } else { "match" }),
1346                 "try this",
1347                 format!(
1348                     "{}matches!({}, {})",
1349                     if b0 { "" } else { "!" },
1350                     snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
1351                     pat_and_guard,
1352                 ),
1353                 applicability,
1354             );
1355             true
1356         } else {
1357             false
1358         }
1359     }
1360 }
1361
1362 /// Extract a `bool` or `{ bool }`
1363 fn find_bool_lit(ex: &ExprKind<'_>, desugared: bool) -> Option<bool> {
1364     match ex {
1365         ExprKind::Lit(Spanned {
1366             node: LitKind::Bool(b), ..
1367         }) => Some(*b),
1368         ExprKind::Block(
1369             rustc_hir::Block {
1370                 stmts: &[],
1371                 expr: Some(exp),
1372                 ..
1373             },
1374             _,
1375         ) if desugared => {
1376             if let ExprKind::Lit(Spanned {
1377                 node: LitKind::Bool(b), ..
1378             }) = exp.kind
1379             {
1380                 Some(b)
1381             } else {
1382                 None
1383             }
1384         },
1385         _ => None,
1386     }
1387 }
1388
1389 #[allow(clippy::too_many_lines)]
1390 fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
1391     if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
1392         return;
1393     }
1394
1395     // HACK:
1396     // This is a hack to deal with arms that are excluded by macros like `#[cfg]`. It is only used here
1397     // to prevent false positives as there is currently no better way to detect if code was excluded by
1398     // a macro. See PR #6435
1399     if_chain! {
1400         if let Some(match_snippet) = snippet_opt(cx, expr.span);
1401         if let Some(arm_snippet) = snippet_opt(cx, arms[0].span);
1402         if let Some(ex_snippet) = snippet_opt(cx, ex.span);
1403         let rest_snippet = match_snippet.replace(&arm_snippet, "").replace(&ex_snippet, "");
1404         if rest_snippet.contains("=>");
1405         then {
1406             // The code it self contains another thick arrow "=>"
1407             // -> Either another arm or a comment
1408             return;
1409         }
1410     }
1411
1412     let matched_vars = ex.span;
1413     let bind_names = arms[0].pat.span;
1414     let match_body = remove_blocks(arms[0].body);
1415     let mut snippet_body = if match_body.span.from_expansion() {
1416         Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
1417     } else {
1418         snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string()
1419     };
1420
1421     // Do we need to add ';' to suggestion ?
1422     match match_body.kind {
1423         ExprKind::Block(block, _) => {
1424             // macro + expr_ty(body) == ()
1425             if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
1426                 snippet_body.push(';');
1427             }
1428         },
1429         _ => {
1430             // expr_ty(body) == ()
1431             if cx.typeck_results().expr_ty(match_body).is_unit() {
1432                 snippet_body.push(';');
1433             }
1434         },
1435     }
1436
1437     let mut applicability = Applicability::MaybeIncorrect;
1438     match arms[0].pat.kind {
1439         PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
1440             // If this match is in a local (`let`) stmt
1441             let (target_span, sugg) = if let Some(parent_let_node) = opt_parent_let(cx, ex) {
1442                 (
1443                     parent_let_node.span,
1444                     format!(
1445                         "let {} = {};\n{}let {} = {};",
1446                         snippet_with_applicability(cx, bind_names, "..", &mut applicability),
1447                         snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
1448                         " ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
1449                         snippet_with_applicability(cx, parent_let_node.pat.span, "..", &mut applicability),
1450                         snippet_body
1451                     ),
1452                 )
1453             } else {
1454                 // If we are in closure, we need curly braces around suggestion
1455                 let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
1456                 let (mut cbrace_start, mut cbrace_end) = ("".to_string(), "".to_string());
1457                 if let Some(parent_expr) = get_parent_expr(cx, expr) {
1458                     if let ExprKind::Closure(..) = parent_expr.kind {
1459                         cbrace_end = format!("\n{}}}", indent);
1460                         // Fix body indent due to the closure
1461                         indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
1462                         cbrace_start = format!("{{\n{}", indent);
1463                     }
1464                 }
1465                 // If the parent is already an arm, and the body is another match statement,
1466                 // we need curly braces around suggestion
1467                 let parent_node_id = cx.tcx.hir().get_parent_node(expr.hir_id);
1468                 if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
1469                     if let ExprKind::Match(..) = arm.body.kind {
1470                         cbrace_end = format!("\n{}}}", indent);
1471                         // Fix body indent due to the match
1472                         indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
1473                         cbrace_start = format!("{{\n{}", indent);
1474                     }
1475                 }
1476                 (
1477                     expr.span,
1478                     format!(
1479                         "{}let {} = {};\n{}{}{}",
1480                         cbrace_start,
1481                         snippet_with_applicability(cx, bind_names, "..", &mut applicability),
1482                         snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
1483                         indent,
1484                         snippet_body,
1485                         cbrace_end
1486                     ),
1487                 )
1488             };
1489             span_lint_and_sugg(
1490                 cx,
1491                 MATCH_SINGLE_BINDING,
1492                 target_span,
1493                 "this match could be written as a `let` statement",
1494                 "consider using `let` statement",
1495                 sugg,
1496                 applicability,
1497             );
1498         },
1499         PatKind::Wild => {
1500             if ex.can_have_side_effects() {
1501                 let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0));
1502                 let sugg = format!(
1503                     "{};\n{}{}",
1504                     snippet_with_applicability(cx, ex.span, "..", &mut applicability),
1505                     indent,
1506                     snippet_body
1507                 );
1508                 span_lint_and_sugg(
1509                     cx,
1510                     MATCH_SINGLE_BINDING,
1511                     expr.span,
1512                     "this match could be replaced by its scrutinee and body",
1513                     "consider using the scrutinee and body instead",
1514                     sugg,
1515                     applicability,
1516                 );
1517             } else {
1518                 span_lint_and_sugg(
1519                     cx,
1520                     MATCH_SINGLE_BINDING,
1521                     expr.span,
1522                     "this match could be replaced by its body itself",
1523                     "consider using the match body instead",
1524                     snippet_body,
1525                     Applicability::MachineApplicable,
1526                 );
1527             }
1528         },
1529         _ => (),
1530     }
1531 }
1532
1533 /// Returns true if the `ex` match expression is in a local (`let`) statement
1534 fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> {
1535     let map = &cx.tcx.hir();
1536     if_chain! {
1537         if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id));
1538         if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id));
1539         then {
1540             return Some(parent_let_expr);
1541         }
1542     }
1543     None
1544 }
1545
1546 /// Gets all arms that are unbounded `PatRange`s.
1547 fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> {
1548     arms.iter()
1549         .filter_map(|arm| {
1550             if let Arm { pat, guard: None, .. } = *arm {
1551                 if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
1552                     let lhs = match lhs {
1553                         Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
1554                         None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
1555                     };
1556                     let rhs = match rhs {
1557                         Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
1558                         None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
1559                     };
1560                     let rhs = match range_end {
1561                         RangeEnd::Included => Bound::Included(rhs),
1562                         RangeEnd::Excluded => Bound::Excluded(rhs),
1563                     };
1564                     return Some(SpannedRange {
1565                         span: pat.span,
1566                         node: (lhs, rhs),
1567                     });
1568                 }
1569
1570                 if let PatKind::Lit(value) = pat.kind {
1571                     let value = constant(cx, cx.typeck_results(), value)?.0;
1572                     return Some(SpannedRange {
1573                         span: pat.span,
1574                         node: (value.clone(), Bound::Included(value)),
1575                     });
1576                 }
1577             }
1578             None
1579         })
1580         .collect()
1581 }
1582
1583 #[derive(Debug, Eq, PartialEq)]
1584 pub struct SpannedRange<T> {
1585     pub span: Span,
1586     pub node: (T, Bound<T>),
1587 }
1588
1589 type TypedRanges = Vec<SpannedRange<u128>>;
1590
1591 /// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
1592 /// and other types than
1593 /// `Uint` and `Int` probably don't make sense.
1594 fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
1595     ranges
1596         .iter()
1597         .filter_map(|range| match range.node {
1598             (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
1599                 span: range.span,
1600                 node: (start, Bound::Included(end)),
1601             }),
1602             (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
1603                 span: range.span,
1604                 node: (start, Bound::Excluded(end)),
1605             }),
1606             (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
1607                 span: range.span,
1608                 node: (start, Bound::Unbounded),
1609             }),
1610             _ => None,
1611         })
1612         .collect()
1613 }
1614
1615 fn is_unit_expr(expr: &Expr<'_>) -> bool {
1616     match expr.kind {
1617         ExprKind::Tup(v) if v.is_empty() => true,
1618         ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none() => true,
1619         _ => false,
1620     }
1621 }
1622
1623 // Checks if arm has the form `None => None`
1624 fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
1625     matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
1626 }
1627
1628 // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
1629 fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotation> {
1630     if_chain! {
1631         if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
1632         if is_lang_ctor(cx, qpath, OptionSome);
1633         if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
1634         if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
1635         if let ExprKind::Call(e, args) = remove_blocks(arm.body).kind;
1636         if let ExprKind::Path(ref some_path) = e.kind;
1637         if is_lang_ctor(cx, some_path, OptionSome) && args.len() == 1;
1638         if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
1639         if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
1640         then {
1641             return Some(rb)
1642         }
1643     }
1644     None
1645 }
1646
1647 fn has_only_ref_pats(arms: &[Arm<'_>]) -> bool {
1648     let mapped = arms
1649         .iter()
1650         .map(|a| {
1651             match a.pat.kind {
1652                 PatKind::Ref(..) => Some(true), // &-patterns
1653                 PatKind::Wild => Some(false),   // an "anything" wildcard is also fine
1654                 _ => None,                      // any other pattern is not fine
1655             }
1656         })
1657         .collect::<Option<Vec<bool>>>();
1658     // look for Some(v) where there's at least one true element
1659     mapped.map_or(false, |v| v.iter().any(|el| *el))
1660 }
1661
1662 pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
1663 where
1664     T: Copy + Ord,
1665 {
1666     #[derive(Copy, Clone, Debug, Eq, PartialEq)]
1667     enum Kind<'a, T> {
1668         Start(T, &'a SpannedRange<T>),
1669         End(Bound<T>, &'a SpannedRange<T>),
1670     }
1671
1672     impl<'a, T: Copy> Kind<'a, T> {
1673         fn range(&self) -> &'a SpannedRange<T> {
1674             match *self {
1675                 Kind::Start(_, r) | Kind::End(_, r) => r,
1676             }
1677         }
1678
1679         fn value(self) -> Bound<T> {
1680             match self {
1681                 Kind::Start(t, _) => Bound::Included(t),
1682                 Kind::End(t, _) => t,
1683             }
1684         }
1685     }
1686
1687     impl<'a, T: Copy + Ord> PartialOrd for Kind<'a, T> {
1688         fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1689             Some(self.cmp(other))
1690         }
1691     }
1692
1693     impl<'a, T: Copy + Ord> Ord for Kind<'a, T> {
1694         fn cmp(&self, other: &Self) -> Ordering {
1695             match (self.value(), other.value()) {
1696                 (Bound::Included(a), Bound::Included(b)) | (Bound::Excluded(a), Bound::Excluded(b)) => a.cmp(&b),
1697                 // Range patterns cannot be unbounded (yet)
1698                 (Bound::Unbounded, _) | (_, Bound::Unbounded) => unimplemented!(),
1699                 (Bound::Included(a), Bound::Excluded(b)) => match a.cmp(&b) {
1700                     Ordering::Equal => Ordering::Greater,
1701                     other => other,
1702                 },
1703                 (Bound::Excluded(a), Bound::Included(b)) => match a.cmp(&b) {
1704                     Ordering::Equal => Ordering::Less,
1705                     other => other,
1706                 },
1707             }
1708         }
1709     }
1710
1711     let mut values = Vec::with_capacity(2 * ranges.len());
1712
1713     for r in ranges {
1714         values.push(Kind::Start(r.node.0, r));
1715         values.push(Kind::End(r.node.1, r));
1716     }
1717
1718     values.sort();
1719
1720     for (a, b) in iter::zip(&values, values.iter().skip(1)) {
1721         match (a, b) {
1722             (&Kind::Start(_, ra), &Kind::End(_, rb)) => {
1723                 if ra.node != rb.node {
1724                     return Some((ra, rb));
1725                 }
1726             },
1727             (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
1728             _ => {
1729                 // skip if the range `a` is completely included into the range `b`
1730                 if let Ordering::Equal | Ordering::Less = a.cmp(b) {
1731                     let kind_a = Kind::End(a.range().node.1, a.range());
1732                     let kind_b = Kind::End(b.range().node.1, b.range());
1733                     if let Ordering::Equal | Ordering::Greater = kind_a.cmp(&kind_b) {
1734                         return None;
1735                     }
1736                 }
1737                 return Some((a.range(), b.range()));
1738             },
1739         }
1740     }
1741
1742     None
1743 }
1744
1745 mod redundant_pattern_match {
1746     use super::REDUNDANT_PATTERN_MATCHING;
1747     use clippy_utils::diagnostics::span_lint_and_then;
1748     use clippy_utils::source::{snippet, snippet_with_applicability};
1749     use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
1750     use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths};
1751     use if_chain::if_chain;
1752     use rustc_ast::ast::LitKind;
1753     use rustc_data_structures::fx::FxHashSet;
1754     use rustc_errors::Applicability;
1755     use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
1756     use rustc_hir::{
1757         intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor},
1758         Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, PatKind, QPath,
1759     };
1760     use rustc_lint::LateContext;
1761     use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
1762     use rustc_span::sym;
1763
1764     pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
1765         if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
1766             match match_source {
1767                 MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
1768                 MatchSource::IfLetDesugar { contains_else_clause } => {
1769                     find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause);
1770                 },
1771                 MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, &arms[0], "while", false),
1772                 _ => {},
1773             }
1774         }
1775     }
1776
1777     /// Checks if the drop order for a type matters. Some std types implement drop solely to
1778     /// deallocate memory. For these types, and composites containing them, changing the drop order
1779     /// won't result in any observable side effects.
1780     fn type_needs_ordered_drop(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
1781         type_needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
1782     }
1783
1784     fn type_needs_ordered_drop_inner(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet<Ty<'tcx>>) -> bool {
1785         if !seen.insert(ty) {
1786             return false;
1787         }
1788         if !ty.needs_drop(cx.tcx, cx.param_env) {
1789             false
1790         } else if !cx
1791             .tcx
1792             .lang_items()
1793             .drop_trait()
1794             .map_or(false, |id| implements_trait(cx, ty, id, &[]))
1795         {
1796             // This type doesn't implement drop, so no side effects here.
1797             // Check if any component type has any.
1798             match ty.kind() {
1799                 ty::Tuple(_) => ty.tuple_fields().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
1800                 ty::Array(ty, _) => type_needs_ordered_drop_inner(cx, ty, seen),
1801                 ty::Adt(adt, subs) => adt
1802                     .all_fields()
1803                     .map(|f| f.ty(cx.tcx, subs))
1804                     .any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
1805                 _ => true,
1806             }
1807         }
1808         // Check for std types which implement drop, but only for memory allocation.
1809         else if is_type_diagnostic_item(cx, ty, sym::vec_type)
1810             || is_type_lang_item(cx, ty, LangItem::OwnedBox)
1811             || is_type_diagnostic_item(cx, ty, sym::Rc)
1812             || is_type_diagnostic_item(cx, ty, sym::Arc)
1813             || is_type_diagnostic_item(cx, ty, sym::cstring_type)
1814             || is_type_diagnostic_item(cx, ty, sym::BTreeMap)
1815             || is_type_diagnostic_item(cx, ty, sym::LinkedList)
1816             || match_type(cx, ty, &paths::WEAK_RC)
1817             || match_type(cx, ty, &paths::WEAK_ARC)
1818         {
1819             // Check all of the generic arguments.
1820             if let ty::Adt(_, subs) = ty.kind() {
1821                 subs.types().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen))
1822             } else {
1823                 true
1824             }
1825         } else {
1826             true
1827         }
1828     }
1829
1830     // Extract the generic arguments out of a type
1831     fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
1832         if_chain! {
1833             if let ty::Adt(_, subs) = ty.kind();
1834             if let Some(sub) = subs.get(index);
1835             if let GenericArgKind::Type(sub_ty) = sub.unpack();
1836             then {
1837                 Some(sub_ty)
1838             } else {
1839                 None
1840             }
1841         }
1842     }
1843
1844     // Checks if there are any temporaries created in the given expression for which drop order
1845     // matters.
1846     fn temporaries_need_ordered_drop(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
1847         struct V<'a, 'tcx> {
1848             cx: &'a LateContext<'tcx>,
1849             res: bool,
1850         }
1851         impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
1852             type Map = ErasedMap<'tcx>;
1853             fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
1854                 NestedVisitorMap::None
1855             }
1856
1857             fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
1858                 match expr.kind {
1859                     // Taking the reference of a value leaves a temporary
1860                     // e.g. In `&String::new()` the string is a temporary value.
1861                     // Remaining fields are temporary values
1862                     // e.g. In `(String::new(), 0).1` the string is a temporary value.
1863                     ExprKind::AddrOf(_, _, expr) | ExprKind::Field(expr, _) => {
1864                         if !matches!(expr.kind, ExprKind::Path(_)) {
1865                             if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(expr)) {
1866                                 self.res = true;
1867                             } else {
1868                                 self.visit_expr(expr);
1869                             }
1870                         }
1871                     },
1872                     // the base type is alway taken by reference.
1873                     // e.g. In `(vec![0])[0]` the vector is a temporary value.
1874                     ExprKind::Index(base, index) => {
1875                         if !matches!(base.kind, ExprKind::Path(_)) {
1876                             if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(base)) {
1877                                 self.res = true;
1878                             } else {
1879                                 self.visit_expr(base);
1880                             }
1881                         }
1882                         self.visit_expr(index);
1883                     },
1884                     // Method calls can take self by reference.
1885                     // e.g. In `String::new().len()` the string is a temporary value.
1886                     ExprKind::MethodCall(_, _, [self_arg, args @ ..], _) => {
1887                         if !matches!(self_arg.kind, ExprKind::Path(_)) {
1888                             let self_by_ref = self
1889                                 .cx
1890                                 .typeck_results()
1891                                 .type_dependent_def_id(expr.hir_id)
1892                                 .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref());
1893                             if self_by_ref
1894                                 && type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(self_arg))
1895                             {
1896                                 self.res = true;
1897                             } else {
1898                                 self.visit_expr(self_arg);
1899                             }
1900                         }
1901                         args.iter().for_each(|arg| self.visit_expr(arg));
1902                     },
1903                     // Either explicitly drops values, or changes control flow.
1904                     ExprKind::DropTemps(_)
1905                     | ExprKind::Ret(_)
1906                     | ExprKind::Break(..)
1907                     | ExprKind::Yield(..)
1908                     | ExprKind::Block(Block { expr: None, .. }, _)
1909                     | ExprKind::Loop(..) => (),
1910
1911                     // Only consider the final expression.
1912                     ExprKind::Block(Block { expr: Some(expr), .. }, _) => self.visit_expr(expr),
1913
1914                     _ => walk_expr(self, expr),
1915                 }
1916             }
1917         }
1918
1919         let mut v = V { cx, res: false };
1920         v.visit_expr(expr);
1921         v.res
1922     }
1923
1924     fn find_sugg_for_if_let<'tcx>(
1925         cx: &LateContext<'tcx>,
1926         expr: &'tcx Expr<'_>,
1927         op: &'tcx Expr<'tcx>,
1928         arm: &Arm<'_>,
1929         keyword: &'static str,
1930         has_else: bool,
1931     ) {
1932         // also look inside refs
1933         let mut kind = &arm.pat.kind;
1934         // if we have &None for example, peel it so we can detect "if let None = x"
1935         if let PatKind::Ref(inner, _mutability) = kind {
1936             kind = &inner.kind;
1937         }
1938         let op_ty = cx.typeck_results().expr_ty(op);
1939         // Determine which function should be used, and the type contained by the corresponding
1940         // variant.
1941         let (good_method, inner_ty) = match kind {
1942             PatKind::TupleStruct(ref path, [sub_pat], _) => {
1943                 if let PatKind::Wild = sub_pat.kind {
1944                     if is_lang_ctor(cx, path, ResultOk) {
1945                         ("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
1946                     } else if is_lang_ctor(cx, path, ResultErr) {
1947                         ("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty))
1948                     } else if is_lang_ctor(cx, path, OptionSome) {
1949                         ("is_some()", op_ty)
1950                     } else if is_lang_ctor(cx, path, PollReady) {
1951                         ("is_ready()", op_ty)
1952                     } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V4) {
1953                         ("is_ipv4()", op_ty)
1954                     } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V6) {
1955                         ("is_ipv6()", op_ty)
1956                     } else {
1957                         return;
1958                     }
1959                 } else {
1960                     return;
1961                 }
1962             },
1963             PatKind::Path(ref path) => {
1964                 let method = if is_lang_ctor(cx, path, OptionNone) {
1965                     "is_none()"
1966                 } else if is_lang_ctor(cx, path, PollPending) {
1967                     "is_pending()"
1968                 } else {
1969                     return;
1970                 };
1971                 // `None` and `Pending` don't have an inner type.
1972                 (method, cx.tcx.types.unit)
1973             },
1974             _ => return,
1975         };
1976
1977         // If this is the last expression in a block or there is an else clause then the whole
1978         // type needs to be considered, not just the inner type of the branch being matched on.
1979         // Note the last expression in a block is dropped after all local bindings.
1980         let check_ty = if has_else
1981             || (keyword == "if" && matches!(cx.tcx.hir().parent_iter(expr.hir_id).next(), Some((_, Node::Block(..)))))
1982         {
1983             op_ty
1984         } else {
1985             inner_ty
1986         };
1987
1988         // All temporaries created in the scrutinee expression are dropped at the same time as the
1989         // scrutinee would be, so they have to be considered as well.
1990         // e.g. in `if let Some(x) = foo.lock().unwrap().baz.as_ref() { .. }` the lock will be held
1991         // for the duration if body.
1992         let needs_drop = type_needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, op);
1993
1994         // check that `while_let_on_iterator` lint does not trigger
1995         if_chain! {
1996             if keyword == "while";
1997             if let ExprKind::MethodCall(method_path, _, _, _) = op.kind;
1998             if method_path.ident.name == sym::next;
1999             if is_trait_method(cx, op, sym::Iterator);
2000             then {
2001                 return;
2002             }
2003         }
2004
2005         let result_expr = match &op.kind {
2006             ExprKind::AddrOf(_, _, borrowed) => borrowed,
2007             _ => op,
2008         };
2009         span_lint_and_then(
2010             cx,
2011             REDUNDANT_PATTERN_MATCHING,
2012             arm.pat.span,
2013             &format!("redundant pattern matching, consider using `{}`", good_method),
2014             |diag| {
2015                 // while let ... = ... { ... }
2016                 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017                 let expr_span = expr.span;
2018
2019                 // while let ... = ... { ... }
2020                 //                 ^^^
2021                 let op_span = result_expr.span.source_callsite();
2022
2023                 // while let ... = ... { ... }
2024                 // ^^^^^^^^^^^^^^^^^^^
2025                 let span = expr_span.until(op_span.shrink_to_hi());
2026
2027                 let mut app = if needs_drop {
2028                     Applicability::MaybeIncorrect
2029                 } else {
2030                     Applicability::MachineApplicable
2031                 };
2032                 let sugg = snippet_with_applicability(cx, op_span, "_", &mut app);
2033
2034                 diag.span_suggestion(span, "try this", format!("{} {}.{}", keyword, sugg, good_method), app);
2035
2036                 if needs_drop {
2037                     diag.note("this will change drop order of the result, as well as all temporaries");
2038                     diag.note("add `#[allow(clippy::redundant_pattern_matching)]` if this is important");
2039                 }
2040             },
2041         );
2042     }
2043
2044     fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
2045         if arms.len() == 2 {
2046             let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
2047
2048             let found_good_method = match node_pair {
2049                 (
2050                     PatKind::TupleStruct(ref path_left, patterns_left, _),
2051                     PatKind::TupleStruct(ref path_right, patterns_right, _),
2052                 ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
2053                     if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
2054                         find_good_method_for_match(
2055                             cx,
2056                             arms,
2057                             path_left,
2058                             path_right,
2059                             &paths::RESULT_OK,
2060                             &paths::RESULT_ERR,
2061                             "is_ok()",
2062                             "is_err()",
2063                         )
2064                         .or_else(|| {
2065                             find_good_method_for_match(
2066                                 cx,
2067                                 arms,
2068                                 path_left,
2069                                 path_right,
2070                                 &paths::IPADDR_V4,
2071                                 &paths::IPADDR_V6,
2072                                 "is_ipv4()",
2073                                 "is_ipv6()",
2074                             )
2075                         })
2076                     } else {
2077                         None
2078                     }
2079                 },
2080                 (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right))
2081                 | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _))
2082                     if patterns.len() == 1 =>
2083                 {
2084                     if let PatKind::Wild = patterns[0].kind {
2085                         find_good_method_for_match(
2086                             cx,
2087                             arms,
2088                             path_left,
2089                             path_right,
2090                             &paths::OPTION_SOME,
2091                             &paths::OPTION_NONE,
2092                             "is_some()",
2093                             "is_none()",
2094                         )
2095                         .or_else(|| {
2096                             find_good_method_for_match(
2097                                 cx,
2098                                 arms,
2099                                 path_left,
2100                                 path_right,
2101                                 &paths::POLL_READY,
2102                                 &paths::POLL_PENDING,
2103                                 "is_ready()",
2104                                 "is_pending()",
2105                             )
2106                         })
2107                     } else {
2108                         None
2109                     }
2110                 },
2111                 _ => None,
2112             };
2113
2114             if let Some(good_method) = found_good_method {
2115                 let span = expr.span.to(op.span);
2116                 let result_expr = match &op.kind {
2117                     ExprKind::AddrOf(_, _, borrowed) => borrowed,
2118                     _ => op,
2119                 };
2120                 span_lint_and_then(
2121                     cx,
2122                     REDUNDANT_PATTERN_MATCHING,
2123                     expr.span,
2124                     &format!("redundant pattern matching, consider using `{}`", good_method),
2125                     |diag| {
2126                         diag.span_suggestion(
2127                             span,
2128                             "try this",
2129                             format!("{}.{}", snippet(cx, result_expr.span, "_"), good_method),
2130                             Applicability::MaybeIncorrect, // snippet
2131                         );
2132                     },
2133                 );
2134             }
2135         }
2136     }
2137
2138     #[allow(clippy::too_many_arguments)]
2139     fn find_good_method_for_match<'a>(
2140         cx: &LateContext<'_>,
2141         arms: &[Arm<'_>],
2142         path_left: &QPath<'_>,
2143         path_right: &QPath<'_>,
2144         expected_left: &[&str],
2145         expected_right: &[&str],
2146         should_be_left: &'a str,
2147         should_be_right: &'a str,
2148     ) -> Option<&'a str> {
2149         let body_node_pair = if is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_left)
2150             && is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_right)
2151         {
2152             (&(*arms[0].body).kind, &(*arms[1].body).kind)
2153         } else if is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_left)
2154             && is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_right)
2155         {
2156             (&(*arms[1].body).kind, &(*arms[0].body).kind)
2157         } else {
2158             return None;
2159         };
2160
2161         match body_node_pair {
2162             (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
2163                 (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
2164                 (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
2165                 _ => None,
2166             },
2167             _ => None,
2168         }
2169     }
2170 }
2171
2172 #[test]
2173 fn test_overlapping() {
2174     use rustc_span::source_map::DUMMY_SP;
2175
2176     let sp = |s, e| SpannedRange {
2177         span: DUMMY_SP,
2178         node: (s, e),
2179     };
2180
2181     assert_eq!(None, overlapping::<u8>(&[]));
2182     assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))]));
2183     assert_eq!(
2184         None,
2185         overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])
2186     );
2187     assert_eq!(
2188         None,
2189         overlapping(&[
2190             sp(1, Bound::Included(4)),
2191             sp(5, Bound::Included(6)),
2192             sp(10, Bound::Included(11))
2193         ],)
2194     );
2195     assert_eq!(
2196         Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))),
2197         overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))])
2198     );
2199     assert_eq!(
2200         Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))),
2201         overlapping(&[
2202             sp(1, Bound::Included(4)),
2203             sp(5, Bound::Included(6)),
2204             sp(6, Bound::Included(11))
2205         ],)
2206     );
2207 }
2208
2209 /// Implementation of `MATCH_SAME_ARMS`.
2210 fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
2211     if let ExprKind::Match(_, arms, MatchSource::Normal) = expr.kind {
2212         let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
2213             let mut h = SpanlessHash::new(cx);
2214             h.hash_expr(arm.body);
2215             h.finish()
2216         };
2217
2218         let eq = |&(lindex, lhs): &(usize, &Arm<'_>), &(rindex, rhs): &(usize, &Arm<'_>)| -> bool {
2219             let min_index = usize::min(lindex, rindex);
2220             let max_index = usize::max(lindex, rindex);
2221
2222             let mut local_map: HirIdMap<HirId> = HirIdMap::default();
2223             let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
2224                 if_chain! {
2225                     if let Some(a_id) = path_to_local(a);
2226                     if let Some(b_id) = path_to_local(b);
2227                     let entry = match local_map.entry(a_id) {
2228                         Entry::Vacant(entry) => entry,
2229                         // check if using the same bindings as before
2230                         Entry::Occupied(entry) => return *entry.get() == b_id,
2231                     };
2232                     // the names technically don't have to match; this makes the lint more conservative
2233                     if cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id);
2234                     if TyS::same_type(cx.typeck_results().expr_ty(a), cx.typeck_results().expr_ty(b));
2235                     if pat_contains_local(lhs.pat, a_id);
2236                     if pat_contains_local(rhs.pat, b_id);
2237                     then {
2238                         entry.insert(b_id);
2239                         true
2240                     } else {
2241                         false
2242                     }
2243                 }
2244             };
2245             // Arms with a guard are ignored, those can’t always be merged together
2246             // This is also the case for arms in-between each there is an arm with a guard
2247             (min_index..=max_index).all(|index| arms[index].guard.is_none())
2248                 && SpanlessEq::new(cx)
2249                     .expr_fallback(eq_fallback)
2250                     .eq_expr(lhs.body, rhs.body)
2251                 // these checks could be removed to allow unused bindings
2252                 && bindings_eq(lhs.pat, local_map.keys().copied().collect())
2253                 && bindings_eq(rhs.pat, local_map.values().copied().collect())
2254         };
2255
2256         let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
2257         for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) {
2258             span_lint_and_then(
2259                 cx,
2260                 MATCH_SAME_ARMS,
2261                 j.body.span,
2262                 "this `match` has identical arm bodies",
2263                 |diag| {
2264                     diag.span_note(i.body.span, "same as this");
2265
2266                     // Note: this does not use `span_suggestion` on purpose:
2267                     // there is no clean way
2268                     // to remove the other arm. Building a span and suggest to replace it to ""
2269                     // makes an even more confusing error message. Also in order not to make up a
2270                     // span for the whole pattern, the suggestion is only shown when there is only
2271                     // one pattern. The user should know about `|` if they are already using it…
2272
2273                     let lhs = snippet(cx, i.pat.span, "<pat1>");
2274                     let rhs = snippet(cx, j.pat.span, "<pat2>");
2275
2276                     if let PatKind::Wild = j.pat.kind {
2277                         // if the last arm is _, then i could be integrated into _
2278                         // note that i.pat cannot be _, because that would mean that we're
2279                         // hiding all the subsequent arms, and rust won't compile
2280                         diag.span_note(
2281                             i.body.span,
2282                             &format!(
2283                                 "`{}` has the same arm body as the `_` wildcard, consider removing it",
2284                                 lhs
2285                             ),
2286                         );
2287                     } else {
2288                         diag.span_help(i.pat.span, &format!("consider refactoring into `{} | {}`", lhs, rhs,))
2289                             .help("...or consider changing the match arm bodies");
2290                     }
2291                 },
2292             );
2293         }
2294     }
2295 }
2296
2297 fn pat_contains_local(pat: &Pat<'_>, id: HirId) -> bool {
2298     let mut result = false;
2299     pat.walk_short(|p| {
2300         result |= matches!(p.kind, PatKind::Binding(_, binding_id, ..) if binding_id == id);
2301         !result
2302     });
2303     result
2304 }
2305
2306 /// Returns true if all the bindings in the `Pat` are in `ids` and vice versa
2307 fn bindings_eq(pat: &Pat<'_>, mut ids: HirIdSet) -> bool {
2308     let mut result = true;
2309     pat.each_binding_or_first(&mut |_, id, _, _| result &= ids.remove(&id));
2310     result && ids.is_empty()
2311 }