Skip to content

Commit b3b7ed0

Browse files
committed
Auto merge of #5852 - wiomoc:feature/lint-duplicate-trait, r=Manishearth
Add lint for duplicate methods of trait bounds rel: #5777 changelog: Add [`trait_duplication_in_bounds`] lint
2 parents 2e0f8b6 + e521c67 commit b3b7ed0

File tree

6 files changed

+156
-2
lines changed

6 files changed

+156
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,7 @@ Released 2018-09-13
17231723
[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
17241724
[`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
17251725
[`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
1726+
[`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds
17261727
[`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
17271728
[`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int
17281729
[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
786786
&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
787787
&temporary_assignment::TEMPORARY_ASSIGNMENT,
788788
&to_digit_is_some::TO_DIGIT_IS_SOME,
789+
&trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
789790
&trait_bounds::TYPE_REPETITION_IN_BOUNDS,
790791
&transmute::CROSSPOINTER_TRANSMUTE,
791792
&transmute::TRANSMUTE_BYTES_TO_STR,
@@ -1174,6 +1175,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11741175
LintId::of(&ranges::RANGE_PLUS_ONE),
11751176
LintId::of(&shadow::SHADOW_UNRELATED),
11761177
LintId::of(&strings::STRING_ADD_ASSIGN),
1178+
LintId::of(&trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
11771179
LintId::of(&trait_bounds::TYPE_REPETITION_IN_BOUNDS),
11781180
LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),
11791181
LintId::of(&types::CAST_LOSSLESS),

clippy_lints/src/trait_bounds.rs

+92-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_
22
use if_chain::if_chain;
33
use rustc_data_structures::fx::FxHashMap;
44
use rustc_errors::Applicability;
5-
use rustc_hir::{GenericBound, Generics, WherePredicate};
5+
use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate};
66
use rustc_lint::{LateContext, LateLintPass};
77
use rustc_session::{declare_tool_lint, impl_lint_pass};
8+
use rustc_span::Span;
89

910
declare_clippy_lint! {
1011
/// **What it does:** This lint warns about unnecessary type repetitions in trait bounds
@@ -29,6 +30,35 @@ declare_clippy_lint! {
2930
"Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`"
3031
}
3132

33+
declare_clippy_lint! {
34+
/// **What it does:** Checks for cases where generics are being used and multiple
35+
/// syntax specifications for trait bounds are used simultaneously.
36+
///
37+
/// **Why is this bad?** Duplicate bounds makes the code
38+
/// less readable than specifing them only once.
39+
///
40+
/// **Known problems:** None.
41+
///
42+
/// **Example:**
43+
/// ```rust
44+
/// fn func<T: Clone + Default>(arg: T) where T: Clone + Default {}
45+
/// ```
46+
///
47+
/// Could be written as:
48+
///
49+
/// ```rust
50+
/// fn func<T: Clone + Default>(arg: T) {}
51+
/// ```
52+
/// or
53+
/// ///
54+
/// ```rust
55+
/// fn func<T>(arg: T) where T: Clone + Default {}
56+
/// ```
57+
pub TRAIT_DUPLICATION_IN_BOUNDS,
58+
pedantic,
59+
"Check if the same trait bounds are specified twice during a function declaration"
60+
}
61+
3262
#[derive(Copy, Clone)]
3363
pub struct TraitBounds {
3464
max_trait_bounds: u64,
@@ -41,10 +71,25 @@ impl TraitBounds {
4171
}
4272
}
4373

44-
impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS]);
74+
impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS]);
4575

4676
impl<'tcx> LateLintPass<'tcx> for TraitBounds {
4777
fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
78+
self.check_type_repetition(cx, gen);
79+
check_trait_bound_duplication(cx, gen);
80+
}
81+
}
82+
83+
fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)> {
84+
if let GenericBound::Trait(t, _) = bound {
85+
Some((t.trait_ref.path.res, t.span))
86+
} else {
87+
None
88+
}
89+
}
90+
91+
impl TraitBounds {
92+
fn check_type_repetition(self, cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
4893
if in_macro(gen.span) {
4994
return;
5095
}
@@ -101,3 +146,48 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
101146
}
102147
}
103148
}
149+
150+
fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
151+
if in_macro(gen.span) || gen.params.is_empty() || gen.where_clause.predicates.is_empty() {
152+
return;
153+
}
154+
155+
let mut map = FxHashMap::default();
156+
for param in gen.params {
157+
if let ParamName::Plain(ref ident) = param.name {
158+
let res = param
159+
.bounds
160+
.iter()
161+
.filter_map(get_trait_res_span_from_bound)
162+
.collect::<Vec<_>>();
163+
map.insert(*ident, res);
164+
}
165+
}
166+
167+
for predicate in gen.where_clause.predicates {
168+
if_chain! {
169+
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
170+
if !in_macro(bound_predicate.span);
171+
if let TyKind::Path(ref path) = bound_predicate.bounded_ty.kind;
172+
if let QPath::Resolved(_, Path { ref segments, .. }) = path;
173+
if let Some(segment) = segments.first();
174+
if let Some(trait_resolutions_direct) = map.get(&segment.ident);
175+
then {
176+
for (res_where, _) in bound_predicate.bounds.iter().filter_map(get_trait_res_span_from_bound) {
177+
if let Some((_, span_direct)) = trait_resolutions_direct
178+
.iter()
179+
.find(|(res_direct, _)| *res_direct == res_where) {
180+
span_lint_and_help(
181+
cx,
182+
TRAIT_DUPLICATION_IN_BOUNDS,
183+
*span_direct,
184+
"this trait bound is already specified in the where clause",
185+
None,
186+
"consider removing this trait bound",
187+
);
188+
}
189+
}
190+
}
191+
}
192+
}
193+
}

src/lintlist/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -2166,6 +2166,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
21662166
deprecation: None,
21672167
module: "misc",
21682168
},
2169+
Lint {
2170+
name: "trait_duplication_in_bounds",
2171+
group: "pedantic",
2172+
desc: "Check if the same trait bounds are specified twice during a function declaration",
2173+
deprecation: None,
2174+
module: "trait_bounds",
2175+
},
21692176
Lint {
21702177
name: "transmute_bytes_to_str",
21712178
group: "complexity",
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#![deny(clippy::trait_duplication_in_bounds)]
2+
3+
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
4+
5+
fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
6+
where
7+
T: Clone,
8+
T: Default,
9+
{
10+
unimplemented!();
11+
}
12+
13+
fn good_bar<T: Clone + Default>(arg: T) {
14+
unimplemented!();
15+
}
16+
17+
fn good_foo<T>(arg: T)
18+
where
19+
T: Clone + Default,
20+
{
21+
unimplemented!();
22+
}
23+
24+
fn good_foobar<T: Default>(arg: T)
25+
where
26+
T: Clone,
27+
{
28+
unimplemented!();
29+
}
30+
31+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error: this trait bound is already specified in the where clause
2+
--> $DIR/trait_duplication_in_bounds.rs:5:15
3+
|
4+
LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
5+
| ^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/trait_duplication_in_bounds.rs:1:9
9+
|
10+
LL | #![deny(clippy::trait_duplication_in_bounds)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
= help: consider removing this trait bound
13+
14+
error: this trait bound is already specified in the where clause
15+
--> $DIR/trait_duplication_in_bounds.rs:5:23
16+
|
17+
LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
18+
| ^^^^^^^
19+
|
20+
= help: consider removing this trait bound
21+
22+
error: aborting due to 2 previous errors
23+

0 commit comments

Comments
 (0)