@@ -69,6 +69,35 @@ declare_clippy_lint! {
69
69
"Check if the same trait bounds are specified twice during a function declaration"
70
70
}
71
71
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
+
72
101
#[ derive( Copy , Clone ) ]
73
102
pub struct TraitBounds {
74
103
max_trait_bounds : u64 ,
@@ -81,12 +110,13 @@ impl TraitBounds {
81
110
}
82
111
}
83
112
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 ] ) ;
85
114
86
115
impl < ' tcx > LateLintPass < ' tcx > for TraitBounds {
87
116
fn check_generics ( & mut self , cx : & LateContext < ' tcx > , gen : & ' tcx Generics < ' _ > ) {
88
117
self . check_type_repetition ( cx, gen) ;
89
118
check_trait_bound_duplication ( cx, gen) ;
119
+ check_bounds_or_where_duplication ( cx, gen) ;
90
120
}
91
121
92
122
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<'_>) {
259
289
}
260
290
}
261
291
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
+
262
339
fn get_trait_info_from_bound < ' a > ( bound : & ' a GenericBound < ' _ > ) -> Option < ( Res , & ' a [ PathSegment < ' a > ] , Span ) > {
263
340
if let GenericBound :: Trait ( t, _) = bound {
264
341
Some ( ( t. trait_ref . path . res , t. trait_ref . path . segments , t. span ) )
0 commit comments