Skip to content

Commit a40b035

Browse files
author
Allen Hsu
committed
Roll up repeated traits and where clauses.
1 parent f2a383d commit a40b035

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;
@@ -287,42 +287,92 @@ fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>
287287

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

306332
for predicate in gen.where_clause.predicates {
307333
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate {
308334
let mut where_clauses = FxHashMap::default();
335+
let mut repeated_spans = false;
336+
309337
for (definition, _, span_direct) in bound_predicate
310338
.bounds
311339
.iter()
312340
.filter_map(get_trait_info_from_bound)
313-
.rev()
314341
{
315-
if let Some(span_direct) = where_clauses.insert(definition, span_direct) {
316-
span_lint_and_help(
317-
cx,
318-
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
319-
span_direct,
320-
"this where clause has already been specified",
321-
None,
322-
"consider removing this where clause",
323-
);
342+
if let Some(_) = where_clauses.insert(definition, span_direct) {
343+
repeated_spans = true;
324344
}
325345
}
346+
347+
if repeated_spans {
348+
let all_trait_span = bound_predicate
349+
.bounds
350+
.get(0)
351+
.unwrap()
352+
.span()
353+
.to(
354+
bound_predicate
355+
.bounds
356+
.iter()
357+
.last()
358+
.unwrap()
359+
.span());
360+
361+
let mut traits = where_clauses.values()
362+
.filter_map(|span| snippet_opt(cx, *span))
363+
.collect::<Vec<_>>();
364+
traits.sort_unstable();
365+
let traits = traits.join(" + ");
366+
span_lint_and_sugg(
367+
cx,
368+
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
369+
all_trait_span,
370+
"this where clause has already been specified",
371+
"try",
372+
traits,
373+
Applicability::MachineApplicable
374+
);
375+
}
326376
}
327377
}
328378
}
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)