Skip to content

Commit 9a8347d

Browse files
committed
New lint [redundant_rest_pattern]
1 parent ecdea8c commit 9a8347d

12 files changed

+158
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5141,6 +5141,7 @@ Released 2018-09-13
51415141
[`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
51425142
[`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
51435143
[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
5144+
[`redundant_rest_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_rest_pattern
51445145
[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
51455146
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
51465147
[`redundant_type_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_type_annotations

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
431431
crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
432432
crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
433433
crate::misc_early::REDUNDANT_PATTERN_INFO,
434+
crate::misc_early::REDUNDANT_REST_PATTERN_INFO,
434435
crate::misc_early::SEPARATED_LITERAL_SUFFIX_INFO,
435436
crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO,
436437
crate::misc_early::UNNEEDED_WILDCARD_PATTERN_INFO,

clippy_lints/src/methods/needless_collect.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
322322

323323
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
324324
// Check function calls on our collection
325-
if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind {
325+
if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind {
326326
if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
327327
self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
328328
self.visit_expr(recv);

clippy_lints/src/methods/str_splitn.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ fn parse_iter_usage<'tcx>(
289289
) -> Option<IterUsage> {
290290
let (kind, span) = match iter.next() {
291291
Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
292-
let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind else {
292+
let ExprKind::MethodCall(name, _, args, _) = e.kind else {
293293
return None;
294294
};
295295
let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?;

clippy_lints/src/misc_early/mod.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod double_neg;
33
mod literal_suffix;
44
mod mixed_case_hex_literals;
55
mod redundant_pattern;
6+
mod redundant_rest_pattern;
67
mod unneeded_field_pattern;
78
mod unneeded_wildcard_pattern;
89
mod zero_prefixed_literal;
@@ -318,6 +319,34 @@ declare_clippy_lint! {
318319
"tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
319320
}
320321

322+
declare_clippy_lint! {
323+
/// ### What it does
324+
/// Checks for `[all @ ..]` patterns.
325+
///
326+
/// ### Why is this bad?
327+
/// In all cases, `all` works fine and can often make code simpler, as you possibly won't need
328+
/// to convert from say a `Vec` to a slice by dereferencing.
329+
///
330+
/// ### Example
331+
/// ```rust,ignore
332+
/// if let [all @ ..] = &*v {
333+
/// // NOTE: Type is a slice here
334+
/// println!("all elements: {all:#?}");
335+
/// }
336+
/// ```
337+
/// Use instead:
338+
/// ```rust,ignore
339+
/// if let all = v {
340+
/// // NOTE: Type is a `Vec` here
341+
/// println!("all elements: {all:#?}");
342+
/// }
343+
/// ```
344+
#[clippy::version = "1.72.0"]
345+
pub REDUNDANT_REST_PATTERN,
346+
complexity,
347+
"checks for `[all @ ..]` where `all` would suffice"
348+
}
349+
321350
declare_lint_pass!(MiscEarlyLints => [
322351
UNNEEDED_FIELD_PATTERN,
323352
DUPLICATE_UNDERSCORE_ARGUMENT,
@@ -329,6 +358,7 @@ declare_lint_pass!(MiscEarlyLints => [
329358
BUILTIN_TYPE_SHADOW,
330359
REDUNDANT_PATTERN,
331360
UNNEEDED_WILDCARD_PATTERN,
361+
REDUNDANT_REST_PATTERN,
332362
]);
333363

334364
impl EarlyLintPass for MiscEarlyLints {
@@ -345,6 +375,7 @@ impl EarlyLintPass for MiscEarlyLints {
345375

346376
unneeded_field_pattern::check(cx, pat);
347377
redundant_pattern::check(cx, pat);
378+
redundant_rest_pattern::check(cx, pat);
348379
unneeded_wildcard_pattern::check(cx, pat);
349380
}
350381

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use rustc_ast::{Pat, PatKind};
3+
use rustc_errors::Applicability;
4+
use rustc_lint::{EarlyContext, LintContext};
5+
use rustc_middle::lint::in_external_macro;
6+
7+
use super::REDUNDANT_REST_PATTERN;
8+
9+
pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
10+
if !in_external_macro(cx.sess(), pat.span)
11+
&& let PatKind::Slice(slice) = &pat.kind
12+
&& let [one] = &**slice
13+
&& let PatKind::Ident(annotation, ident, Some(rest)) = &one.kind
14+
&& let PatKind::Rest = rest.kind
15+
{
16+
span_lint_and_sugg(
17+
cx,
18+
REDUNDANT_REST_PATTERN,
19+
pat.span,
20+
"using a rest pattern to bind an entire slice to a local",
21+
"this is better represented with just the binding",
22+
format!("{}{ident}", annotation.prefix_str()),
23+
Applicability::MachineApplicable,
24+
);
25+
}
26+
}

clippy_utils/src/sugg.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
942942
},
943943
// item is used in a call
944944
// i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)`
945-
ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [call_args @ ..], _) => {
945+
ExprKind::Call(_, call_args) | ExprKind::MethodCall(_, _, call_args, _) => {
946946
let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id);
947947
let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind();
948948

tests/ui/manual_let_else_match.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![allow(unused_braces, unused_variables, dead_code)]
2-
#![allow(clippy::collapsible_else_if, clippy::let_unit_value)]
2+
#![allow(clippy::collapsible_else_if, clippy::let_unit_value, clippy::redundant_rest_pattern)]
33
#![warn(clippy::manual_let_else)]
44
// Ensure that we don't conflict with match -> if let lints
55
#![warn(clippy::single_match_else, clippy::single_match)]

tests/ui/match_on_vec_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![warn(clippy::match_on_vec_items)]
2-
#![allow(clippy::useless_vec)]
2+
#![allow(clippy::redundant_rest_pattern, clippy::useless_vec)]
33

44
fn match_with_wildcard() {
55
let arr = vec![0, 1, 2, 3];

tests/ui/redundant_rest_pattern.fixed

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//@run-rustfix
2+
//@aux-build:proc_macros.rs
3+
#![allow(irrefutable_let_patterns, unused)]
4+
#![warn(clippy::redundant_rest_pattern)]
5+
6+
#[macro_use]
7+
extern crate proc_macros;
8+
9+
fn main() {
10+
if let a = [()] {}
11+
if let ref a = [()] {}
12+
if let mut a = [()] {}
13+
if let ref mut a = [()] {}
14+
let v = vec![()];
15+
if let a = &*v {}
16+
let s = &[()];
17+
if let a = s {}
18+
// Don't lint
19+
if let [..] = &*v {}
20+
if let [a] = &*v {}
21+
if let [()] = &*v {}
22+
if let [first, rest @ ..] = &*v {}
23+
if let a = [()] {}
24+
external! {
25+
if let [a @ ..] = [()] {}
26+
}
27+
}

0 commit comments

Comments
 (0)