Skip to content

Commit d20642e

Browse files
author
Allen Hsu
committed
Add repeated where clause or trait bound lint.
1 parent 526f02e commit d20642e

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
@@ -3861,6 +3861,7 @@ Released 2018-09-13
38613861
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
38623862
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
38633863
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
3864+
[`repeated_where_clauses_or_trait_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeated_where_clauses_or_trait_bounds
38643865
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
38653866
[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
38663867
[`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
@@ -516,6 +516,7 @@ store.register_lints(&[
516516
temporary_assignment::TEMPORARY_ASSIGNMENT,
517517
to_digit_is_some::TO_DIGIT_IS_SOME,
518518
trailing_empty_array::TRAILING_EMPTY_ARRAY,
519+
trait_bounds::REPEATED_WHERE_CLAUSES_OR_TRAIT_BOUNDS,
519520
trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
520521
trait_bounds::TYPE_REPETITION_IN_BOUNDS,
521522
transmute::CROSSPOINTER_TRANSMUTE,

clippy_lints/src/lib.register_pedantic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
8686
LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
8787
LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
8888
LintId::of(strings::STRING_ADD_ASSIGN),
89+
LintId::of(trait_bounds::REPEATED_WHERE_CLAUSES_OR_TRAIT_BOUNDS),
8990
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
9091
LintId::of(types::LINKEDLIST),
9192
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
@@ -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_CLAUSES_OR_TRAIT_BOUNDS,
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_CLAUSES_OR_TRAIT_BOUNDS]);
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>) {
@@ -241,6 +271,53 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
241271
}
242272
}
243273

274+
fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
275+
if gen.span.from_expansion() {
276+
return;
277+
}
278+
279+
for param in gen.params {
280+
let mut map = FxHashMap::default();
281+
if let ParamName::Plain(name) = param.name {
282+
for (definition, _, span_direct) in param.bounds.iter().rev().filter_map(get_trait_info_from_bound) {
283+
if let Some(span_direct) = map.insert((name, definition), span_direct) {
284+
span_lint_and_help(
285+
cx,
286+
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
287+
span_direct,
288+
"this trait bound has already been specified",
289+
None,
290+
"consider removing this trait bound",
291+
);
292+
}
293+
}
294+
}
295+
}
296+
297+
for predicate in gen.where_clause.predicates {
298+
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate {
299+
let mut where_clauses = FxHashMap::default();
300+
for (definition, _, span_direct) in bound_predicate
301+
.bounds
302+
.iter()
303+
.filter_map(get_trait_info_from_bound)
304+
.rev()
305+
{
306+
if let Some(span_direct) = where_clauses.insert(definition, span_direct) {
307+
span_lint_and_help(
308+
cx,
309+
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
310+
span_direct,
311+
"this where clause has already been specified",
312+
None,
313+
"consider removing this where clause",
314+
);
315+
}
316+
}
317+
}
318+
}
319+
}
320+
244321
fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> {
245322
if let GenericBound::Trait(t, tbm) = bound {
246323
let trait_path = t.trait_ref.path;
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)