Skip to content

Commit 49a2f38

Browse files
authored
Unneeded wildcard improvement (#16733)
*[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust-clippy/pull/16733)* changelog: [`unneeded_wildcard_pattern`]: add support for struct constructs. Closes [#16638](#16638) The existing lint only looks at tuples and tuplestructs. This change adds support for standard structs, looking for cases where one or more `_` immediately preceed a `..`. The preceeding `_` members may be omitted, as they will be collected by the `..` operator.
2 parents 389a32a + df2f81b commit 49a2f38

8 files changed

Lines changed: 114 additions & 23 deletions

clippy_lints/src/misc_early/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ declare_clippy_lint! {
197197

198198
declare_clippy_lint! {
199199
/// ### What it does
200-
/// Checks for tuple patterns with a wildcard
200+
/// Checks for tuple and struct patterns with a wildcard
201201
/// pattern (`_`) is next to a rest pattern (`..`).
202202
///
203203
/// _NOTE_: While `_, ..` means there is at least one element left, `..`
@@ -231,7 +231,7 @@ declare_clippy_lint! {
231231
#[clippy::version = "1.40.0"]
232232
pub UNNEEDED_WILDCARD_PATTERN,
233233
complexity,
234-
"tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
234+
"tuple and struct patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
235235
}
236236

237237
declare_clippy_lint! {

clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use rustc_ast::ast::{Pat, PatKind};
2+
use rustc_ast::ast::{Pat, PatFieldsRest, PatKind};
33
use rustc_errors::Applicability;
44
use rustc_lint::EarlyContext;
55
use rustc_span::Span;
@@ -32,6 +32,19 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
3232
right_index == 0,
3333
);
3434
}
35+
} else if let PatKind::Struct(_, _, patfields, rest) = &pat.kind
36+
&& let PatFieldsRest::Rest(rspan) = rest
37+
&& let Some((right_index, _right_pat)) = patfields
38+
.iter()
39+
.rev()
40+
.take_while(|patfield| matches!(patfield.pat.kind, PatKind::Wild))
41+
.enumerate()
42+
.last()
43+
{
44+
// Unlike the tuples above, structs have patfields rathter than patterns, and separate out the
45+
// `..` into a separate parameter. Also, the `..` can only be at the end of the pattern.
46+
let singlewild = patfields.len() - right_index - 1;
47+
span_lint(cx, patfields[singlewild].span.until(*rspan), right_index == 0);
3548
}
3649
}
3750

tests/ui/needless_borrowed_ref.fixed

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
irrefutable_let_patterns,
55
non_shorthand_field_patterns,
66
clippy::needless_borrow,
7-
clippy::needless_ifs
7+
clippy::needless_ifs,
8+
clippy::unneeded_wildcard_pattern
89
)]
910

1011
fn main() {}

tests/ui/needless_borrowed_ref.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
irrefutable_let_patterns,
55
non_shorthand_field_patterns,
66
clippy::needless_borrow,
7-
clippy::needless_ifs
7+
clippy::needless_ifs,
8+
clippy::unneeded_wildcard_pattern
89
)]
910

1011
fn main() {}

tests/ui/needless_borrowed_ref.stderr

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: this pattern takes a reference on something that is being dereferenced
2-
--> tests/ui/needless_borrowed_ref.rs:30:34
2+
--> tests/ui/needless_borrowed_ref.rs:31:34
33
|
44
LL | let _ = v.iter_mut().filter(|&ref a| a.is_empty());
55
| ^^^^^^
@@ -13,7 +13,7 @@ LL + let _ = v.iter_mut().filter(|a| a.is_empty());
1313
|
1414

1515
error: this pattern takes a reference on something that is being dereferenced
16-
--> tests/ui/needless_borrowed_ref.rs:35:17
16+
--> tests/ui/needless_borrowed_ref.rs:36:17
1717
|
1818
LL | if let Some(&ref v) = thingy {}
1919
| ^^^^^^
@@ -25,7 +25,7 @@ LL + if let Some(v) = thingy {}
2525
|
2626

2727
error: this pattern takes a reference on something that is being dereferenced
28-
--> tests/ui/needless_borrowed_ref.rs:38:14
28+
--> tests/ui/needless_borrowed_ref.rs:39:14
2929
|
3030
LL | if let &[&ref a, ref b] = slice_of_refs {}
3131
| ^^^^^^
@@ -37,7 +37,7 @@ LL + if let &[a, ref b] = slice_of_refs {}
3737
|
3838

3939
error: dereferencing a slice pattern where every element takes a reference
40-
--> tests/ui/needless_borrowed_ref.rs:41:9
40+
--> tests/ui/needless_borrowed_ref.rs:42:9
4141
|
4242
LL | let &[ref a, ..] = &array;
4343
| ^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL + let [a, ..] = &array;
4949
|
5050

5151
error: dereferencing a slice pattern where every element takes a reference
52-
--> tests/ui/needless_borrowed_ref.rs:43:9
52+
--> tests/ui/needless_borrowed_ref.rs:44:9
5353
|
5454
LL | let &[ref a, ref b, ..] = &array;
5555
| ^^^^^^^^^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL + let [a, b, ..] = &array;
6161
|
6262

6363
error: dereferencing a slice pattern where every element takes a reference
64-
--> tests/ui/needless_borrowed_ref.rs:46:12
64+
--> tests/ui/needless_borrowed_ref.rs:47:12
6565
|
6666
LL | if let &[ref a, ref b] = slice {}
6767
| ^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL + if let [a, b] = slice {}
7373
|
7474

7575
error: dereferencing a slice pattern where every element takes a reference
76-
--> tests/ui/needless_borrowed_ref.rs:48:12
76+
--> tests/ui/needless_borrowed_ref.rs:49:12
7777
|
7878
LL | if let &[ref a, ref b] = &vec[..] {}
7979
| ^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@ LL + if let [a, b] = &vec[..] {}
8585
|
8686

8787
error: dereferencing a slice pattern where every element takes a reference
88-
--> tests/ui/needless_borrowed_ref.rs:51:12
88+
--> tests/ui/needless_borrowed_ref.rs:52:12
8989
|
9090
LL | if let &[ref a, ref b, ..] = slice {}
9191
| ^^^^^^^^^^^^^^^^^^^
@@ -97,7 +97,7 @@ LL + if let [a, b, ..] = slice {}
9797
|
9898

9999
error: dereferencing a slice pattern where every element takes a reference
100-
--> tests/ui/needless_borrowed_ref.rs:53:12
100+
--> tests/ui/needless_borrowed_ref.rs:54:12
101101
|
102102
LL | if let &[ref a, .., ref b] = slice {}
103103
| ^^^^^^^^^^^^^^^^^^^
@@ -109,7 +109,7 @@ LL + if let [a, .., b] = slice {}
109109
|
110110

111111
error: dereferencing a slice pattern where every element takes a reference
112-
--> tests/ui/needless_borrowed_ref.rs:55:12
112+
--> tests/ui/needless_borrowed_ref.rs:56:12
113113
|
114114
LL | if let &[.., ref a, ref b] = slice {}
115115
| ^^^^^^^^^^^^^^^^^^^
@@ -121,7 +121,7 @@ LL + if let [.., a, b] = slice {}
121121
|
122122

123123
error: dereferencing a slice pattern where every element takes a reference
124-
--> tests/ui/needless_borrowed_ref.rs:58:12
124+
--> tests/ui/needless_borrowed_ref.rs:59:12
125125
|
126126
LL | if let &[ref a, _] = slice {}
127127
| ^^^^^^^^^^^
@@ -133,7 +133,7 @@ LL + if let [a, _] = slice {}
133133
|
134134

135135
error: dereferencing a tuple pattern where every element takes a reference
136-
--> tests/ui/needless_borrowed_ref.rs:61:12
136+
--> tests/ui/needless_borrowed_ref.rs:62:12
137137
|
138138
LL | if let &(ref a, ref b, ref c) = &tuple {}
139139
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +145,7 @@ LL + if let (a, b, c) = &tuple {}
145145
|
146146

147147
error: dereferencing a tuple pattern where every element takes a reference
148-
--> tests/ui/needless_borrowed_ref.rs:63:12
148+
--> tests/ui/needless_borrowed_ref.rs:64:12
149149
|
150150
LL | if let &(ref a, _, ref c) = &tuple {}
151151
| ^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL + if let (a, _, c) = &tuple {}
157157
|
158158

159159
error: dereferencing a tuple pattern where every element takes a reference
160-
--> tests/ui/needless_borrowed_ref.rs:65:12
160+
--> tests/ui/needless_borrowed_ref.rs:66:12
161161
|
162162
LL | if let &(ref a, ..) = &tuple {}
163163
| ^^^^^^^^^^^^
@@ -169,7 +169,7 @@ LL + if let (a, ..) = &tuple {}
169169
|
170170

171171
error: dereferencing a tuple pattern where every element takes a reference
172-
--> tests/ui/needless_borrowed_ref.rs:68:12
172+
--> tests/ui/needless_borrowed_ref.rs:69:12
173173
|
174174
LL | if let &TupleStruct(ref a, ..) = &tuple_struct {}
175175
| ^^^^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL + if let TupleStruct(a, ..) = &tuple_struct {}
181181
|
182182

183183
error: dereferencing a struct pattern where every field's pattern takes a reference
184-
--> tests/ui/needless_borrowed_ref.rs:71:12
184+
--> tests/ui/needless_borrowed_ref.rs:72:12
185185
|
186186
LL | if let &Struct {
187187
| ____________^
@@ -202,7 +202,7 @@ LL ~ c: renamed,
202202
|
203203

204204
error: dereferencing a struct pattern where every field's pattern takes a reference
205-
--> tests/ui/needless_borrowed_ref.rs:79:12
205+
--> tests/ui/needless_borrowed_ref.rs:80:12
206206
|
207207
LL | if let &Struct { ref a, b: _, .. } = &s {}
208208
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/ui/unneeded_wildcard_pattern.fixed

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,30 @@ fn main() {
6464
let t = (0, 1, 2, 3);
6565
if let (0, _, ..) = t {};
6666
}
67+
68+
struct Struct4 {
69+
a: u32,
70+
b: u32,
71+
c: u32,
72+
d: u32,
73+
}
74+
75+
let fourval = Struct4 {
76+
a: 5,
77+
b: 10,
78+
c: 15,
79+
d: 20,
80+
};
81+
82+
// unlike the tuple forms, the struct form can only have the `..` at the end of the list
83+
let Struct4 { mut a, mut b, .. } = fourval;
84+
//~^ unneeded_wildcard_pattern
85+
let Struct4 { mut b, .. } = fourval;
86+
//~^ unneeded_wildcard_pattern
87+
let Struct4 { mut a, b, c, d: _ } = fourval;
88+
let Struct4 { mut c, d, .. } = fourval;
89+
let Struct4 { .. } = fourval;
90+
//~^ unneeded_wildcard_pattern
91+
let Struct4 { .. } = fourval;
92+
//~^ unneeded_wildcard_pattern
6793
}

tests/ui/unneeded_wildcard_pattern.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,30 @@ fn main() {
6464
let t = (0, 1, 2, 3);
6565
if let (0, _, ..) = t {};
6666
}
67+
68+
struct Struct4 {
69+
a: u32,
70+
b: u32,
71+
c: u32,
72+
d: u32,
73+
}
74+
75+
let fourval = Struct4 {
76+
a: 5,
77+
b: 10,
78+
c: 15,
79+
d: 20,
80+
};
81+
82+
// unlike the tuple forms, the struct form can only have the `..` at the end of the list
83+
let Struct4 { mut a, mut b, c: _, .. } = fourval;
84+
//~^ unneeded_wildcard_pattern
85+
let Struct4 { mut b, c: _, d: _, .. } = fourval;
86+
//~^ unneeded_wildcard_pattern
87+
let Struct4 { mut a, b, c, d: _ } = fourval;
88+
let Struct4 { mut c, d, .. } = fourval;
89+
let Struct4 { b: _, c: _, .. } = fourval;
90+
//~^ unneeded_wildcard_pattern
91+
let Struct4 { c: _, .. } = fourval;
92+
//~^ unneeded_wildcard_pattern
6793
}

tests/ui/unneeded_wildcard_pattern.stderr

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,29 @@ error: these patterns are unneeded as the `..` pattern can match those elements
8888
LL | if let S(0, .., _, _,) = s {};
8989
| ^^^^^^ help: remove them
9090

91-
error: aborting due to 14 previous errors
91+
error: this pattern is unneeded as the `..` pattern can match that element
92+
--> tests/ui/unneeded_wildcard_pattern.rs:83:33
93+
|
94+
LL | let Struct4 { mut a, mut b, c: _, .. } = fourval;
95+
| ^^^^^^ help: remove it
96+
97+
error: these patterns are unneeded as the `..` pattern can match those elements
98+
--> tests/ui/unneeded_wildcard_pattern.rs:85:26
99+
|
100+
LL | let Struct4 { mut b, c: _, d: _, .. } = fourval;
101+
| ^^^^^^^^^^^^ help: remove them
102+
103+
error: these patterns are unneeded as the `..` pattern can match those elements
104+
--> tests/ui/unneeded_wildcard_pattern.rs:89:19
105+
|
106+
LL | let Struct4 { b: _, c: _, .. } = fourval;
107+
| ^^^^^^^^^^^^ help: remove them
108+
109+
error: this pattern is unneeded as the `..` pattern can match that element
110+
--> tests/ui/unneeded_wildcard_pattern.rs:91:19
111+
|
112+
LL | let Struct4 { c: _, .. } = fourval;
113+
| ^^^^^^ help: remove it
114+
115+
error: aborting due to 18 previous errors
92116

0 commit comments

Comments
 (0)