Skip to content

Commit 0517a6c

Browse files
author
Allen Hsu
committed
Roll up repeated traits and where clauses.
1 parent db66322 commit 0517a6c

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

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

315341
for predicate in gen.where_clause.predicates {
316342
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate {
317343
let mut where_clauses = FxHashMap::default();
344+
let mut repeated_spans = false;
345+
318346
for (definition, _, span_direct) in bound_predicate
319347
.bounds
320348
.iter()
321349
.filter_map(get_trait_info_from_bound)
322-
.rev()
323350
{
324-
if let Some(span_direct) = where_clauses.insert(definition, span_direct) {
325-
span_lint_and_help(
326-
cx,
327-
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
328-
span_direct,
329-
"this where clause has already been specified",
330-
None,
331-
"consider removing this where clause",
332-
);
351+
if let Some(_) = where_clauses.insert(definition, span_direct) {
352+
repeated_spans = true;
333353
}
334354
}
355+
356+
if repeated_spans {
357+
let all_trait_span = bound_predicate
358+
.bounds
359+
.get(0)
360+
.unwrap()
361+
.span()
362+
.to(
363+
bound_predicate
364+
.bounds
365+
.iter()
366+
.last()
367+
.unwrap()
368+
.span());
369+
370+
let mut traits = where_clauses.values()
371+
.filter_map(|span| snippet_opt(cx, *span))
372+
.collect::<Vec<_>>();
373+
traits.sort_unstable();
374+
let traits = traits.join(" + ");
375+
span_lint_and_sugg(
376+
cx,
377+
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
378+
all_trait_span,
379+
"this where clause has already been specified",
380+
"try",
381+
traits,
382+
Applicability::MachineApplicable
383+
);
384+
}
335385
}
336386
}
337387
}
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)