@@ -8,7 +8,8 @@ use rustc_data_structures::unhash::UnhashMap;
8
8
use rustc_errors:: Applicability ;
9
9
use rustc_hir:: def:: Res ;
10
10
use rustc_hir:: {
11
- GenericBound , Generics , Item , ItemKind , Node , Path , PathSegment , QPath , TraitItem , Ty , TyKind , WherePredicate ,
11
+ GenericArg , GenericBound , Generics , Item , ItemKind , Node , Path , PathSegment , QPath , TraitItem , Ty , TyKind ,
12
+ WherePredicate ,
12
13
} ;
13
14
use rustc_lint:: { LateContext , LateLintPass } ;
14
15
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -94,7 +95,7 @@ declare_clippy_lint! {
94
95
/// ```
95
96
#[ clippy:: version = "1.62.0" ]
96
97
pub REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND ,
97
- pedantic ,
98
+ nursery ,
98
99
"Traits are repeated within trait bounds or where clause"
99
100
}
100
101
@@ -280,61 +281,26 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
280
281
}
281
282
}
282
283
283
- fn check_bounds_or_where_duplication ( cx : & LateContext < ' _ > , gen : & ' _ Generics < ' _ > ) {
284
- fn rollup_traits ( cx : & LateContext < ' _ > , bounds : & [ GenericBound < ' _ > ] , msg : & str ) {
285
- let mut map = FxHashMap :: default ( ) ;
286
- let mut repeated_spans = false ;
287
- for bound in bounds. iter ( ) . filter_map ( get_trait_info_from_bound) {
288
- let ( definition, _, span_direct) = bound;
289
- if map. insert ( definition, span_direct) . is_some ( ) {
290
- repeated_spans = true ;
291
- }
292
- }
293
-
294
- if_chain ! {
295
- if repeated_spans;
296
- if let Some ( first_trait) = bounds. get( 0 ) ;
297
- if let Some ( last_trait) = bounds. iter( ) . last( ) ;
298
- then {
299
- let all_trait_span = first_trait. span( ) . to( last_trait. span( ) ) ;
300
-
301
- let mut traits = map. values( )
302
- . filter_map( |span| snippet_opt( cx, * span) )
303
- . collect:: <Vec <_>>( ) ;
304
- traits. sort_unstable( ) ;
305
- let traits = traits. join( " + " ) ;
284
+ #[ derive( PartialEq , Eq , Hash , Debug ) ]
285
+ struct ComparableBound (
286
+ Res ,
287
+ Vec < Res > ,
288
+ // Vec<ComparableBound>
289
+ ) ;
306
290
307
- span_lint_and_sugg(
308
- cx,
309
- REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND ,
310
- all_trait_span,
311
- msg,
312
- "try" ,
313
- traits,
314
- Applicability :: MachineApplicable
315
- ) ;
316
- }
317
- }
318
- }
319
-
320
- if gen. span . from_expansion ( ) || ( gen. params . is_empty ( ) && gen. where_clause . predicates . is_empty ( ) ) {
291
+ fn check_bounds_or_where_duplication ( cx : & LateContext < ' _ > , gen : & ' _ Generics < ' _ > ) {
292
+ if gen. span . from_expansion ( ) {
321
293
return ;
322
294
}
323
295
324
- for param in gen. params {
325
- if let ParamName :: Plain ( _) = param. name {
326
- // other alternatives are errors and elided which won't have duplicates
327
- rollup_traits ( cx, param. bounds , "this trait bound contains repeated elements" ) ;
328
- }
329
- }
330
-
331
- for predicate in gen. where_clause . predicates {
296
+ for predicate in gen. predicates {
332
297
if let WherePredicate :: BoundPredicate ( ref bound_predicate) = predicate {
333
- rollup_traits (
334
- cx,
335
- bound_predicate. bounds ,
336
- "this where clause contains repeated elements" ,
337
- ) ;
298
+ let msg = if predicate. in_where_clause ( ) {
299
+ "these where clauses contain repeated elements"
300
+ } else {
301
+ "these bounds contain repeated elements"
302
+ } ;
303
+ rollup_traits ( cx, bound_predicate. bounds , msg) ;
338
304
}
339
305
}
340
306
}
@@ -346,3 +312,76 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'
346
312
None
347
313
}
348
314
}
315
+
316
+ fn try_into_comparable_bound ( bound : & GenericBound < ' _ > ) -> Option < ComparableBound > {
317
+ if let GenericBound :: Trait ( t, _) = bound {
318
+ Some ( ComparableBound (
319
+ t. trait_ref . path . res ,
320
+ t. trait_ref
321
+ . path
322
+ . segments
323
+ . iter ( )
324
+ . filter_map ( |segment| {
325
+ // get trait bound type arguments
326
+ Some ( segment. args ?. args . iter ( ) . filter_map ( |arg| {
327
+ if_chain ! {
328
+ if let GenericArg :: Type ( ty) = arg;
329
+ if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = ty. kind;
330
+ then { return Some ( path. res) }
331
+ }
332
+ None
333
+ } ) )
334
+ } )
335
+ . flatten ( )
336
+ . collect ( ) ,
337
+ // t.bound_generic_params
338
+ // .iter()
339
+ // .flat_map(|param| param.bounds.iter().filter_map(try_into_comparable_bound))
340
+ // .collect(),
341
+ ) )
342
+ } else {
343
+ None
344
+ }
345
+ }
346
+
347
+ fn rollup_traits ( cx : & LateContext < ' _ > , bounds : & [ GenericBound < ' _ > ] , msg : & str ) {
348
+ let mut map = FxHashMap :: default ( ) ;
349
+ let mut repeated_spans = false ;
350
+ for bound in bounds. iter ( ) . filter_map ( |bound| {
351
+ if let GenericBound :: Trait ( t, _) = bound {
352
+ Some ( ( try_into_comparable_bound ( bound) ?, t. span ) )
353
+ } else {
354
+ None
355
+ }
356
+ } ) {
357
+ let ( comparable_bound, span_direct) = bound;
358
+ if map. insert ( comparable_bound, span_direct) . is_some ( ) {
359
+ repeated_spans = true ;
360
+ }
361
+ }
362
+
363
+ if_chain ! {
364
+ if repeated_spans;
365
+ if let Some ( first_trait) = bounds. get( 0 ) ;
366
+ if let Some ( last_trait) = bounds. iter( ) . last( ) ;
367
+ then {
368
+ let all_trait_span = first_trait. span( ) . to( last_trait. span( ) ) ;
369
+
370
+ let mut traits = map. values( )
371
+ . filter_map( |span| snippet_opt( cx, * span) )
372
+ . collect:: <Vec <_>>( ) ;
373
+ traits. sort_unstable( ) ;
374
+ let traits = traits. join( " + " ) ;
375
+
376
+ span_lint_and_sugg(
377
+ cx,
378
+ REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND ,
379
+ all_trait_span,
380
+ msg,
381
+ "try" ,
382
+ traits,
383
+ Applicability :: MachineApplicable
384
+ ) ;
385
+ }
386
+ }
387
+ }
0 commit comments