Skip to content

Commit 2a9eb78

Browse files
authored
redundant_pattern_match: clean-up (#15796)
- cast `&[Arm]` to `&[Arm; 2]` early on to hopefully avoid bounds checks - use `if let [pattern] = X { .. }` instead of `if let patterns = X { let pattern = patterns[0]; .. }` - use `Symbol`s instead of `&str`s - reduce indentation Diff best viewed with whitespace ignored changelog: none
2 parents d289009 + 1da0092 commit 2a9eb78

File tree

1 file changed

+67
-80
lines changed

1 file changed

+67
-80
lines changed

clippy_lints/src/matches/redundant_pattern_match.rs

Lines changed: 67 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -269,66 +269,61 @@ fn find_method_sugg_for_if_let<'tcx>(
269269
}
270270

271271
pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
272-
if arms.len() == 2 {
273-
let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
274-
275-
if let Some((good_method, maybe_guard)) = found_good_method(cx, arms, node_pair) {
276-
let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span));
277-
let result_expr = match &op.kind {
278-
ExprKind::AddrOf(_, _, borrowed) => borrowed,
279-
_ => op,
280-
};
281-
let mut app = Applicability::MachineApplicable;
282-
let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_paren();
283-
let mut sugg = format!("{receiver_sugg}.{good_method}");
284-
285-
if let Some(guard) = maybe_guard {
286-
// wow, the HIR for match guards in `PAT if let PAT = expr && expr => ...` is annoying!
287-
// `guard` here is `Guard::If` with the let expression somewhere deep in the tree of exprs,
288-
// counter to the intuition that it should be `Guard::IfLet`, so we need another check
289-
// to see that there aren't any let chains anywhere in the guard, as that would break
290-
// if we suggest `t.is_none() && (let X = y && z)` for:
291-
// `match t { None if let X = y && z => true, _ => false }`
292-
let has_nested_let_chain = for_each_expr_without_closures(guard, |expr| {
293-
if matches!(expr.kind, ExprKind::Let(..)) {
294-
ControlFlow::Break(())
295-
} else {
296-
ControlFlow::Continue(())
297-
}
298-
})
299-
.is_some();
300-
301-
if has_nested_let_chain {
302-
return;
272+
if let Ok(arms) = arms.try_into() // TODO: use `slice::as_array` once stabilized
273+
&& let Some((good_method, maybe_guard)) = found_good_method(cx, arms)
274+
{
275+
let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span));
276+
let result_expr = match &op.kind {
277+
ExprKind::AddrOf(_, _, borrowed) => borrowed,
278+
_ => op,
279+
};
280+
let mut app = Applicability::MachineApplicable;
281+
let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_paren();
282+
let mut sugg = format!("{receiver_sugg}.{good_method}");
283+
284+
if let Some(guard) = maybe_guard {
285+
// wow, the HIR for match guards in `PAT if let PAT = expr && expr => ...` is annoying!
286+
// `guard` here is `Guard::If` with the let expression somewhere deep in the tree of exprs,
287+
// counter to the intuition that it should be `Guard::IfLet`, so we need another check
288+
// to see that there aren't any let chains anywhere in the guard, as that would break
289+
// if we suggest `t.is_none() && (let X = y && z)` for:
290+
// `match t { None if let X = y && z => true, _ => false }`
291+
let has_nested_let_chain = for_each_expr_without_closures(guard, |expr| {
292+
if matches!(expr.kind, ExprKind::Let(..)) {
293+
ControlFlow::Break(())
294+
} else {
295+
ControlFlow::Continue(())
303296
}
297+
})
298+
.is_some();
304299

305-
let guard = Sugg::hir(cx, guard, "..");
306-
let _ = write!(sugg, " && {}", guard.maybe_paren());
300+
if has_nested_let_chain {
301+
return;
307302
}
308303

309-
span_lint_and_sugg(
310-
cx,
311-
REDUNDANT_PATTERN_MATCHING,
312-
span,
313-
format!("redundant pattern matching, consider using `{good_method}`"),
314-
"try",
315-
sugg,
316-
app,
317-
);
304+
let guard = Sugg::hir(cx, guard, "..");
305+
let _ = write!(sugg, " && {}", guard.maybe_paren());
318306
}
307+
308+
span_lint_and_sugg(
309+
cx,
310+
REDUNDANT_PATTERN_MATCHING,
311+
span,
312+
format!("redundant pattern matching, consider using `{good_method}`"),
313+
"try",
314+
sugg,
315+
app,
316+
);
319317
}
320318
}
321319

322320
fn found_good_method<'tcx>(
323321
cx: &LateContext<'_>,
324-
arms: &'tcx [Arm<'tcx>],
325-
node: (&PatKind<'_>, &PatKind<'_>),
322+
arms: &'tcx [Arm<'tcx>; 2],
326323
) -> Option<(&'static str, Option<&'tcx Expr<'tcx>>)> {
327-
match node {
328-
(PatKind::TupleStruct(path_left, patterns_left, _), PatKind::TupleStruct(path_right, patterns_right, _))
329-
if patterns_left.len() == 1 && patterns_right.len() == 1 =>
330-
{
331-
if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
324+
match (&arms[0].pat.kind, &arms[1].pat.kind) {
325+
(PatKind::TupleStruct(path_left, [pattern_left], _), PatKind::TupleStruct(path_right, [pattern_right], _)) => {
326+
if let (PatKind::Wild, PatKind::Wild) = (&pattern_left.kind, &pattern_right.kind) {
332327
find_good_method_for_match(
333328
cx,
334329
arms,
@@ -356,7 +351,7 @@ fn found_good_method<'tcx>(
356351
}
357352
},
358353
(
359-
PatKind::TupleStruct(path_left, patterns, _),
354+
PatKind::TupleStruct(path_left, [pattern], _),
360355
PatKind::Expr(PatExpr {
361356
kind: PatExprKind::Path(path_right),
362357
..
@@ -367,9 +362,9 @@ fn found_good_method<'tcx>(
367362
kind: PatExprKind::Path(path_left),
368363
..
369364
}),
370-
PatKind::TupleStruct(path_right, patterns, _),
371-
) if patterns.len() == 1 => {
372-
if let PatKind::Wild = patterns[0].kind {
365+
PatKind::TupleStruct(path_right, [pattern], _),
366+
) => {
367+
if let PatKind::Wild = pattern.kind {
373368
find_good_method_for_match(
374369
cx,
375370
arms,
@@ -396,8 +391,8 @@ fn found_good_method<'tcx>(
396391
None
397392
}
398393
},
399-
(PatKind::TupleStruct(path_left, patterns, _), PatKind::Wild) if patterns.len() == 1 => {
400-
if let PatKind::Wild = patterns[0].kind {
394+
(PatKind::TupleStruct(path_left, [pattern], _), PatKind::Wild) => {
395+
if let PatKind::Wild = pattern.kind {
401396
get_good_method(cx, arms, path_left)
402397
} else {
403398
None
@@ -426,31 +421,23 @@ fn get_ident(path: &QPath<'_>) -> Option<rustc_span::symbol::Ident> {
426421

427422
fn get_good_method<'tcx>(
428423
cx: &LateContext<'_>,
429-
arms: &'tcx [Arm<'tcx>],
424+
arms: &'tcx [Arm<'tcx>; 2],
430425
path_left: &QPath<'_>,
431426
) -> Option<(&'static str, Option<&'tcx Expr<'tcx>>)> {
432-
if let Some(name) = get_ident(path_left) {
433-
let (expected_item_left, should_be_left, should_be_right) = match name.as_str() {
434-
"Ok" => (Item::Lang(ResultOk), "is_ok()", "is_err()"),
435-
"Err" => (Item::Lang(ResultErr), "is_err()", "is_ok()"),
436-
"Some" => (Item::Lang(OptionSome), "is_some()", "is_none()"),
437-
"None" => (Item::Lang(OptionNone), "is_none()", "is_some()"),
438-
"Ready" => (Item::Lang(PollReady), "is_ready()", "is_pending()"),
439-
"Pending" => (Item::Lang(PollPending), "is_pending()", "is_ready()"),
440-
"V4" => (Item::Diag(sym::IpAddr, sym::V4), "is_ipv4()", "is_ipv6()"),
441-
"V6" => (Item::Diag(sym::IpAddr, sym::V6), "is_ipv6()", "is_ipv4()"),
442-
_ => return None,
443-
};
444-
return find_good_method_for_matches_macro(
445-
cx,
446-
arms,
447-
path_left,
448-
expected_item_left,
449-
should_be_left,
450-
should_be_right,
451-
);
452-
}
453-
None
427+
let ident = get_ident(path_left)?;
428+
429+
let (expected_item_left, should_be_left, should_be_right) = match ident.name {
430+
sym::Ok => (Item::Lang(ResultOk), "is_ok()", "is_err()"),
431+
sym::Err => (Item::Lang(ResultErr), "is_err()", "is_ok()"),
432+
sym::Some => (Item::Lang(OptionSome), "is_some()", "is_none()"),
433+
sym::None => (Item::Lang(OptionNone), "is_none()", "is_some()"),
434+
sym::Ready => (Item::Lang(PollReady), "is_ready()", "is_pending()"),
435+
sym::Pending => (Item::Lang(PollPending), "is_pending()", "is_ready()"),
436+
sym::V4 => (Item::Diag(sym::IpAddr, sym::V4), "is_ipv4()", "is_ipv6()"),
437+
sym::V6 => (Item::Diag(sym::IpAddr, sym::V6), "is_ipv6()", "is_ipv4()"),
438+
_ => return None,
439+
};
440+
find_good_method_for_matches_macro(cx, arms, path_left, expected_item_left, should_be_left, should_be_right)
454441
}
455442

456443
#[derive(Clone, Copy)]
@@ -490,7 +477,7 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte
490477
#[expect(clippy::too_many_arguments)]
491478
fn find_good_method_for_match<'a, 'tcx>(
492479
cx: &LateContext<'_>,
493-
arms: &'tcx [Arm<'tcx>],
480+
arms: &'tcx [Arm<'tcx>; 2],
494481
path_left: &QPath<'_>,
495482
path_right: &QPath<'_>,
496483
expected_item_left: Item,
@@ -525,7 +512,7 @@ fn find_good_method_for_match<'a, 'tcx>(
525512

526513
fn find_good_method_for_matches_macro<'a, 'tcx>(
527514
cx: &LateContext<'_>,
528-
arms: &'tcx [Arm<'tcx>],
515+
arms: &'tcx [Arm<'tcx>; 2],
529516
path_left: &QPath<'_>,
530517
expected_item_left: Item,
531518
should_be_left: &'a str,

0 commit comments

Comments
 (0)