Add unneeded-wildcard-pattern lint

This commit is contained in:
Michael Wright 2019-09-12 08:25:05 +02:00
parent 6ca5b2053a
commit 4a3bc6b592
8 changed files with 254 additions and 3 deletions

View file

@ -1188,6 +1188,7 @@ Released 2018-09-13
[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
[`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern
[`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal
[`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name
[`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization

View file

@ -6,7 +6,7 @@
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
[There are 313 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
[There are 314 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:

View file

@ -825,6 +825,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
misc_early::REDUNDANT_CLOSURE_CALL,
misc_early::REDUNDANT_PATTERN,
misc_early::UNNEEDED_FIELD_PATTERN,
misc_early::UNNEEDED_WILDCARD_PATTERN,
misc_early::ZERO_PREFIXED_LITERAL,
mut_reference::UNNECESSARY_MUT_PASSED,
mutex_atomic::MUTEX_ATOMIC,
@ -1044,6 +1045,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
methods::USELESS_ASREF,
misc::SHORT_CIRCUIT_STATEMENT,
misc_early::REDUNDANT_CLOSURE_CALL,
misc_early::UNNEEDED_WILDCARD_PATTERN,
misc_early::ZERO_PREFIXED_LITERAL,
needless_bool::BOOL_COMPARISON,
needless_bool::NEEDLESS_BOOL,

View file

@ -195,6 +195,40 @@ declare_clippy_lint! {
"using `name @ _` in a pattern"
}
declare_clippy_lint! {
/// **What it does:** Checks for tuple patterns with a wildcard
/// pattern (`_`) is next to a rest pattern (`..`) pattern.
///
/// **Why is this bad?** The wildcard pattern is unneeded as the rest pattern
/// can match that element as well.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// # struct TupleStruct(u32, u32, u32);
/// # let t = TupleStruct(1, 2, 3);
///
/// match t {
/// TupleStruct(0, .., _) => (),
/// _ => (),
/// }
/// ```
/// can be written as
/// ```rust
/// # struct TupleStruct(u32, u32, u32);
/// # let t = TupleStruct(1, 2, 3);
///
/// match t {
/// TupleStruct(0, ..) => (),
/// _ => (),
/// }
/// ```
pub UNNEEDED_WILDCARD_PATTERN,
complexity,
"tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`) pattern"
}
declare_lint_pass!(MiscEarlyLints => [
UNNEEDED_FIELD_PATTERN,
DUPLICATE_UNDERSCORE_ARGUMENT,
@ -204,7 +238,8 @@ declare_lint_pass!(MiscEarlyLints => [
UNSEPARATED_LITERAL_SUFFIX,
ZERO_PREFIXED_LITERAL,
BUILTIN_TYPE_SHADOW,
REDUNDANT_PATTERN
REDUNDANT_PATTERN,
UNNEEDED_WILDCARD_PATTERN,
]);
// Used to find `return` statements or equivalents e.g., `?`
@ -326,6 +361,62 @@ impl EarlyLintPass for MiscEarlyLints {
);
}
}
if let PatKind::TupleStruct(_, ref patterns) | PatKind::Tuple(ref patterns) = pat.node {
fn span_lint(cx: &EarlyContext<'_>, span: Span, only_one: bool) {
span_lint_and_sugg(
cx,
UNNEEDED_WILDCARD_PATTERN,
span,
if only_one {
"this pattern is unneeded as the `..` pattern can match that element"
} else {
"these patterns are unneeded as the `..` pattern can match those elements"
},
if only_one { "remove it" } else { "remove them" },
"".to_string(),
Applicability::MachineApplicable,
);
}
fn is_rest<P: std::ops::Deref<Target = Pat>>(pat: &P) -> bool {
if let PatKind::Rest = pat.node {
true
} else {
false
}
}
fn is_wild<P: std::ops::Deref<Target = Pat>>(pat: &&P) -> bool {
if let PatKind::Wild = pat.node {
true
} else {
false
}
}
if let Some(rest_index) = patterns.iter().position(is_rest) {
if let Some((left_index, left_pat)) = patterns[..rest_index]
.iter()
.rev()
.take_while(is_wild)
.enumerate()
.last()
{
span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0);
}
if let Some((right_index, right_pat)) =
patterns[rest_index + 1..].iter().take_while(is_wild).enumerate().last()
{
span_lint(
cx,
patterns[rest_index].span.shrink_to_hi().to(right_pat.span),
right_index == 0,
);
}
}
}
}
fn check_fn(&mut self, cx: &EarlyContext<'_>, _: FnKind<'_>, decl: &FnDecl, _: Span, _: NodeId) {

View file

@ -6,7 +6,7 @@ pub use lint::Lint;
pub use lint::LINT_LEVELS;
// begin lint list, do not remove this comment, its used in `update_lints`
pub const ALL_LINTS: [Lint; 313] = [
pub const ALL_LINTS: [Lint; 314] = [
Lint {
name: "absurd_extreme_comparisons",
group: "correctness",
@ -1974,6 +1974,13 @@ pub const ALL_LINTS: [Lint; 313] = [
deprecation: None,
module: "misc_early",
},
Lint {
name: "unneeded_wildcard_pattern",
group: "complexity",
desc: "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`) pattern",
deprecation: None,
module: "misc_early",
},
Lint {
name: "unreadable_literal",
group: "style",

View file

@ -0,0 +1,41 @@
// run-rustfix
#![feature(stmt_expr_attributes)]
#![deny(clippy::unneeded_wildcard_pattern)]
fn main() {
let t = (0, 1, 2, 3);
if let (0, ..) = t {};
if let (0, ..) = t {};
if let (0, ..) = t {};
if let (0, ..) = t {};
if let (_, 0, ..) = t {};
if let (.., 0, _) = t {};
if let (0, _, _, _) = t {};
if let (0, ..) = t {};
if let (.., 0) = t {};
#[rustfmt::skip]
{
if let (0, ..,) = t {};
}
struct S(usize, usize, usize, usize);
let s = S(0, 1, 2, 3);
if let S(0, ..) = s {};
if let S(0, ..) = s {};
if let S(0, ..) = s {};
if let S(0, ..) = s {};
if let S(_, 0, ..) = s {};
if let S(.., 0, _) = s {};
if let S(0, _, _, _) = s {};
if let S(0, ..) = s {};
if let S(.., 0) = s {};
#[rustfmt::skip]
{
if let S(0, ..,) = s {};
}
}

View file

@ -0,0 +1,41 @@
// run-rustfix
#![feature(stmt_expr_attributes)]
#![deny(clippy::unneeded_wildcard_pattern)]
fn main() {
let t = (0, 1, 2, 3);
if let (0, .., _) = t {};
if let (0, _, ..) = t {};
if let (0, _, _, ..) = t {};
if let (0, .., _, _) = t {};
if let (_, 0, ..) = t {};
if let (.., 0, _) = t {};
if let (0, _, _, _) = t {};
if let (0, ..) = t {};
if let (.., 0) = t {};
#[rustfmt::skip]
{
if let (0, .., _, _,) = t {};
}
struct S(usize, usize, usize, usize);
let s = S(0, 1, 2, 3);
if let S(0, .., _) = s {};
if let S(0, _, ..) = s {};
if let S(0, _, _, ..) = s {};
if let S(0, .., _, _) = s {};
if let S(_, 0, ..) = s {};
if let S(.., 0, _) = s {};
if let S(0, _, _, _) = s {};
if let S(0, ..) = s {};
if let S(.., 0) = s {};
#[rustfmt::skip]
{
if let S(0, .., _, _,) = s {};
}
}

View file

@ -0,0 +1,68 @@
error: this pattern is unneeded as the `..` pattern can match that element
--> $DIR/unneeded_wildcard_pattern.rs:8:18
|
LL | if let (0, .., _) = t {};
| ^^^ help: remove it
|
note: lint level defined here
--> $DIR/unneeded_wildcard_pattern.rs:3:9
|
LL | #![deny(clippy::unneeded_wildcard_pattern)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this pattern is unneeded as the `..` pattern can match that element
--> $DIR/unneeded_wildcard_pattern.rs:9:16
|
LL | if let (0, _, ..) = t {};
| ^^^ help: remove it
error: these patterns are unneeded as the `..` pattern can match those elements
--> $DIR/unneeded_wildcard_pattern.rs:10:16
|
LL | if let (0, _, _, ..) = t {};
| ^^^^^^ help: remove them
error: these patterns are unneeded as the `..` pattern can match those elements
--> $DIR/unneeded_wildcard_pattern.rs:11:18
|
LL | if let (0, .., _, _) = t {};
| ^^^^^^ help: remove them
error: these patterns are unneeded as the `..` pattern can match those elements
--> $DIR/unneeded_wildcard_pattern.rs:20:22
|
LL | if let (0, .., _, _,) = t {};
| ^^^^^^ help: remove them
error: this pattern is unneeded as the `..` pattern can match that element
--> $DIR/unneeded_wildcard_pattern.rs:27:19
|
LL | if let S(0, .., _) = s {};
| ^^^ help: remove it
error: this pattern is unneeded as the `..` pattern can match that element
--> $DIR/unneeded_wildcard_pattern.rs:28:17
|
LL | if let S(0, _, ..) = s {};
| ^^^ help: remove it
error: these patterns are unneeded as the `..` pattern can match those elements
--> $DIR/unneeded_wildcard_pattern.rs:29:17
|
LL | if let S(0, _, _, ..) = s {};
| ^^^^^^ help: remove them
error: these patterns are unneeded as the `..` pattern can match those elements
--> $DIR/unneeded_wildcard_pattern.rs:30:19
|
LL | if let S(0, .., _, _) = s {};
| ^^^^^^ help: remove them
error: these patterns are unneeded as the `..` pattern can match those elements
--> $DIR/unneeded_wildcard_pattern.rs:39:23
|
LL | if let S(0, .., _, _,) = s {};
| ^^^^^^ help: remove them
error: aborting due to 10 previous errors