1 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
2 use clippy_utils::source::{indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability};
3 use clippy_utils::sugg::Sugg;
5 get_parent_expr, is_lang_ctor, is_refutable, is_wild, meets_msrv, msrvs, path_to_local_id, peel_blocks,
9 use if_chain::if_chain;
10 use rustc_errors::Applicability;
11 use rustc_hir::LangItem::{OptionNone, OptionSome};
13 Arm, BindingAnnotation, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, Node, Pat, PatKind, QPath,
15 use rustc_lint::{LateContext, LateLintPass};
17 use rustc_semver::RustcVersion;
18 use rustc_session::{declare_tool_lint, impl_lint_pass};
21 mod match_like_matches;
24 mod match_wild_err_arm;
26 mod redundant_pattern_match;
29 declare_clippy_lint! {
31 /// Checks for matches with a single arm where an `if let`
32 /// will usually suffice.
34 /// ### Why is this bad?
35 /// Just readability – `if let` nests less than a `match`.
39 /// # fn bar(stool: &str) {}
40 /// # let x = Some("abc");
43 /// Some(ref foo) => bar(foo),
48 /// if let Some(ref foo) = x {
52 #[clippy::version = "pre 1.29.0"]
55 "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`"
58 declare_clippy_lint! {
60 /// Checks for matches with two arms where an `if let else` will
63 /// ### Why is this bad?
64 /// Just readability – `if let` nests less than a `match`.
66 /// ### Known problems
67 /// Personal style preferences may differ.
73 /// # fn bar(foo: &usize) {}
74 /// # let other_ref: usize = 1;
75 /// # let x: Option<&usize> = Some(&1);
77 /// Some(ref foo) => bar(foo),
78 /// _ => bar(&other_ref),
82 /// Using `if let` with `else`:
85 /// # fn bar(foo: &usize) {}
86 /// # let other_ref: usize = 1;
87 /// # let x: Option<&usize> = Some(&1);
88 /// if let Some(ref foo) = x {
94 #[clippy::version = "pre 1.29.0"]
95 pub SINGLE_MATCH_ELSE,
97 "a `match` statement with two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
100 declare_clippy_lint! {
102 /// Checks for matches where all arms match a reference,
103 /// suggesting to remove the reference and deref the matched expression
104 /// instead. It also checks for `if let &foo = bar` blocks.
106 /// ### Why is this bad?
107 /// It just makes the code less readable. That reference
108 /// destructuring adds nothing to the code.
114 /// &A(ref y) => foo(y),
121 /// A(ref y) => foo(y),
126 #[clippy::version = "pre 1.29.0"]
129 "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression"
132 declare_clippy_lint! {
134 /// Checks for matches where match expression is a `bool`. It
135 /// suggests to replace the expression with an `if...else` block.
137 /// ### Why is this bad?
138 /// It makes the code less readable.
144 /// let condition: bool = true;
145 /// match condition {
150 /// Use if/else instead:
154 /// let condition: bool = true;
161 #[clippy::version = "pre 1.29.0"]
164 "a `match` on a boolean expression instead of an `if..else` block"
167 declare_clippy_lint! {
169 /// Checks for overlapping match arms.
171 /// ### Why is this bad?
172 /// It is likely to be an error and if not, makes the code
179 /// 1..=10 => println!("1 ... 10"),
180 /// 5..=15 => println!("5 ... 15"),
184 #[clippy::version = "pre 1.29.0"]
185 pub MATCH_OVERLAPPING_ARM,
187 "a `match` with overlapping arms"
190 declare_clippy_lint! {
192 /// Checks for arm which matches all errors with `Err(_)`
193 /// and take drastic actions like `panic!`.
195 /// ### Why is this bad?
196 /// It is generally a bad practice, similar to
197 /// catching all exceptions in java with `catch(Exception)`
201 /// let x: Result<i32, &str> = Ok(3);
203 /// Ok(_) => println!("ok"),
204 /// Err(_) => panic!("err"),
207 #[clippy::version = "pre 1.29.0"]
208 pub MATCH_WILD_ERR_ARM,
210 "a `match` with `Err(_)` arm and take drastic actions"
213 declare_clippy_lint! {
215 /// Checks for match which is used to add a reference to an
218 /// ### Why is this bad?
219 /// Using `as_ref()` or `as_mut()` instead is shorter.
223 /// let x: Option<()> = None;
226 /// let r: Option<&()> = match x {
228 /// Some(ref v) => Some(v),
232 /// let r: Option<&()> = x.as_ref();
234 #[clippy::version = "pre 1.29.0"]
237 "a `match` on an Option value instead of using `as_ref()` or `as_mut`"
240 declare_clippy_lint! {
242 /// Checks for wildcard enum matches using `_`.
244 /// ### Why is this bad?
245 /// New enum variants added by library updates can be missed.
247 /// ### Known problems
248 /// Suggested replacements may be incorrect if guards exhaustively cover some
249 /// variants, and also may not use correct path to enum if it's not present in the current scope.
253 /// # enum Foo { A(usize), B(usize) }
254 /// # let x = Foo::B(1);
267 #[clippy::version = "1.34.0"]
268 pub WILDCARD_ENUM_MATCH_ARM,
270 "a wildcard enum match arm using `_`"
273 declare_clippy_lint! {
275 /// Checks for wildcard enum matches for a single variant.
277 /// ### Why is this bad?
278 /// New enum variants added by library updates can be missed.
280 /// ### Known problems
281 /// Suggested replacements may not use correct path to enum
282 /// if it's not present in the current scope.
286 /// # enum Foo { A, B, C }
287 /// # let x = Foo::B;
302 #[clippy::version = "1.45.0"]
303 pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
305 "a wildcard enum match for a single variant"
308 declare_clippy_lint! {
310 /// Checks for wildcard pattern used with others patterns in same match arm.
312 /// ### Why is this bad?
313 /// Wildcard pattern already covers any other pattern as it will match anyway.
314 /// It makes the code less readable, especially to spot wildcard pattern use in match arm.
330 #[clippy::version = "1.42.0"]
331 pub WILDCARD_IN_OR_PATTERNS,
333 "a wildcard pattern used with others patterns in same match arm"
336 declare_clippy_lint! {
338 /// Checks for matches being used to destructure a single-variant enum
339 /// or tuple struct where a `let` will suffice.
341 /// ### Why is this bad?
342 /// Just readability – `let` doesn't nest, whereas a `match` does.
350 /// let wrapper = Wrapper::Data(42);
352 /// let data = match wrapper {
353 /// Wrapper::Data(i) => i,
357 /// The correct use would be:
363 /// let wrapper = Wrapper::Data(42);
364 /// let Wrapper::Data(data) = wrapper;
366 #[clippy::version = "pre 1.29.0"]
367 pub INFALLIBLE_DESTRUCTURING_MATCH,
369 "a `match` statement with a single infallible arm instead of a `let`"
372 declare_clippy_lint! {
374 /// Checks for useless match that binds to only one value.
376 /// ### Why is this bad?
377 /// Readability and needless complexity.
379 /// ### Known problems
380 /// Suggested replacements may be incorrect when `match`
381 /// is actually binding temporary value, bringing a 'dropped while borrowed' error.
396 /// let (c, d) = (a, b);
398 #[clippy::version = "1.43.0"]
399 pub MATCH_SINGLE_BINDING,
401 "a match with a single binding instead of using `let` statement"
404 declare_clippy_lint! {
406 /// Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched.
408 /// ### Why is this bad?
409 /// Correctness and readability. It's like having a wildcard pattern after
410 /// matching all enum variants explicitly.
414 /// # struct A { a: i32 }
415 /// let a = A { a: 5 };
419 /// A { a: 5, .. } => {},
425 /// A { a: 5 } => {},
429 #[clippy::version = "1.43.0"]
430 pub REST_PAT_IN_FULLY_BOUND_STRUCTS,
432 "a match on a struct that binds all fields but still uses the wildcard pattern"
435 declare_clippy_lint! {
437 /// Lint for redundant pattern matching over `Result`, `Option`,
438 /// `std::task::Poll` or `std::net::IpAddr`
440 /// ### Why is this bad?
441 /// It's more concise and clear to just use the proper
444 /// ### Known problems
445 /// This will change the drop order for the matched type. Both `if let` and
446 /// `while let` will drop the value at the end of the block, both `if` and `while` will drop the
447 /// value before entering the block. For most types this change will not matter, but for a few
448 /// types this will not be an acceptable change (e.g. locks). See the
449 /// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
454 /// # use std::task::Poll;
455 /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
456 /// if let Ok(_) = Ok::<i32, i32>(42) {}
457 /// if let Err(_) = Err::<i32, i32>(42) {}
458 /// if let None = None::<()> {}
459 /// if let Some(_) = Some(42) {}
460 /// if let Poll::Pending = Poll::Pending::<()> {}
461 /// if let Poll::Ready(_) = Poll::Ready(42) {}
462 /// if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {}
463 /// if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {}
464 /// match Ok::<i32, i32>(42) {
470 /// The more idiomatic use would be:
473 /// # use std::task::Poll;
474 /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
475 /// if Ok::<i32, i32>(42).is_ok() {}
476 /// if Err::<i32, i32>(42).is_err() {}
477 /// if None::<()>.is_none() {}
478 /// if Some(42).is_some() {}
479 /// if Poll::Pending::<()>.is_pending() {}
480 /// if Poll::Ready(42).is_ready() {}
481 /// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
482 /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
483 /// Ok::<i32, i32>(42).is_ok();
485 #[clippy::version = "1.31.0"]
486 pub REDUNDANT_PATTERN_MATCHING,
488 "use the proper utility function avoiding an `if let`"
491 declare_clippy_lint! {
493 /// Checks for `match` or `if let` expressions producing a
494 /// `bool` that could be written using `matches!`
496 /// ### Why is this bad?
497 /// Readability and needless complexity.
499 /// ### Known problems
500 /// This lint falsely triggers, if there are arms with
501 /// `cfg` attributes that remove an arm evaluating to `false`.
508 /// let a = match x {
513 /// let a = if let Some(0) = x {
520 /// let a = matches!(x, Some(0));
522 #[clippy::version = "1.47.0"]
523 pub MATCH_LIKE_MATCHES_MACRO,
525 "a match that could be written with the matches! macro"
528 declare_clippy_lint! {
530 /// Checks for `match` with identical arm bodies.
532 /// ### Why is this bad?
533 /// This is probably a copy & paste error. If arm bodies
534 /// are the same on purpose, you can factor them
535 /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
537 /// ### Known problems
538 /// False positive possible with order dependent `match`
540 /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
547 /// Baz => bar(), // <= oops
551 /// This should probably be
556 /// Baz => baz(), // <= fixed
560 /// or if the original code was not a typo:
563 /// Bar | Baz => bar(), // <= shows the intent better
567 #[clippy::version = "pre 1.29.0"]
570 "`match` with identical arm bodies"
575 msrv: Option<RustcVersion>,
576 infallible_destructuring_match_linted: bool,
581 pub fn new(msrv: Option<RustcVersion>) -> Self {
589 impl_lint_pass!(Matches => [
594 MATCH_OVERLAPPING_ARM,
597 WILDCARD_ENUM_MATCH_ARM,
598 MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
599 WILDCARD_IN_OR_PATTERNS,
600 MATCH_SINGLE_BINDING,
601 INFALLIBLE_DESTRUCTURING_MATCH,
602 REST_PAT_IN_FULLY_BOUND_STRUCTS,
603 REDUNDANT_PATTERN_MATCHING,
604 MATCH_LIKE_MATCHES_MACRO,
608 impl<'tcx> LateLintPass<'tcx> for Matches {
609 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
610 if expr.span.from_expansion() {
614 redundant_pattern_match::check(cx, expr);
616 if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) {
617 if !match_like_matches::check(cx, expr) {
618 match_same_arms::check(cx, expr);
621 match_same_arms::check(cx, expr);
624 if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
625 single_match::check(cx, ex, arms, expr);
626 match_bool::check(cx, ex, arms, expr);
627 overlapping_arms::check(cx, ex, arms);
628 match_wild_err_arm::check(cx, ex, arms);
629 match_wild_enum::check(cx, ex, arms);
630 check_match_as_ref(cx, ex, arms, expr);
631 check_wild_in_or_pats(cx, arms);
633 if self.infallible_destructuring_match_linted {
634 self.infallible_destructuring_match_linted = false;
636 check_match_single_binding(cx, ex, arms, expr);
639 if let ExprKind::Match(ex, arms, _) = expr.kind {
640 check_match_ref_pats(cx, ex, arms.iter().map(|el| el.pat), expr);
644 fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
646 if !local.span.from_expansion();
647 if let Some(expr) = local.init;
648 if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind;
649 if arms.len() == 1 && arms[0].guard.is_none();
650 if let PatKind::TupleStruct(
651 QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
653 if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
654 let body = peel_blocks(arms[0].body);
655 if path_to_local_id(body, arg);
658 let mut applicability = Applicability::MachineApplicable;
659 self.infallible_destructuring_match_linted = true;
662 INFALLIBLE_DESTRUCTURING_MATCH,
664 "you seem to be trying to use `match` to destructure a single infallible pattern. \
665 Consider using `let`",
669 snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
670 snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
671 snippet_with_applicability(cx, target.span, "..", &mut applicability),
679 fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
681 if !pat.span.from_expansion();
682 if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
683 if let Some(def_id) = path.res.opt_def_id();
684 let ty = cx.tcx.type_of(def_id);
685 if let ty::Adt(def, _) = ty.kind();
686 if def.is_struct() || def.is_union();
687 if fields.len() == def.non_enum_variant().fields.len();
692 REST_PAT_IN_FULLY_BOUND_STRUCTS,
694 "unnecessary use of `..` pattern in struct binding. All fields were already bound",
696 "consider removing `..` from this binding",
702 extract_msrv_attr!(LateContext);
705 fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
708 I: Clone + Iterator<Item = &'a Pat<'b>>,
710 if !has_multiple_ref_pats(pats.clone()) {
714 let (first_sugg, msg, title);
715 let span = ex.span.source_callsite();
716 if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
717 first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
719 title = "you don't need to add `&` to both the expression and the patterns";
721 first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
722 msg = "instead of prefixing all patterns with `&`, you can dereference the expression";
723 title = "you don't need to add `&` to all patterns";
726 let remaining_suggs = pats.filter_map(|pat| {
727 if let PatKind::Ref(refp, _) = pat.kind {
728 Some((pat.span, snippet(cx, refp.span, "..").to_string()))
734 span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
735 if !expr.span.from_expansion() {
736 multispan_sugg(diag, msg, first_sugg.chain(remaining_suggs));
741 fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
742 if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
743 let arm_ref: Option<BindingAnnotation> = if is_none_arm(cx, &arms[0]) {
744 is_ref_some_arm(cx, &arms[1])
745 } else if is_none_arm(cx, &arms[1]) {
746 is_ref_some_arm(cx, &arms[0])
750 if let Some(rb) = arm_ref {
751 let suggestion = if rb == BindingAnnotation::Ref {
757 let output_ty = cx.typeck_results().expr_ty(expr);
758 let input_ty = cx.typeck_results().expr_ty(ex);
760 let cast = if_chain! {
761 if let ty::Adt(_, substs) = input_ty.kind();
762 let input_ty = substs.type_at(0);
763 if let ty::Adt(_, substs) = output_ty.kind();
764 let output_ty = substs.type_at(0);
765 if let ty::Ref(_, output_ty, _) = *output_ty.kind();
766 if input_ty != output_ty;
774 let mut applicability = Applicability::MachineApplicable;
779 &format!("use `{}()` instead", suggestion),
783 snippet_with_applicability(cx, ex.span, "_", &mut applicability),
793 fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
795 if let PatKind::Or(fields) = arm.pat.kind {
796 // look for multiple fields in this arm that contains at least one Wild pattern
797 if fields.len() > 1 && fields.iter().any(is_wild) {
800 WILDCARD_IN_OR_PATTERNS,
802 "wildcard pattern covers any other pattern as it will match anyway",
804 "consider handling `_` separately",
811 #[allow(clippy::too_many_lines)]
812 fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
813 if expr.span.from_expansion() || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
818 // This is a hack to deal with arms that are excluded by macros like `#[cfg]`. It is only used here
819 // to prevent false positives as there is currently no better way to detect if code was excluded by
820 // a macro. See PR #6435
822 if let Some(match_snippet) = snippet_opt(cx, expr.span);
823 if let Some(arm_snippet) = snippet_opt(cx, arms[0].span);
824 if let Some(ex_snippet) = snippet_opt(cx, ex.span);
825 let rest_snippet = match_snippet.replace(&arm_snippet, "").replace(&ex_snippet, "");
826 if rest_snippet.contains("=>");
828 // The code it self contains another thick arrow "=>"
829 // -> Either another arm or a comment
834 let matched_vars = ex.span;
835 let bind_names = arms[0].pat.span;
836 let match_body = peel_blocks(arms[0].body);
837 let mut snippet_body = if match_body.span.from_expansion() {
838 Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
840 snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string()
843 // Do we need to add ';' to suggestion ?
844 match match_body.kind {
845 ExprKind::Block(block, _) => {
846 // macro + expr_ty(body) == ()
847 if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
848 snippet_body.push(';');
852 // expr_ty(body) == ()
853 if cx.typeck_results().expr_ty(match_body).is_unit() {
854 snippet_body.push(';');
859 let mut applicability = Applicability::MaybeIncorrect;
860 match arms[0].pat.kind {
861 PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
862 // If this match is in a local (`let`) stmt
863 let (target_span, sugg) = if let Some(parent_let_node) = opt_parent_let(cx, ex) {
865 parent_let_node.span,
867 "let {} = {};\n{}let {} = {};",
868 snippet_with_applicability(cx, bind_names, "..", &mut applicability),
869 snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
870 " ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
871 snippet_with_applicability(cx, parent_let_node.pat.span, "..", &mut applicability),
876 // If we are in closure, we need curly braces around suggestion
877 let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
878 let (mut cbrace_start, mut cbrace_end) = ("".to_string(), "".to_string());
879 if let Some(parent_expr) = get_parent_expr(cx, expr) {
880 if let ExprKind::Closure(..) = parent_expr.kind {
881 cbrace_end = format!("\n{}}}", indent);
882 // Fix body indent due to the closure
883 indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
884 cbrace_start = format!("{{\n{}", indent);
887 // If the parent is already an arm, and the body is another match statement,
888 // we need curly braces around suggestion
889 let parent_node_id = cx.tcx.hir().get_parent_node(expr.hir_id);
890 if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
891 if let ExprKind::Match(..) = arm.body.kind {
892 cbrace_end = format!("\n{}}}", indent);
893 // Fix body indent due to the match
894 indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
895 cbrace_start = format!("{{\n{}", indent);
901 "{}let {} = {};\n{}{}{}",
903 snippet_with_applicability(cx, bind_names, "..", &mut applicability),
904 snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
913 MATCH_SINGLE_BINDING,
915 "this match could be written as a `let` statement",
916 "consider using `let` statement",
922 if ex.can_have_side_effects() {
923 let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0));
926 snippet_with_applicability(cx, ex.span, "..", &mut applicability),
932 MATCH_SINGLE_BINDING,
934 "this match could be replaced by its scrutinee and body",
935 "consider using the scrutinee and body instead",
942 MATCH_SINGLE_BINDING,
944 "this match could be replaced by its body itself",
945 "consider using the match body instead",
947 Applicability::MachineApplicable,
955 /// Returns true if the `ex` match expression is in a local (`let`) statement
956 fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> {
957 let map = &cx.tcx.hir();
959 if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id));
960 if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id));
962 return Some(parent_let_expr);
968 // Checks if arm has the form `None => None`
969 fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
970 matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
973 // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
974 fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotation> {
976 if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
977 if is_lang_ctor(cx, qpath, OptionSome);
978 if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
979 if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
980 if let ExprKind::Call(e, args) = peel_blocks(arm.body).kind;
981 if let ExprKind::Path(ref some_path) = e.kind;
982 if is_lang_ctor(cx, some_path, OptionSome) && args.len() == 1;
983 if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
984 if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
992 fn has_multiple_ref_pats<'a, 'b, I>(pats: I) -> bool
995 I: Iterator<Item = &'a Pat<'b>>,
997 let mut ref_count = 0;
998 for opt in pats.map(|pat| match pat.kind {
999 PatKind::Ref(..) => Some(true), // &-patterns
1000 PatKind::Wild => Some(false), // an "anything" wildcard is also fine
1001 _ => None, // any other pattern is not fine
1003 if let Some(inner) = opt {