Skip to content

Commit d305640

Browse files
author
Allen Hsu
committed
Add repeated where clause or trait bound lint.
1 parent 39231b4 commit d305640

File tree

6 files changed

+260
-1
lines changed

6 files changed

+260
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3692,6 +3692,7 @@ Released 2018-09-13
36923692
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
36933693
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
36943694
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
3695+
[`repeated_where_clauses_or_trait_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeated_where_clauses_or_trait_bounds
36953696
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
36963697
[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
36973698
[`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ store.register_lints(&[
500500
temporary_assignment::TEMPORARY_ASSIGNMENT,
501501
to_digit_is_some::TO_DIGIT_IS_SOME,
502502
trailing_empty_array::TRAILING_EMPTY_ARRAY,
503+
trait_bounds::REPEATED_WHERE_CLAUSES_OR_TRAIT_BOUNDS,
503504
trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
504505
trait_bounds::TYPE_REPETITION_IN_BOUNDS,
505506
transmute::CROSSPOINTER_TRANSMUTE,

clippy_lints/src/lib.register_pedantic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
8585
LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
8686
LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
8787
LintId::of(strings::STRING_ADD_ASSIGN),
88+
LintId::of(trait_bounds::REPEATED_WHERE_CLAUSES_OR_TRAIT_BOUNDS),
8889
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
8990
LintId::of(types::LINKEDLIST),
9091
LintId::of(types::OPTION_OPTION),

clippy_lints/src/trait_bounds.rs

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,35 @@ declare_clippy_lint! {
7070
"Check if the same trait bounds are specified twice during a function declaration"
7171
}
7272

73+
declare_clippy_lint! {
74+
/// ### What it does
75+
/// Checks for multiple instances of the same where clause or trait bound
76+
///
77+
/// ### Why is this bad?
78+
/// Adds to code noise
79+
///
80+
/// ### Example
81+
/// ```rust
82+
/// fn foo<T: Default + Default>(bar: T) {}
83+
/// ```
84+
/// Use instead:
85+
/// ```rust
86+
/// fn foo<T: Default>(bar: T) {}
87+
/// ```
88+
///
89+
/// ```rust
90+
/// fn foo<T>(bar: T) where T: Default + Default {}
91+
/// ```
92+
/// Use instead:
93+
/// ```rust
94+
/// fn foo<T>(bar: T) where T: Default {}
95+
/// ```
96+
#[clippy::version = "1.62.0"]
97+
pub REPEATED_WHERE_CLAUSES_OR_TRAIT_BOUNDS,
98+
pedantic,
99+
"Traits are repeated within trait bounds or where clause"
100+
}
101+
73102
#[derive(Copy, Clone)]
74103
pub struct TraitBounds {
75104
max_trait_bounds: u64,
@@ -82,12 +111,13 @@ impl TraitBounds {
82111
}
83112
}
84113

85-
impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS]);
114+
impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS, REPEATED_WHERE_CLAUSES_OR_TRAIT_BOUNDS]);
86115

87116
impl<'tcx> LateLintPass<'tcx> for TraitBounds {
88117
fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
89118
self.check_type_repetition(cx, gen);
90119
check_trait_bound_duplication(cx, gen);
120+
check_bounds_or_where_duplication(cx, gen);
91121
}
92122

93123
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
@@ -254,6 +284,53 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
254284
}
255285
}
256286

287+
fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
288+
if gen.span.from_expansion() {
289+
return;
290+
}
291+
292+
for param in gen.params {
293+
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+
);
305+
}
306+
}
307+
}
308+
}
309+
310+
for predicate in gen.where_clause.predicates {
311+
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate {
312+
let mut where_clauses = FxHashMap::default();
313+
for (definition, _, span_direct) in bound_predicate
314+
.bounds
315+
.iter()
316+
.filter_map(get_trait_info_from_bound)
317+
.rev()
318+
{
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+
);
328+
}
329+
}
330+
}
331+
}
332+
}
333+
257334
fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> {
258335
if let GenericBound::Trait(t, _) = bound {
259336
Some((t.trait_ref.path.res, t.trait_ref.path.segments, t.span))
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#![deny(clippy::repeated_where_clause_or_trait_bound)]
2+
3+
fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
4+
unimplemented!();
5+
}
6+
7+
fn bad_bar<T, U>(arg0: T, arg1: U)
8+
where
9+
T: Clone + Clone + Clone + Copy,
10+
U: Clone + Copy,
11+
{
12+
unimplemented!();
13+
}
14+
15+
fn good_bar<T: Clone + Copy, U: Clone + Copy>(arg0: T, arg1: U) {
16+
unimplemented!();
17+
}
18+
19+
fn good_foo<T, U>(arg0: T, arg1: U)
20+
where
21+
T: Clone + Copy,
22+
U: Clone + Copy,
23+
{
24+
unimplemented!();
25+
}
26+
27+
trait GoodSelfTraitBound: Clone + Copy {
28+
fn f();
29+
}
30+
31+
trait GoodSelfWhereClause {
32+
fn f()
33+
where
34+
Self: Clone + Copy;
35+
}
36+
37+
trait BadSelfTraitBound: Clone + Clone + Clone {
38+
fn f();
39+
}
40+
41+
trait BadSelfWhereClause {
42+
fn f()
43+
where
44+
Self: Clone + Clone + Clone;
45+
}
46+
47+
trait GoodTraitBound<T: Clone + Copy, U: Clone + Copy> {
48+
fn f();
49+
}
50+
51+
trait GoodWhereClause<T, U> {
52+
fn f()
53+
where
54+
T: Clone + Copy,
55+
U: Clone + Copy;
56+
}
57+
58+
trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
59+
fn f();
60+
}
61+
62+
trait BadWhereClause<T, U> {
63+
fn f()
64+
where
65+
T: Clone + Clone + Clone + Copy,
66+
U: Clone + Copy;
67+
}
68+
69+
struct GoodStructBound<T: Clone + Copy, U: Clone + Copy> {
70+
t: T,
71+
u: U,
72+
}
73+
74+
impl<T: Clone + Copy, U: Clone + Copy> GoodTraitBound<T, U> for GoodStructBound<T, U> {
75+
// this should not warn
76+
fn f() {}
77+
}
78+
79+
struct GoodStructWhereClause;
80+
81+
impl<T, U> GoodTraitBound<T, U> for GoodStructWhereClause
82+
where
83+
T: Clone + Copy,
84+
U: Clone + Copy,
85+
{
86+
// this should not warn
87+
fn f() {}
88+
}
89+
90+
fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
91+
92+
fn main() {}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
error: this trait bound has already been specified
2+
--> $DIR/repeated_where_clause_or_trait_bound.rs:3:31
3+
|
4+
LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
5+
| ^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/repeated_where_clause_or_trait_bound.rs:1:9
9+
|
10+
LL | #![deny(clippy::repeated_where_clause_or_trait_bound)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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
29+
30+
error: this where clause has already been specified
31+
--> $DIR/repeated_where_clause_or_trait_bound.rs:9:16
32+
|
33+
LL | T: Clone + Clone + Clone + Copy,
34+
| ^^^^^
35+
|
36+
= help: consider removing this where clause
37+
38+
error: this where clause has already been specified
39+
--> $DIR/repeated_where_clause_or_trait_bound.rs:44:31
40+
|
41+
LL | Self: Clone + Clone + Clone;
42+
| ^^^^^
43+
|
44+
= help: consider removing this where clause
45+
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
56+
|
57+
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
69+
70+
error: this where clause has already been specified
71+
--> $DIR/repeated_where_clause_or_trait_bound.rs:65:28
72+
|
73+
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
85+
86+
error: aborting due to 10 previous errors
87+

0 commit comments

Comments
 (0)