@@ -2,7 +2,7 @@ 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;
77use clippy_utils:: { higher, is_lang_ctor, is_trait_method, match_def_path, paths} ;
88use if_chain:: if_chain;
@@ -12,7 +12,7 @@ use rustc_hir::LangItem::{OptionNone, PollPending};
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 , def_id :: DefId } ;
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 , & paths:: IPADDR_V4 , 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 , & paths:: IPADDR_V6 , Item :: Diag ( sym ! ( IpAddr ) , sym ! ( V6 ) ) ) {
8181 ( "is_ipv6()" , op_ty)
8282 } else {
8383 return ;
@@ -174,6 +174,7 @@ fn find_sugg_for_if_let<'tcx>(
174174
175175pub ( super ) fn check_match < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > , op : & Expr < ' _ > , arms : & [ Arm < ' _ > ] ) {
176176 if arms. len ( ) == 2 {
177+ let lang_items = cx. tcx . lang_items ( ) ;
177178 let node_pair = ( & arms[ 0 ] . pat . kind , & arms[ 1 ] . pat . kind ) ;
178179
179180 let found_good_method = match node_pair {
@@ -188,7 +189,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
188189 path_left,
189190 path_right,
190191 & paths:: RESULT_OK ,
192+ Item :: Lang ( lang_items. result_ok_variant ( ) ) ,
191193 & paths:: RESULT_ERR ,
194+ Item :: Lang ( lang_items. result_err_variant ( ) ) ,
192195 "is_ok()" ,
193196 "is_err()" ,
194197 )
@@ -199,7 +202,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
199202 path_left,
200203 path_right,
201204 & paths:: IPADDR_V4 ,
205+ Item :: Diag ( sym ! ( IpAddr ) , sym ! ( V4 ) ) ,
202206 & paths:: IPADDR_V6 ,
207+ Item :: Diag ( sym ! ( IpAddr ) , sym ! ( V6 ) ) ,
203208 "is_ipv4()" ,
204209 "is_ipv6()" ,
205210 )
@@ -213,13 +218,16 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
213218 if patterns. len ( ) == 1 =>
214219 {
215220 if let PatKind :: Wild = patterns[ 0 ] . kind {
221+
216222 find_good_method_for_match (
217223 cx,
218224 arms,
219225 path_left,
220226 path_right,
221227 & paths:: OPTION_SOME ,
228+ Item :: Lang ( lang_items. option_some_variant ( ) ) ,
222229 & paths:: OPTION_NONE ,
230+ Item :: Lang ( lang_items. option_none_variant ( ) ) ,
223231 "is_some()" ,
224232 "is_none()" ,
225233 )
@@ -230,7 +238,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
230238 path_left,
231239 path_right,
232240 & paths:: POLL_READY ,
241+ Item :: Lang ( lang_items. poll_ready_variant ( ) ) ,
233242 & paths:: POLL_PENDING ,
243+ Item :: Lang ( lang_items. poll_pending_variant ( ) ) ,
234244 "is_ready()" ,
235245 "is_pending()" ,
236246 )
@@ -266,28 +276,67 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
266276 }
267277}
268278
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+
269313#[ expect( clippy:: too_many_arguments) ]
270314fn find_good_method_for_match < ' a > (
271315 cx : & LateContext < ' _ > ,
272316 arms : & [ Arm < ' _ > ] ,
273317 path_left : & QPath < ' _ > ,
274318 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 ,
277323 should_be_left : & ' a str ,
278324 should_be_right : & ' a str ,
279325) -> 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+ ) {
289334 ( & 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+ ) {
291340 ( & arms[ 1 ] . body . kind , & arms[ 0 ] . body . kind )
292341 } else {
293342 return None ;
0 commit comments