@@ -120,62 +120,68 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) {
120120 . cloned ( )
121121 . collect ( ) ;
122122
123- // Issue lints for fully unused crates that suggest removing them.
124- for ( & def_id, & span) in & unused_extern_crates {
125- assert_eq ! ( def_id. krate, LOCAL_CRATE ) ;
126- let hir_id = tcx. hir . definitions ( ) . def_index_to_hir_id ( def_id. index ) ;
127- let id = tcx. hir . hir_to_node_id ( hir_id) ;
128- let msg = "unused extern crate" ;
129- tcx. struct_span_lint_node ( lint, id, span, msg)
130- . span_suggestion_short ( span, "remove it" , "" . to_string ( ) )
131- . emit ( ) ;
132- }
133-
134- // If we are not in Rust 2018 edition, we are done.
135- if !tcx. sess . rust_2018 ( ) {
136- return ;
137- }
138-
139- // Otherwise, we can *also* suggest rewriting `extern crate`
140- // into `use` etc.
141- let mut crates_to_convert_to_use = vec ! [ ] ;
123+ // Collect all the extern crates (in a reliable order).
124+ let mut crates_to_lint = vec ! [ ] ;
142125 tcx. hir . krate ( ) . visit_all_item_likes ( & mut CollectExternCrateVisitor {
143126 tcx,
144- unused_extern_crates : & unused_extern_crates,
145- crates_to_convert_to_use : & mut crates_to_convert_to_use,
127+ crates_to_lint : & mut crates_to_lint,
146128 } ) ;
147129
148- for to_convert in & crates_to_convert_to_use {
149- assert_eq ! ( to_convert. def_id. krate, LOCAL_CRATE ) ;
150- let hir_id = tcx. hir . definitions ( ) . def_index_to_hir_id ( to_convert. def_id . index ) ;
130+ for extern_crate in & crates_to_lint {
131+ assert ! ( extern_crate. def_id. is_local( ) ) ;
132+
133+ // If the crate is fully unused, we suggest removing it altogether.
134+ // We do this in any edition.
135+ if let Some ( & span) = unused_extern_crates. get ( & extern_crate. def_id ) {
136+ assert_eq ! ( extern_crate. def_id. krate, LOCAL_CRATE ) ;
137+ let hir_id = tcx. hir . definitions ( ) . def_index_to_hir_id ( extern_crate. def_id . index ) ;
138+ let id = tcx. hir . hir_to_node_id ( hir_id) ;
139+ let msg = "unused extern crate" ;
140+ tcx. struct_span_lint_node ( lint, id, span, msg)
141+ . span_suggestion_short ( span, "remove it" , "" . to_string ( ) )
142+ . emit ( ) ;
143+ continue ;
144+ }
145+
146+ // If we are not in Rust 2018 edition, then we don't make any further
147+ // suggestions.
148+ if !tcx. sess . rust_2018 ( ) {
149+ continue ;
150+ }
151+
152+ // If the extern crate has any attributes, they may have funky
153+ // semantics we can't faithfully represent using `use` (most
154+ // notably `#[macro_use]`). Ignore it.
155+ if !tcx. get_attrs ( extern_crate. def_id ) . is_empty ( ) {
156+ continue ;
157+ }
158+
159+ // Otherwise, we can convert it into a `use` of some kind.
160+ let hir_id = tcx. hir . definitions ( ) . def_index_to_hir_id ( extern_crate. def_id . index ) ;
151161 let id = tcx. hir . hir_to_node_id ( hir_id) ;
152162 let item = tcx. hir . expect_item ( id) ;
153163 let msg = "`extern crate` is not idiomatic in the new edition" ;
154-
155164 let help = format ! (
156165 "convert it to a `{}`" ,
157166 visibility_qualified( & item. vis, "use" )
158167 ) ;
159-
160- let base_replacement = match to_convert. orig_name {
168+ let base_replacement = match extern_crate. orig_name {
161169 Some ( orig_name) => format ! ( "use {} as {};" , orig_name, item. name) ,
162170 None => format ! ( "use {};" , item. name) ,
163171 } ;
164172 let replacement = visibility_qualified ( & item. vis , & base_replacement) ;
165-
166- tcx. struct_span_lint_node ( lint, id, to_convert. span , msg)
167- . span_suggestion_short ( to_convert. span , & help, replacement)
173+ tcx. struct_span_lint_node ( lint, id, extern_crate. span , msg)
174+ . span_suggestion_short ( extern_crate. span , & help, replacement)
168175 . emit ( ) ;
169176 }
170177}
171178
172179struct CollectExternCrateVisitor < ' a , ' tcx : ' a > {
173180 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
174- unused_extern_crates : & ' a FxHashMap < DefId , Span > ,
175- crates_to_convert_to_use : & ' a mut Vec < ExternCrateToConvertToUse > ,
181+ crates_to_lint : & ' a mut Vec < ExternCrateToLint > ,
176182}
177183
178- struct ExternCrateToConvertToUse {
184+ struct ExternCrateToLint {
179185 /// def-id of the extern crate
180186 def_id : DefId ,
181187
@@ -192,22 +198,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CollectExternCrateVisitor<'a, 'tcx> {
192198 fn visit_item ( & mut self , item : & hir:: Item ) {
193199 if let hir:: ItemExternCrate ( orig_name) = item. node {
194200 let extern_crate_def_id = self . tcx . hir . local_def_id ( item. id ) ;
195-
196- // If the crate is fully unused, we are going to suggest
197- // removing it anyway, so ignore it.
198- if self . unused_extern_crates . contains_key ( & extern_crate_def_id) {
199- return ;
200- }
201-
202- // If the extern crate has any attributes, they may have funky
203- // semantics we can't entirely understand. Ignore it.
204- if !self . tcx . get_attrs ( extern_crate_def_id) . is_empty ( ) {
205- return ;
206- }
207-
208- // Otherwise, we can convert it into a `use` of some kind.
209- self . crates_to_convert_to_use . push (
210- ExternCrateToConvertToUse {
201+ self . crates_to_lint . push (
202+ ExternCrateToLint {
211203 def_id : extern_crate_def_id,
212204 span : item. span ,
213205 orig_name,
0 commit comments