@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
33use clippy_utils:: { SpanlessEq , SpanlessHash } ;
44use core:: hash:: { Hash , Hasher } ;
55use if_chain:: if_chain;
6- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
6+ use rustc_data_structures:: fx:: FxHashMap ;
77use rustc_data_structures:: unhash:: UnhashMap ;
88use rustc_errors:: Applicability ;
99use rustc_hir:: def:: Res ;
@@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
9191
9292 fn check_trait_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx TraitItem < ' tcx > ) {
9393 let Generics { where_clause, .. } = & item. generics ;
94- let mut self_bounds_set = FxHashSet :: default ( ) ;
94+ let mut self_bounds_map = FxHashMap :: default ( ) ;
9595
9696 for predicate in where_clause. predicates {
9797 if_chain ! {
@@ -108,27 +108,29 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
108108 )
109109 ) = cx. tcx. hir( ) . get_if_local( * def_id) ;
110110 then {
111- if self_bounds_set . is_empty( ) {
111+ if self_bounds_map . is_empty( ) {
112112 for bound in self_bounds. iter( ) {
113- let Some ( ( self_res, _) ) = get_trait_res_span_from_bound ( bound) else { continue } ;
114- self_bounds_set . insert( self_res) ;
113+ let Some ( ( self_res, self_segments , _) ) = get_trait_info_from_bound ( bound) else { continue } ;
114+ self_bounds_map . insert( self_res, self_segments ) ;
115115 }
116116 }
117117
118118 bound_predicate
119119 . bounds
120120 . iter( )
121- . filter_map( get_trait_res_span_from_bound)
122- . for_each( |( trait_item_res, span) | {
123- if self_bounds_set. get( & trait_item_res) . is_some( ) {
124- span_lint_and_help(
125- cx,
126- TRAIT_DUPLICATION_IN_BOUNDS ,
127- span,
128- "this trait bound is already specified in trait declaration" ,
129- None ,
130- "consider removing this trait bound" ,
131- ) ;
121+ . filter_map( get_trait_info_from_bound)
122+ . for_each( |( trait_item_res, trait_item_segments, span) | {
123+ if let Some ( self_segments) = self_bounds_map. get( & trait_item_res) {
124+ if SpanlessEq :: new( cx) . eq_path_segments( self_segments, trait_item_segments) {
125+ span_lint_and_help(
126+ cx,
127+ TRAIT_DUPLICATION_IN_BOUNDS ,
128+ span,
129+ "this trait bound is already specified in trait declaration" ,
130+ None ,
131+ "consider removing this trait bound" ,
132+ ) ;
133+ }
132134 }
133135 } ) ;
134136 }
@@ -137,14 +139,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
137139 }
138140}
139141
140- fn get_trait_res_span_from_bound ( bound : & GenericBound < ' _ > ) -> Option < ( Res , Span ) > {
141- if let GenericBound :: Trait ( t, _) = bound {
142- Some ( ( t. trait_ref . path . res , t. span ) )
143- } else {
144- None
145- }
146- }
147-
148142impl TraitBounds {
149143 fn check_type_repetition < ' tcx > ( self , cx : & LateContext < ' tcx > , gen : & ' tcx Generics < ' _ > ) {
150144 struct SpanlessTy < ' cx , ' tcx > {
@@ -231,7 +225,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
231225 let res = param
232226 . bounds
233227 . iter ( )
234- . filter_map ( get_trait_res_span_from_bound )
228+ . filter_map ( get_trait_info_from_bound )
235229 . collect :: < Vec < _ > > ( ) ;
236230 map. insert ( * ident, res) ;
237231 }
@@ -245,10 +239,10 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
245239 if let Some ( segment) = segments. first( ) ;
246240 if let Some ( trait_resolutions_direct) = map. get( & segment. ident) ;
247241 then {
248- for ( res_where, _) in bound_predicate. bounds. iter( ) . filter_map( get_trait_res_span_from_bound ) {
249- if let Some ( ( _, span_direct) ) = trait_resolutions_direct
242+ for ( res_where, _, _ ) in bound_predicate. bounds. iter( ) . filter_map( get_trait_info_from_bound ) {
243+ if let Some ( ( _, _ , span_direct) ) = trait_resolutions_direct
250244 . iter( )
251- . find( |( res_direct, _) | * res_direct == res_where) {
245+ . find( |( res_direct, _, _ ) | * res_direct == res_where) {
252246 span_lint_and_help(
253247 cx,
254248 TRAIT_DUPLICATION_IN_BOUNDS ,
@@ -263,3 +257,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
263257 }
264258 }
265259}
260+
261+ fn get_trait_info_from_bound < ' a > ( bound : & ' a GenericBound < ' _ > ) -> Option < ( Res , & ' a [ PathSegment < ' a > ] , Span ) > {
262+ if let GenericBound :: Trait ( t, _) = bound {
263+ Some ( ( t. trait_ref . path . res , t. trait_ref . path . segments , t. span ) )
264+ } else {
265+ None
266+ }
267+ }
0 commit comments