@@ -2,17 +2,17 @@ use super::REDUNDANT_PATTERN_MATCHING;
22use clippy_utils:: diagnostics:: span_lint_and_then;
33use clippy_utils:: source:: snippet;
44use clippy_utils:: sugg:: Sugg ;
5- use clippy_utils:: ty:: needs_ordered_drop;
5+ use clippy_utils:: ty:: { is_type_diagnostic_item , needs_ordered_drop} ;
66use clippy_utils:: visitors:: any_temporaries_need_ordered_drop;
7- use clippy_utils:: { higher, is_lang_ctor, is_trait_method, match_def_path , paths } ;
7+ use clippy_utils:: { higher, is_lang_ctor, is_trait_method} ;
88use if_chain:: if_chain;
99use rustc_ast:: ast:: LitKind ;
1010use rustc_errors:: Applicability ;
11- use rustc_hir:: LangItem :: { OptionNone , PollPending } ;
11+ use rustc_hir:: LangItem :: { self , OptionSome , OptionNone , PollPending , PollReady , ResultOk , ResultErr } ;
1212use rustc_hir:: { Arm , Expr , ExprKind , Node , Pat , PatKind , QPath , UnOp } ;
1313use rustc_lint:: LateContext ;
1414use rustc_middle:: ty:: { self , subst:: GenericArgKind , DefIdTree , Ty } ;
15- use rustc_span:: sym;
15+ use rustc_span:: { sym, Symbol } ;
1616
1717pub ( super ) fn check < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
1818 if let Some ( higher:: WhileLet { let_pat, let_expr, .. } ) = higher:: WhileLet :: hir ( expr) {
@@ -75,9 +75,9 @@ fn find_sugg_for_if_let<'tcx>(
7575 ( "is_some()" , op_ty)
7676 } else if Some ( id) == lang_items. poll_ready_variant ( ) {
7777 ( "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 , Item :: Diag ( sym :: IpAddr , sym ! ( V4 ) ) ) {
7979 ( "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 , Item :: Diag ( sym :: IpAddr , sym ! ( V6 ) ) ) {
8181 ( "is_ipv6()" , op_ty)
8282 } else {
8383 return ;
@@ -187,8 +187,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
187187 arms,
188188 path_left,
189189 path_right,
190- & paths :: RESULT_OK ,
191- & paths :: RESULT_ERR ,
190+ Item :: Lang ( ResultOk ) ,
191+ Item :: Lang ( ResultErr ) ,
192192 "is_ok()" ,
193193 "is_err()" ,
194194 )
@@ -198,8 +198,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
198198 arms,
199199 path_left,
200200 path_right,
201- & paths :: IPADDR_V4 ,
202- & paths :: IPADDR_V6 ,
201+ Item :: Diag ( sym :: IpAddr , sym ! ( V4 ) ) ,
202+ Item :: Diag ( sym :: IpAddr , sym ! ( V6 ) ) ,
203203 "is_ipv4()" ,
204204 "is_ipv6()" ,
205205 )
@@ -213,13 +213,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
213213 if patterns. len ( ) == 1 =>
214214 {
215215 if let PatKind :: Wild = patterns[ 0 ] . kind {
216+
216217 find_good_method_for_match (
217218 cx,
218219 arms,
219220 path_left,
220221 path_right,
221- & paths :: OPTION_SOME ,
222- & paths :: OPTION_NONE ,
222+ Item :: Lang ( OptionSome ) ,
223+ Item :: Lang ( OptionNone ) ,
223224 "is_some()" ,
224225 "is_none()" ,
225226 )
@@ -229,8 +230,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
229230 arms,
230231 path_left,
231232 path_right,
232- & paths :: POLL_READY ,
233- & paths :: POLL_PENDING ,
233+ Item :: Lang ( PollReady ) ,
234+ Item :: Lang ( PollPending ) ,
234235 "is_ready()" ,
235236 "is_pending()" ,
236237 )
@@ -266,28 +267,61 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
266267 }
267268}
268269
270+ #[ derive( Clone , Copy ) ]
271+ enum Item {
272+ Lang ( LangItem ) ,
273+ Diag ( Symbol , Symbol ) ,
274+ }
275+
276+ fn is_pat_variant ( cx : & LateContext < ' _ > , pat : & Pat < ' _ > , path : & QPath < ' _ > , expected_item : Item ) -> bool {
277+ let Some ( id) = cx. typeck_results ( ) . qpath_res ( path, pat. hir_id ) . opt_def_id ( ) else { return false } ;
278+
279+ match expected_item {
280+ Item :: Lang ( expected_lang_item) => {
281+ let expected_id = cx. tcx . lang_items ( ) . require ( expected_lang_item) . unwrap ( ) ;
282+ cx. tcx . parent ( id) == expected_id
283+ } ,
284+ Item :: Diag ( expected_ty, expected_variant) => {
285+ let ty = cx. typeck_results ( ) . pat_ty ( pat) ;
286+
287+ if is_type_diagnostic_item ( cx, ty, expected_ty) {
288+ let variant = ty. ty_adt_def ( )
289+ . expect ( "struct pattern type is not an ADT" )
290+ . variant_of_res ( cx. qpath_res ( path, pat. hir_id ) ) ;
291+
292+ return variant. name == expected_variant
293+ }
294+
295+ false
296+ }
297+ }
298+ }
299+
269300#[ expect( clippy:: too_many_arguments) ]
270301fn find_good_method_for_match < ' a > (
271302 cx : & LateContext < ' _ > ,
272303 arms : & [ Arm < ' _ > ] ,
273304 path_left : & QPath < ' _ > ,
274305 path_right : & QPath < ' _ > ,
275- expected_left : & [ & str ] ,
276- expected_right : & [ & str ] ,
306+ expected_item_left : Item ,
307+ expected_item_right : Item ,
277308 should_be_left : & ' a str ,
278309 should_be_right : & ' a str ,
279310) -> 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) {
311+ let pat_left = arms[ 0 ] . pat ;
312+ let pat_right = arms[ 1 ] . pat ;
313+
314+ let body_node_pair = if (
315+ is_pat_variant ( cx, pat_left, path_left, expected_item_left)
316+ ) && (
317+ is_pat_variant ( cx, pat_right, path_right, expected_item_right)
318+ ) {
289319 ( & 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) {
320+ } else if (
321+ is_pat_variant ( cx, pat_left, path_left, expected_item_right)
322+ ) && (
323+ is_pat_variant ( cx, pat_right, path_right, expected_item_left)
324+ ) {
291325 ( & arms[ 1 ] . body . kind , & arms[ 0 ] . body . kind )
292326 } else {
293327 return None ;
0 commit comments