Skip to content

Commit 06ded88

Browse files
authored
fix(match_like_matches_macro): FP with guards containing if let (#15876)
Fixes #15841 changelog: [`match_like_matches_macro`]: FP with guards containing `if let`
2 parents 16eaf79 + 7b83f42 commit 06ded88

File tree

5 files changed

+243
-33
lines changed

5 files changed

+243
-33
lines changed

clippy_lints/src/matches/match_like_matches.rs

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
22
33
use super::REDUNDANT_PATTERN_MATCHING;
4-
use clippy_utils::diagnostics::span_lint_and_sugg;
4+
use clippy_utils::diagnostics::span_lint_and_then;
5+
use clippy_utils::higher::has_let_expr;
56
use clippy_utils::source::snippet_with_applicability;
67
use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment};
78
use rustc_ast::LitKind;
@@ -43,18 +44,23 @@ pub(crate) fn check_if_let<'tcx>(
4344
{
4445
ex_new = ex_inner;
4546
}
46-
span_lint_and_sugg(
47+
span_lint_and_then(
4748
cx,
4849
MATCH_LIKE_MATCHES_MACRO,
4950
expr.span,
50-
"if let .. else expression looks like `matches!` macro",
51-
"try",
52-
format!(
53-
"{}matches!({}, {pat})",
54-
if b0 { "" } else { "!" },
55-
snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
56-
),
57-
applicability,
51+
"`if let .. else` expression looks like `matches!` macro",
52+
|diag| {
53+
diag.span_suggestion_verbose(
54+
expr.span,
55+
"use `matches!` directly",
56+
format!(
57+
"{}matches!({}, {pat})",
58+
if b0 { "" } else { "!" },
59+
snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
60+
),
61+
applicability,
62+
);
63+
},
5864
);
5965
}
6066
}
@@ -87,7 +93,10 @@ pub(super) fn check_match<'tcx>(
8793
// ```rs
8894
// matches!(e, Either::Left $(if $guard)|+)
8995
// ```
90-
middle_arms.is_empty()
96+
//
97+
// But if the guard _is_ present, it may not be an `if-let` guard, as `matches!` doesn't
98+
// support these (currently?)
99+
(middle_arms.is_empty() && first_arm.guard.is_none_or(|g| !has_let_expr(g)))
91100

92101
// - (added in #6216) There are middle arms
93102
//
@@ -169,18 +178,23 @@ pub(super) fn check_match<'tcx>(
169178
{
170179
ex_new = ex_inner;
171180
}
172-
span_lint_and_sugg(
181+
span_lint_and_then(
173182
cx,
174183
MATCH_LIKE_MATCHES_MACRO,
175184
e.span,
176185
"match expression looks like `matches!` macro",
177-
"try",
178-
format!(
179-
"{}matches!({}, {pat_and_guard})",
180-
if b0 { "" } else { "!" },
181-
snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
182-
),
183-
applicability,
186+
|diag| {
187+
diag.span_suggestion_verbose(
188+
e.span,
189+
"use `matches!` directly",
190+
format!(
191+
"{}matches!({}, {pat_and_guard})",
192+
if b0 { "" } else { "!" },
193+
snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
194+
),
195+
applicability,
196+
);
197+
},
184198
);
185199
true
186200
} else {

tests/ui/match_like_matches_macro.fixed

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,10 @@ fn msrv_1_42() {
223223
let _y = matches!(Some(5), Some(0));
224224
//~^^^^ match_like_matches_macro
225225
}
226+
227+
#[expect(clippy::option_option)]
228+
fn issue15841(opt: Option<Option<Option<i32>>>, value: i32) {
229+
// Lint: no if-let _in the guard_
230+
let _ = matches!(opt, Some(first) if (if let Some(second) = first { true } else { todo!() }));
231+
//~^^^^ match_like_matches_macro
232+
}

tests/ui/match_like_matches_macro.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,13 @@ fn msrv_1_42() {
267267
};
268268
//~^^^^ match_like_matches_macro
269269
}
270+
271+
#[expect(clippy::option_option)]
272+
fn issue15841(opt: Option<Option<Option<i32>>>, value: i32) {
273+
// Lint: no if-let _in the guard_
274+
let _ = match opt {
275+
Some(first) if (if let Some(second) = first { true } else { todo!() }) => true,
276+
_ => false,
277+
};
278+
//~^^^^ match_like_matches_macro
279+
}

tests/ui/match_like_matches_macro.stderr

Lines changed: 142 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,18 @@ LL | let _y = match x {
66
LL | | Some(0) => true,
77
LL | | _ => false,
88
LL | | };
9-
| |_____^ help: try: `matches!(x, Some(0))`
9+
| |_____^
1010
|
1111
= note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
1212
= help: to override `-D warnings` add `#[allow(clippy::match_like_matches_macro)]`
13+
help: use `matches!` directly
14+
|
15+
LL - let _y = match x {
16+
LL - Some(0) => true,
17+
LL - _ => false,
18+
LL - };
19+
LL + let _y = matches!(x, Some(0));
20+
|
1321

1422
error: redundant pattern matching, consider using `is_some()`
1523
--> tests/ui/match_like_matches_macro.rs:20:14
@@ -42,13 +50,28 @@ LL | let _zz = match x {
4250
LL | | Some(r) if r == 0 => false,
4351
LL | | _ => true,
4452
LL | | };
45-
| |_____^ help: try: `!matches!(x, Some(r) if r == 0)`
53+
| |_____^
54+
|
55+
help: use `matches!` directly
56+
|
57+
LL - let _zz = match x {
58+
LL - Some(r) if r == 0 => false,
59+
LL - _ => true,
60+
LL - };
61+
LL + let _zz = !matches!(x, Some(r) if r == 0);
62+
|
4663

47-
error: if let .. else expression looks like `matches!` macro
64+
error: `if let .. else` expression looks like `matches!` macro
4865
--> tests/ui/match_like_matches_macro.rs:41:16
4966
|
5067
LL | let _zzz = if let Some(5) = x { true } else { false };
51-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(x, Some(5))`
68+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
69+
|
70+
help: use `matches!` directly
71+
|
72+
LL - let _zzz = if let Some(5) = x { true } else { false };
73+
LL + let _zzz = matches!(x, Some(5));
74+
|
5275

5376
error: match expression looks like `matches!` macro
5477
--> tests/ui/match_like_matches_macro.rs:66:20
@@ -59,7 +82,17 @@ LL | | E::A(_) => true,
5982
LL | | E::B(_) => true,
6083
LL | | _ => false,
6184
LL | | };
62-
| |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
85+
| |_________^
86+
|
87+
help: use `matches!` directly
88+
|
89+
LL - let _ans = match x {
90+
LL - E::A(_) => true,
91+
LL - E::B(_) => true,
92+
LL - _ => false,
93+
LL - };
94+
LL + let _ans = matches!(x, E::A(_) | E::B(_));
95+
|
6396

6497
error: match expression looks like `matches!` macro
6598
--> tests/ui/match_like_matches_macro.rs:77:20
@@ -71,7 +104,19 @@ LL | | true
71104
... |
72105
LL | | _ => false,
73106
LL | | };
74-
| |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
107+
| |_________^
108+
|
109+
help: use `matches!` directly
110+
|
111+
LL - let _ans = match x {
112+
LL - E::A(_) => {
113+
LL - true
114+
LL - }
115+
LL - E::B(_) => true,
116+
LL - _ => false,
117+
LL - };
118+
LL + let _ans = matches!(x, E::A(_) | E::B(_));
119+
|
75120

76121
error: match expression looks like `matches!` macro
77122
--> tests/ui/match_like_matches_macro.rs:88:20
@@ -82,7 +127,17 @@ LL | | E::B(_) => false,
82127
LL | | E::C => false,
83128
LL | | _ => true,
84129
LL | | };
85-
| |_________^ help: try: `!matches!(x, E::B(_) | E::C)`
130+
| |_________^
131+
|
132+
help: use `matches!` directly
133+
|
134+
LL - let _ans = match x {
135+
LL - E::B(_) => false,
136+
LL - E::C => false,
137+
LL - _ => true,
138+
LL - };
139+
LL + let _ans = !matches!(x, E::B(_) | E::C);
140+
|
86141

87142
error: match expression looks like `matches!` macro
88143
--> tests/ui/match_like_matches_macro.rs:149:18
@@ -92,7 +147,16 @@ LL | let _z = match &z {
92147
LL | | Some(3) => true,
93148
LL | | _ => false,
94149
LL | | };
95-
| |_________^ help: try: `matches!(z, Some(3))`
150+
| |_________^
151+
|
152+
help: use `matches!` directly
153+
|
154+
LL - let _z = match &z {
155+
LL - Some(3) => true,
156+
LL - _ => false,
157+
LL - };
158+
LL + let _z = matches!(z, Some(3));
159+
|
96160

97161
error: match expression looks like `matches!` macro
98162
--> tests/ui/match_like_matches_macro.rs:159:18
@@ -102,7 +166,16 @@ LL | let _z = match &z {
102166
LL | | Some(3) => true,
103167
LL | | _ => false,
104168
LL | | };
105-
| |_________^ help: try: `matches!(&z, Some(3))`
169+
| |_________^
170+
|
171+
help: use `matches!` directly
172+
|
173+
LL - let _z = match &z {
174+
LL - Some(3) => true,
175+
LL - _ => false,
176+
LL - };
177+
LL + let _z = matches!(&z, Some(3));
178+
|
106179

107180
error: match expression looks like `matches!` macro
108181
--> tests/ui/match_like_matches_macro.rs:177:21
@@ -112,7 +185,16 @@ LL | let _ = match &z {
112185
LL | | AnEnum::X => true,
113186
LL | | _ => false,
114187
LL | | };
115-
| |_____________^ help: try: `matches!(&z, AnEnum::X)`
188+
| |_____________^
189+
|
190+
help: use `matches!` directly
191+
|
192+
LL - let _ = match &z {
193+
LL - AnEnum::X => true,
194+
LL - _ => false,
195+
LL - };
196+
LL + let _ = matches!(&z, AnEnum::X);
197+
|
116198

117199
error: match expression looks like `matches!` macro
118200
--> tests/ui/match_like_matches_macro.rs:192:20
@@ -122,7 +204,16 @@ LL | let _res = match &val {
122204
LL | | &Some(ref _a) => true,
123205
LL | | _ => false,
124206
LL | | };
125-
| |_________^ help: try: `matches!(&val, &Some(ref _a))`
207+
| |_________^
208+
|
209+
help: use `matches!` directly
210+
|
211+
LL - let _res = match &val {
212+
LL - &Some(ref _a) => true,
213+
LL - _ => false,
214+
LL - };
215+
LL + let _res = matches!(&val, &Some(ref _a));
216+
|
126217

127218
error: match expression looks like `matches!` macro
128219
--> tests/ui/match_like_matches_macro.rs:205:20
@@ -132,7 +223,16 @@ LL | let _res = match &val {
132223
LL | | &Some(ref _a) => true,
133224
LL | | _ => false,
134225
LL | | };
135-
| |_________^ help: try: `matches!(&val, &Some(ref _a))`
226+
| |_________^
227+
|
228+
help: use `matches!` directly
229+
|
230+
LL - let _res = match &val {
231+
LL - &Some(ref _a) => true,
232+
LL - _ => false,
233+
LL - };
234+
LL + let _res = matches!(&val, &Some(ref _a));
235+
|
136236

137237
error: match expression looks like `matches!` macro
138238
--> tests/ui/match_like_matches_macro.rs:264:14
@@ -142,7 +242,35 @@ LL | let _y = match Some(5) {
142242
LL | | Some(0) => true,
143243
LL | | _ => false,
144244
LL | | };
145-
| |_____^ help: try: `matches!(Some(5), Some(0))`
245+
| |_____^
246+
|
247+
help: use `matches!` directly
248+
|
249+
LL - let _y = match Some(5) {
250+
LL - Some(0) => true,
251+
LL - _ => false,
252+
LL - };
253+
LL + let _y = matches!(Some(5), Some(0));
254+
|
255+
256+
error: match expression looks like `matches!` macro
257+
--> tests/ui/match_like_matches_macro.rs:274:13
258+
|
259+
LL | let _ = match opt {
260+
| _____________^
261+
LL | | Some(first) if (if let Some(second) = first { true } else { todo!() }) => true,
262+
LL | | _ => false,
263+
LL | | };
264+
| |_____^
265+
|
266+
help: use `matches!` directly
267+
|
268+
LL - let _ = match opt {
269+
LL - Some(first) if (if let Some(second) = first { true } else { todo!() }) => true,
270+
LL - _ => false,
271+
LL - };
272+
LL + let _ = matches!(opt, Some(first) if (if let Some(second) = first { true } else { todo!() }));
273+
|
146274

147-
error: aborting due to 14 previous errors
275+
error: aborting due to 15 previous errors
148276

0 commit comments

Comments
 (0)