@@ -8,8 +8,8 @@ use rustc_data_structures::unhash::UnhashMap;
88use rustc_errors:: Applicability ;
99use rustc_hir:: def:: Res ;
1010use 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 ,
1313} ;
1414use rustc_lint:: { LateContext , LateLintPass } ;
1515use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -289,44 +289,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
289289 }
290290}
291291
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 > ) ;
328294
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 ( ) {
330297 return ;
331298 }
332299
@@ -355,3 +322,76 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'
355322 None
356323 }
357324}
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