18
18
//
19
19
20
20
use std:: ops:: { Deref , DerefMut } ;
21
+ use std:: collections:: HashMap ;
21
22
22
23
use Resolver ;
23
24
use Namespace :: { TypeNS , ValueNS } ;
24
25
25
26
use rustc:: lint;
26
27
use rustc:: middle:: privacy:: { DependsOn , LastImport , Used , Unused } ;
27
28
use syntax:: ast;
28
- use syntax:: codemap:: { Span , DUMMY_SP } ;
29
+ use syntax:: codemap:: { Span , MultiSpan , DUMMY_SP } ;
29
30
30
31
use rustc_front:: hir;
31
32
use rustc_front:: hir:: { ViewPathGlob , ViewPathList , ViewPathSimple } ;
32
33
use rustc_front:: intravisit:: Visitor ;
33
34
34
35
struct UnusedImportCheckVisitor < ' a , ' b : ' a , ' tcx : ' b > {
35
36
resolver : & ' a mut Resolver < ' b , ' tcx > ,
37
+ unused_imports : HashMap < ast:: NodeId , Vec < Span > > ,
36
38
}
37
39
38
40
// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
@@ -58,16 +60,13 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
58
60
// only check imports and namespaces which are used. In particular, this
59
61
// means that if an import could name either a public or private item, we
60
62
// will check the correct thing, dependent on how the import is used.
61
- fn finalize_import ( & mut self , id : ast:: NodeId , span : Span ) {
63
+ fn finalize_import ( & mut self , item_id : ast :: NodeId , id : ast:: NodeId , span : Span ) {
62
64
debug ! ( "finalizing import uses for {:?}" ,
63
65
self . session. codemap( ) . span_to_snippet( span) ) ;
64
66
65
67
if !self . used_imports . contains ( & ( id, TypeNS ) ) &&
66
68
!self . used_imports . contains ( & ( id, ValueNS ) ) {
67
- self . session . add_lint ( lint:: builtin:: UNUSED_IMPORTS ,
68
- id,
69
- span,
70
- "unused import" . to_string ( ) ) ;
69
+ self . unused_imports . entry ( item_id) . or_insert_with ( Vec :: new) . push ( span) ;
71
70
}
72
71
73
72
let mut def_map = self . def_map . borrow_mut ( ) ;
@@ -135,22 +134,19 @@ impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
135
134
hir:: ItemUse ( ref p) => {
136
135
match p. node {
137
136
ViewPathSimple ( _, _) => {
138
- self . finalize_import ( item. id , p. span )
137
+ self . finalize_import ( item. id , item . id , p. span )
139
138
}
140
139
141
140
ViewPathList ( _, ref list) => {
142
141
for i in list {
143
- self . finalize_import ( i. node . id ( ) , i. span ) ;
142
+ self . finalize_import ( item . id , i. node . id ( ) , i. span ) ;
144
143
}
145
144
}
146
145
ViewPathGlob ( _) => {
147
146
if !self . used_imports . contains ( & ( item. id , TypeNS ) ) &&
148
147
!self . used_imports . contains ( & ( item. id , ValueNS ) ) {
149
- self . session
150
- . add_lint ( lint:: builtin:: UNUSED_IMPORTS ,
151
- item. id ,
152
- p. span ,
153
- "unused import" . to_string ( ) ) ;
148
+ self . unused_imports . entry ( item. id ) . or_insert_with ( Vec :: new)
149
+ . push ( item. span ) ;
154
150
}
155
151
}
156
152
}
@@ -161,6 +157,20 @@ impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
161
157
}
162
158
163
159
pub fn check_crate ( resolver : & mut Resolver , krate : & hir:: Crate ) {
164
- let mut visitor = UnusedImportCheckVisitor { resolver : resolver } ;
160
+ let mut visitor = UnusedImportCheckVisitor { resolver : resolver,
161
+ unused_imports : HashMap :: new ( ) } ;
165
162
krate. visit_all_items ( & mut visitor) ;
163
+
164
+ for ( id, spans) in & visitor. unused_imports {
165
+ let ms = spans. iter ( ) . fold ( MultiSpan :: new ( ) , |mut acc, & sp| { acc. push_merge ( sp) ; acc } ) ;
166
+
167
+ visitor. session . add_lint ( lint:: builtin:: UNUSED_IMPORTS ,
168
+ * id,
169
+ ms,
170
+ if spans. len ( ) > 1 {
171
+ "unused imports" . to_string ( )
172
+ } else {
173
+ "unused import" . to_string ( )
174
+ } ) ;
175
+ }
166
176
}
0 commit comments