Skip to content

Commit c90f42a

Browse files
committed
uplift trait_duplication_in_bounds from clippy to rustc
1 parent 0e41c62 commit c90f42a

File tree

6 files changed

+106
-91
lines changed

6 files changed

+106
-91
lines changed

compiler/rustc_lint/src/builtin.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3140,3 +3140,101 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
31403140
}
31413141
}
31423142
}
3143+
3144+
declare_lint! {
3145+
/// ### what it does
3146+
/// checks for cases where generics are being used and multiple
3147+
/// syntax specifications for trait bounds are used simultaneously.
3148+
///
3149+
/// ### why is this bad?
3150+
/// duplicate bounds makes the code
3151+
/// less readable than specifing them only once.
3152+
///
3153+
/// ### example
3154+
/// ```rust
3155+
/// fn func<t: clone + default>(arg: t) where t: clone + default {}
3156+
/// ```
3157+
///
3158+
/// could be written as:
3159+
///
3160+
/// ```rust
3161+
/// fn func<T: Clone + Default>(arg: T) {}
3162+
/// ```
3163+
/// or
3164+
///
3165+
/// ```rust
3166+
/// fn func<T>(arg: T) where T: Clone + Default {}
3167+
/// ```
3168+
pub TRAIT_DUPLICATION_IN_BOUNDS,
3169+
Warn,
3170+
"Check if the same trait bounds are specified twice during a function declaration"
3171+
}
3172+
3173+
declare_lint_pass!(TraitDuplicationInBounds => [TRAIT_DUPLICATION_IN_BOUNDS]);
3174+
3175+
impl<'tcx> LateLintPass<'tcx> for TraitDuplicationInBounds {
3176+
fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx hir::Generics<'_>) {
3177+
fn get_trait_res_span_from_bound(bound: &hir::GenericBound<'_>) -> Option<(Res, Span)> {
3178+
if let hir::GenericBound::Trait(t, _) = bound {
3179+
Some((t.trait_ref.path.res, t.span))
3180+
} else {
3181+
None
3182+
}
3183+
}
3184+
if gen.span.from_expansion()
3185+
|| gen.params.is_empty()
3186+
|| gen.where_clause.predicates.is_empty()
3187+
{
3188+
return;
3189+
}
3190+
3191+
let mut map = FxHashMap::default();
3192+
for param in gen.params {
3193+
if let hir::ParamName::Plain(ref ident) = param.name {
3194+
let res = param
3195+
.bounds
3196+
.iter()
3197+
.filter_map(get_trait_res_span_from_bound)
3198+
.collect::<Vec<_>>();
3199+
map.insert(*ident, res);
3200+
}
3201+
}
3202+
3203+
for predicate in gen.where_clause.predicates {
3204+
if let hir::WherePredicate::BoundPredicate(ref bound_predicate) = predicate {
3205+
if !bound_predicate.span.from_expansion() {
3206+
if let hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { segments, .. })) =
3207+
bound_predicate.bounded_ty.kind
3208+
{
3209+
if let Some(segment) = segments.first() {
3210+
if let Some(trait_resolutions_direct) = map.get(&segment.ident) {
3211+
for (res_where, _) in bound_predicate
3212+
.bounds
3213+
.iter()
3214+
.filter_map(get_trait_res_span_from_bound)
3215+
{
3216+
if let Some((_, span_direct)) = trait_resolutions_direct
3217+
.iter()
3218+
.find(|(res_direct, _)| *res_direct == res_where)
3219+
{
3220+
cx.struct_span_lint(
3221+
TRAIT_DUPLICATION_IN_BOUNDS,
3222+
*span_direct,
3223+
|lint| {
3224+
lint.build(
3225+
"this trait bound is already specified in the where clause"
3226+
)
3227+
.help("consider removing this trait bound")
3228+
.emit()
3229+
},
3230+
);
3231+
}
3232+
}
3233+
}
3234+
}
3235+
}
3236+
}
3237+
}
3238+
}
3239+
}
3240+
}

compiler/rustc_lint/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ macro_rules! late_lint_mod_passes {
197197
// Depends on referenced function signatures in expressions
198198
MutableTransmutes: MutableTransmutes,
199199
TypeAliasBounds: TypeAliasBounds,
200+
TraitDuplicationInBounds: TraitDuplicationInBounds,
200201
TrivialConstraints: TrivialConstraints,
201202
TypeLimits: TypeLimits::new(),
202203
NonSnakeCase: NonSnakeCase,

src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs renamed to src/test/ui/lint/trait_duplication_in_bounds.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
#![deny(clippy::trait_duplication_in_bounds)]
1+
#![deny(trait_duplication_in_bounds)]
22

33
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
44

55
fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
6+
//~^ ERROR this trait bound is already specified in the where clause
7+
//~| ERROR this trait bound is already specified in the where clause
68
where
79
T: Clone,
810
T: Default,

src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr renamed to src/test/ui/lint/trait_duplication_in_bounds.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
77
note: the lint level is defined here
88
--> $DIR/trait_duplication_in_bounds.rs:1:9
99
|
10-
LL | #![deny(clippy::trait_duplication_in_bounds)]
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
10+
LL | #![deny(trait_duplication_in_bounds)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212
= help: consider removing this trait bound
1313

1414
error: this trait bound is already specified in the where clause

src/tools/clippy/clippy_lints/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
925925
temporary_assignment::TEMPORARY_ASSIGNMENT,
926926
to_digit_is_some::TO_DIGIT_IS_SOME,
927927
to_string_in_display::TO_STRING_IN_DISPLAY,
928-
trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
929928
trait_bounds::TYPE_REPETITION_IN_BOUNDS,
930929
transmute::CROSSPOINTER_TRANSMUTE,
931930
transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
@@ -1133,7 +1132,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11331132
LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
11341133
LintId::of(shadow::SHADOW_UNRELATED),
11351134
LintId::of(strings::STRING_ADD_ASSIGN),
1136-
LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
11371135
LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
11381136
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
11391137
LintId::of(types::LINKEDLIST),

src/tools/clippy/clippy_lints/src/trait_bounds.rs

Lines changed: 2 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_help;
22
use clippy_utils::source::{snippet, snippet_with_applicability};
33
use clippy_utils::{in_macro, SpanlessHash};
44
use if_chain::if_chain;
5-
use rustc_data_structures::fx::FxHashMap;
65
use rustc_data_structures::unhash::UnhashMap;
76
use rustc_errors::Applicability;
8-
use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate};
7+
use rustc_hir::{GenericBound, Generics, WherePredicate};
98
use rustc_lint::{LateContext, LateLintPass};
109
use rustc_session::{declare_tool_lint, impl_lint_pass};
11-
use rustc_span::Span;
1210

1311
declare_clippy_lint! {
1412
/// ### What it does
@@ -33,35 +31,6 @@ declare_clippy_lint! {
3331
"Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`"
3432
}
3533

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

77-
impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS]);
46+
impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS]);
7847

7948
impl<'tcx> LateLintPass<'tcx> for TraitBounds {
8049
fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
8150
self.check_type_repetition(cx, gen);
82-
check_trait_bound_duplication(cx, gen);
83-
}
84-
}
85-
86-
fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)> {
87-
if let GenericBound::Trait(t, _) = bound {
88-
Some((t.trait_ref.path.res, t.span))
89-
} else {
90-
None
9151
}
9252
}
9353

@@ -149,47 +109,3 @@ impl TraitBounds {
149109
}
150110
}
151111
}
152-
153-
fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
154-
if in_macro(gen.span) || gen.params.is_empty() || gen.where_clause.predicates.is_empty() {
155-
return;
156-
}
157-
158-
let mut map = FxHashMap::default();
159-
for param in gen.params {
160-
if let ParamName::Plain(ref ident) = param.name {
161-
let res = param
162-
.bounds
163-
.iter()
164-
.filter_map(get_trait_res_span_from_bound)
165-
.collect::<Vec<_>>();
166-
map.insert(*ident, res);
167-
}
168-
}
169-
170-
for predicate in gen.where_clause.predicates {
171-
if_chain! {
172-
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
173-
if !in_macro(bound_predicate.span);
174-
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
175-
if let Some(segment) = segments.first();
176-
if let Some(trait_resolutions_direct) = map.get(&segment.ident);
177-
then {
178-
for (res_where, _) in bound_predicate.bounds.iter().filter_map(get_trait_res_span_from_bound) {
179-
if let Some((_, span_direct)) = trait_resolutions_direct
180-
.iter()
181-
.find(|(res_direct, _)| *res_direct == res_where) {
182-
span_lint_and_help(
183-
cx,
184-
TRAIT_DUPLICATION_IN_BOUNDS,
185-
*span_direct,
186-
"this trait bound is already specified in the where clause",
187-
None,
188-
"consider removing this trait bound",
189-
);
190-
}
191-
}
192-
}
193-
}
194-
}
195-
}

0 commit comments

Comments
 (0)