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

Commit 6d6c63e

Browse files
committed
Lint single_match with Options, Results, and Cows
1 parent b3c94c0 commit 6d6c63e

File tree

3 files changed

+82
-24
lines changed

3 files changed

+82
-24
lines changed

clippy_lints/src/matches/single_match.rs

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,23 @@ fn check_opt_like<'a>(
140140
ty: Ty<'a>,
141141
els: Option<&Expr<'_>>,
142142
) {
143+
// We want to suggest to exclude an arm that contains only wildcards or forms the exhaustive
144+
// match with the second branch, without enum variants in matches.
145+
if !contains_only_wilds(arms[1].pat) && !form_exhaustive_matches(cx, ty, arms[0].pat, arms[1].pat) {
146+
return;
147+
}
148+
149+
let mut paths_and_types = Vec::new();
150+
if !collect_pat_paths(&mut paths_and_types, cx, arms[1].pat, ty) {
151+
return;
152+
}
153+
154+
if paths_and_types.iter().all(|info| in_candidate_enum(cx, info)) {
155+
report_single_pattern(cx, ex, arms, expr, els);
156+
}
157+
}
158+
159+
fn in_candidate_enum<'a>(cx: &LateContext<'a>, path_info: &(String, Ty<'_>)) -> bool {
143160
// list of candidate `Enum`s we know will never get any more members
144161
let candidates = &[
145162
(&paths::COW, "Borrowed"),
@@ -151,29 +168,13 @@ fn check_opt_like<'a>(
151168
(&paths::RESULT, "Ok"),
152169
];
153170

154-
// We want to suggest to exclude an arm that contains only wildcards or forms the exhaustive
155-
// match with the second branch, without enum variants in matches.
156-
if !contains_only_wilds(arms[1].pat) && !form_exhaustive_matches(arms[0].pat, arms[1].pat) {
157-
return;
158-
}
159-
160-
let mut paths_and_types = Vec::new();
161-
if !collect_pat_paths(&mut paths_and_types, cx, arms[1].pat, ty) {
162-
return;
163-
}
164-
165-
let in_candidate_enum = |path_info: &(String, Ty<'_>)| -> bool {
166-
let (path, ty) = path_info;
167-
for &(ty_path, pat_path) in candidates {
168-
if path == pat_path && match_type(cx, *ty, ty_path) {
169-
return true;
170-
}
171+
let (path, ty) = path_info;
172+
for &(ty_path, pat_path) in candidates {
173+
if path == pat_path && match_type(cx, *ty, ty_path) {
174+
return true;
171175
}
172-
false
173-
};
174-
if paths_and_types.iter().all(in_candidate_enum) {
175-
report_single_pattern(cx, ex, arms, expr, els);
176176
}
177+
false
177178
}
178179

179180
/// Collects paths and their types from the given patterns. Returns true if the given pattern could
@@ -218,7 +219,7 @@ fn contains_only_wilds(pat: &Pat<'_>) -> bool {
218219

219220
/// Returns true if the given patterns forms only exhaustive matches that don't contain enum
220221
/// patterns without a wildcard.
221-
fn form_exhaustive_matches(left: &Pat<'_>, right: &Pat<'_>) -> bool {
222+
fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>, right: &Pat<'_>) -> bool {
222223
match (&left.kind, &right.kind) {
223224
(PatKind::Wild, _) | (_, PatKind::Wild) => true,
224225
(PatKind::Tuple(left_in, left_pos), PatKind::Tuple(right_in, right_pos)) => {
@@ -264,6 +265,14 @@ fn form_exhaustive_matches(left: &Pat<'_>, right: &Pat<'_>) -> bool {
264265
}
265266
true
266267
},
268+
(PatKind::TupleStruct(..), PatKind::Path(_) | PatKind::TupleStruct(..)) => {
269+
let mut paths_and_types = Vec::new();
270+
if !collect_pat_paths(&mut paths_and_types, cx, right, ty) {
271+
return false;
272+
}
273+
274+
paths_and_types.iter().all(|info| in_candidate_enum(cx, info))
275+
},
267276
_ => false,
268277
}
269278
}

tests/ui/single_match.stderr

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ LL | | _ => {},
3838
LL | | };
3939
| |_____^ help: try this: `if let (2..=3, 7..=9) = z { dummy() }`
4040

41+
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
42+
--> $DIR/single_match.rs:54:5
43+
|
44+
LL | / match x {
45+
LL | | Some(y) => dummy(),
46+
LL | | None => (),
47+
LL | | };
48+
| |_____^ help: try this: `if let Some(y) = x { dummy() }`
49+
4150
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
4251
--> $DIR/single_match.rs:59:5
4352
|
@@ -146,5 +155,5 @@ LL | | (..) => {},
146155
LL | | }
147156
| |_____^ help: try this: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}`
148157

149-
error: aborting due to 15 previous errors
158+
error: aborting due to 16 previous errors
150159

tests/ui/single_match_else.stderr

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,45 @@ LL + None
2020
LL ~ };
2121
|
2222

23-
error: aborting due to previous error
23+
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
24+
--> $DIR/single_match_else.rs:84:5
25+
|
26+
LL | / match Some(1) {
27+
LL | | Some(a) => println!("${:?}", a),
28+
LL | | None => {
29+
LL | | println!("else block");
30+
LL | | return
31+
LL | | },
32+
LL | | }
33+
| |_____^
34+
|
35+
help: try this
36+
|
37+
LL ~ if let Some(a) = Some(1) { println!("${:?}", a) } else {
38+
LL + println!("else block");
39+
LL + return
40+
LL + }
41+
|
42+
43+
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
44+
--> $DIR/single_match_else.rs:93:5
45+
|
46+
LL | / match Some(1) {
47+
LL | | Some(a) => println!("${:?}", a),
48+
LL | | None => {
49+
LL | | println!("else block");
50+
LL | | return;
51+
LL | | },
52+
LL | | }
53+
| |_____^
54+
|
55+
help: try this
56+
|
57+
LL ~ if let Some(a) = Some(1) { println!("${:?}", a) } else {
58+
LL + println!("else block");
59+
LL + return;
60+
LL + }
61+
|
62+
63+
error: aborting due to 3 previous errors
2464

0 commit comments

Comments
 (0)