@@ -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