@@ -120,62 +120,68 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) {
120
120
. cloned ( )
121
121
. collect ( ) ;
122
122
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 ! [ ] ;
142
125
tcx. hir . krate ( ) . visit_all_item_likes ( & mut CollectExternCrateVisitor {
143
126
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,
146
128
} ) ;
147
129
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 ) ;
151
161
let id = tcx. hir . hir_to_node_id ( hir_id) ;
152
162
let item = tcx. hir . expect_item ( id) ;
153
163
let msg = "`extern crate` is not idiomatic in the new edition" ;
154
-
155
164
let help = format ! (
156
165
"convert it to a `{}`" ,
157
166
visibility_qualified( & item. vis, "use" )
158
167
) ;
159
-
160
- let base_replacement = match to_convert. orig_name {
168
+ let base_replacement = match extern_crate. orig_name {
161
169
Some ( orig_name) => format ! ( "use {} as {};" , orig_name, item. name) ,
162
170
None => format ! ( "use {};" , item. name) ,
163
171
} ;
164
172
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)
168
175
. emit ( ) ;
169
176
}
170
177
}
171
178
172
179
struct CollectExternCrateVisitor < ' a , ' tcx : ' a > {
173
180
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 > ,
176
182
}
177
183
178
- struct ExternCrateToConvertToUse {
184
+ struct ExternCrateToLint {
179
185
/// def-id of the extern crate
180
186
def_id : DefId ,
181
187
@@ -192,22 +198,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CollectExternCrateVisitor<'a, 'tcx> {
192
198
fn visit_item ( & mut self , item : & hir:: Item ) {
193
199
if let hir:: ItemExternCrate ( orig_name) = item. node {
194
200
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 {
211
203
def_id : extern_crate_def_id,
212
204
span : item. span ,
213
205
orig_name,
0 commit comments