@@ -2,7 +2,7 @@ use super::REDUNDANT_PATTERN_MATCHING;
2
2
use clippy_utils:: diagnostics:: span_lint_and_then;
3
3
use clippy_utils:: source:: snippet;
4
4
use clippy_utils:: sugg:: Sugg ;
5
- use clippy_utils:: ty:: needs_ordered_drop;
5
+ use clippy_utils:: ty:: { is_type_diagnostic_item , needs_ordered_drop} ;
6
6
use clippy_utils:: visitors:: any_temporaries_need_ordered_drop;
7
7
use clippy_utils:: { higher, is_lang_ctor, is_trait_method, match_def_path, paths} ;
8
8
use if_chain:: if_chain;
@@ -12,7 +12,7 @@ use rustc_hir::LangItem::{OptionNone, PollPending};
12
12
use rustc_hir:: { Arm , Expr , ExprKind , Node , Pat , PatKind , QPath , UnOp } ;
13
13
use rustc_lint:: LateContext ;
14
14
use rustc_middle:: ty:: { self , subst:: GenericArgKind , DefIdTree , Ty } ;
15
- use rustc_span:: sym;
15
+ use rustc_span:: { sym, Symbol , def_id :: DefId } ;
16
16
17
17
pub ( super ) fn check < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
18
18
if let Some ( higher:: WhileLet { let_pat, let_expr, .. } ) = higher:: WhileLet :: hir ( expr) {
@@ -75,9 +75,9 @@ fn find_sugg_for_if_let<'tcx>(
75
75
( "is_some()" , op_ty)
76
76
} else if Some ( id) == lang_items. poll_ready_variant ( ) {
77
77
( "is_ready()" , op_ty)
78
- } else if match_def_path ( cx, id , & paths:: IPADDR_V4 ) {
78
+ } else if is_pat_variant ( cx, check_pat , qpath , & paths:: IPADDR_V4 , Item :: Diag ( sym ! ( IpAddr ) , sym ! ( V4 ) ) ) {
79
79
( "is_ipv4()" , op_ty)
80
- } else if match_def_path ( cx, id , & paths:: IPADDR_V6 ) {
80
+ } else if is_pat_variant ( cx, check_pat , qpath , & paths:: IPADDR_V6 , Item :: Diag ( sym ! ( IpAddr ) , sym ! ( V6 ) ) ) {
81
81
( "is_ipv6()" , op_ty)
82
82
} else {
83
83
return ;
@@ -174,6 +174,7 @@ fn find_sugg_for_if_let<'tcx>(
174
174
175
175
pub ( super ) fn check_match < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > , op : & Expr < ' _ > , arms : & [ Arm < ' _ > ] ) {
176
176
if arms. len ( ) == 2 {
177
+ let lang_items = cx. tcx . lang_items ( ) ;
177
178
let node_pair = ( & arms[ 0 ] . pat . kind , & arms[ 1 ] . pat . kind ) ;
178
179
179
180
let found_good_method = match node_pair {
@@ -188,7 +189,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
188
189
path_left,
189
190
path_right,
190
191
& paths:: RESULT_OK ,
192
+ Item :: Lang ( lang_items. result_ok_variant ( ) ) ,
191
193
& paths:: RESULT_ERR ,
194
+ Item :: Lang ( lang_items. result_err_variant ( ) ) ,
192
195
"is_ok()" ,
193
196
"is_err()" ,
194
197
)
@@ -199,7 +202,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
199
202
path_left,
200
203
path_right,
201
204
& paths:: IPADDR_V4 ,
205
+ Item :: Diag ( sym ! ( IpAddr ) , sym ! ( V4 ) ) ,
202
206
& paths:: IPADDR_V6 ,
207
+ Item :: Diag ( sym ! ( IpAddr ) , sym ! ( V6 ) ) ,
203
208
"is_ipv4()" ,
204
209
"is_ipv6()" ,
205
210
)
@@ -213,13 +218,16 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
213
218
if patterns. len ( ) == 1 =>
214
219
{
215
220
if let PatKind :: Wild = patterns[ 0 ] . kind {
221
+
216
222
find_good_method_for_match (
217
223
cx,
218
224
arms,
219
225
path_left,
220
226
path_right,
221
227
& paths:: OPTION_SOME ,
228
+ Item :: Lang ( lang_items. option_some_variant ( ) ) ,
222
229
& paths:: OPTION_NONE ,
230
+ Item :: Lang ( lang_items. option_none_variant ( ) ) ,
223
231
"is_some()" ,
224
232
"is_none()" ,
225
233
)
@@ -230,7 +238,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
230
238
path_left,
231
239
path_right,
232
240
& paths:: POLL_READY ,
241
+ Item :: Lang ( lang_items. poll_ready_variant ( ) ) ,
233
242
& paths:: POLL_PENDING ,
243
+ Item :: Lang ( lang_items. poll_pending_variant ( ) ) ,
234
244
"is_ready()" ,
235
245
"is_pending()" ,
236
246
)
@@ -266,28 +276,67 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
266
276
}
267
277
}
268
278
279
+ #[ derive( Clone , Copy ) ]
280
+ enum Item {
281
+ Lang ( Option < DefId > ) ,
282
+ Diag ( Symbol , Symbol ) ,
283
+ }
284
+
285
+ fn is_pat_variant ( cx : & LateContext < ' _ > , pat : & Pat < ' _ > , path : & QPath < ' _ > , expected_path : & [ & str ] , expected_item : Item ) -> bool {
286
+ let Some ( id) = cx. typeck_results ( ) . qpath_res ( path, pat. hir_id ) . opt_def_id ( ) else { return false } ;
287
+
288
+ // TODO: Path matching can be removed when `IpAddr` is a diagnostic item.
289
+ if match_def_path ( cx, id, expected_path) {
290
+ return true
291
+ }
292
+
293
+ match expected_item {
294
+ Item :: Lang ( expected_id) => {
295
+ Some ( cx. tcx . parent ( id) ) == expected_id
296
+ } ,
297
+ Item :: Diag ( expected_ty, expected_variant) => {
298
+ let ty = cx. typeck_results ( ) . pat_ty ( pat) ;
299
+
300
+ if is_type_diagnostic_item ( cx, ty, expected_ty) {
301
+ let variant = ty. ty_adt_def ( )
302
+ . expect ( "struct pattern type is not an ADT" )
303
+ . variant_of_res ( cx. qpath_res ( path, pat. hir_id ) ) ;
304
+
305
+ return variant. name == expected_variant
306
+ }
307
+
308
+ false
309
+ }
310
+ }
311
+ }
312
+
269
313
#[ expect( clippy:: too_many_arguments) ]
270
314
fn find_good_method_for_match < ' a > (
271
315
cx : & LateContext < ' _ > ,
272
316
arms : & [ Arm < ' _ > ] ,
273
317
path_left : & QPath < ' _ > ,
274
318
path_right : & QPath < ' _ > ,
275
- expected_left : & [ & str ] ,
276
- expected_right : & [ & str ] ,
319
+ expected_path_left : & [ & str ] ,
320
+ expected_item_left : Item ,
321
+ expected_path_right : & [ & str ] ,
322
+ expected_item_right : Item ,
277
323
should_be_left : & ' a str ,
278
324
should_be_right : & ' a str ,
279
325
) -> Option < & ' a str > {
280
- let left_id = cx
281
- . typeck_results ( )
282
- . qpath_res ( path_left, arms[ 0 ] . pat . hir_id )
283
- . opt_def_id ( ) ?;
284
- let right_id = cx
285
- . typeck_results ( )
286
- . qpath_res ( path_right, arms[ 1 ] . pat . hir_id )
287
- . opt_def_id ( ) ?;
288
- let body_node_pair = if match_def_path ( cx, left_id, expected_left) && match_def_path ( cx, right_id, expected_right) {
326
+ let pat_left = arms[ 0 ] . pat ;
327
+ let pat_right = arms[ 1 ] . pat ;
328
+
329
+ let body_node_pair = if (
330
+ is_pat_variant ( cx, pat_left, path_left, expected_path_left, expected_item_left)
331
+ ) && (
332
+ is_pat_variant ( cx, pat_right, path_right, expected_path_right, expected_item_right)
333
+ ) {
289
334
( & arms[ 0 ] . body . kind , & arms[ 1 ] . body . kind )
290
- } else if match_def_path ( cx, right_id, expected_left) && match_def_path ( cx, right_id, expected_right) {
335
+ } else if (
336
+ is_pat_variant ( cx, pat_left, path_left, expected_path_right, expected_item_right)
337
+ ) && (
338
+ is_pat_variant ( cx, pat_right, path_right, expected_path_left, expected_item_left)
339
+ ) {
291
340
( & arms[ 1 ] . body . kind , & arms[ 0 ] . body . kind )
292
341
} else {
293
342
return None ;
0 commit comments