@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
3
3
use clippy_utils:: { SpanlessEq , SpanlessHash } ;
4
4
use core:: hash:: { Hash , Hasher } ;
5
5
use if_chain:: if_chain;
6
- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
6
+ use rustc_data_structures:: fx:: FxHashMap ;
7
7
use rustc_data_structures:: unhash:: UnhashMap ;
8
8
use rustc_errors:: Applicability ;
9
9
use rustc_hir:: def:: Res ;
@@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
91
91
92
92
fn check_trait_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx TraitItem < ' tcx > ) {
93
93
let Generics { where_clause, .. } = & item. generics ;
94
- let mut self_bounds_set = FxHashSet :: default ( ) ;
94
+ let mut self_bounds_map = FxHashMap :: default ( ) ;
95
95
96
96
for predicate in where_clause. predicates {
97
97
if_chain ! {
@@ -108,27 +108,29 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
108
108
)
109
109
) = cx. tcx. hir( ) . get_if_local( * def_id) ;
110
110
then {
111
- if self_bounds_set . is_empty( ) {
111
+ if self_bounds_map . is_empty( ) {
112
112
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 ) ;
115
115
}
116
116
}
117
117
118
118
bound_predicate
119
119
. bounds
120
120
. 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
+ }
132
134
}
133
135
} ) ;
134
136
}
@@ -137,14 +139,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
137
139
}
138
140
}
139
141
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
-
148
142
impl TraitBounds {
149
143
fn check_type_repetition < ' tcx > ( self , cx : & LateContext < ' tcx > , gen : & ' tcx Generics < ' _ > ) {
150
144
struct SpanlessTy < ' cx , ' tcx > {
@@ -231,7 +225,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
231
225
let res = param
232
226
. bounds
233
227
. iter ( )
234
- . filter_map ( get_trait_res_span_from_bound )
228
+ . filter_map ( get_trait_info_from_bound )
235
229
. collect :: < Vec < _ > > ( ) ;
236
230
map. insert ( * ident, res) ;
237
231
}
@@ -245,10 +239,10 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
245
239
if let Some ( segment) = segments. first( ) ;
246
240
if let Some ( trait_resolutions_direct) = map. get( & segment. ident) ;
247
241
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
250
244
. iter( )
251
- . find( |( res_direct, _) | * res_direct == res_where) {
245
+ . find( |( res_direct, _, _ ) | * res_direct == res_where) {
252
246
span_lint_and_help(
253
247
cx,
254
248
TRAIT_DUPLICATION_IN_BOUNDS ,
@@ -263,3 +257,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
263
257
}
264
258
}
265
259
}
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