Skip to content

Commit 4771fe7

Browse files
author
Allen Hsu
committed
Roll up repeated traits and where clauses.
1 parent d305640 commit 4771fe7

File tree

4 files changed

+189
-86
lines changed

4 files changed

+189
-86
lines changed

clippy_lints/src/trait_bounds.rs

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use clippy_utils::diagnostics::span_lint_and_help;
2-
use clippy_utils::source::{snippet, snippet_with_applicability};
1+
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_help};
2+
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_opt};
33
use clippy_utils::{SpanlessEq, SpanlessHash};
44
use core::hash::{Hash, Hasher};
55
use if_chain::if_chain;
@@ -291,42 +291,92 @@ fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>
291291

292292
for param in gen.params {
293293
let mut map = FxHashMap::default();
294-
if let ParamName::Plain(name) = param.name {
295-
for (definition, _, span_direct) in param.bounds.iter().rev().filter_map(get_trait_info_from_bound) {
296-
if let Some(span_direct) = map.insert((name, definition), span_direct) {
297-
span_lint_and_help(
298-
cx,
299-
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
300-
span_direct,
301-
"this trait bound has already been specified",
302-
None,
303-
"consider removing this trait bound",
304-
);
294+
let mut repeated_spans = false;
295+
if let ParamName::Plain(name) = param.name { // other alternatives are errors and elided which won't have duplicates
296+
for bound in param.bounds.iter().filter_map(get_trait_info_from_bound) {
297+
let (definition, _, span_direct) = bound;
298+
if let Some(_) = map.insert(definition, span_direct) {
299+
repeated_spans = true;
305300
}
306301
}
302+
303+
if repeated_spans {
304+
let all_trait_span = param
305+
.bounds
306+
.get(0)
307+
.unwrap()
308+
.span()
309+
.to(
310+
param
311+
.bounds
312+
.iter()
313+
.last()
314+
.unwrap()
315+
.span());
316+
317+
let mut traits = map.values()
318+
.filter_map(|span| snippet_opt(cx, *span))
319+
.collect::<Vec<_>>();
320+
traits.sort_unstable();
321+
let traits = traits.join(" + ");
322+
323+
span_lint_and_sugg(
324+
cx,
325+
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
326+
all_trait_span,
327+
"this trait bound contains repeated elements",
328+
"try",
329+
traits,
330+
Applicability::MachineApplicable
331+
);
332+
}
307333
}
308334
}
309335

310336
for predicate in gen.where_clause.predicates {
311337
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate {
312338
let mut where_clauses = FxHashMap::default();
339+
let mut repeated_spans = false;
340+
313341
for (definition, _, span_direct) in bound_predicate
314342
.bounds
315343
.iter()
316344
.filter_map(get_trait_info_from_bound)
317-
.rev()
318345
{
319-
if let Some(span_direct) = where_clauses.insert(definition, span_direct) {
320-
span_lint_and_help(
321-
cx,
322-
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
323-
span_direct,
324-
"this where clause has already been specified",
325-
None,
326-
"consider removing this where clause",
327-
);
346+
if let Some(_) = where_clauses.insert(definition, span_direct) {
347+
repeated_spans = true;
328348
}
329349
}
350+
351+
if repeated_spans {
352+
let all_trait_span = bound_predicate
353+
.bounds
354+
.get(0)
355+
.unwrap()
356+
.span()
357+
.to(
358+
bound_predicate
359+
.bounds
360+
.iter()
361+
.last()
362+
.unwrap()
363+
.span());
364+
365+
let mut traits = where_clauses.values()
366+
.filter_map(|span| snippet_opt(cx, *span))
367+
.collect::<Vec<_>>();
368+
traits.sort_unstable();
369+
let traits = traits.join(" + ");
370+
span_lint_and_sugg(
371+
cx,
372+
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
373+
all_trait_span,
374+
"this where clause has already been specified",
375+
"try",
376+
traits,
377+
Applicability::MachineApplicable
378+
);
379+
}
330380
}
331381
}
332382
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// run-rustfix
2+
//
3+
#![allow(
4+
unused,
5+
)]
6+
#![deny(clippy::repeated_where_clause_or_trait_bound)]
7+
8+
fn bad_foo<T: Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
9+
unimplemented!();
10+
}
11+
12+
fn bad_bar<T, U>(arg0: T, arg1: U)
13+
where
14+
T: Clone + Copy,
15+
U: Clone + Copy,
16+
{
17+
unimplemented!();
18+
}
19+
20+
fn good_bar<T: Clone + Copy, U: Clone + Copy>(arg0: T, arg1: U) {
21+
unimplemented!();
22+
}
23+
24+
fn good_foo<T, U>(arg0: T, arg1: U)
25+
where
26+
T: Clone + Copy,
27+
U: Clone + Copy,
28+
{
29+
unimplemented!();
30+
}
31+
32+
trait GoodSelfTraitBound: Clone + Copy {
33+
fn f();
34+
}
35+
36+
trait GoodSelfWhereClause {
37+
fn f()
38+
where
39+
Self: Clone + Copy;
40+
}
41+
42+
trait BadSelfTraitBound: Clone + Clone + Clone {
43+
fn f();
44+
}
45+
46+
trait BadSelfWhereClause {
47+
fn f()
48+
where
49+
Self: Clone;
50+
}
51+
52+
trait GoodTraitBound<T: Clone + Copy, U: Clone + Copy> {
53+
fn f();
54+
}
55+
56+
trait GoodWhereClause<T, U> {
57+
fn f()
58+
where
59+
T: Clone + Copy,
60+
U: Clone + Copy;
61+
}
62+
63+
trait BadTraitBound<T: Clone + Copy, U: Clone + Copy> {
64+
fn f();
65+
}
66+
67+
trait BadWhereClause<T, U> {
68+
fn f()
69+
where
70+
T: Clone + Copy,
71+
U: Clone + Copy;
72+
}
73+
74+
struct GoodStructBound<T: Clone + Copy, U: Clone + Copy> {
75+
t: T,
76+
u: U,
77+
}
78+
79+
impl<T: Clone + Copy, U: Clone + Copy> GoodTraitBound<T, U> for GoodStructBound<T, U> {
80+
// this should not warn
81+
fn f() {}
82+
}
83+
84+
struct GoodStructWhereClause;
85+
86+
impl<T, U> GoodTraitBound<T, U> for GoodStructWhereClause
87+
where
88+
T: Clone + Copy,
89+
U: Clone + Copy,
90+
{
91+
// this should not warn
92+
fn f() {}
93+
}
94+
95+
fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
96+
97+
fn main() {}

tests/ui/repeated_where_clause_or_trait_bound.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// run-rustfix
2+
//
3+
#![allow(
4+
unused,
5+
)]
16
#![deny(clippy::repeated_where_clause_or_trait_bound)]
27

38
fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
Lines changed: 14 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,38 @@
1-
error: this trait bound has already been specified
2-
--> $DIR/repeated_where_clause_or_trait_bound.rs:3:31
1+
error: this trait bound contains repeated elements
2+
--> $DIR/repeated_where_clause_or_trait_bound.rs:8:15
33
|
44
LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
5-
| ^^^^^
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
66
|
77
note: the lint level is defined here
8-
--> $DIR/repeated_where_clause_or_trait_bound.rs:1:9
8+
--> $DIR/repeated_where_clause_or_trait_bound.rs:6:9
99
|
1010
LL | #![deny(clippy::repeated_where_clause_or_trait_bound)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12-
= help: consider removing this trait bound
13-
14-
error: this trait bound has already been specified
15-
--> $DIR/repeated_where_clause_or_trait_bound.rs:3:23
16-
|
17-
LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
18-
| ^^^^^
19-
|
20-
= help: consider removing this trait bound
21-
22-
error: this where clause has already been specified
23-
--> $DIR/repeated_where_clause_or_trait_bound.rs:9:24
24-
|
25-
LL | T: Clone + Clone + Clone + Copy,
26-
| ^^^^^
27-
|
28-
= help: consider removing this where clause
2912

3013
error: this where clause has already been specified
31-
--> $DIR/repeated_where_clause_or_trait_bound.rs:9:16
14+
--> $DIR/repeated_where_clause_or_trait_bound.rs:14:8
3215
|
3316
LL | T: Clone + Clone + Clone + Copy,
34-
| ^^^^^
35-
|
36-
= help: consider removing this where clause
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
3718

3819
error: this where clause has already been specified
39-
--> $DIR/repeated_where_clause_or_trait_bound.rs:44:31
20+
--> $DIR/repeated_where_clause_or_trait_bound.rs:49:15
4021
|
4122
LL | Self: Clone + Clone + Clone;
42-
| ^^^^^
43-
|
44-
= help: consider removing this where clause
23+
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
4524

46-
error: this where clause has already been specified
47-
--> $DIR/repeated_where_clause_or_trait_bound.rs:44:23
48-
|
49-
LL | Self: Clone + Clone + Clone;
50-
| ^^^^^
51-
|
52-
= help: consider removing this where clause
53-
54-
error: this trait bound has already been specified
55-
--> $DIR/repeated_where_clause_or_trait_bound.rs:58:40
25+
error: this trait bound contains repeated elements
26+
--> $DIR/repeated_where_clause_or_trait_bound.rs:63:24
5627
|
5728
LL | trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
58-
| ^^^^^
59-
|
60-
= help: consider removing this trait bound
61-
62-
error: this trait bound has already been specified
63-
--> $DIR/repeated_where_clause_or_trait_bound.rs:58:32
64-
|
65-
LL | trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
66-
| ^^^^^
67-
|
68-
= help: consider removing this trait bound
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
6930

7031
error: this where clause has already been specified
71-
--> $DIR/repeated_where_clause_or_trait_bound.rs:65:28
32+
--> $DIR/repeated_where_clause_or_trait_bound.rs:70:12
7233
|
7334
LL | T: Clone + Clone + Clone + Copy,
74-
| ^^^^^
75-
|
76-
= help: consider removing this where clause
77-
78-
error: this where clause has already been specified
79-
--> $DIR/repeated_where_clause_or_trait_bound.rs:65:20
80-
|
81-
LL | T: Clone + Clone + Clone + Copy,
82-
| ^^^^^
83-
|
84-
= help: consider removing this where clause
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
8536

86-
error: aborting due to 10 previous errors
37+
error: aborting due to 5 previous errors
8738

0 commit comments

Comments
 (0)