@@ -4,7 +4,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_re
4
4
use clippy_utils:: { is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs} ;
5
5
use core:: cmp:: max;
6
6
use rustc_errors:: Applicability ;
7
- use rustc_hir:: { Arm , BindingAnnotation , Block , Expr , ExprKind , Pat , PatKind } ;
7
+ use rustc_hir:: { Arm , BindingAnnotation , Expr , ExprKind , Pat , PatKind } ;
8
8
use rustc_lint:: LateContext ;
9
9
use rustc_middle:: ty:: { self , Ty } ;
10
10
use rustc_span:: { sym, Span } ;
@@ -28,67 +28,46 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
28
28
29
29
#[ rustfmt:: skip]
30
30
pub ( 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 ) {
44
40
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 ) ) {
47
43
// single statement/expr "else" block, don't lint
48
44
return ;
49
45
}
50
46
// block with 2+ statements or 1 expr and 1+ statement
51
- Some ( els )
47
+ Some ( arm2 . body )
52
48
} else {
53
49
// not a block or an empty block w/ comments, don't lint
54
50
return ;
55
51
} ;
56
52
57
53
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 ( cx, ex, arms, expr, els) ;
60
- check_opt_like ( cx, ex, arms, expr, ty, 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) ;
61
58
}
62
59
}
63
60
}
64
61
65
- fn check_single_pattern (
66
- cx : & LateContext < ' _ > ,
67
- ex : & Expr < ' _ > ,
68
- arms : & [ Arm < ' _ > ] ,
69
- expr : & Expr < ' _ > ,
70
- els : Option < & Expr < ' _ > > ,
71
- ) {
72
- if is_wild ( arms[ 1 ] . pat ) {
73
- report_single_pattern ( cx, ex, arms, expr, els) ;
74
- }
75
- }
76
-
77
- fn report_single_pattern (
78
- cx : & LateContext < ' _ > ,
79
- ex : & Expr < ' _ > ,
80
- arms : & [ Arm < ' _ > ] ,
81
- expr : & Expr < ' _ > ,
82
- els : Option < & Expr < ' _ > > ,
83
- ) {
62
+ fn report_single_pattern ( cx : & LateContext < ' _ > , ex : & Expr < ' _ > , arm : & Arm < ' _ > , expr : & Expr < ' _ > , els : Option < & Expr < ' _ > > ) {
84
63
let lint = if els. is_some ( ) { SINGLE_MATCH_ELSE } else { SINGLE_MATCH } ;
85
64
let ctxt = expr. span . ctxt ( ) ;
86
65
let mut app = Applicability :: HasPlaceholders ;
87
66
let els_str = els. map_or ( String :: new ( ) , |els| {
88
67
format ! ( " else {}" , expr_block( cx, els, ctxt, ".." , Some ( expr. span) , & mut app) )
89
68
} ) ;
90
69
91
- let ( pat, pat_ref_count) = peel_hir_pat_refs ( arms [ 0 ] . pat ) ;
70
+ let ( pat, pat_ref_count) = peel_hir_pat_refs ( arm . pat ) ;
92
71
let ( msg, sugg) = if let PatKind :: Path ( _) | PatKind :: Lit ( _) = pat. kind
93
72
&& let ( ty, ty_ref_count) = peel_mid_ty_refs ( cx. typeck_results ( ) . expr_ty ( ex) )
94
73
&& let Some ( spe_trait_id) = cx. tcx . lang_items ( ) . structural_peq_trait ( )
@@ -122,39 +101,24 @@ fn report_single_pattern(
122
101
snippet( cx, ex. span, ".." ) ,
123
102
// PartialEq for different reference counts may not exist.
124
103
"&" . repeat( ref_count_diff) ,
125
- snippet( cx, arms [ 0 ] . pat. span, ".." ) ,
126
- 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) ,
127
106
) ;
128
107
( msg, sugg)
129
108
} else {
130
109
let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" ;
131
110
let sugg = format ! (
132
111
"if let {} = {} {}{els_str}" ,
133
- snippet( cx, arms [ 0 ] . pat. span, ".." ) ,
112
+ snippet( cx, arm . pat. span, ".." ) ,
134
113
snippet( cx, ex. span, ".." ) ,
135
- expr_block( cx, arms [ 0 ] . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
114
+ expr_block( cx, arm . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
136
115
) ;
137
116
( msg, sugg)
138
117
} ;
139
118
140
119
span_lint_and_sugg ( cx, lint, expr. span , msg, "try" , sugg, app) ;
141
120
}
142
121
143
- fn check_opt_like < ' a > (
144
- cx : & LateContext < ' a > ,
145
- ex : & Expr < ' _ > ,
146
- arms : & [ Arm < ' _ > ] ,
147
- expr : & Expr < ' _ > ,
148
- ty : Ty < ' a > ,
149
- els : Option < & Expr < ' _ > > ,
150
- ) {
151
- // We don't want to lint if the second arm contains an enum which could
152
- // have more variants in the future.
153
- if form_exhaustive_matches ( cx, ty, arms[ 0 ] . pat , arms[ 1 ] . pat ) {
154
- report_single_pattern ( cx, ex, arms, expr, els) ;
155
- }
156
- }
157
-
158
122
/// Returns `true` if all of the types in the pattern are enums which we know
159
123
/// won't be expanded in the future
160
124
fn pat_in_candidate_enum < ' a > ( cx : & LateContext < ' a > , ty : Ty < ' a > , pat : & Pat < ' _ > ) -> bool {
0 commit comments