Skip to content

Commit f690978

Browse files
committed
cover trait for trait_duplication_in_bounds
1 parent 83a9f68 commit f690978

File tree

3 files changed

+128
-11
lines changed

3 files changed

+128
-11
lines changed

clippy_lints/src/trait_bounds.rs

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
33
use clippy_utils::{SpanlessEq, SpanlessHash};
44
use core::hash::{Hash, Hasher};
55
use if_chain::if_chain;
6-
use rustc_data_structures::fx::FxHashMap;
6+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
77
use rustc_data_structures::unhash::UnhashMap;
88
use rustc_errors::Applicability;
9-
use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, Ty, TyKind, WherePredicate};
9+
use rustc_hir::def::Res;
10+
use rustc_hir::{
11+
GenericBound, Generics, Item, ItemKind, Node, ParamName, Path, PathSegment, QPath, TraitItem, Ty, TyKind,
12+
WherePredicate,
13+
};
1014
use rustc_lint::{LateContext, LateLintPass};
1115
use rustc_session::{declare_tool_lint, impl_lint_pass};
1216
use rustc_span::Span;
@@ -84,6 +88,46 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
8488
self.check_type_repetition(cx, gen);
8589
check_trait_bound_duplication(cx, gen);
8690
}
91+
92+
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
93+
let Generics { where_clause, .. } = &item.generics;
94+
let mut self_bounds_set = FxHashSet::default();
95+
96+
for predicate in where_clause.predicates {
97+
if_chain! {
98+
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
99+
if !bound_predicate.span.from_expansion();
100+
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
101+
if let Some(PathSegment { res: Some(Res::SelfTy(Some(def_id), _)), .. }) = segments.first();
102+
103+
if let Some(
104+
Node::Item(
105+
Item {
106+
kind: ItemKind::Trait(_, _, _, self_bounds, _),
107+
.. }
108+
)
109+
) = cx.tcx.hir().get_if_local(*def_id);
110+
then {
111+
if self_bounds_set.is_empty() {
112+
for bound in self_bounds.iter() {
113+
let Some((self_res, _)) = get_trait_res_span_from_bound(bound) else { continue };
114+
self_bounds_set.insert(self_res);
115+
}
116+
}
117+
118+
bound_predicate
119+
.bounds
120+
.iter()
121+
.filter_map(get_trait_res_span_from_bound)
122+
.for_each(|(trait_item_res, span)| {
123+
if self_bounds_set.get(&trait_item_res).is_some() {
124+
emit_lint(cx, span);
125+
}
126+
});
127+
}
128+
}
129+
}
130+
}
87131
}
88132

89133
fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)> {
@@ -198,17 +242,21 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
198242
if let Some((_, span_direct)) = trait_resolutions_direct
199243
.iter()
200244
.find(|(res_direct, _)| *res_direct == res_where) {
201-
span_lint_and_help(
202-
cx,
203-
TRAIT_DUPLICATION_IN_BOUNDS,
204-
*span_direct,
205-
"this trait bound is already specified in the where clause",
206-
None,
207-
"consider removing this trait bound",
208-
);
245+
emit_lint(cx, *span_direct);
209246
}
210247
}
211248
}
212249
}
213250
}
214251
}
252+
253+
fn emit_lint(cx: &LateContext<'_>, span: Span) {
254+
span_lint_and_help(
255+
cx,
256+
TRAIT_DUPLICATION_IN_BOUNDS,
257+
span,
258+
"this trait bound is already specified in the where clause",
259+
None,
260+
"consider removing this trait bound",
261+
);
262+
}

tests/ui/trait_duplication_in_bounds.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,41 @@ where
2828
unimplemented!();
2929
}
3030

31+
trait T: Default {
32+
fn f()
33+
where
34+
Self: Default;
35+
}
36+
37+
trait U: Default {
38+
fn f()
39+
where
40+
Self: Clone;
41+
}
42+
43+
trait ZZ: Default {
44+
fn f()
45+
where
46+
Self: Default + Clone;
47+
}
48+
49+
trait BadTrait: Default + Clone {
50+
fn f()
51+
where
52+
Self: Default + Clone;
53+
}
54+
55+
#[derive(Default, Clone)]
56+
struct Life {}
57+
58+
impl T for Life {
59+
// this should not warn
60+
fn f() {}
61+
}
62+
63+
impl U for Life {
64+
// this should not warn
65+
fn f() {}
66+
}
67+
3168
fn main() {}

tests/ui/trait_duplication_in_bounds.stderr

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,37 @@ LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
1919
|
2020
= help: consider removing this trait bound
2121

22-
error: aborting due to 2 previous errors
22+
error: this trait bound is already specified in the where clause
23+
--> $DIR/trait_duplication_in_bounds.rs:34:15
24+
|
25+
LL | Self: Default;
26+
| ^^^^^^^
27+
|
28+
= help: consider removing this trait bound
29+
30+
error: this trait bound is already specified in the where clause
31+
--> $DIR/trait_duplication_in_bounds.rs:46:15
32+
|
33+
LL | Self: Default + Clone;
34+
| ^^^^^^^
35+
|
36+
= help: consider removing this trait bound
37+
38+
error: this trait bound is already specified in the where clause
39+
--> $DIR/trait_duplication_in_bounds.rs:52:15
40+
|
41+
LL | Self: Default + Clone;
42+
| ^^^^^^^
43+
|
44+
= help: consider removing this trait bound
45+
46+
error: this trait bound is already specified in the where clause
47+
--> $DIR/trait_duplication_in_bounds.rs:52:25
48+
|
49+
LL | Self: Default + Clone;
50+
| ^^^^^
51+
|
52+
= help: consider removing this trait bound
53+
54+
error: aborting due to 6 previous errors
2355

0 commit comments

Comments
 (0)