Skip to content

Commit 6ce78d1

Browse files
committed
Auto merge of rust-lang#3652 - Aehmlo:where_the_wild_things_are, r=phansch
Add wildcard_match_arm lint This lint prevents using a wildcard in a match arm. Implemented as a restriction currently, because this is pretty much an edge case. See rust-lang#3649 for more information. Didn't add any tests because I wasn't sure how, but if someone wants to point me in the right direction, I'd be happy to!
2 parents 6b1a2a9 + 7fa50fb commit 6ce78d1

File tree

6 files changed

+99
-2
lines changed

6 files changed

+99
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,7 @@ All notable changes to this project will be documented in this file.
10281028
[`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
10291029
[`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
10301030
[`wildcard_dependencies`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_dependencies
1031+
[`wildcard_enum_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm
10311032
[`write_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_literal
10321033
[`write_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_with_newline
10331034
[`writeln_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#writeln_empty_string

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

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

10-
[There are 293 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
10+
[There are 294 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1111

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

clippy_lints/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
499499
indexing_slicing::INDEXING_SLICING,
500500
inherent_impl::MULTIPLE_INHERENT_IMPL,
501501
literal_representation::DECIMAL_LITERAL_REPRESENTATION,
502+
matches::WILDCARD_ENUM_MATCH_ARM,
502503
mem_forget::MEM_FORGET,
503504
methods::CLONE_ON_REF_PTR,
504505
methods::OPTION_UNWRAP_USED,

clippy_lints/src/matches.rs

+39-1
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,25 @@ declare_clippy_lint! {
187187
"a match on an Option value instead of using `as_ref()` or `as_mut`"
188188
}
189189

190+
/// **What it does:** Checks for wildcard enum matches using `_`.
191+
///
192+
/// **Why is this bad?** New enum variants added by library updates can be missed.
193+
///
194+
/// **Known problems:** Nested wildcards a la `Foo(_)` are currently not detected.
195+
///
196+
/// **Example:**
197+
/// ```rust
198+
/// match x {
199+
/// A => {},
200+
/// _ => {},
201+
/// }
202+
/// ```
203+
declare_clippy_lint! {
204+
pub WILDCARD_ENUM_MATCH_ARM,
205+
restriction,
206+
"a wildcard enum match arm using `_`"
207+
}
208+
190209
#[allow(missing_copy_implementations)]
191210
pub struct MatchPass;
192211

@@ -199,7 +218,8 @@ impl LintPass for MatchPass {
199218
SINGLE_MATCH_ELSE,
200219
MATCH_OVERLAPPING_ARM,
201220
MATCH_WILD_ERR_ARM,
202-
MATCH_AS_REF
221+
MATCH_AS_REF,
222+
WILDCARD_ENUM_MATCH_ARM
203223
)
204224
}
205225

@@ -218,6 +238,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchPass {
218238
check_match_bool(cx, ex, arms, expr);
219239
check_overlapping_arms(cx, ex, arms);
220240
check_wild_err_arm(cx, ex, arms);
241+
check_wild_enum_match(cx, ex, arms);
221242
check_match_as_ref(cx, ex, arms, expr);
222243
}
223244
if let ExprKind::Match(ref ex, ref arms, _) = expr.node {
@@ -442,6 +463,23 @@ fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]) {
442463
}
443464
}
444465

466+
fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]) {
467+
if cx.tables.expr_ty(ex).is_enum() {
468+
for arm in arms {
469+
if is_wild(&arm.pats[0]) {
470+
span_note_and_lint(
471+
cx,
472+
WILDCARD_ENUM_MATCH_ARM,
473+
arm.pats[0].span,
474+
"wildcard match will miss any future added variants.",
475+
arm.pats[0].span,
476+
"to resolve, match each variant explicitly",
477+
);
478+
}
479+
}
480+
}
481+
}
482+
445483
// If the block contains only a `panic!` macro (as expression or statement)
446484
fn is_panic_block(block: &Block) -> bool {
447485
match (&block.expr, block.stmts.len(), block.stmts.first()) {

tests/ui/wildcard_enum_match_arm.rs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#![deny(clippy::wildcard_enum_match_arm)]
2+
3+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4+
enum Color {
5+
Red,
6+
Green,
7+
Blue,
8+
Rgb(u8, u8, u8),
9+
Cyan,
10+
}
11+
12+
impl Color {
13+
fn is_monochrome(self) -> bool {
14+
match self {
15+
Color::Red | Color::Green | Color::Blue => true,
16+
Color::Rgb(r, g, b) => r | g == 0 || r | b == 0 || g | b == 0,
17+
Color::Cyan => false,
18+
}
19+
}
20+
}
21+
22+
fn main() {
23+
let color = Color::Rgb(0, 0, 127);
24+
match color {
25+
Color::Red => println!("Red"),
26+
_ => eprintln!("Not red"),
27+
};
28+
match color {
29+
Color::Red => {},
30+
Color::Green => {},
31+
Color::Blue => {},
32+
Color::Cyan => {},
33+
c if c.is_monochrome() => {},
34+
Color::Rgb(_, _, _) => {},
35+
};
36+
let x: u8 = unimplemented!();
37+
match x {
38+
0 => {},
39+
140 => {},
40+
_ => {},
41+
};
42+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: wildcard match will miss any future added variants.
2+
--> $DIR/wildcard_enum_match_arm.rs:26:9
3+
|
4+
LL | _ => eprintln!("Not red"),
5+
| ^
6+
|
7+
note: lint level defined here
8+
--> $DIR/wildcard_enum_match_arm.rs:1:9
9+
|
10+
LL | #![deny(clippy::wildcard_enum_match_arm)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
= note: to resolve, match each variant explicitly
13+
14+
error: aborting due to previous error
15+

0 commit comments

Comments
 (0)