@@ -8,8 +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 , ParamName , Path , PathSegment , QPath , TraitItem , Ty , TyKind ,
12
- WherePredicate ,
11
+ GenericArg , GenericBound , Generics , Item , ItemKind , Node , ParamName , Path , PathSegment , QPath , TraitItem , Ty ,
12
+ TyKind , WherePredicate ,
13
13
} ;
14
14
use rustc_lint:: { LateContext , LateLintPass } ;
15
15
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -289,44 +289,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
289
289
}
290
290
}
291
291
292
- fn check_bounds_or_where_duplication ( cx : & LateContext < ' _ > , gen : & ' _ Generics < ' _ > ) {
293
- fn rollup_traits ( cx : & LateContext < ' _ > , bounds : & [ GenericBound < ' _ > ] , msg : & str ) {
294
- let mut map = FxHashMap :: default ( ) ;
295
- let mut repeated_spans = false ;
296
- for bound in bounds. iter ( ) . filter_map ( get_trait_info_from_bound) {
297
- let ( definition, _, span_direct) = bound;
298
- if map. insert ( definition, span_direct) . is_some ( ) {
299
- repeated_spans = true ;
300
- }
301
- }
302
-
303
- if_chain ! {
304
- if repeated_spans;
305
- if let Some ( first_trait) = bounds. get( 0 ) ;
306
- if let Some ( last_trait) = bounds. iter( ) . last( ) ;
307
- then {
308
- let all_trait_span = first_trait. span( ) . to( last_trait. span( ) ) ;
309
-
310
- let mut traits = map. values( )
311
- . filter_map( |span| snippet_opt( cx, * span) )
312
- . collect:: <Vec <_>>( ) ;
313
- traits. sort_unstable( ) ;
314
- let traits = traits. join( " + " ) ;
315
-
316
- span_lint_and_sugg(
317
- cx,
318
- REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND ,
319
- all_trait_span,
320
- msg,
321
- "try" ,
322
- traits,
323
- Applicability :: MachineApplicable
324
- ) ;
325
- }
326
- }
327
- }
292
+ #[ derive( PartialEq , Eq , Hash , Debug ) ]
293
+ struct ComparableBound ( Res , Vec < Res > , Vec < ComparableBound > ) ;
328
294
329
- if gen. span . from_expansion ( ) || ( gen. params . is_empty ( ) && gen. where_clause . predicates . is_empty ( ) ) {
295
+ fn check_bounds_or_where_duplication ( cx : & LateContext < ' _ > , gen : & ' _ Generics < ' _ > ) {
296
+ if gen. span . from_expansion ( ) {
330
297
return ;
331
298
}
332
299
@@ -355,3 +322,76 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'
355
322
None
356
323
}
357
324
}
325
+
326
+ fn try_into_comparable_bound ( bound : & GenericBound < ' _ > ) -> Option < ComparableBound > {
327
+ if let GenericBound :: Trait ( t, _) = bound {
328
+ Some ( ComparableBound (
329
+ t. trait_ref . path . res ,
330
+ t. trait_ref
331
+ . path
332
+ . segments
333
+ . iter ( )
334
+ . filter_map ( |segment| {
335
+ // get trait bound type arguments
336
+ Some ( segment. args ?. args . iter ( ) . filter_map ( |arg| {
337
+ if_chain ! {
338
+ if let GenericArg :: Type ( ty) = arg;
339
+ if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = ty. kind;
340
+ then { return Some ( path. res) }
341
+ }
342
+ None
343
+ } ) )
344
+ } )
345
+ . flatten ( )
346
+ . collect ( ) ,
347
+ t. bound_generic_params
348
+ . iter ( )
349
+ . flat_map ( |param| param. bounds . iter ( ) . filter_map ( try_into_comparable_bound) )
350
+ . collect ( ) ,
351
+ ) )
352
+ } else {
353
+ None
354
+ }
355
+ }
356
+
357
+ fn rollup_traits ( cx : & LateContext < ' _ > , bounds : & [ GenericBound < ' _ > ] , msg : & str ) {
358
+ let mut map = FxHashMap :: default ( ) ;
359
+ let mut repeated_spans = false ;
360
+ for bound in bounds. iter ( ) . filter_map ( |bound| {
361
+ if let GenericBound :: Trait ( t, _) = bound {
362
+ Some ( ( try_into_comparable_bound ( bound) ?, t. span ) )
363
+ } else {
364
+ None
365
+ }
366
+ } ) {
367
+ let ( comparable_bound, span_direct) = bound;
368
+ if map. insert ( comparable_bound, span_direct) . is_some ( ) {
369
+ repeated_spans = true ;
370
+ }
371
+ }
372
+
373
+ if_chain ! {
374
+ if repeated_spans;
375
+ if let Some ( first_trait) = bounds. get( 0 ) ;
376
+ if let Some ( last_trait) = bounds. iter( ) . last( ) ;
377
+ then {
378
+ let all_trait_span = first_trait. span( ) . to( last_trait. span( ) ) ;
379
+
380
+ let mut traits = map. values( )
381
+ . filter_map( |span| snippet_opt( cx, * span) )
382
+ . collect:: <Vec <_>>( ) ;
383
+ traits. sort_unstable( ) ;
384
+ let traits = traits. join( " + " ) ;
385
+
386
+ span_lint_and_sugg(
387
+ cx,
388
+ REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND ,
389
+ all_trait_span,
390
+ msg,
391
+ "try" ,
392
+ traits,
393
+ Applicability :: MachineApplicable
394
+ ) ;
395
+ }
396
+ }
397
+ }
0 commit comments