@@ -4,12 +4,12 @@ use rustc_data_structures::fx::FxHashMap;
4
4
use rustc_errors:: MultiSpan ;
5
5
use rustc_hir:: intravisit:: { walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor } ;
6
6
use rustc_hir:: {
7
- GenericParamKind , Generics , ImplItem , ImplItemKind , Item , ItemKind , LifetimeParamKind , Ty , TyKind , WherePredicate ,
7
+ GenericParamKind , Generics , ImplItem , ImplItemKind , Item , ItemKind , PredicateOrigin , Ty , TyKind , WherePredicate ,
8
8
} ;
9
9
use rustc_lint:: { LateContext , LateLintPass } ;
10
10
use rustc_middle:: hir:: nested_filter;
11
11
use 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 } ;
13
13
14
14
declare_clippy_lint ! {
15
15
/// ### What it does
@@ -39,44 +39,52 @@ declare_clippy_lint! {
39
39
}
40
40
declare_lint_pass ! ( ExtraUnusedTypeParameters => [ EXTRA_UNUSED_TYPE_PARAMETERS ] ) ;
41
41
42
+ /// A visitor struct that walks a given function and gathers generic type parameters, plus any
43
+ /// trait bounds those parameters have.
42
44
struct TypeWalker < ' cx , ' tcx > {
43
45
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.
46
51
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 ,
49
58
}
50
59
51
60
impl < ' cx , ' tcx > TypeWalker < ' cx , ' tcx > {
52
61
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
55
64
. params
56
65
. 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
+ }
64
73
None
65
- } ,
74
+ }
66
75
} )
67
76
. collect ( ) ;
68
77
Self {
69
78
cx,
70
- map,
79
+ ty_params,
80
+ bounds : FxHashMap :: default ( ) ,
71
81
generics,
72
- has_non_ty_params,
73
- bound_map : FxHashMap :: default ( ) ,
74
- some_params_used : false ,
82
+ all_params_unused,
75
83
}
76
84
}
77
85
78
86
fn emit_lint ( & self ) {
79
- let ( msg, help) = match self . map . len ( ) {
87
+ let ( msg, help) = match self . ty_params . len ( ) {
80
88
0 => return ,
81
89
1 => (
82
90
"type parameter goes unused in function definition" ,
@@ -89,27 +97,21 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
89
97
} ;
90
98
91
99
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 {
93
103
MultiSpan :: from_spans (
94
- self . map
104
+ self . ty_params
95
105
. 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 ( ) )
108
112
} )
109
113
. collect ( ) ,
110
114
)
111
- } else {
112
- self . generics . span . into ( )
113
115
} ;
114
116
115
117
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> {
121
123
122
124
fn visit_ty ( & mut self , t : & ' tcx Ty < ' tcx > ) {
123
125
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 ;
126
128
}
127
129
} else if let TyKind :: OpaqueDef ( id, _, _) = t. kind {
128
130
// 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> {
140
142
// Collect spans for bounds that appear in the list of generics (not in a where-clause)
141
143
// for use in forming the help message
142
144
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
144
146
{
145
- self . bound_map . insert ( def_id, predicate. span ) ;
147
+ self . bounds . insert ( def_id, predicate. span ) ;
146
148
}
147
149
// Only walk the right-hand side of where-bounds
148
150
for bound in predicate. bounds {
0 commit comments