@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet, snippet_opt, 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 ;
6
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
7
7
use rustc_data_structures:: unhash:: UnhashMap ;
8
8
use rustc_errors:: Applicability ;
9
9
use rustc_hir:: def:: Res ;
@@ -262,30 +262,43 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
262
262
return ;
263
263
}
264
264
265
- let mut map = FxHashMap :: < _ , Vec < _ > > :: default ( ) ;
266
- for predicate in gen. predicates {
265
+ let where_predicates = gen
266
+ . predicates
267
+ . iter ( )
268
+ . filter_map ( |pred| {
269
+ if_chain ! {
270
+ if pred. in_where_clause( ) ;
271
+ if let WherePredicate :: BoundPredicate ( bound) = pred;
272
+ if let Ty { kind: TyKind :: Path ( QPath :: Resolved ( _, path, ..) ) , ..} = bound. bounded_ty;
273
+ then {
274
+ return Some ( bound. bounds. iter( ) . filter_map( |t| {
275
+ Some ( ( path. res, into_comparable_trait_ref( t. trait_ref( ) ?) ) )
276
+ } ) )
277
+ }
278
+ }
279
+ None
280
+ } )
281
+ . flatten ( )
282
+ . collect :: < FxHashSet < _ > > ( ) ;
283
+
284
+ for predicate in gen. predicates . iter ( ) . filter ( |pred| !pred. in_where_clause ( ) ) {
267
285
if_chain ! {
268
- if let WherePredicate :: BoundPredicate ( ref bound_predicate) = predicate;
269
- if !bound_predicate. span. from_expansion( ) ;
270
- if let TyKind :: Path ( QPath :: Resolved ( _, Path { segments, .. } ) ) = bound_predicate. bounded_ty. kind;
271
- if let Some ( segment) = segments. first( ) ;
286
+ if let WherePredicate :: BoundPredicate ( bound) = predicate;
287
+ if let Ty { kind: TyKind :: Path ( QPath :: Resolved ( _, path, ..) ) , ..} = bound. bounded_ty;
272
288
then {
273
- for ( res_where, _, span_where) in bound_predicate. bounds. iter( ) . filter_map( get_trait_info_from_bound) {
274
- let trait_resolutions_direct = map. entry( segment. ident) . or_default( ) ;
275
- if let Some ( ( _, span_direct) ) = trait_resolutions_direct
276
- . iter( )
277
- . find( |( res_direct, _) | * res_direct == res_where) {
278
- span_lint_and_help(
279
- cx,
280
- TRAIT_DUPLICATION_IN_BOUNDS ,
281
- * span_direct,
282
- "this trait bound is already specified in the where clause" ,
283
- None ,
284
- "consider removing this trait bound" ,
285
- ) ;
286
- }
287
- else {
288
- trait_resolutions_direct. push( ( res_where, span_where) ) ;
289
+ for t in bound. bounds {
290
+ if let Some ( trait_ref) = t. trait_ref( ) {
291
+ let key = ( path. res, into_comparable_trait_ref( trait_ref) ) ;
292
+ if where_predicates. contains( & key) {
293
+ span_lint_and_help(
294
+ cx,
295
+ TRAIT_DUPLICATION_IN_BOUNDS ,
296
+ t. span( ) ,
297
+ "this trait bound is already specified in the where clause" ,
298
+ None ,
299
+ "consider removing this trait bound" ,
300
+ ) ;
301
+ }
289
302
}
290
303
}
291
304
}
0 commit comments