Skip to content

Commit edbaca0

Browse files
committed
Don't lint if local came from an or pattern
1 parent b17a96a commit edbaca0

File tree

4 files changed

+56
-46
lines changed

4 files changed

+56
-46
lines changed

clippy_lints/src/matches/redundant_guards.rs

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -34,31 +34,25 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
3434
],
3535
MatchSource::Normal,
3636
) = if_expr.kind
37-
&& let Some((pat_binding, can_use_shorthand)) = get_pat_binding(cx, scrutinee, outer_arm)
3837
{
3938
emit_redundant_guards(
4039
cx,
4140
outer_arm,
4241
if_expr.span,
43-
pat_binding,
44-
can_use_shorthand,
42+
scrutinee,
4543
arm.pat.span,
4644
arm.guard,
4745
&mut app,
4846
);
4947
}
5048
// `Some(x) if let Some(2) = x`
51-
else if let Guard::IfLet(let_expr) = guard
52-
&& let pat = let_expr.pat
53-
&& let Some((pat_binding, can_use_shorthand)) = get_pat_binding(cx, let_expr.init, outer_arm)
54-
{
49+
else if let Guard::IfLet(let_expr) = guard {
5550
emit_redundant_guards(
5651
cx,
5752
outer_arm,
5853
let_expr.span,
59-
pat_binding,
60-
can_use_shorthand,
61-
pat.span,
54+
let_expr.init,
55+
let_expr.pat.span,
6256
None,
6357
&mut app,
6458
);
@@ -67,7 +61,6 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
6761
else if let Guard::If(if_expr) = guard
6862
&& let ExprKind::Binary(bin_op, local, pat) = if_expr.kind
6963
&& matches!(bin_op.node, BinOpKind::Eq)
70-
&& let Some((pat_binding, can_use_shorthand)) = get_pat_binding(cx, local, outer_arm)
7164
&& expr_can_be_pat(cx, pat)
7265
// Ensure they have the same type. If they don't, we'd need deref coercion which isn't
7366
// possible (currently) in a pattern. In some cases, you can use something like
@@ -81,8 +74,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
8174
cx,
8275
outer_arm,
8376
if_expr.span,
84-
pat_binding,
85-
can_use_shorthand,
77+
local,
8678
pat.span,
8779
None,
8880
&mut app,
@@ -94,12 +86,18 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
9486
fn get_pat_binding<'tcx>(cx: &LateContext<'tcx>, guard_expr: &Expr<'_>, outer_arm: &Arm<'tcx>) -> Option<(Span, bool)> {
9587
if let Some(local) = path_to_local(guard_expr) && !is_local_used(cx, outer_arm.body, local) {
9688
let mut span = None;
97-
// FIXME: hir_id == local is only true for the first or, this will always be false
9889
let mut multiple_bindings = false;
99-
outer_arm.pat.each_binding(|_, hir_id, binding_span, _| {
100-
if hir_id == local && span.replace(binding_span).is_some() {
90+
// `each_binding` gives the `HirId` of the `Pat` itself, not the binding
91+
outer_arm.pat.walk(|pat| {
92+
if let PatKind::Binding(_, hir_id, _, _) = pat.kind
93+
&& hir_id == local
94+
&& span.replace(pat.span).is_some()
95+
{
10196
multiple_bindings = true;
97+
return false;
10298
}
99+
100+
true
103101
});
104102

105103
if !multiple_bindings {
@@ -115,28 +113,19 @@ fn get_pat_binding<'tcx>(cx: &LateContext<'tcx>, guard_expr: &Expr<'_>, outer_ar
115113
None
116114
}
117115

118-
fn get_guard(cx: &LateContext<'_>, guard: Option<Guard<'_>>, app: &mut Applicability) -> String {
119-
guard.map_or_else(String::new, |guard| {
120-
let (prefix, span) = match guard {
121-
Guard::If(e) => ("if", e.span),
122-
Guard::IfLet(l) => ("if let", l.span),
123-
};
124-
125-
format!(" {prefix} {}", snippet_with_applicability(cx, span, "<guard>", app))
126-
})
127-
}
128-
129-
#[expect(clippy::too_many_arguments)]
130-
fn emit_redundant_guards(
131-
cx: &LateContext<'_>,
132-
outer_arm: &Arm<'_>,
116+
fn emit_redundant_guards<'tcx>(
117+
cx: &LateContext<'tcx>,
118+
outer_arm: &Arm<'tcx>,
133119
guard_span: Span,
134-
pat_binding: Span,
135-
can_use_shorthand: bool,
120+
local: &Expr<'_>,
136121
pat_span: Span,
137122
inner_guard: Option<Guard<'_>>,
138123
app: &mut Applicability,
139124
) {
125+
let Some((pat_binding, can_use_shorthand)) = get_pat_binding(cx, local, outer_arm) else {
126+
return;
127+
};
128+
140129
span_lint_and_then(
141130
cx,
142131
REDUNDANT_GUARDS,
@@ -154,7 +143,14 @@ fn emit_redundant_guards(
154143
},
155144
(
156145
guard_span.source_callsite().with_lo(outer_arm.pat.span.hi()),
157-
get_guard(cx, inner_guard, app),
146+
inner_guard.map_or_else(String::new, |guard| {
147+
let (prefix, span) = match guard {
148+
Guard::If(e) => ("if", e.span),
149+
Guard::IfLet(l) => ("if let", l.span),
150+
};
151+
152+
format!(" {prefix} {}", snippet_with_applicability(cx, span, "<guard>", app))
153+
}),
158154
),
159155
],
160156
*app,

tests/ui/redundant_guards.fixed

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//@run-rustfix
2-
//@aux-build:proc_macros.rs
2+
//@aux-build:proc_macros.rs:proc-macro
33
#![feature(if_let_guard)]
44
#![allow(clippy::no_effect, unused)]
55
#![warn(clippy::redundant_guards)]
@@ -80,22 +80,23 @@ fn main() {
8080
}
8181
}
8282

83+
// Do not lint
84+
8385
enum E {
8486
A(&'static str),
8587
B(&'static str),
8688
C(&'static str),
8789
}
8890

89-
#[allow(clippy::redundant_guards)] // FIXME: hir_id == local is only true for the first or
9091
fn i() {
9192
match E::A("") {
9293
E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {},
94+
// Ok well, this one is fine. Lint it
95+
E::A("not from an or pattern") => {},
9396
_ => {},
94-
}
97+
};
9598
}
9699

97-
// Do not lint
98-
99100
fn f(s: Option<std::ffi::OsString>) {
100101
match s {
101102
Some(x) if x == "a" => {},

tests/ui/redundant_guards.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//@run-rustfix
2-
//@aux-build:proc_macros.rs
2+
//@aux-build:proc_macros.rs:proc-macro
33
#![feature(if_let_guard)]
44
#![allow(clippy::no_effect, unused)]
55
#![warn(clippy::redundant_guards)]
@@ -80,22 +80,23 @@ fn main() {
8080
}
8181
}
8282

83+
// Do not lint
84+
8385
enum E {
8486
A(&'static str),
8587
B(&'static str),
8688
C(&'static str),
8789
}
8890

89-
#[allow(clippy::redundant_guards)] // FIXME: hir_id == local is only true for the first or
9091
fn i() {
9192
match E::A("") {
9293
E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {},
94+
// Ok well, this one is fine. Lint it
95+
E::A(y) if y == "not from an or pattern" => {},
9396
_ => {},
94-
}
97+
};
9598
}
9699

97-
// Do not lint
98-
99100
fn f(s: Option<std::ffi::OsString>) {
100101
match s {
101102
Some(x) if x == "a" => {},

tests/ui/redundant_guards.stderr

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,19 @@ LL + B { e: Some(A(2)) } => ..,
7171
|
7272

7373
error: redundant guard
74-
--> $DIR/redundant_guards.rs:108:14
74+
--> $DIR/redundant_guards.rs:95:20
75+
|
76+
LL | E::A(y) if y == "not from an or pattern" => {},
77+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
78+
|
79+
help: try
80+
|
81+
LL - E::A(y) if y == "not from an or pattern" => {},
82+
LL + E::A("not from an or pattern") => {},
83+
|
84+
85+
error: redundant guard
86+
--> $DIR/redundant_guards.rs:109:14
7587
|
7688
LL | x if matches!(x, Some(0)) => ..,
7789
| ^^^^^^^^^^^^^^^^^^^^
@@ -82,5 +94,5 @@ LL - x if matches!(x, Some(0)) => ..,
8294
LL + Some(0) => ..,
8395
|
8496

85-
error: aborting due to 7 previous errors
97+
error: aborting due to 8 previous errors
8698

0 commit comments

Comments
 (0)