@@ -8,7 +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 , Path , PathSegment , QPath , TraitItem , Ty , TyKind , WherePredicate ,
11+ GenericArg , GenericBound , GenericBound , Generics , Item , ItemKind , Node , ParamName , Path , PathSegment , QPath ,
12+ TraitItem , Ty , TyKind , WherePredicate ,
1213} ;
1314use rustc_lint:: { LateContext , LateLintPass } ;
1415use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -280,44 +281,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
280281 }
281282}
282283
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( " + " ) ;
306-
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- }
284+ #[ derive( PartialEq , Eq , Hash , Debug ) ]
285+ struct ComparableBound ( Res , Vec < Res > , Vec < ComparableBound > ) ;
319286
320- if gen. span . from_expansion ( ) || ( gen. params . is_empty ( ) && gen. where_clause . predicates . is_empty ( ) ) {
287+ fn check_bounds_or_where_duplication ( cx : & LateContext < ' _ > , gen : & ' _ Generics < ' _ > ) {
288+ if gen. span . from_expansion ( ) {
321289 return ;
322290 }
323291
@@ -346,3 +314,76 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'
346314 None
347315 }
348316}
317+
318+ fn try_into_comparable_bound ( bound : & GenericBound < ' _ > ) -> Option < ComparableBound > {
319+ if let GenericBound :: Trait ( t, _) = bound {
320+ Some ( ComparableBound (
321+ t. trait_ref . path . res ,
322+ t. trait_ref
323+ . path
324+ . segments
325+ . iter ( )
326+ . filter_map ( |segment| {
327+ // get trait bound type arguments
328+ Some ( segment. args ?. args . iter ( ) . filter_map ( |arg| {
329+ if_chain ! {
330+ if let GenericArg :: Type ( ty) = arg;
331+ if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = ty. kind;
332+ then { return Some ( path. res) }
333+ }
334+ None
335+ } ) )
336+ } )
337+ . flatten ( )
338+ . collect ( ) ,
339+ t. bound_generic_params
340+ . iter ( )
341+ . flat_map ( |param| param. bounds . iter ( ) . filter_map ( try_into_comparable_bound) )
342+ . collect ( ) ,
343+ ) )
344+ } else {
345+ None
346+ }
347+ }
348+
349+ fn rollup_traits ( cx : & LateContext < ' _ > , bounds : & [ GenericBound < ' _ > ] , msg : & str ) {
350+ let mut map = FxHashMap :: default ( ) ;
351+ let mut repeated_spans = false ;
352+ for bound in bounds. iter ( ) . filter_map ( |bound| {
353+ if let GenericBound :: Trait ( t, _) = bound {
354+ Some ( ( try_into_comparable_bound ( bound) ?, t. span ) )
355+ } else {
356+ None
357+ }
358+ } ) {
359+ let ( comparable_bound, span_direct) = bound;
360+ if map. insert ( comparable_bound, span_direct) . is_some ( ) {
361+ repeated_spans = true ;
362+ }
363+ }
364+
365+ if_chain ! {
366+ if repeated_spans;
367+ if let Some ( first_trait) = bounds. get( 0 ) ;
368+ if let Some ( last_trait) = bounds. iter( ) . last( ) ;
369+ then {
370+ let all_trait_span = first_trait. span( ) . to( last_trait. span( ) ) ;
371+
372+ let mut traits = map. values( )
373+ . filter_map( |span| snippet_opt( cx, * span) )
374+ . collect:: <Vec <_>>( ) ;
375+ traits. sort_unstable( ) ;
376+ let traits = traits. join( " + " ) ;
377+
378+ span_lint_and_sugg(
379+ cx,
380+ REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND ,
381+ all_trait_span,
382+ msg,
383+ "try" ,
384+ traits,
385+ Applicability :: MachineApplicable
386+ ) ;
387+ }
388+ }
389+ }
0 commit comments