@@ -4,7 +4,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_re
44use clippy_utils:: { is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs} ;
55use core:: cmp:: max;
66use rustc_errors:: Applicability ;
7- use rustc_hir:: { Arm , BindingMode , Block , Expr , ExprKind , Pat , PatKind } ;
7+ use rustc_hir:: { Arm , BindingMode , Expr , ExprKind , Pat , PatKind } ;
88use rustc_lint:: LateContext ;
99use rustc_middle:: ty:: { self , Ty } ;
1010use rustc_span:: { sym, Span } ;
@@ -28,59 +28,46 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
2828
2929#[ rustfmt:: skip]
3030pub ( crate ) fn check ( cx : & LateContext < ' _ > , ex : & Expr < ' _ > , arms : & [ Arm < ' _ > ] , expr : & Expr < ' _ > ) {
31- if arms. len ( ) == 2 && arms[ 0 ] . guard . is_none ( ) && arms[ 1 ] . guard . is_none ( ) {
32- if expr. span . from_expansion ( ) {
33- // Don't lint match expressions present in
34- // macro_rules! block
35- return ;
36- }
37- if let PatKind :: Or ( ..) = arms[ 0 ] . pat . kind {
38- // don't lint for or patterns for now, this makes
39- // the lint noisy in unnecessary situations
40- return ;
41- }
42- let els = arms[ 1 ] . body ;
43- let els = if is_unit_expr ( peel_blocks ( els) ) && !empty_arm_has_comment ( cx, els. span ) {
31+ if let [ arm1, arm2] = arms
32+ && arm1. guard . is_none ( )
33+ && arm2. guard . is_none ( )
34+ && !expr. span . from_expansion ( )
35+ // don't lint for or patterns for now, this makes
36+ // the lint noisy in unnecessary situations
37+ && !matches ! ( arm1. pat. kind, PatKind :: Or ( ..) )
38+ {
39+ let els = if is_unit_expr ( peel_blocks ( arm2. body ) ) && !empty_arm_has_comment ( cx, arm2. body . span ) {
4440 None
45- } else if let ExprKind :: Block ( Block { stmts , expr : block_expr , .. } , _) = els . kind {
46- if stmts. len ( ) == 1 && block_expr . is_none ( ) || stmts . is_empty ( ) && block_expr . is_some ( ) {
41+ } else if let ExprKind :: Block ( block , _) = arm2 . body . kind {
42+ if matches ! ( ( block . stmts, block . expr ) , ( [ ] , Some ( _ ) ) | ( [ _ ] , None ) ) {
4743 // single statement/expr "else" block, don't lint
4844 return ;
4945 }
5046 // block with 2+ statements or 1 expr and 1+ statement
51- Some ( els )
47+ Some ( arm2 . body )
5248 } else {
5349 // not a block or an empty block w/ comments, don't lint
5450 return ;
5551 } ;
5652
5753 let ty = cx. typeck_results ( ) . expr_ty ( ex) ;
58- if ( * ty. kind ( ) != ty:: Bool || is_lint_allowed ( cx, MATCH_BOOL , ex. hir_id ) ) &&
59- ( check_single_pattern ( arms) || check_opt_like ( cx, arms, ty) ) {
60- report_single_pattern ( cx, ex, arms, expr, els) ;
54+ if ( * ty. kind ( ) != ty:: Bool || is_lint_allowed ( cx, MATCH_BOOL , ex. hir_id ) )
55+ && ( is_wild ( arm2. pat ) || form_exhaustive_matches ( cx, ty, arm1. pat , arm2. pat ) )
56+ {
57+ report_single_pattern ( cx, ex, arm1, expr, els) ;
6158 }
6259 }
6360}
6461
65- fn check_single_pattern ( arms : & [ Arm < ' _ > ] ) -> bool {
66- is_wild ( arms[ 1 ] . pat )
67- }
68-
69- fn report_single_pattern (
70- cx : & LateContext < ' _ > ,
71- ex : & Expr < ' _ > ,
72- arms : & [ Arm < ' _ > ] ,
73- expr : & Expr < ' _ > ,
74- els : Option < & Expr < ' _ > > ,
75- ) {
62+ fn report_single_pattern ( cx : & LateContext < ' _ > , ex : & Expr < ' _ > , arm : & Arm < ' _ > , expr : & Expr < ' _ > , els : Option < & Expr < ' _ > > ) {
7663 let lint = if els. is_some ( ) { SINGLE_MATCH_ELSE } else { SINGLE_MATCH } ;
7764 let ctxt = expr. span . ctxt ( ) ;
7865 let mut app = Applicability :: MachineApplicable ;
7966 let els_str = els. map_or ( String :: new ( ) , |els| {
8067 format ! ( " else {}" , expr_block( cx, els, ctxt, ".." , Some ( expr. span) , & mut app) )
8168 } ) ;
8269
83- let ( pat, pat_ref_count) = peel_hir_pat_refs ( arms [ 0 ] . pat ) ;
70+ let ( pat, pat_ref_count) = peel_hir_pat_refs ( arm . pat ) ;
8471 let ( msg, sugg) = if let PatKind :: Path ( _) | PatKind :: Lit ( _) = pat. kind
8572 && let ( ty, ty_ref_count) = peel_mid_ty_refs ( cx. typeck_results ( ) . expr_ty ( ex) )
8673 && let Some ( spe_trait_id) = cx. tcx . lang_items ( ) . structural_peq_trait ( )
@@ -114,30 +101,24 @@ fn report_single_pattern(
114101 snippet( cx, ex. span, ".." ) ,
115102 // PartialEq for different reference counts may not exist.
116103 "&" . repeat( ref_count_diff) ,
117- snippet( cx, arms [ 0 ] . pat. span, ".." ) ,
118- expr_block( cx, arms [ 0 ] . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
104+ snippet( cx, arm . pat. span, ".." ) ,
105+ expr_block( cx, arm . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
119106 ) ;
120107 ( msg, sugg)
121108 } else {
122109 let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" ;
123110 let sugg = format ! (
124111 "if let {} = {} {}{els_str}" ,
125- snippet( cx, arms [ 0 ] . pat. span, ".." ) ,
112+ snippet( cx, arm . pat. span, ".." ) ,
126113 snippet( cx, ex. span, ".." ) ,
127- expr_block( cx, arms [ 0 ] . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
114+ expr_block( cx, arm . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
128115 ) ;
129116 ( msg, sugg)
130117 } ;
131118
132119 span_lint_and_sugg ( cx, lint, expr. span , msg, "try" , sugg, app) ;
133120}
134121
135- fn check_opt_like < ' a > ( cx : & LateContext < ' a > , arms : & [ Arm < ' _ > ] , ty : Ty < ' a > ) -> bool {
136- // We don't want to lint if the second arm contains an enum which could
137- // have more variants in the future.
138- form_exhaustive_matches ( cx, ty, arms[ 0 ] . pat , arms[ 1 ] . pat )
139- }
140-
141122/// Returns `true` if all of the types in the pattern are enums which we know
142123/// won't be expanded in the future
143124fn pat_in_candidate_enum < ' a > ( cx : & LateContext < ' a > , ty : Ty < ' a > , pat : & Pat < ' _ > ) -> bool {
0 commit comments