1
- use clippy_utils:: diagnostics:: span_lint ;
1
+ use clippy_utils:: diagnostics:: span_lint_and_help ;
2
2
use clippy_utils:: trait_ref_of_method;
3
3
use rustc_data_structures:: fx:: FxHashMap ;
4
+ use rustc_errors:: MultiSpan ;
4
5
use rustc_hir:: intravisit:: { walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor } ;
5
6
use rustc_hir:: { GenericParamKind , Generics , ImplItem , ImplItemKind , Item , ItemKind , Ty , TyKind , WherePredicate } ;
6
7
use rustc_lint:: { LateContext , LateLintPass } ;
7
8
use rustc_middle:: hir:: nested_filter;
8
9
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
9
- use rustc_span:: { def_id:: DefId , Span } ;
10
+ use rustc_span:: { def_id:: DefId , source_map :: SourceMap , BytePos , Span } ;
10
11
11
12
declare_clippy_lint ! {
12
13
/// ### What it does
@@ -39,10 +40,12 @@ declare_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
39
40
struct TypeWalker < ' cx , ' tcx > {
40
41
cx : & ' cx LateContext < ' tcx > ,
41
42
map : FxHashMap < DefId , Span > ,
43
+ generics : & ' tcx Generics < ' tcx > ,
44
+ some_params_used : bool ,
42
45
}
43
46
44
47
impl < ' cx , ' tcx > TypeWalker < ' cx , ' tcx > {
45
- fn new ( cx : & ' cx LateContext < ' tcx > , generics : & Generics < ' tcx > ) -> Self {
48
+ fn new ( cx : & ' cx LateContext < ' tcx > , generics : & ' tcx Generics < ' tcx > ) -> Self {
46
49
Self {
47
50
cx,
48
51
map : generics
@@ -53,27 +56,78 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
53
56
_ => None ,
54
57
} )
55
58
. collect ( ) ,
59
+ generics,
60
+ some_params_used : false ,
56
61
}
57
62
}
58
63
59
64
fn emit_lint ( & self ) {
60
- for span in self . map . values ( ) {
61
- span_lint (
62
- self . cx ,
63
- EXTRA_UNUSED_TYPE_PARAMETERS ,
64
- * span,
65
+ let ( msg, help) = match self . map . len ( ) {
66
+ 0 => return ,
67
+ 1 => (
65
68
"type parameter goes unused in function definition" ,
66
- ) ;
69
+ "consider removing the parameter" ,
70
+ ) ,
71
+ _ => (
72
+ "type parameters go unused in function definition" ,
73
+ "consider removing the parameters" ,
74
+ ) ,
75
+ } ;
76
+
77
+ let source_map = self . cx . tcx . sess . source_map ( ) ;
78
+ let span = if self . some_params_used {
79
+ MultiSpan :: from_spans (
80
+ self . map
81
+ . values ( )
82
+ . into_iter ( )
83
+ . map ( |& span| {
84
+ let span = span_extend_through_nested_brackets ( & source_map, span) ;
85
+ let span = span_extend_through_next_char ( & source_map, span, ',' , false ) ;
86
+ let max_hi = self . generics . span . hi ( ) ;
87
+ if span. hi ( ) >= max_hi {
88
+ span. with_hi ( BytePos ( max_hi. 0 - 1 ) )
89
+ } else {
90
+ span
91
+ }
92
+ } )
93
+ . collect ( ) ,
94
+ )
95
+ } else {
96
+ self . generics . span . into ( )
97
+ } ;
98
+
99
+ span_lint_and_help ( self . cx , EXTRA_UNUSED_TYPE_PARAMETERS , span, msg, None , help) ;
100
+ }
101
+ }
102
+
103
+ fn span_extend_through_next_char ( source_map : & SourceMap , span : Span , c : char , accept_commas : bool ) -> Span {
104
+ if let Ok ( next_source) = source_map. span_to_next_source ( span) {
105
+ let next_source = next_source. split ( c) . next ( ) . unwrap_or ( "" ) ;
106
+ if !next_source. contains ( '\n' ) && ( accept_commas || !next_source. contains ( ',' ) ) {
107
+ return span. with_hi ( BytePos ( span. hi ( ) . 0 + next_source. len ( ) as u32 + 1 ) ) ;
67
108
}
68
109
}
110
+
111
+ span
112
+ }
113
+
114
+ fn span_extend_through_nested_brackets ( source_map : & SourceMap , span : Span ) -> Span {
115
+ let mut new_span = span_extend_through_next_char ( source_map, span, '<' , false ) ;
116
+ if new_span. hi ( ) == span. hi ( ) {
117
+ return span;
118
+ }
119
+ new_span = span_extend_through_nested_brackets ( source_map, new_span) ;
120
+ span_extend_through_next_char ( source_map, new_span, '>' , true )
69
121
}
70
122
71
123
impl < ' cx , ' tcx > Visitor < ' tcx > for TypeWalker < ' cx , ' tcx > {
72
124
type NestedFilter = nested_filter:: OnlyBodies ;
73
125
74
126
fn visit_ty ( & mut self , t : & ' tcx Ty < ' tcx > ) {
75
127
if let Some ( ( def_id, _) ) = t. peel_refs ( ) . as_generic_param ( ) {
76
- self . map . remove ( & def_id) ;
128
+ if self . map . remove ( & def_id) . is_some ( ) {
129
+ self . some_params_used = true ;
130
+ }
77
131
} else if let TyKind :: OpaqueDef ( id, _, _) = t. kind {
78
132
// Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls
79
133
// `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're
0 commit comments