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