diff options
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | clippy_lints/src/lib.rs | 2 | ||||
| -rw-r--r-- | clippy_lints/src/misc_early.rs | 93 | ||||
| -rw-r--r-- | src/lintlist/mod.rs | 9 | ||||
| -rw-r--r-- | tests/ui/unneeded_wildcard_pattern.fixed | 41 | ||||
| -rw-r--r-- | tests/ui/unneeded_wildcard_pattern.rs | 41 | ||||
| -rw-r--r-- | tests/ui/unneeded_wildcard_pattern.stderr | 68 |
8 files changed, 254 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index dbdf3df4ddc..eb710654caf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index dd315fd397b..4541af9c844 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9d0a91c5318..de4d262bddc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -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, diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index a9907ed132d..2e1be755d09 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -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) { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 223e6aa9acd..589ae6b3d35 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 313] = [ +pub const ALL_LINTS: [Lint; 314] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1975,6 +1975,13 @@ pub const ALL_LINTS: [Lint; 313] = [ 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", desc: "long integer literal without underscores", diff --git a/tests/ui/unneeded_wildcard_pattern.fixed b/tests/ui/unneeded_wildcard_pattern.fixed new file mode 100644 index 00000000000..d0b62fa6f43 --- /dev/null +++ b/tests/ui/unneeded_wildcard_pattern.fixed @@ -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 {}; + } +} diff --git a/tests/ui/unneeded_wildcard_pattern.rs b/tests/ui/unneeded_wildcard_pattern.rs new file mode 100644 index 00000000000..bad158907ba --- /dev/null +++ b/tests/ui/unneeded_wildcard_pattern.rs @@ -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 {}; + } +} diff --git a/tests/ui/unneeded_wildcard_pattern.stderr b/tests/ui/unneeded_wildcard_pattern.stderr new file mode 100644 index 00000000000..8cc2516959a --- /dev/null +++ b/tests/ui/unneeded_wildcard_pattern.stderr @@ -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 + |
