@@ -11,6 +11,7 @@ use rustc_middle::lint::in_external_macro;
11
11
use rustc_semver:: RustcVersion ;
12
12
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
13
13
use rustc_span:: symbol:: sym;
14
+ use serde:: Deserialize ;
14
15
use std:: ops:: ControlFlow ;
15
16
16
17
declare_clippy_lint ! {
@@ -47,12 +48,16 @@ declare_clippy_lint! {
47
48
48
49
pub struct ManualLetElse {
49
50
msrv : Option < RustcVersion > ,
51
+ matches_behaviour : MatchLintBehaviour ,
50
52
}
51
53
52
54
impl ManualLetElse {
53
55
#[ must_use]
54
- pub fn new ( msrv : Option < RustcVersion > ) -> Self {
55
- Self { msrv }
56
+ pub fn new ( msrv : Option < RustcVersion > , matches_behaviour : MatchLintBehaviour ) -> Self {
57
+ Self {
58
+ msrv,
59
+ matches_behaviour,
60
+ }
56
61
}
57
62
}
58
63
@@ -89,6 +94,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
89
94
}
90
95
} ,
91
96
IfLetOrMatch :: Match ( _match_expr, arms, source) => {
97
+ if self . matches_behaviour == MatchLintBehaviour :: Never {
98
+ return ;
99
+ }
92
100
if source != MatchSource :: Normal {
93
101
return ;
94
102
}
@@ -97,6 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
97
105
if arms. len ( ) != 2 {
98
106
return ;
99
107
}
108
+ let check_types = self . matches_behaviour == MatchLintBehaviour :: WellKnownTypes ;
100
109
// We iterate over both arms, trying to find one that is an identity,
101
110
// one that diverges. Our check needs to work regardless of the order
102
111
// of both arms.
@@ -109,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
109
118
}
110
119
if expr_is_simple_identity ( arm. pat , arm. body ) {
111
120
found_identity_arm = true ;
112
- } else if expr_diverges ( cx, arm. body ) && pat_allowed_for_else ( cx, arm. pat ) {
121
+ } else if expr_diverges ( cx, arm. body ) && pat_allowed_for_else ( cx, arm. pat , check_types ) {
113
122
found_diverging_arm = true ;
114
123
}
115
124
}
@@ -178,7 +187,7 @@ fn expr_diverges(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
178
187
. is_some ( )
179
188
}
180
189
181
- fn pat_allowed_for_else ( cx : & LateContext < ' _ > , pat : & ' _ Pat < ' _ > ) -> bool {
190
+ fn pat_allowed_for_else ( cx : & LateContext < ' _ > , pat : & ' _ Pat < ' _ > , check_types : bool ) -> bool {
182
191
// Check whether the pattern contains any bindings, as the
183
192
// binding might potentially be used in the body.
184
193
// TODO: only look for *used* bindings.
@@ -188,6 +197,11 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>) -> bool {
188
197
return false ;
189
198
}
190
199
200
+ // If we shouldn't check the types, exit early.
201
+ if !check_types {
202
+ return true ;
203
+ }
204
+
191
205
// Check whether any possibly "unknown" patterns are included,
192
206
// because users might not know which values some enum has.
193
207
// Well-known enums are excepted, as we assume people know them.
@@ -245,3 +259,10 @@ fn expr_is_simple_identity(pat: &'_ Pat<'_>, expr: &'_ Expr<'_>) -> bool {
245
259
}
246
260
true
247
261
}
262
+
263
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash , Deserialize ) ]
264
+ pub enum MatchLintBehaviour {
265
+ AllTypes ,
266
+ WellKnownTypes ,
267
+ Never ,
268
+ }
0 commit comments