1
1
use clippy_utils:: diagnostics:: span_lint_and_then;
2
2
use clippy_utils:: source:: snippet;
3
+ use rustc_errors:: { Applicability , SuggestionStyle } ;
3
4
use rustc_hir:: def_id:: LocalDefId ;
4
5
use rustc_hir:: intravisit:: FnKind ;
5
- use rustc_hir:: { Body , FnDecl , FnRetTy , GenericArg , GenericBound , ItemKind , TraitBoundModifier , TyKind } ;
6
+ use rustc_hir:: {
7
+ Body , FnDecl , FnRetTy , GenericArg , GenericBound , ImplItem , ImplItemKind , ItemKind , TraitBoundModifier , TraitItem ,
8
+ TraitItemKind , TyKind ,
9
+ } ;
6
10
use rustc_hir_analysis:: hir_ty_to_ty;
7
11
use rustc_lint:: { LateContext , LateLintPass } ;
8
- use rustc_errors:: { Applicability , SuggestionStyle } ;
9
12
use rustc_middle:: ty:: { self , ClauseKind , TyCtxt } ;
10
13
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
11
14
use rustc_span:: Span ;
@@ -94,6 +97,86 @@ fn is_same_generics(
94
97
} )
95
98
}
96
99
100
+ fn check ( cx : & LateContext < ' _ > , decl : & FnDecl < ' _ > ) {
101
+ if let FnRetTy :: Return ( ty) = decl. output
102
+ &&let TyKind :: OpaqueDef ( item_id, ..) = ty. kind
103
+ && let item = cx. tcx . hir ( ) . item ( item_id)
104
+ && let ItemKind :: OpaqueTy ( opaque_ty) = item. kind
105
+ // Very often there is only a single bound, e.g. `impl Deref<..>`, in which case
106
+ // we can avoid doing a bunch of stuff unnecessarily.
107
+ && opaque_ty. bounds . len ( ) > 1
108
+ {
109
+ // Get all the (implied) trait predicates in the bounds.
110
+ // For `impl Deref + DerefMut` this will contain [`Deref`].
111
+ // The implied `Deref` comes from `DerefMut` because `trait DerefMut: Deref {}`.
112
+ // N.B. (G)ATs are fine to disregard, because they must be the same for all of its supertraits.
113
+ // Example:
114
+ // `impl Deref<Target = i32> + DerefMut<Target = u32>` is not allowed.
115
+ // `DerefMut::Target` needs to match `Deref::Target`.
116
+ let implied_bounds: Vec < _ > = opaque_ty. bounds . iter ( ) . filter_map ( |bound| {
117
+ if let GenericBound :: Trait ( poly_trait, TraitBoundModifier :: None ) = bound
118
+ && let [ .., path] = poly_trait. trait_ref . path . segments
119
+ && poly_trait. bound_generic_params . is_empty ( )
120
+ && let Some ( trait_def_id) = path. res . opt_def_id ( )
121
+ && let predicates = cx. tcx . super_predicates_of ( trait_def_id) . predicates
122
+ && !predicates. is_empty ( ) // If the trait has no supertrait, there is nothing to add.
123
+ {
124
+ Some ( ( bound. span ( ) , path. args . map_or ( [ ] . as_slice ( ) , |a| a. args ) , predicates) )
125
+ } else {
126
+ None
127
+ }
128
+ } ) . collect ( ) ;
129
+
130
+ // Lint all bounds in the `impl Trait` type that are also in the `implied_bounds` vec.
131
+ // This involves some extra logic when generic arguments are present, since
132
+ // simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
133
+ for ( index, bound) in opaque_ty. bounds . iter ( ) . enumerate ( ) {
134
+ if let GenericBound :: Trait ( poly_trait, TraitBoundModifier :: None ) = bound
135
+ && let [ .., path] = poly_trait. trait_ref . path . segments
136
+ && let implied_args = path. args . map_or ( [ ] . as_slice ( ) , |a| a. args )
137
+ && let Some ( def_id) = poly_trait. trait_ref . path . res . opt_def_id ( )
138
+ && let Some ( implied_by_span) = implied_bounds. iter ( ) . find_map ( |& ( span, implied_by_args, preds) | {
139
+ preds. iter ( ) . find_map ( |( clause, _) | {
140
+ if let ClauseKind :: Trait ( tr) = clause. kind ( ) . skip_binder ( )
141
+ && tr. def_id ( ) == def_id
142
+ && is_same_generics ( cx. tcx , tr. trait_ref . args , implied_by_args, implied_args)
143
+ {
144
+ Some ( span)
145
+ } else {
146
+ None
147
+ }
148
+ } )
149
+ } )
150
+ {
151
+ let implied_by = snippet ( cx, implied_by_span, ".." ) ;
152
+ span_lint_and_then (
153
+ cx, IMPLIED_BOUNDS_IN_IMPLS ,
154
+ poly_trait. span ,
155
+ & format ! ( "this bound is already specified as the supertrait of `{implied_by}`" ) ,
156
+ |diag| {
157
+ // If we suggest removing a bound, we may also need extend the span
158
+ // to include the `+` token, so we don't end up with something like `impl + B`
159
+
160
+ let implied_span_extended = if let Some ( next_bound) = opaque_ty. bounds . get ( index + 1 ) {
161
+ poly_trait. span . to ( next_bound. span ( ) . shrink_to_lo ( ) )
162
+ } else {
163
+ poly_trait. span
164
+ } ;
165
+
166
+ diag. span_suggestion_with_style (
167
+ implied_span_extended,
168
+ "try removing this bound" ,
169
+ "" ,
170
+ Applicability :: MachineApplicable ,
171
+ SuggestionStyle :: ShowAlways
172
+ ) ;
173
+ }
174
+ ) ;
175
+ }
176
+ }
177
+ }
178
+ }
179
+
97
180
impl LateLintPass < ' _ > for ImpliedBoundsInImpls {
98
181
fn check_fn (
99
182
& mut self ,
@@ -104,82 +187,16 @@ impl LateLintPass<'_> for ImpliedBoundsInImpls {
104
187
_: Span ,
105
188
_: LocalDefId ,
106
189
) {
107
- if let FnRetTy :: Return ( ty) = decl. output
108
- &&let TyKind :: OpaqueDef ( item_id, ..) = ty. kind
109
- && let item = cx. tcx . hir ( ) . item ( item_id)
110
- && let ItemKind :: OpaqueTy ( opaque_ty) = item. kind
111
- // Very often there is only a single bound, e.g. `impl Deref<..>`, in which case
112
- // we can avoid doing a bunch of stuff unnecessarily.
113
- && opaque_ty. bounds . len ( ) > 1
114
- {
115
- // Get all the (implied) trait predicates in the bounds.
116
- // For `impl Deref + DerefMut` this will contain [`Deref`].
117
- // The implied `Deref` comes from `DerefMut` because `trait DerefMut: Deref {}`.
118
- // N.B. (G)ATs are fine to disregard, because they must be the same for all of its supertraits.
119
- // Example:
120
- // `impl Deref<Target = i32> + DerefMut<Target = u32>` is not allowed.
121
- // `DerefMut::Target` needs to match `Deref::Target`.
122
- let implied_bounds: Vec < _ > = opaque_ty. bounds . iter ( ) . filter_map ( |bound| {
123
- if let GenericBound :: Trait ( poly_trait, TraitBoundModifier :: None ) = bound
124
- && let [ .., path] = poly_trait. trait_ref . path . segments
125
- && poly_trait. bound_generic_params . is_empty ( )
126
- && let Some ( trait_def_id) = path. res . opt_def_id ( )
127
- && let predicates = cx. tcx . super_predicates_of ( trait_def_id) . predicates
128
- && !predicates. is_empty ( ) // If the trait has no supertrait, there is nothing to add.
129
- {
130
- Some ( ( bound. span ( ) , path. args . map_or ( [ ] . as_slice ( ) , |a| a. args ) , predicates) )
131
- } else {
132
- None
133
- }
134
- } ) . collect ( ) ;
135
-
136
- // Lint all bounds in the `impl Trait` type that are also in the `implied_bounds` vec.
137
- // This involves some extra logic when generic arguments are present, since
138
- // simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
139
- for ( index, bound) in opaque_ty. bounds . iter ( ) . enumerate ( ) {
140
- if let GenericBound :: Trait ( poly_trait, TraitBoundModifier :: None ) = bound
141
- && let [ .., path] = poly_trait. trait_ref . path . segments
142
- && let implied_args = path. args . map_or ( [ ] . as_slice ( ) , |a| a. args )
143
- && let Some ( def_id) = poly_trait. trait_ref . path . res . opt_def_id ( )
144
- && let Some ( implied_by_span) = implied_bounds. iter ( ) . find_map ( |& ( span, implied_by_args, preds) | {
145
- preds. iter ( ) . find_map ( |( clause, _) | {
146
- if let ClauseKind :: Trait ( tr) = clause. kind ( ) . skip_binder ( )
147
- && tr. def_id ( ) == def_id
148
- && is_same_generics ( cx. tcx , tr. trait_ref . args , implied_by_args, implied_args)
149
- {
150
- Some ( span)
151
- } else {
152
- None
153
- }
154
- } )
155
- } )
156
- {
157
- let implied_by = snippet ( cx, implied_by_span, ".." ) ;
158
- span_lint_and_then (
159
- cx, IMPLIED_BOUNDS_IN_IMPLS ,
160
- poly_trait. span ,
161
- & format ! ( "this bound is already specified as the supertrait of `{}`" , implied_by) ,
162
- |diag| {
163
- // If we suggest removing a bound, we may also need extend the span
164
- // to include the `+` token, so we don't end up with something like `impl + B`
165
-
166
- let implied_span_extended = if let Some ( next_bound) = opaque_ty. bounds . get ( index + 1 ) {
167
- poly_trait. span . to ( next_bound. span ( ) . shrink_to_lo ( ) )
168
- } else {
169
- poly_trait. span
170
- } ;
171
-
172
- diag. span_suggestion_with_style (
173
- implied_span_extended,
174
- "try removing this bound" ,
175
- "" ,
176
- Applicability :: MachineApplicable ,
177
- SuggestionStyle :: ShowAlways
178
- ) ;
179
- }
180
- ) ;
181
- }
182
- }
190
+ check ( cx, decl) ;
191
+ }
192
+ fn check_trait_item ( & mut self , cx : & LateContext < ' _ > , item : & TraitItem < ' _ > ) {
193
+ if let TraitItemKind :: Fn ( sig, ..) = & item. kind {
194
+ check ( cx, sig. decl ) ;
195
+ }
196
+ }
197
+ fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , item : & ImplItem < ' _ > ) {
198
+ if let ImplItemKind :: Fn ( sig, ..) = & item. kind {
199
+ check ( cx, sig. decl ) ;
183
200
}
184
201
}
185
202
}
0 commit comments