1
- use crate :: utils:: { match_qpath, match_trait_method, paths, snippet, span_lint_and_then} ;
1
+ use crate :: utils:: { in_constant , match_qpath, match_trait_method, paths, snippet, span_lint_and_then} ;
2
2
use if_chain:: if_chain;
3
3
use rustc_ast:: ast:: LitKind ;
4
4
use rustc_errors:: Applicability ;
5
- use rustc_hir:: { Arm , Expr , ExprKind , MatchSource , PatKind , QPath } ;
5
+ use rustc_hir:: { Arm , Expr , ExprKind , HirId , MatchSource , PatKind , QPath } ;
6
6
use rustc_lint:: { LateContext , LateLintPass } ;
7
+ use rustc_middle:: ty;
8
+ use rustc_mir:: const_eval:: is_const_fn;
7
9
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
10
+ use rustc_span:: source_map:: Symbol ;
8
11
9
12
declare_clippy_lint ! {
10
13
/// **What it does:** Lint for redundant pattern matching over `Result` or
@@ -64,26 +67,37 @@ fn find_sugg_for_if_let<'a, 'tcx>(
64
67
arms : & [ Arm < ' _ > ] ,
65
68
keyword : & ' static str ,
66
69
) {
70
+ fn find_suggestion ( cx : & LateContext < ' _ , ' _ > , hir_id : HirId , path : & QPath < ' _ > ) -> Option < & ' static str > {
71
+ if match_qpath ( path, & paths:: RESULT_OK ) && can_suggest ( cx, hir_id, sym ! ( result_type) , "is_ok" ) {
72
+ return Some ( "is_ok()" ) ;
73
+ }
74
+ if match_qpath ( path, & paths:: RESULT_ERR ) && can_suggest ( cx, hir_id, sym ! ( result_type) , "is_err" ) {
75
+ return Some ( "is_err()" ) ;
76
+ }
77
+ if match_qpath ( path, & paths:: OPTION_SOME ) && can_suggest ( cx, hir_id, sym ! ( option_type) , "is_some" ) {
78
+ return Some ( "is_some()" ) ;
79
+ }
80
+ if match_qpath ( path, & paths:: OPTION_NONE ) && can_suggest ( cx, hir_id, sym ! ( option_type) , "is_none" ) {
81
+ return Some ( "is_none()" ) ;
82
+ }
83
+ None
84
+ }
85
+
86
+ let hir_id = expr. hir_id ;
67
87
let good_method = match arms[ 0 ] . pat . kind {
68
88
PatKind :: TupleStruct ( ref path, ref patterns, _) if patterns. len ( ) == 1 => {
69
89
if let PatKind :: Wild = patterns[ 0 ] . kind {
70
- if match_qpath ( path, & paths:: RESULT_OK ) {
71
- "is_ok()"
72
- } else if match_qpath ( path, & paths:: RESULT_ERR ) {
73
- "is_err()"
74
- } else if match_qpath ( path, & paths:: OPTION_SOME ) {
75
- "is_some()"
76
- } else {
77
- return ;
78
- }
90
+ find_suggestion ( cx, hir_id, path)
79
91
} else {
80
- return ;
92
+ None
81
93
}
82
94
} ,
83
-
84
- PatKind :: Path ( ref path) if match_qpath ( path, & paths:: OPTION_NONE ) => "is_none()" ,
85
-
86
- _ => return ,
95
+ PatKind :: Path ( ref path) => find_suggestion ( cx, hir_id, path) ,
96
+ _ => None ,
97
+ } ;
98
+ let good_method = match good_method {
99
+ Some ( method) => method,
100
+ None => return ,
87
101
} ;
88
102
89
103
// check that `while_let_on_iterator` lint does not trigger
@@ -128,6 +142,7 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
128
142
if arms. len ( ) == 2 {
129
143
let node_pair = ( & arms[ 0 ] . pat . kind , & arms[ 1 ] . pat . kind ) ;
130
144
145
+ let hir_id = expr. hir_id ;
131
146
let found_good_method = match node_pair {
132
147
(
133
148
PatKind :: TupleStruct ( ref path_left, ref patterns_left, _) ,
@@ -142,6 +157,8 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
142
157
& paths:: RESULT_ERR ,
143
158
"is_ok()" ,
144
159
"is_err()" ,
160
+ || can_suggest ( cx, hir_id, sym ! ( result_type) , "is_ok" ) ,
161
+ || can_suggest ( cx, hir_id, sym ! ( result_type) , "is_err" ) ,
145
162
)
146
163
} else {
147
164
None
@@ -160,6 +177,8 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
160
177
& paths:: OPTION_NONE ,
161
178
"is_some()" ,
162
179
"is_none()" ,
180
+ || can_suggest ( cx, hir_id, sym ! ( option_type) , "is_some" ) ,
181
+ || can_suggest ( cx, hir_id, sym ! ( option_type) , "is_none" ) ,
163
182
)
164
183
} else {
165
184
None
@@ -188,6 +207,7 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
188
207
}
189
208
}
190
209
210
+ #[ allow( clippy:: too_many_arguments) ]
191
211
fn find_good_method_for_match < ' a > (
192
212
arms : & [ Arm < ' _ > ] ,
193
213
path_left : & QPath < ' _ > ,
@@ -196,6 +216,8 @@ fn find_good_method_for_match<'a>(
196
216
expected_right : & [ & str ] ,
197
217
should_be_left : & ' a str ,
198
218
should_be_right : & ' a str ,
219
+ can_suggest_left : impl Fn ( ) -> bool ,
220
+ can_suggest_right : impl Fn ( ) -> bool ,
199
221
) -> Option < & ' a str > {
200
222
let body_node_pair = if match_qpath ( path_left, expected_left) && match_qpath ( path_right, expected_right) {
201
223
( & ( * arms[ 0 ] . body ) . kind , & ( * arms[ 1 ] . body ) . kind )
@@ -207,10 +229,32 @@ fn find_good_method_for_match<'a>(
207
229
208
230
match body_node_pair {
209
231
( ExprKind :: Lit ( ref lit_left) , ExprKind :: Lit ( ref lit_right) ) => match ( & lit_left. node , & lit_right. node ) {
210
- ( LitKind :: Bool ( true ) , LitKind :: Bool ( false ) ) => Some ( should_be_left) ,
211
- ( LitKind :: Bool ( false ) , LitKind :: Bool ( true ) ) => Some ( should_be_right) ,
232
+ ( LitKind :: Bool ( true ) , LitKind :: Bool ( false ) ) if can_suggest_left ( ) => Some ( should_be_left) ,
233
+ ( LitKind :: Bool ( false ) , LitKind :: Bool ( true ) ) if can_suggest_right ( ) => Some ( should_be_right) ,
212
234
_ => None ,
213
235
} ,
214
236
_ => None ,
215
237
}
216
238
}
239
+
240
+ fn can_suggest ( cx : & LateContext < ' _ , ' _ > , hir_id : HirId , diag_item : Symbol , name : & str ) -> bool {
241
+ if !in_constant ( cx, hir_id) {
242
+ return true ;
243
+ }
244
+
245
+ // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
246
+ cx. tcx
247
+ . get_diagnostic_item ( diag_item)
248
+ . and_then ( |def_id| {
249
+ cx. tcx . inherent_impls ( def_id) . iter ( ) . find_map ( |imp| {
250
+ cx. tcx
251
+ . associated_items ( * imp)
252
+ . in_definition_order ( )
253
+ . find_map ( |item| match item. kind {
254
+ ty:: AssocKind :: Fn if item. ident . name . as_str ( ) == name => Some ( item. def_id ) ,
255
+ _ => None ,
256
+ } )
257
+ } )
258
+ } )
259
+ . map_or ( false , |def_id| is_const_fn ( cx. tcx , def_id) )
260
+ }
0 commit comments