@@ -4,10 +4,12 @@ use rustc_data_structures::fx::FxHashMap;
44use rustc_errors:: MultiSpan ;
55use rustc_hir:: intravisit:: { walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor } ;
66use rustc_hir:: {
7- GenericParamKind , Generics , ImplItem , ImplItemKind , Item , ItemKind , PredicateOrigin , Ty , TyKind , WherePredicate ,
7+ BodyId , ExprKind , GenericParamKind , Generics , ImplItem , ImplItemKind , Item , ItemKind , PredicateOrigin , Ty , TyKind ,
8+ WherePredicate ,
89} ;
9- use rustc_lint:: { LateContext , LateLintPass } ;
10+ use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
1011use rustc_middle:: hir:: nested_filter;
12+ use rustc_middle:: lint:: in_external_macro;
1113use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1214use rustc_span:: { def_id:: DefId , Span } ;
1315
@@ -55,10 +57,13 @@ struct TypeWalker<'cx, 'tcx> {
5557 /// Otherwise, if any type parameters end up being used, or if any lifetime or const-generic
5658 /// parameters are present, this will be set to `false`.
5759 all_params_unused : bool ,
60+ /// Whether or not the function has an empty body, in which case any bounded type parameters
61+ /// will not be linted.
62+ fn_body_empty : bool ,
5863}
5964
6065impl < ' cx , ' tcx > TypeWalker < ' cx , ' tcx > {
61- fn new ( cx : & ' cx LateContext < ' tcx > , generics : & ' tcx Generics < ' tcx > ) -> Self {
66+ fn new ( cx : & ' cx LateContext < ' tcx > , generics : & ' tcx Generics < ' tcx > , body_id : BodyId ) -> Self {
6267 let mut all_params_unused = true ;
6368 let ty_params = generics
6469 . params
@@ -74,12 +79,18 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
7479 }
7580 } )
7681 . collect ( ) ;
82+
83+ let body = cx. tcx . hir ( ) . body ( body_id) . value ;
84+ let fn_body_empty =
85+ matches ! ( & body. kind, ExprKind :: Block ( block, None ) if block. stmts. is_empty( ) && block. expr. is_none( ) ) ;
86+
7787 Self {
7888 cx,
7989 ty_params,
8090 bounds : FxHashMap :: default ( ) ,
8191 generics,
8292 all_params_unused,
93+ fn_body_empty,
8394 }
8495 }
8596
@@ -96,7 +107,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
96107 ) ,
97108 } ;
98109
99- let source_map = self . cx . tcx . sess . source_map ( ) ;
110+ let source_map = self . cx . sess ( ) . source_map ( ) ;
100111 let span = if self . all_params_unused {
101112 self . generics . span . into ( ) // Remove the entire list of generics
102113 } else {
@@ -139,12 +150,17 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
139150
140151 fn visit_where_predicate ( & mut self , predicate : & ' tcx WherePredicate < ' tcx > ) {
141152 if let WherePredicate :: BoundPredicate ( predicate) = predicate {
142- // Collect spans for bounds that appear in the list of generics (not in a where-clause)
143- // for use in forming the help message
144- if let Some ( ( def_id, _) ) = predicate. bounded_ty . peel_refs ( ) . as_generic_param ( )
145- && let PredicateOrigin :: GenericParam = predicate. origin
146- {
147- self . bounds . insert ( def_id, predicate. span ) ;
153+ // Collect spans for any bounds on type parameters. We only keep bounds that appear in
154+ // the list of generics (not in a where-clause).
155+ //
156+ // Also, if the function body is empty, we don't lint the corresponding type parameters
157+ // (See https://github.com/rust-lang/rust-clippy/issues/10319).
158+ if let Some ( ( def_id, _) ) = predicate. bounded_ty . peel_refs ( ) . as_generic_param ( ) {
159+ if self . fn_body_empty {
160+ self . ty_params . remove ( & def_id) ;
161+ } else if let PredicateOrigin :: GenericParam = predicate. origin {
162+ self . bounds . insert ( def_id, predicate. span ) ;
163+ }
148164 }
149165 // Only walk the right-hand side of where-bounds
150166 for bound in predicate. bounds {
@@ -160,17 +176,22 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
160176
161177impl < ' tcx > LateLintPass < ' tcx > for ExtraUnusedTypeParameters {
162178 fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx Item < ' tcx > ) {
163- if let ItemKind :: Fn ( _, generics, _) = item. kind {
164- let mut walker = TypeWalker :: new ( cx, generics) ;
179+ if let ItemKind :: Fn ( _, generics, body_id) = item. kind
180+ && !in_external_macro ( cx. sess ( ) , item. span )
181+ {
182+ let mut walker = TypeWalker :: new ( cx, generics, body_id) ;
165183 walk_item ( & mut walker, item) ;
166184 walker. emit_lint ( ) ;
167185 }
168186 }
169187
170188 fn check_impl_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx ImplItem < ' tcx > ) {
171189 // Only lint on inherent methods, not trait methods.
172- if let ImplItemKind :: Fn ( ..) = item. kind && trait_ref_of_method ( cx, item. owner_id . def_id ) . is_none ( ) {
173- let mut walker = TypeWalker :: new ( cx, item. generics ) ;
190+ if let ImplItemKind :: Fn ( .., body_id) = item. kind
191+ && trait_ref_of_method ( cx, item. owner_id . def_id ) . is_none ( )
192+ && !in_external_macro ( cx. sess ( ) , item. span )
193+ {
194+ let mut walker = TypeWalker :: new ( cx, item. generics , body_id) ;
174195 walk_impl_item ( & mut walker, item) ;
175196 walker. emit_lint ( ) ;
176197 }
0 commit comments