about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCatherine <114838443+Centri3@users.noreply.github.com>2023-06-23 06:02:39 -0500
committerCatherine <114838443+Centri3@users.noreply.github.com>2023-06-27 06:06:56 -0500
commit9a8347ded53a14fb381f404abd32302e59ef20a9 (patch)
treed0af5b2929416864c7306a4bc651f800c7811d7e
parentecdea8cdd386260970dad617cae2a71b25a307f5 (diff)
downloadrust-9a8347ded53a14fb381f404abd32302e59ef20a9.tar.gz
rust-9a8347ded53a14fb381f404abd32302e59ef20a9.zip
New lint [`redundant_rest_pattern`]
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_lints/src/methods/needless_collect.rs2
-rw-r--r--clippy_lints/src/methods/str_splitn.rs2
-rw-r--r--clippy_lints/src/misc_early/mod.rs31
-rw-r--r--clippy_lints/src/misc_early/redundant_rest_pattern.rs26
-rw-r--r--clippy_utils/src/sugg.rs2
-rw-r--r--tests/ui/manual_let_else_match.rs2
-rw-r--r--tests/ui/match_on_vec_items.rs2
-rw-r--r--tests/ui/redundant_rest_pattern.fixed27
-rw-r--r--tests/ui/redundant_rest_pattern.rs27
-rw-r--r--tests/ui/redundant_rest_pattern.stderr40
12 files changed, 158 insertions, 5 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 941efb1abff..6350d9c118f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5141,6 +5141,7 @@ Released 2018-09-13
 [`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
 [`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
+[`redundant_rest_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_rest_pattern
 [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
 [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
 [`redundant_type_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_type_annotations
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 0eec18a91bc..13b0f9d5ee3 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -431,6 +431,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
     crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
     crate::misc_early::REDUNDANT_PATTERN_INFO,
+    crate::misc_early::REDUNDANT_REST_PATTERN_INFO,
     crate::misc_early::SEPARATED_LITERAL_SUFFIX_INFO,
     crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO,
     crate::misc_early::UNNEEDED_WILDCARD_PATTERN_INFO,
diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs
index 99f810c27cf..3c3919dffe5 100644
--- a/clippy_lints/src/methods/needless_collect.rs
+++ b/clippy_lints/src/methods/needless_collect.rs
@@ -322,7 +322,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         // Check function calls on our collection
-        if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind {
+        if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind {
             if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
                 self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
                 self.visit_expr(recv);
diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs
index 5ea12c44184..88a3c2620a4 100644
--- a/clippy_lints/src/methods/str_splitn.rs
+++ b/clippy_lints/src/methods/str_splitn.rs
@@ -289,7 +289,7 @@ fn parse_iter_usage<'tcx>(
 ) -> Option<IterUsage> {
     let (kind, span) = match iter.next() {
         Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
-            let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind else {
+            let ExprKind::MethodCall(name, _, args, _) = e.kind else {
                 return None;
             };
             let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs
index 78253ab6cdc..fcf19f17958 100644
--- a/clippy_lints/src/misc_early/mod.rs
+++ b/clippy_lints/src/misc_early/mod.rs
@@ -3,6 +3,7 @@ mod double_neg;
 mod literal_suffix;
 mod mixed_case_hex_literals;
 mod redundant_pattern;
+mod redundant_rest_pattern;
 mod unneeded_field_pattern;
 mod unneeded_wildcard_pattern;
 mod zero_prefixed_literal;
@@ -318,6 +319,34 @@ declare_clippy_lint! {
     "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `[all @ ..]` patterns.
+    ///
+    /// ### Why is this bad?
+    /// In all cases, `all` works fine and can often make code simpler, as you possibly won't need
+    /// to convert from say a `Vec` to a slice by dereferencing.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// if let [all @ ..] = &*v {
+    ///     // NOTE: Type is a slice here
+    ///     println!("all elements: {all:#?}");
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// if let all = v {
+    ///     // NOTE: Type is a `Vec` here
+    ///     println!("all elements: {all:#?}");
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub REDUNDANT_REST_PATTERN,
+    complexity,
+    "checks for `[all @ ..]` where `all` would suffice"
+}
+
 declare_lint_pass!(MiscEarlyLints => [
     UNNEEDED_FIELD_PATTERN,
     DUPLICATE_UNDERSCORE_ARGUMENT,
@@ -329,6 +358,7 @@ declare_lint_pass!(MiscEarlyLints => [
     BUILTIN_TYPE_SHADOW,
     REDUNDANT_PATTERN,
     UNNEEDED_WILDCARD_PATTERN,
+    REDUNDANT_REST_PATTERN,
 ]);
 
 impl EarlyLintPass for MiscEarlyLints {
@@ -345,6 +375,7 @@ impl EarlyLintPass for MiscEarlyLints {
 
         unneeded_field_pattern::check(cx, pat);
         redundant_pattern::check(cx, pat);
+        redundant_rest_pattern::check(cx, pat);
         unneeded_wildcard_pattern::check(cx, pat);
     }
 
diff --git a/clippy_lints/src/misc_early/redundant_rest_pattern.rs b/clippy_lints/src/misc_early/redundant_rest_pattern.rs
new file mode 100644
index 00000000000..87e1ed8317c
--- /dev/null
+++ b/clippy_lints/src/misc_early/redundant_rest_pattern.rs
@@ -0,0 +1,26 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::{Pat, PatKind};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+
+use super::REDUNDANT_REST_PATTERN;
+
+pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
+    if !in_external_macro(cx.sess(), pat.span)
+        && let PatKind::Slice(slice) = &pat.kind
+        && let [one] = &**slice
+        && let PatKind::Ident(annotation, ident, Some(rest)) = &one.kind
+        && let PatKind::Rest = rest.kind
+    {
+        span_lint_and_sugg(
+            cx,
+            REDUNDANT_REST_PATTERN,
+            pat.span,
+            "using a rest pattern to bind an entire slice to a local",
+            "this is better represented with just the binding",
+            format!("{}{ident}", annotation.prefix_str()),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs
index f477524eec5..bc3e58169e6 100644
--- a/clippy_utils/src/sugg.rs
+++ b/clippy_utils/src/sugg.rs
@@ -942,7 +942,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
                         },
                         // item is used in a call
                         // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)`
-                        ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [call_args @ ..], _) => {
+                        ExprKind::Call(_, call_args) | ExprKind::MethodCall(_, _, call_args, _) => {
                             let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id);
                             let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind();
 
diff --git a/tests/ui/manual_let_else_match.rs b/tests/ui/manual_let_else_match.rs
index 07cd5a53a7c..073094ea789 100644
--- a/tests/ui/manual_let_else_match.rs
+++ b/tests/ui/manual_let_else_match.rs
@@ -1,5 +1,5 @@
 #![allow(unused_braces, unused_variables, dead_code)]
-#![allow(clippy::collapsible_else_if, clippy::let_unit_value)]
+#![allow(clippy::collapsible_else_if, clippy::let_unit_value, clippy::redundant_rest_pattern)]
 #![warn(clippy::manual_let_else)]
 // Ensure that we don't conflict with match -> if let lints
 #![warn(clippy::single_match_else, clippy::single_match)]
diff --git a/tests/ui/match_on_vec_items.rs b/tests/ui/match_on_vec_items.rs
index d82a736963a..fe214904365 100644
--- a/tests/ui/match_on_vec_items.rs
+++ b/tests/ui/match_on_vec_items.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::match_on_vec_items)]
-#![allow(clippy::useless_vec)]
+#![allow(clippy::redundant_rest_pattern, clippy::useless_vec)]
 
 fn match_with_wildcard() {
     let arr = vec![0, 1, 2, 3];
diff --git a/tests/ui/redundant_rest_pattern.fixed b/tests/ui/redundant_rest_pattern.fixed
new file mode 100644
index 00000000000..d9a98622c42
--- /dev/null
+++ b/tests/ui/redundant_rest_pattern.fixed
@@ -0,0 +1,27 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs
+#![allow(irrefutable_let_patterns, unused)]
+#![warn(clippy::redundant_rest_pattern)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn main() {
+    if let a = [()] {}
+    if let ref a = [()] {}
+    if let mut a = [()] {}
+    if let ref mut a = [()] {}
+    let v = vec![()];
+    if let a = &*v {}
+    let s = &[()];
+    if let a = s {}
+    // Don't lint
+    if let [..] = &*v {}
+    if let [a] = &*v {}
+    if let [()] = &*v {}
+    if let [first, rest @ ..] = &*v {}
+    if let a = [()] {}
+    external! {
+        if let [a @ ..] = [()] {}
+    }
+}
diff --git a/tests/ui/redundant_rest_pattern.rs b/tests/ui/redundant_rest_pattern.rs
new file mode 100644
index 00000000000..60a12bfd6fb
--- /dev/null
+++ b/tests/ui/redundant_rest_pattern.rs
@@ -0,0 +1,27 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs
+#![allow(irrefutable_let_patterns, unused)]
+#![warn(clippy::redundant_rest_pattern)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn main() {
+    if let [a @ ..] = [()] {}
+    if let [ref a @ ..] = [()] {}
+    if let [mut a @ ..] = [()] {}
+    if let [ref mut a @ ..] = [()] {}
+    let v = vec![()];
+    if let [a @ ..] = &*v {}
+    let s = &[()];
+    if let [a @ ..] = s {}
+    // Don't lint
+    if let [..] = &*v {}
+    if let [a] = &*v {}
+    if let [()] = &*v {}
+    if let [first, rest @ ..] = &*v {}
+    if let a = [()] {}
+    external! {
+        if let [a @ ..] = [()] {}
+    }
+}
diff --git a/tests/ui/redundant_rest_pattern.stderr b/tests/ui/redundant_rest_pattern.stderr
new file mode 100644
index 00000000000..630909a0a16
--- /dev/null
+++ b/tests/ui/redundant_rest_pattern.stderr
@@ -0,0 +1,40 @@
+error: using a rest pattern to bind an entire slice to a local
+  --> $DIR/redundant_rest_pattern.rs:10:12
+   |
+LL |     if let [a @ ..] = [()] {}
+   |            ^^^^^^^^ help: this is better represented with just the binding: `a`
+   |
+   = note: `-D clippy::redundant-rest-pattern` implied by `-D warnings`
+
+error: using a rest pattern to bind an entire slice to a local
+  --> $DIR/redundant_rest_pattern.rs:11:12
+   |
+LL |     if let [ref a @ ..] = [()] {}
+   |            ^^^^^^^^^^^^ help: this is better represented with just the binding: `ref a`
+
+error: using a rest pattern to bind an entire slice to a local
+  --> $DIR/redundant_rest_pattern.rs:12:12
+   |
+LL |     if let [mut a @ ..] = [()] {}
+   |            ^^^^^^^^^^^^ help: this is better represented with just the binding: `mut a`
+
+error: using a rest pattern to bind an entire slice to a local
+  --> $DIR/redundant_rest_pattern.rs:13:12
+   |
+LL |     if let [ref mut a @ ..] = [()] {}
+   |            ^^^^^^^^^^^^^^^^ help: this is better represented with just the binding: `ref mut a`
+
+error: using a rest pattern to bind an entire slice to a local
+  --> $DIR/redundant_rest_pattern.rs:15:12
+   |
+LL |     if let [a @ ..] = &*v {}
+   |            ^^^^^^^^ help: this is better represented with just the binding: `a`
+
+error: using a rest pattern to bind an entire slice to a local
+  --> $DIR/redundant_rest_pattern.rs:17:12
+   |
+LL |     if let [a @ ..] = s {}
+   |            ^^^^^^^^ help: this is better represented with just the binding: `a`
+
+error: aborting due to 6 previous errors
+