Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 850d77e

Browse files
committed
[redundant_pattern_matching]: catch if let true
1 parent a859e5c commit 850d77e

File tree

10 files changed

+50
-12
lines changed

10 files changed

+50
-12
lines changed

clippy_lints/src/format_push_string.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
5757
Some(higher::IfLetOrMatch::Match(_, arms, MatchSource::Normal)) => {
5858
arms.iter().any(|arm| is_format(cx, arm.body))
5959
},
60-
Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => {
60+
Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else, _)) => {
6161
is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e))
6262
},
6363
_ => false,

clippy_lints/src/loops/manual_flatten.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub(super) fn check<'tcx>(
2020
span: Span,
2121
) {
2222
let inner_expr = peel_blocks_with_stmt(body);
23-
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
23+
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None, .. })
2424
= higher::IfLet::hir(cx, inner_expr)
2525
// Ensure match_expr in `if let` statement is the same as the pat from the for-loop
2626
&& let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind

clippy_lints/src/manual_let_else.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl<'tcx> QuestionMark {
6161
&& let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
6262
{
6363
match if_let_or_match {
64-
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => {
64+
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => {
6565
if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then)
6666
&& let Some(if_else) = if_else
6767
&& is_never_expr(cx, if_else).is_some()

clippy_lints/src/matches/collapsible_match.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fn check_arm<'tcx>(
4141
let inner_expr = peel_blocks_with_stmt(outer_then_body);
4242
if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr)
4343
&& let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
44-
IfLetOrMatch::IfLet(scrutinee, pat, _, els) => Some((scrutinee, pat, els)),
44+
IfLetOrMatch::IfLet(scrutinee, pat, _, els, _) => Some((scrutinee, pat, els)),
4545
IfLetOrMatch::Match(scrutinee, arms, ..) => if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none())
4646
// if there are more than two arms, collapsing would be non-trivial
4747
// one of the arms must be "wild-like"
@@ -75,7 +75,7 @@ fn check_arm<'tcx>(
7575
)
7676
// ...or anywhere in the inner expression
7777
&& match inner {
78-
IfLetOrMatch::IfLet(_, _, body, els) => {
78+
IfLetOrMatch::IfLet(_, _, body, els, _) => {
7979
!is_local_used(cx, body, binding_id) && els.map_or(true, |e| !is_local_used(cx, e, binding_id))
8080
},
8181
IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)),

clippy_lints/src/matches/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
11041104
if_let.let_pat,
11051105
if_let.let_expr,
11061106
if_let.if_else.is_some(),
1107+
if_let.let_span,
11071108
);
11081109
needless_match::check_if_let(cx, expr, &if_let);
11091110
}

clippy_lints/src/matches/redundant_pattern_match.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady,
1212
use rustc_hir::{Arm, Expr, ExprKind, Guard, Node, Pat, PatKind, QPath, UnOp};
1313
use rustc_lint::LateContext;
1414
use rustc_middle::ty::{self, GenericArgKind, Ty};
15-
use rustc_span::{sym, Symbol};
15+
use rustc_span::{sym, Span, Symbol};
1616
use std::fmt::Write;
1717
use std::ops::ControlFlow;
1818

1919
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
2020
if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
21-
find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
21+
find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
2222
}
2323
}
2424

@@ -28,8 +28,34 @@ pub(super) fn check_if_let<'tcx>(
2828
pat: &'tcx Pat<'_>,
2929
scrutinee: &'tcx Expr<'_>,
3030
has_else: bool,
31+
let_span: Span,
3132
) {
32-
find_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else);
33+
find_if_let_true(cx, pat, scrutinee, let_span);
34+
find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else);
35+
}
36+
37+
fn find_if_let_true<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, scrutinee: &'tcx Expr<'_>, let_span: Span) {
38+
if let PatKind::Lit(lit) = pat.kind
39+
&& let ExprKind::Lit(lit) = lit.kind
40+
&& let LitKind::Bool(is_true) = lit.node
41+
{
42+
let mut snip = snippet(cx, scrutinee.span, "..").into_owned();
43+
44+
if !is_true {
45+
// Invert condition for `if let false = ...`
46+
snip.insert(0, '!');
47+
}
48+
49+
span_lint_and_sugg(
50+
cx,
51+
REDUNDANT_PATTERN_MATCHING,
52+
let_span,
53+
"using `if let` to pattern match a boolean",
54+
"consider using a regular `if` expression",
55+
snip,
56+
Applicability::MachineApplicable,
57+
);
58+
}
3359
}
3460

3561
// Extract the generic arguments out of a type
@@ -100,7 +126,7 @@ fn find_method_and_type<'tcx>(
100126
}
101127
}
102128

103-
fn find_sugg_for_if_let<'tcx>(
129+
fn find_method_sugg_for_if_let<'tcx>(
104130
cx: &LateContext<'tcx>,
105131
expr: &'tcx Expr<'_>,
106132
let_pat: &Pat<'_>,

clippy_lints/src/methods/filter_map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
186186
match higher::IfLetOrMatch::parse(cx, map_body.value) {
187187
// For `if let` we want to check that the variant matching arm references the local created by
188188
// its pattern
189-
Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_)))
189+
Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_), ..))
190190
if let Some((ident, span)) = expr_uses_local(pat, then) =>
191191
{
192192
(sc, else_, ident, span)

clippy_lints/src/option_if_let_else.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
238238
let_expr,
239239
if_then,
240240
if_else: Some(if_else),
241+
..
241242
}) = higher::IfLet::hir(cx, expr)
242243
&& !cx.typeck_results().expr_ty(expr).is_unit()
243244
&& !is_else_clause(cx.tcx, expr)

clippy_lints/src/question_mark.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ impl QuestionMark {
256256
let_expr,
257257
if_then,
258258
if_else,
259+
..
259260
}) = higher::IfLet::hir(cx, expr)
260261
&& !is_else_clause(cx.tcx, expr)
261262
&& let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind

clippy_utils/src/higher.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ pub struct IfLet<'hir> {
9191
pub if_then: &'hir Expr<'hir>,
9292
/// `if let` else expression
9393
pub if_else: Option<&'hir Expr<'hir>>,
94+
/// `if let PAT = EXPR`
95+
/// ^^^^^^^^^^^^^^
96+
pub let_span: Span,
9497
}
9598

9699
impl<'hir> IfLet<'hir> {
@@ -99,9 +102,10 @@ impl<'hir> IfLet<'hir> {
99102
if let ExprKind::If(
100103
Expr {
101104
kind:
102-
ExprKind::Let(hir::Let {
105+
ExprKind::Let(&hir::Let {
103106
pat: let_pat,
104107
init: let_expr,
108+
span: let_span,
105109
..
106110
}),
107111
..
@@ -129,6 +133,7 @@ impl<'hir> IfLet<'hir> {
129133
let_expr,
130134
if_then,
131135
if_else,
136+
let_span,
132137
});
133138
}
134139
None
@@ -146,6 +151,9 @@ pub enum IfLetOrMatch<'hir> {
146151
&'hir Pat<'hir>,
147152
&'hir Expr<'hir>,
148153
Option<&'hir Expr<'hir>>,
154+
/// `if let PAT = EXPR`
155+
/// ^^^^^^^^^^^^^^
156+
Span,
149157
),
150158
}
151159

@@ -160,7 +168,8 @@ impl<'hir> IfLetOrMatch<'hir> {
160168
let_pat,
161169
if_then,
162170
if_else,
163-
}| { Self::IfLet(let_expr, let_pat, if_then, if_else) },
171+
let_span,
172+
}| { Self::IfLet(let_expr, let_pat, if_then, if_else, let_span) },
164173
),
165174
}
166175
}

0 commit comments

Comments
 (0)