Skip to content

Commit db66322

Browse files
author
Allen Hsu
committed
Add repeated where clause or trait bound lint.
1 parent c7e6863 commit db66322

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
@@ -3552,6 +3552,7 @@ Released 2018-09-13
35523552
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
35533553
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
35543554
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
3555+
[`repeated_where_clause_or_trait_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeated_where_clause_or_trait_bound
35553556
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
35563557
[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
35573558
[`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
@@ -484,6 +484,7 @@ store.register_lints(&[
484484
temporary_assignment::TEMPORARY_ASSIGNMENT,
485485
to_digit_is_some::TO_DIGIT_IS_SOME,
486486
trailing_empty_array::TRAILING_EMPTY_ARRAY,
487+
trait_bounds::REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
487488
trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
488489
trait_bounds::TYPE_REPETITION_IN_BOUNDS,
489490
transmute::CROSSPOINTER_TRANSMUTE,

clippy_lints/src/lib.register_pedantic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
8383
LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
8484
LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
8585
LintId::of(strings::STRING_ADD_ASSIGN),
86+
LintId::of(trait_bounds::REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND),
8687
LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
8788
LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
8889
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),

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>) {
@@ -259,6 +289,53 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
259289
}
260290
}
261291

292+
fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
293+
if gen.span.from_expansion() {
294+
return;
295+
}
296+
297+
for param in gen.params {
298+
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+
);
310+
}
311+
}
312+
}
313+
}
314+
315+
for predicate in gen.where_clause.predicates {
316+
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate {
317+
let mut where_clauses = FxHashMap::default();
318+
for (definition, _, span_direct) in bound_predicate
319+
.bounds
320+
.iter()
321+
.filter_map(get_trait_info_from_bound)
322+
.rev()
323+
{
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+
);
333+
}
334+
}
335+
}
336+
}
337+
}
338+
262339
fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> {
263340
if let GenericBound::Trait(t, _) = bound {
264341
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)