@@ -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 > ) {
@@ -250,6 +280,53 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
250
280
}
251
281
}
252
282
283
+ fn check_bounds_or_where_duplication ( cx : & LateContext < ' _ > , gen : & ' _ Generics < ' _ > ) {
284
+ if gen. span . from_expansion ( ) {
285
+ return ;
286
+ }
287
+
288
+ for param in gen. params {
289
+ let mut map = FxHashMap :: default ( ) ;
290
+ if let ParamName :: Plain ( name) = param. name {
291
+ for ( definition, _, span_direct) in param. bounds . iter ( ) . rev ( ) . filter_map ( get_trait_info_from_bound) {
292
+ if let Some ( span_direct) = map. insert ( ( name, definition) , span_direct) {
293
+ span_lint_and_help (
294
+ cx,
295
+ REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND ,
296
+ span_direct,
297
+ "this trait bound has already been specified" ,
298
+ None ,
299
+ "consider removing this trait bound" ,
300
+ ) ;
301
+ }
302
+ }
303
+ }
304
+ }
305
+
306
+ for predicate in gen. where_clause . predicates {
307
+ if let WherePredicate :: BoundPredicate ( ref bound_predicate) = predicate {
308
+ let mut where_clauses = FxHashMap :: default ( ) ;
309
+ for ( definition, _, span_direct) in bound_predicate
310
+ . bounds
311
+ . iter ( )
312
+ . filter_map ( get_trait_info_from_bound)
313
+ . rev ( )
314
+ {
315
+ if let Some ( span_direct) = where_clauses. insert ( definition, span_direct) {
316
+ span_lint_and_help (
317
+ cx,
318
+ REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND ,
319
+ span_direct,
320
+ "this where clause has already been specified" ,
321
+ None ,
322
+ "consider removing this where clause" ,
323
+ ) ;
324
+ }
325
+ }
326
+ }
327
+ }
328
+ }
329
+
253
330
fn get_trait_info_from_bound < ' a > ( bound : & ' a GenericBound < ' _ > ) -> Option < ( Res , & ' a [ PathSegment < ' a > ] , Span ) > {
254
331
if let GenericBound :: Trait ( t, _) = bound {
255
332
Some ( ( t. trait_ref . path . res , t. trait_ref . path . segments , t. span ) )
0 commit comments