Skip to content

Commit 6940893

Browse files
committed
New lint: pats_with_wild_match_arm
- Wildcard use with other pattern in same match arm
1 parent b0c4744 commit 6940893

File tree

8 files changed

+158
-3
lines changed

8 files changed

+158
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,7 @@ Released 2018-09-13
12371237
[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
12381238
[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
12391239
[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
1240+
[`pats_with_wild_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#pats_with_wild_match_arm
12401241
[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
12411242
[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
12421243
[`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
88

9-
[There are 341 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
9+
[There are 342 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1010

1111
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1212

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
592592
&matches::MATCH_OVERLAPPING_ARM,
593593
&matches::MATCH_REF_PATS,
594594
&matches::MATCH_WILD_ERR_ARM,
595+
&matches::PATS_WITH_WILD_MATCH_ARM,
595596
&matches::SINGLE_MATCH,
596597
&matches::SINGLE_MATCH_ELSE,
597598
&matches::WILDCARD_ENUM_MATCH_ARM,
@@ -991,6 +992,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
991992
LintId::of(&integer_division::INTEGER_DIVISION),
992993
LintId::of(&let_underscore::LET_UNDERSCORE_MUST_USE),
993994
LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION),
995+
LintId::of(&matches::PATS_WITH_WILD_MATCH_ARM),
994996
LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM),
995997
LintId::of(&mem_forget::MEM_FORGET),
996998
LintId::of(&methods::CLONE_ON_REF_PTR),

clippy_lints/src/matches.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,26 @@ declare_clippy_lint! {
223223
"a wildcard enum match arm using `_`"
224224
}
225225

226+
declare_clippy_lint! {
227+
/// **What it does:** Checks for wildcard pattern used with others patterns in same match arm.
228+
///
229+
/// **Why is this bad?** Wildcard pattern already covers any other pattern as it will match anyway.
230+
/// It makes the code less readable, especially to spot wildcard pattern use in match arm.
231+
///
232+
/// **Known problems:** None.
233+
///
234+
/// **Example:**
235+
/// ```rust
236+
/// match "foo" {
237+
/// "a" => {},
238+
/// "bar" | _ => {},
239+
/// }
240+
/// ```
241+
pub PATS_WITH_WILD_MATCH_ARM,
242+
restriction,
243+
"a wildcard pattern used with others patterns in same match arm"
244+
}
245+
226246
declare_lint_pass!(Matches => [
227247
SINGLE_MATCH,
228248
MATCH_REF_PATS,
@@ -231,7 +251,8 @@ declare_lint_pass!(Matches => [
231251
MATCH_OVERLAPPING_ARM,
232252
MATCH_WILD_ERR_ARM,
233253
MATCH_AS_REF,
234-
WILDCARD_ENUM_MATCH_ARM
254+
WILDCARD_ENUM_MATCH_ARM,
255+
PATS_WITH_WILD_MATCH_ARM
235256
]);
236257

237258
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
@@ -246,6 +267,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
246267
check_wild_err_arm(cx, ex, arms);
247268
check_wild_enum_match(cx, ex, arms);
248269
check_match_as_ref(cx, ex, arms, expr);
270+
check_pats_wild_match(cx, ex, arms, expr);
249271
}
250272
if let ExprKind::Match(ref ex, ref arms, _) = expr.kind {
251273
check_match_ref_pats(cx, ex, arms, expr);
@@ -664,6 +686,25 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
664686
}
665687
}
666688

689+
fn check_pats_wild_match(cx: &LateContext<'_, '_>, _ex: &Expr, arms: &[Arm], _expr: &Expr) {
690+
for arm in arms {
691+
if let PatKind::Or(ref fields) = arm.pat.kind {
692+
// look for multiple fields where one at least matches Wild pattern
693+
if fields.len() > 1 && fields.into_iter().any(|pat| is_wild(pat)) {
694+
span_lint_and_sugg(
695+
cx,
696+
PATS_WITH_WILD_MATCH_ARM,
697+
arm.pat.span,
698+
"wildcard pattern covers any other pattern as it will match anyway. Consider replacing with wildcard pattern only",
699+
"try this",
700+
"_".to_string(),
701+
Applicability::MachineApplicable,
702+
)
703+
}
704+
}
705+
}
706+
}
707+
667708
/// Gets all arms that are unbounded `PatRange`s.
668709
fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm]) -> Vec<SpannedRange<Constant>> {
669710
arms.iter()

src/lintlist/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub use lint::Lint;
66
pub use lint::LINT_LEVELS;
77

88
// begin lint list, do not remove this comment, it’s used in `update_lints`
9-
pub const ALL_LINTS: [Lint; 341] = [
9+
pub const ALL_LINTS: [Lint; 342] = [
1010
Lint {
1111
name: "absurd_extreme_comparisons",
1212
group: "correctness",
@@ -1540,6 +1540,13 @@ pub const ALL_LINTS: [Lint; 341] = [
15401540
deprecation: None,
15411541
module: "path_buf_push_overwrite",
15421542
},
1543+
Lint {
1544+
name: "pats_with_wild_match_arm",
1545+
group: "restriction",
1546+
desc: "a wildcard pattern used with others patterns in same match arm",
1547+
deprecation: None,
1548+
module: "matches",
1549+
},
15431550
Lint {
15441551
name: "possible_missing_comma",
15451552
group: "correctness",
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::pats_with_wild_match_arm)]
4+
5+
fn main() {
6+
match "foo" {
7+
"a" => {
8+
dbg!("matched a");
9+
},
10+
_ => {
11+
dbg!("matched (bar or) wild");
12+
},
13+
};
14+
match "foo" {
15+
"a" => {
16+
dbg!("matched a");
17+
},
18+
_ => {
19+
dbg!("matched (bar or bar2 or) wild");
20+
},
21+
};
22+
match "foo" {
23+
"a" => {
24+
dbg!("matched a");
25+
},
26+
_ => {
27+
dbg!("matched (bar or) wild");
28+
},
29+
};
30+
match "foo" {
31+
"a" => {
32+
dbg!("matched a");
33+
},
34+
_ => {
35+
dbg!("matched (bar or) wild");
36+
},
37+
};
38+
}

tests/ui/pats_with_wild_match_arm.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::pats_with_wild_match_arm)]
4+
5+
fn main() {
6+
match "foo" {
7+
"a" => {
8+
dbg!("matched a");
9+
},
10+
"bar" | _ => {
11+
dbg!("matched (bar or) wild");
12+
},
13+
};
14+
match "foo" {
15+
"a" => {
16+
dbg!("matched a");
17+
},
18+
"bar" | "bar2" | _ => {
19+
dbg!("matched (bar or bar2 or) wild");
20+
},
21+
};
22+
match "foo" {
23+
"a" => {
24+
dbg!("matched a");
25+
},
26+
_ | "bar" | _ => {
27+
dbg!("matched (bar or) wild");
28+
},
29+
};
30+
match "foo" {
31+
"a" => {
32+
dbg!("matched a");
33+
},
34+
_ | "bar" => {
35+
dbg!("matched (bar or) wild");
36+
},
37+
};
38+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: wildcard pattern covers any other pattern as it will match anyway. Consider replacing with wildcard pattern only
2+
--> $DIR/pats_with_wild_match_arm.rs:10:9
3+
|
4+
LL | "bar" | _ => {
5+
| ^^^^^^^^^ help: try this: `_`
6+
|
7+
= note: `-D clippy::pats-with-wild-match-arm` implied by `-D warnings`
8+
9+
error: wildcard pattern covers any other pattern as it will match anyway. Consider replacing with wildcard pattern only
10+
--> $DIR/pats_with_wild_match_arm.rs:18:9
11+
|
12+
LL | "bar" | "bar2" | _ => {
13+
| ^^^^^^^^^^^^^^^^^^ help: try this: `_`
14+
15+
error: wildcard pattern covers any other pattern as it will match anyway. Consider replacing with wildcard pattern only
16+
--> $DIR/pats_with_wild_match_arm.rs:26:9
17+
|
18+
LL | _ | "bar" | _ => {
19+
| ^^^^^^^^^^^^^ help: try this: `_`
20+
21+
error: wildcard pattern covers any other pattern as it will match anyway. Consider replacing with wildcard pattern only
22+
--> $DIR/pats_with_wild_match_arm.rs:34:9
23+
|
24+
LL | _ | "bar" => {
25+
| ^^^^^^^^^ help: try this: `_`
26+
27+
error: aborting due to 4 previous errors
28+

0 commit comments

Comments
 (0)