Skip to content

Commit f2a383d

Browse files
author
Allen Hsu
committed
Add repeated where clause or trait bound lint.
1 parent 43756b6 commit f2a383d

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
@@ -3661,6 +3661,7 @@ Released 2018-09-13
36613661
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
36623662
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
36633663
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
3664+
[`repeated_where_clause_or_trait_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeated_where_clause_or_trait_bound
36643665
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
36653666
[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
36663667
[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ store.register_lints(&[
493493
temporary_assignment::TEMPORARY_ASSIGNMENT,
494494
to_digit_is_some::TO_DIGIT_IS_SOME,
495495
trailing_empty_array::TRAILING_EMPTY_ARRAY,
496+
trait_bounds::REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
496497
trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
497498
trait_bounds::TYPE_REPETITION_IN_BOUNDS,
498499
transmute::CROSSPOINTER_TRANSMUTE,

clippy_lints/src/lib.register_nursery.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
2828
LintId::of(strings::STRING_LIT_AS_BYTES),
2929
LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
3030
LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
31+
LintId::of(trait_bounds::REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND),
3132
LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
3233
LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
3334
LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR),

clippy_lints/src/trait_bounds.rs

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

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

84-
impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS]);
113+
impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS, REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND]);
85114

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

92122
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
@@ -250,6 +280,53 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
250280
}
251281
}
252282

283+
fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
284+
if gen.span.from_expansion() {
285+
return;
286+
}
287+
288+
for param in gen.params {
289+
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+
);
301+
}
302+
}
303+
}
304+
}
305+
306+
for predicate in gen.where_clause.predicates {
307+
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate {
308+
let mut where_clauses = FxHashMap::default();
309+
for (definition, _, span_direct) in bound_predicate
310+
.bounds
311+
.iter()
312+
.filter_map(get_trait_info_from_bound)
313+
.rev()
314+
{
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+
);
324+
}
325+
}
326+
}
327+
}
328+
}
329+
253330
fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> {
254331
if let GenericBound::Trait(t, _) = bound {
255332
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)