@@ -2,16 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_then;
2
2
use clippy_utils:: source:: snippet;
3
3
use rustc_errors:: { Applicability , SuggestionStyle } ;
4
4
use rustc_hir:: def_id:: DefId ;
5
- use rustc_hir:: intravisit:: FnKind ;
6
- use rustc_hir:: {
7
- Body , FnDecl , FnRetTy , GenericArg , GenericBound , ImplItem , ImplItemKind , ItemKind , OpaqueTy , TraitBoundModifier ,
8
- TraitItem , TraitItemKind , TyKind , TypeBinding ,
9
- } ;
5
+ use rustc_hir:: { GenericArg , GenericBound , GenericBounds , ItemKind , TraitBoundModifier , TyKind , TypeBinding } ;
10
6
use rustc_hir_analysis:: hir_ty_to_ty;
11
7
use rustc_lint:: { LateContext , LateLintPass } ;
12
8
use rustc_middle:: ty:: { self , ClauseKind , Generics , Ty , TyCtxt } ;
13
9
use rustc_session:: declare_lint_pass;
14
- use rustc_span:: def_id:: LocalDefId ;
15
10
use rustc_span:: Span ;
16
11
17
12
declare_clippy_lint ! {
@@ -54,7 +49,7 @@ declare_lint_pass!(ImpliedBoundsInImpls => [IMPLIED_BOUNDS_IN_IMPLS]);
54
49
fn emit_lint (
55
50
cx : & LateContext < ' _ > ,
56
51
poly_trait : & rustc_hir:: PolyTraitRef < ' _ > ,
57
- opaque_ty : & rustc_hir :: OpaqueTy < ' _ > ,
52
+ bounds : GenericBounds < ' _ > ,
58
53
index : usize ,
59
54
// The bindings that were implied, used for suggestion purposes since removing a bound with associated types
60
55
// means we might need to then move it to a different bound
@@ -73,10 +68,10 @@ fn emit_lint(
73
68
// to include the `+` token that is ahead or behind,
74
69
// so we don't end up with something like `impl + B` or `impl A + `
75
70
76
- let implied_span_extended = if let Some ( next_bound) = opaque_ty . bounds . get ( index + 1 ) {
71
+ let implied_span_extended = if let Some ( next_bound) = bounds. get ( index + 1 ) {
77
72
poly_trait. span . to ( next_bound. span ( ) . shrink_to_lo ( ) )
78
73
} else if index > 0
79
- && let Some ( prev_bound) = opaque_ty . bounds . get ( index - 1 )
74
+ && let Some ( prev_bound) = bounds. get ( index - 1 )
80
75
{
81
76
prev_bound. span ( ) . shrink_to_hi ( ) . to ( poly_trait. span . shrink_to_hi ( ) )
82
77
} else {
@@ -240,9 +235,8 @@ struct ImplTraitBound<'tcx> {
240
235
/// For `impl Deref + DerefMut + Eq` this returns `[Deref, PartialEq]`.
241
236
/// The `Deref` comes from `DerefMut` because `trait DerefMut: Deref {}`, and `PartialEq` comes from
242
237
/// `Eq`.
243
- fn collect_supertrait_bounds < ' tcx > ( cx : & LateContext < ' tcx > , opaque_ty : & OpaqueTy < ' tcx > ) -> Vec < ImplTraitBound < ' tcx > > {
244
- opaque_ty
245
- . bounds
238
+ fn collect_supertrait_bounds < ' tcx > ( cx : & LateContext < ' tcx > , bounds : GenericBounds < ' tcx > ) -> Vec < ImplTraitBound < ' tcx > > {
239
+ bounds
246
240
. iter ( )
247
241
. filter_map ( |bound| {
248
242
if let GenericBound :: Trait ( poly_trait, TraitBoundModifier :: None ) = bound
@@ -295,64 +289,49 @@ fn find_bound_in_supertraits<'a, 'tcx>(
295
289
} )
296
290
}
297
291
298
- fn check ( cx : & LateContext < ' _ > , decl : & FnDecl < ' _ > ) {
299
- if let FnRetTy :: Return ( ty) = decl. output
300
- && let TyKind :: OpaqueDef ( item_id, ..) = ty. kind
301
- && let item = cx. tcx . hir ( ) . item ( item_id)
302
- && let ItemKind :: OpaqueTy ( opaque_ty) = item. kind
292
+ fn check < ' tcx > ( cx : & LateContext < ' tcx > , bounds : GenericBounds < ' tcx > ) {
293
+ if bounds. len ( ) == 1 {
303
294
// Very often there is only a single bound, e.g. `impl Deref<..>`, in which case
304
- // we can avoid doing a bunch of stuff unnecessarily.
305
- && opaque_ty . bounds . len ( ) > 1
306
- {
307
- let supertraits = collect_supertrait_bounds ( cx , opaque_ty ) ;
295
+ // we can avoid doing a bunch of stuff unnecessarily; there will trivially be
296
+ // no duplicate bounds
297
+ return ;
298
+ }
308
299
309
- // Lint all bounds in the `impl Trait` type that we've previously also seen in the set of
310
- // supertraits of each of the bounds.
311
- // This involves some extra logic when generic arguments are present, since
312
- // simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
313
- for ( index, bound) in opaque_ty. bounds . iter ( ) . enumerate ( ) {
314
- if let GenericBound :: Trait ( poly_trait, TraitBoundModifier :: None ) = bound
315
- && let [ .., path] = poly_trait. trait_ref . path . segments
316
- && let implied_args = path. args . map_or ( [ ] . as_slice ( ) , |a| a. args )
317
- && let implied_bindings = path. args . map_or ( [ ] . as_slice ( ) , |a| a. bindings )
318
- && let Some ( def_id) = poly_trait. trait_ref . path . res . opt_def_id ( )
319
- && let Some ( bound) = find_bound_in_supertraits ( cx, def_id, implied_args, & supertraits)
320
- // If the implied bound has a type binding that also exists in the implied-by trait,
321
- // then we shouldn't lint. See #11880 for an example.
322
- && let assocs = cx. tcx . associated_items ( bound. trait_def_id )
323
- && !implied_bindings. iter ( ) . any ( |binding| {
324
- assocs
325
- . filter_by_name_unhygienic ( binding. ident . name )
326
- . next ( )
327
- . is_some_and ( |assoc| assoc. kind == ty:: AssocKind :: Type )
328
- } )
329
- {
330
- emit_lint ( cx, poly_trait, opaque_ty, index, implied_bindings, bound) ;
331
- }
300
+ let supertraits = collect_supertrait_bounds ( cx, bounds) ;
301
+
302
+ // Lint all bounds in the `impl Trait` type that we've previously also seen in the set of
303
+ // supertraits of each of the bounds.
304
+ // This involves some extra logic when generic arguments are present, since
305
+ // simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
306
+ for ( index, bound) in bounds. iter ( ) . enumerate ( ) {
307
+ if let GenericBound :: Trait ( poly_trait, TraitBoundModifier :: None ) = bound
308
+ && let [ .., path] = poly_trait. trait_ref . path . segments
309
+ && let implied_args = path. args . map_or ( [ ] . as_slice ( ) , |a| a. args )
310
+ && let implied_bindings = path. args . map_or ( [ ] . as_slice ( ) , |a| a. bindings )
311
+ && let Some ( def_id) = poly_trait. trait_ref . path . res . opt_def_id ( )
312
+ && let Some ( bound) = find_bound_in_supertraits ( cx, def_id, implied_args, & supertraits)
313
+ // If the implied bound has a type binding that also exists in the implied-by trait,
314
+ // then we shouldn't lint. See #11880 for an example.
315
+ && let assocs = cx. tcx . associated_items ( bound. trait_def_id )
316
+ && !implied_bindings. iter ( ) . any ( |binding| {
317
+ assocs
318
+ . filter_by_name_unhygienic ( binding. ident . name )
319
+ . next ( )
320
+ . is_some_and ( |assoc| assoc. kind == ty:: AssocKind :: Type )
321
+ } )
322
+ {
323
+ emit_lint ( cx, poly_trait, bounds, index, implied_bindings, bound) ;
332
324
}
333
325
}
334
326
}
335
327
336
- impl LateLintPass < ' _ > for ImpliedBoundsInImpls {
337
- fn check_fn (
338
- & mut self ,
339
- cx : & LateContext < ' _ > ,
340
- _: FnKind < ' _ > ,
341
- decl : & FnDecl < ' _ > ,
342
- _: & Body < ' _ > ,
343
- _: Span ,
344
- _: LocalDefId ,
345
- ) {
346
- check ( cx, decl) ;
347
- }
348
- fn check_trait_item ( & mut self , cx : & LateContext < ' _ > , item : & TraitItem < ' _ > ) {
349
- if let TraitItemKind :: Fn ( sig, ..) = & item. kind {
350
- check ( cx, sig. decl ) ;
351
- }
352
- }
353
- fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , item : & ImplItem < ' _ > ) {
354
- if let ImplItemKind :: Fn ( sig, ..) = & item. kind {
355
- check ( cx, sig. decl ) ;
328
+ impl < ' tcx > LateLintPass < ' tcx > for ImpliedBoundsInImpls {
329
+ fn check_ty ( & mut self , cx : & LateContext < ' _ > , ty : & rustc_hir:: Ty < ' _ > ) {
330
+ if let TyKind :: OpaqueDef ( item_id, ..) = ty. kind
331
+ && let item = cx. tcx . hir ( ) . item ( item_id)
332
+ && let ItemKind :: OpaqueTy ( opaque_ty) = item. kind
333
+ {
334
+ check ( cx, opaque_ty. bounds ) ;
356
335
}
357
336
}
358
337
}
0 commit comments