1818//
1919
2020use std:: ops:: { Deref , DerefMut } ;
21+ use std:: collections:: HashMap ;
2122
2223use Resolver ;
2324use Namespace :: { TypeNS , ValueNS } ;
2425
2526use rustc:: lint;
2627use rustc:: middle:: privacy:: { DependsOn , LastImport , Used , Unused } ;
2728use syntax:: ast;
28- use syntax:: codemap:: { Span , DUMMY_SP } ;
29+ use syntax:: codemap:: { Span , MultiSpan , DUMMY_SP } ;
2930
3031use rustc_front:: hir;
3132use rustc_front:: hir:: { ViewPathGlob , ViewPathList , ViewPathSimple } ;
3233use rustc_front:: intravisit:: Visitor ;
3334
3435struct UnusedImportCheckVisitor < ' a , ' b : ' a , ' tcx : ' b > {
3536 resolver : & ' a mut Resolver < ' b , ' tcx > ,
37+ unused_imports : HashMap < ast:: NodeId , Vec < Span > > ,
3638}
3739
3840// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
@@ -58,16 +60,13 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
5860 // only check imports and namespaces which are used. In particular, this
5961 // means that if an import could name either a public or private item, we
6062 // 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 ) {
6264 debug ! ( "finalizing import uses for {:?}" ,
6365 self . session. codemap( ) . span_to_snippet( span) ) ;
6466
6567 if !self . used_imports . contains ( & ( id, TypeNS ) ) &&
6668 !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) ;
7170 }
7271
7372 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> {
135134 hir:: ItemUse ( ref p) => {
136135 match p. node {
137136 ViewPathSimple ( _, _) => {
138- self . finalize_import ( item. id , p. span )
137+ self . finalize_import ( item. id , item . id , p. span )
139138 }
140139
141140 ViewPathList ( _, ref list) => {
142141 for i in list {
143- self . finalize_import ( i. node . id ( ) , i. span ) ;
142+ self . finalize_import ( item . id , i. node . id ( ) , i. span ) ;
144143 }
145144 }
146145 ViewPathGlob ( _) => {
147146 if !self . used_imports . contains ( & ( item. id , TypeNS ) ) &&
148147 !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 ) ;
154150 }
155151 }
156152 }
@@ -161,6 +157,20 @@ impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
161157}
162158
163159pub 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 ( ) } ;
165162 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+ }
166176}
0 commit comments