@@ -4,12 +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 ,  LifetimeParamKind ,  Ty ,  TyKind ,  WherePredicate , 
7+     GenericParamKind ,  Generics ,  ImplItem ,  ImplItemKind ,  Item ,  ItemKind ,  PredicateOrigin ,  Ty ,  TyKind ,  WherePredicate , 
88} ; 
99use  rustc_lint:: { LateContext ,  LateLintPass } ; 
1010use  rustc_middle:: hir:: nested_filter; 
1111use  rustc_session:: { declare_lint_pass,  declare_tool_lint} ; 
12- use  rustc_span:: { def_id:: DefId ,  BytePos ,   Span } ; 
12+ use  rustc_span:: { def_id:: DefId ,  Span } ; 
1313
1414declare_clippy_lint !  { 
1515    /// ### What it does 
@@ -39,44 +39,52 @@ declare_clippy_lint! {
3939} 
4040declare_lint_pass ! ( ExtraUnusedTypeParameters  => [ EXTRA_UNUSED_TYPE_PARAMETERS ] ) ; 
4141
42+ /// A visitor struct that walks a given function and gathers generic type parameters, plus any 
43+ /// trait bounds those parameters have. 
4244struct  TypeWalker < ' cx ,  ' tcx >  { 
4345    cx :  & ' cx  LateContext < ' tcx > , 
44-     map :  FxHashMap < DefId ,  Span > , 
45-     bound_map :  FxHashMap < DefId ,  Span > , 
46+     /// Collection of all the type parameters and their spans. 
47+      ty_params :  FxHashMap < DefId ,  Span > , 
48+     /// Collection of any (inline) trait bounds corresponding to each type parameter. 
49+      bounds :  FxHashMap < DefId ,  Span > , 
50+     /// The entire `Generics` object of the function, useful for querying purposes. 
4651     generics :  & ' tcx  Generics < ' tcx > , 
47-     some_params_used :  bool , 
48-     has_non_ty_params :  bool , 
52+     /// The value of this will remain `true` if *every* parameter: 
53+      ///   1. Is a type parameter, and 
54+      ///   2. Goes unused in the function. 
55+      /// Otherwise, if any type parameters end up being used, or if any lifetime or const-generic 
56+      /// parameters are present, this will be set to `false`. 
57+      all_params_unused :  bool , 
4958} 
5059
5160impl < ' cx ,  ' tcx >  TypeWalker < ' cx ,  ' tcx >  { 
5261    fn  new ( cx :  & ' cx  LateContext < ' tcx > ,  generics :  & ' tcx  Generics < ' tcx > )  -> Self  { 
53-         let  mut  has_non_ty_params  = false ; 
54-         let  map  = generics
62+         let  mut  all_params_unused  = true ; 
63+         let  ty_params  = generics
5564            . params 
5665            . iter ( ) 
57-             . filter_map ( |param| match   & param . kind   { 
58-                 GenericParamKind :: Type  {  .. }  =>  Some ( ( param. def_id . into ( ) ,  param . span ) ) , 
59-                 GenericParamKind :: Lifetime   { 
60-                      kind :   LifetimeParamKind :: Elided , 
61-                 }  =>  None , 
62-                 _ =>  { 
63-                     has_non_ty_params =  true ; 
66+             . filter_map ( |param| { 
67+                 if   let   GenericParamKind :: Type  {  .. }  =  param. kind   { 
68+                      Some ( ( param . def_id . into ( ) ,  param . span ) ) 
69+                 }   else   { 
70+                      if  !param . is_elided_lifetime ( )   { 
71+                         all_params_unused =  false ; 
72+                     } 
6473                    None 
65-                 } , 
74+                 } 
6675            } ) 
6776            . collect ( ) ; 
6877        Self  { 
6978            cx, 
70-             map, 
79+             ty_params, 
80+             bounds :  FxHashMap :: default ( ) , 
7181            generics, 
72-             has_non_ty_params, 
73-             bound_map :  FxHashMap :: default ( ) , 
74-             some_params_used :  false , 
82+             all_params_unused, 
7583        } 
7684    } 
7785
7886    fn  emit_lint ( & self )  { 
79-         let  ( msg,  help)  = match  self . map . len ( )  { 
87+         let  ( msg,  help)  = match  self . ty_params . len ( )  { 
8088            0  => return , 
8189            1  => ( 
8290                "type parameter goes unused in function definition" , 
@@ -89,27 +97,21 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
8997        } ; 
9098
9199        let  source_map = self . cx . tcx . sess . source_map ( ) ; 
92-         let  span = if  self . some_params_used  || self . has_non_ty_params  { 
100+         let  span = if  self . all_params_unused  { 
101+             self . generics . span . into ( )  // Remove the entire list of generics 
102+         }  else  { 
93103            MultiSpan :: from_spans ( 
94-                 self . map 
104+                 self . ty_params 
95105                    . iter ( ) 
96-                     . map ( |( def_id,  & ( mut  span) ) | { 
97-                         if  let  Some ( bound_span)  = self . bound_map . get ( def_id)  { 
98-                             span = span. with_hi ( bound_span. hi ( ) ) ; 
99-                         } 
100-                         span = source_map. span_extend_to_next_char ( span,  ',' ,  false ) ; 
101-                         span = span. with_hi ( BytePos ( span. hi ( ) . 0  + 1 ) ) ; 
102- 
103-                         let  max_hi = self . generics . span . hi ( ) ; 
104-                         if  span. hi ( )  >= max_hi { 
105-                             span = span. with_hi ( BytePos ( max_hi. 0  - 1 ) ) ; 
106-                         } 
107-                         span
106+                     . map ( |( def_id,  & span) | { 
107+                         // Extend the span past any trait bounds, and include the comma at the end. 
108+                         let  span_to_extend = self . bounds . get ( def_id) . copied ( ) . map_or ( span,  Span :: shrink_to_hi) ; 
109+                         let  comma_range = source_map. span_extend_to_next_char ( span_to_extend,  '>' ,  false ) ; 
110+                         let  comma_span = source_map. span_through_char ( comma_range,  ',' ) ; 
111+                         span. with_hi ( comma_span. hi ( ) ) 
108112                    } ) 
109113                    . collect ( ) , 
110114            ) 
111-         }  else  { 
112-             self . generics . span . into ( ) 
113115        } ; 
114116
115117        span_lint_and_help ( self . cx ,  EXTRA_UNUSED_TYPE_PARAMETERS ,  span,  msg,  None ,  help) ; 
@@ -121,8 +123,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
121123
122124    fn  visit_ty ( & mut  self ,  t :  & ' tcx  Ty < ' tcx > )  { 
123125        if  let  Some ( ( def_id,  _) )  = t. peel_refs ( ) . as_generic_param ( )  { 
124-             if  self . map . remove ( & def_id) . is_some ( )  { 
125-                 self . some_params_used  = true ; 
126+             if  self . ty_params . remove ( & def_id) . is_some ( )  { 
127+                 self . all_params_unused  = false ; 
126128            } 
127129        }  else  if  let  TyKind :: OpaqueDef ( id,  _,  _)  = t. kind  { 
128130            // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls 
@@ -140,9 +142,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
140142            // Collect spans for bounds that appear in the list of generics (not in a where-clause) 
141143            // for use in forming the help message 
142144            if  let  Some ( ( def_id,  _) )  = predicate. bounded_ty . peel_refs ( ) . as_generic_param ( ) 
143-                 && predicate . span  <  self . generics . where_clause_span 
145+                 && let   PredicateOrigin :: GenericParam  = predicate . origin 
144146            { 
145-                 self . bound_map . insert ( def_id,  predicate. span ) ; 
147+                 self . bounds . insert ( def_id,  predicate. span ) ; 
146148            } 
147149            // Only walk the right-hand side of where-bounds 
148150            for  bound in  predicate. bounds  { 
0 commit comments