Skip to content

Commit ef73648

Browse files
committed
Auto merge of #11468 - mojave2:issue-11465, r=blyxyas
add extra `byref` checking for the guard's local changelog: [`redundant_guards`]: Now checks if the variable is bound using `ref` before linting. The lint should not be emitted, when the local variable is bind by-ref in the pattern. fixes #11465
2 parents f54275f + 67f0ba4 commit ef73648

File tree

4 files changed

+221
-29
lines changed

4 files changed

+221
-29
lines changed

clippy_lints/src/matches/redundant_guards.rs

Lines changed: 66 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::path_to_local;
33
use clippy_utils::source::snippet_with_applicability;
44
use clippy_utils::visitors::{for_each_expr, is_local_used};
5-
use rustc_ast::LitKind;
5+
use rustc_ast::{BorrowKind, LitKind};
66
use rustc_errors::Applicability;
77
use rustc_hir::def::{DefKind, Res};
88
use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, Guard, MatchSource, Node, Pat, PatKind};
99
use rustc_lint::LateContext;
10+
use rustc_span::symbol::Ident;
1011
use rustc_span::Span;
1112
use std::ops::ControlFlow;
1213

@@ -34,24 +35,37 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
3435
],
3536
MatchSource::Normal,
3637
) = if_expr.kind
38+
&& let Some(binding) = get_pat_binding(cx, scrutinee, outer_arm)
3739
{
40+
let pat_span = match (arm.pat.kind, binding.byref_ident) {
41+
(PatKind::Ref(pat, _), Some(_)) => pat.span,
42+
(PatKind::Ref(..), None) | (_, Some(_)) => continue,
43+
_ => arm.pat.span,
44+
};
3845
emit_redundant_guards(
3946
cx,
4047
outer_arm,
4148
if_expr.span,
42-
scrutinee,
43-
arm.pat.span,
49+
pat_span,
50+
&binding,
4451
arm.guard,
4552
);
4653
}
4754
// `Some(x) if let Some(2) = x`
48-
else if let Guard::IfLet(let_expr) = guard {
55+
else if let Guard::IfLet(let_expr) = guard
56+
&& let Some(binding) = get_pat_binding(cx, let_expr.init, outer_arm)
57+
{
58+
let pat_span = match (let_expr.pat.kind, binding.byref_ident) {
59+
(PatKind::Ref(pat, _), Some(_)) => pat.span,
60+
(PatKind::Ref(..), None) | (_, Some(_)) => continue,
61+
_ => let_expr.pat.span,
62+
};
4963
emit_redundant_guards(
5064
cx,
5165
outer_arm,
5266
let_expr.span,
53-
let_expr.init,
54-
let_expr.pat.span,
67+
pat_span,
68+
&binding,
5569
None,
5670
);
5771
}
@@ -67,43 +81,63 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
6781
//
6882
// This isn't necessary in the other two checks, as they must be a pattern already.
6983
&& cx.typeck_results().expr_ty(local) == cx.typeck_results().expr_ty(pat)
84+
&& let Some(binding) = get_pat_binding(cx, local, outer_arm)
7085
{
86+
let pat_span = match (pat.kind, binding.byref_ident) {
87+
(ExprKind::AddrOf(BorrowKind::Ref, _, expr), Some(_)) => expr.span,
88+
(ExprKind::AddrOf(..), None) | (_, Some(_)) => continue,
89+
_ => pat.span,
90+
};
7191
emit_redundant_guards(
7292
cx,
7393
outer_arm,
7494
if_expr.span,
75-
local,
76-
pat.span,
95+
pat_span,
96+
&binding,
7797
None,
7898
);
7999
}
80100
}
81101
}
82102

83-
fn get_pat_binding<'tcx>(cx: &LateContext<'tcx>, guard_expr: &Expr<'_>, outer_arm: &Arm<'tcx>) -> Option<(Span, bool)> {
103+
struct PatBindingInfo {
104+
span: Span,
105+
byref_ident: Option<Ident>,
106+
is_field: bool,
107+
}
108+
109+
fn get_pat_binding<'tcx>(
110+
cx: &LateContext<'tcx>,
111+
guard_expr: &Expr<'_>,
112+
outer_arm: &Arm<'tcx>,
113+
) -> Option<PatBindingInfo> {
84114
if let Some(local) = path_to_local(guard_expr) && !is_local_used(cx, outer_arm.body, local) {
85115
let mut span = None;
116+
let mut byref_ident = None;
86117
let mut multiple_bindings = false;
87118
// `each_binding` gives the `HirId` of the `Pat` itself, not the binding
88119
outer_arm.pat.walk(|pat| {
89-
if let PatKind::Binding(_, hir_id, _, _) = pat.kind
120+
if let PatKind::Binding(bind_annot, hir_id, ident, _) = pat.kind
90121
&& hir_id == local
91-
&& span.replace(pat.span).is_some()
92122
{
93-
multiple_bindings = true;
94-
return false;
123+
if matches!(bind_annot.0, rustc_ast::ByRef::Yes) {
124+
let _ = byref_ident.insert(ident);
125+
}
126+
// the second call of `replace()` returns a `Some(span)`, meaning a multi-binding pattern
127+
if span.replace(pat.span).is_some() {
128+
multiple_bindings = true;
129+
return false;
130+
}
95131
}
96-
97132
true
98133
});
99134

100135
// Ignore bindings from or patterns, like `First(x) | Second(x, _) | Third(x, _, _)`
101136
if !multiple_bindings {
102-
return span.map(|span| {
103-
(
104-
span,
105-
!matches!(cx.tcx.hir().get_parent(local), Node::PatField(_)),
106-
)
137+
return span.map(|span| PatBindingInfo {
138+
span,
139+
byref_ident,
140+
is_field: matches!(cx.tcx.hir().get_parent(local), Node::PatField(_)),
107141
});
108142
}
109143
}
@@ -115,14 +149,11 @@ fn emit_redundant_guards<'tcx>(
115149
cx: &LateContext<'tcx>,
116150
outer_arm: &Arm<'tcx>,
117151
guard_span: Span,
118-
local: &Expr<'_>,
119152
pat_span: Span,
153+
pat_binding: &PatBindingInfo,
120154
inner_guard: Option<Guard<'_>>,
121155
) {
122156
let mut app = Applicability::MaybeIncorrect;
123-
let Some((pat_binding, can_use_shorthand)) = get_pat_binding(cx, local, outer_arm) else {
124-
return;
125-
};
126157

127158
span_lint_and_then(
128159
cx,
@@ -131,14 +162,21 @@ fn emit_redundant_guards<'tcx>(
131162
"redundant guard",
132163
|diag| {
133164
let binding_replacement = snippet_with_applicability(cx, pat_span, "<binding_repl>", &mut app);
165+
let suggestion_span = match *pat_binding {
166+
PatBindingInfo {
167+
span,
168+
byref_ident: Some(ident),
169+
is_field: true,
170+
} => (span, format!("{ident}: {binding_replacement}")),
171+
PatBindingInfo {
172+
span, is_field: true, ..
173+
} => (span.shrink_to_hi(), format!(": {binding_replacement}")),
174+
PatBindingInfo { span, .. } => (span, binding_replacement.into_owned()),
175+
};
134176
diag.multipart_suggestion_verbose(
135177
"try",
136178
vec![
137-
if can_use_shorthand {
138-
(pat_binding, binding_replacement.into_owned())
139-
} else {
140-
(pat_binding.shrink_to_hi(), format!(": {binding_replacement}"))
141-
},
179+
suggestion_span,
142180
(
143181
guard_span.source_callsite().with_lo(outer_arm.pat.span.hi()),
144182
inner_guard.map_or_else(String::new, |guard| {

tests/ui/redundant_guards.fixed

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,44 @@ fn g(opt_s: Option<S>) {
143143
_ => {},
144144
}
145145
}
146+
147+
mod issue11465 {
148+
enum A {
149+
Foo([u8; 3]),
150+
}
151+
152+
struct B {
153+
b: String,
154+
c: i32,
155+
}
156+
157+
fn issue11465() {
158+
let c = Some(1);
159+
match c {
160+
Some(1) => {},
161+
Some(2) => {},
162+
Some(3) => {},
163+
_ => {},
164+
};
165+
166+
let enum_a = A::Foo([98, 97, 114]);
167+
match enum_a {
168+
A::Foo(ref arr) if arr == b"foo" => {},
169+
A::Foo(ref arr) if let b"bar" = arr => {},
170+
A::Foo(ref arr) if matches!(arr, b"baz") => {},
171+
_ => {},
172+
};
173+
174+
let struct_b = B {
175+
b: "bar".to_string(),
176+
c: 42,
177+
};
178+
match struct_b {
179+
B { ref b, .. } if b == "bar" => {},
180+
B { c: 1, .. } => {},
181+
B { c: 1, .. } => {},
182+
B { c: 1, .. } => {},
183+
_ => {},
184+
}
185+
}
186+
}

tests/ui/redundant_guards.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,44 @@ fn g(opt_s: Option<S>) {
143143
_ => {},
144144
}
145145
}
146+
147+
mod issue11465 {
148+
enum A {
149+
Foo([u8; 3]),
150+
}
151+
152+
struct B {
153+
b: String,
154+
c: i32,
155+
}
156+
157+
fn issue11465() {
158+
let c = Some(1);
159+
match c {
160+
Some(ref x) if x == &1 => {},
161+
Some(ref x) if let &2 = x => {},
162+
Some(ref x) if matches!(x, &3) => {},
163+
_ => {},
164+
};
165+
166+
let enum_a = A::Foo([98, 97, 114]);
167+
match enum_a {
168+
A::Foo(ref arr) if arr == b"foo" => {},
169+
A::Foo(ref arr) if let b"bar" = arr => {},
170+
A::Foo(ref arr) if matches!(arr, b"baz") => {},
171+
_ => {},
172+
};
173+
174+
let struct_b = B {
175+
b: "bar".to_string(),
176+
c: 42,
177+
};
178+
match struct_b {
179+
B { ref b, .. } if b == "bar" => {},
180+
B { ref c, .. } if c == &1 => {},
181+
B { ref c, .. } if let &1 = c => {},
182+
B { ref c, .. } if matches!(c, &1) => {},
183+
_ => {},
184+
}
185+
}
186+
}

tests/ui/redundant_guards.stderr

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,5 +95,77 @@ LL - x if matches!(x, Some(0)) => ..,
9595
LL + Some(0) => ..,
9696
|
9797

98-
error: aborting due to 8 previous errors
98+
error: redundant guard
99+
--> $DIR/redundant_guards.rs:160:28
100+
|
101+
LL | Some(ref x) if x == &1 => {},
102+
| ^^^^^^^
103+
|
104+
help: try
105+
|
106+
LL - Some(ref x) if x == &1 => {},
107+
LL + Some(1) => {},
108+
|
109+
110+
error: redundant guard
111+
--> $DIR/redundant_guards.rs:161:28
112+
|
113+
LL | Some(ref x) if let &2 = x => {},
114+
| ^^^^^^^^^^
115+
|
116+
help: try
117+
|
118+
LL - Some(ref x) if let &2 = x => {},
119+
LL + Some(2) => {},
120+
|
121+
122+
error: redundant guard
123+
--> $DIR/redundant_guards.rs:162:28
124+
|
125+
LL | Some(ref x) if matches!(x, &3) => {},
126+
| ^^^^^^^^^^^^^^^
127+
|
128+
help: try
129+
|
130+
LL - Some(ref x) if matches!(x, &3) => {},
131+
LL + Some(3) => {},
132+
|
133+
134+
error: redundant guard
135+
--> $DIR/redundant_guards.rs:180:32
136+
|
137+
LL | B { ref c, .. } if c == &1 => {},
138+
| ^^^^^^^
139+
|
140+
help: try
141+
|
142+
LL - B { ref c, .. } if c == &1 => {},
143+
LL + B { c: 1, .. } => {},
144+
|
145+
146+
error: redundant guard
147+
--> $DIR/redundant_guards.rs:181:32
148+
|
149+
LL | B { ref c, .. } if let &1 = c => {},
150+
| ^^^^^^^^^^
151+
|
152+
help: try
153+
|
154+
LL - B { ref c, .. } if let &1 = c => {},
155+
LL + B { c: 1, .. } => {},
156+
|
157+
158+
error: redundant guard
159+
--> $DIR/redundant_guards.rs:182:32
160+
|
161+
LL | B { ref c, .. } if matches!(c, &1) => {},
162+
| ^^^^^^^^^^^^^^^
163+
|
164+
help: try
165+
|
166+
LL - B { ref c, .. } if matches!(c, &1) => {},
167+
LL + B { c: 1, .. } => {},
168+
|
169+
170+
error: aborting due to 14 previous errors
99171

0 commit comments

Comments
 (0)