@@ -39,6 +39,7 @@ use rustc_session::lint::BuiltinLintDiag;
39
39
use rustc_span:: symbol:: { kw, Ident } ;
40
40
use rustc_span:: { Span , DUMMY_SP } ;
41
41
42
+ #[ derive( Debug ) ]
42
43
struct UnusedImport {
43
44
use_tree : ast:: UseTree ,
44
45
use_tree_id : ast:: NodeId ,
@@ -137,6 +138,81 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
137
138
self . check_import_as_underscore ( item, * id) ;
138
139
}
139
140
}
141
+
142
+ fn report_unused_extern_crate_items (
143
+ & mut self ,
144
+ maybe_unused_extern_crates : FxHashMap < ast:: NodeId , Span > ,
145
+ ) {
146
+ let tcx = self . r . tcx ( ) ;
147
+ for extern_crate in & self . extern_crate_items {
148
+ let warn_if_unused = !extern_crate. ident . name . as_str ( ) . starts_with ( '_' ) ;
149
+
150
+ // If the crate is fully unused, we suggest removing it altogether.
151
+ // We do this in any edition.
152
+ if warn_if_unused {
153
+ if let Some ( & span) = maybe_unused_extern_crates. get ( & extern_crate. id ) {
154
+ self . r . lint_buffer . buffer_lint_with_diagnostic (
155
+ UNUSED_EXTERN_CRATES ,
156
+ extern_crate. id ,
157
+ span,
158
+ "unused extern crate" ,
159
+ BuiltinLintDiag :: UnusedExternCrate {
160
+ removal_span : extern_crate. span_with_attributes ,
161
+ } ,
162
+ ) ;
163
+ continue ;
164
+ }
165
+ }
166
+
167
+ // If we are not in Rust 2018 edition, then we don't make any further
168
+ // suggestions.
169
+ if !tcx. sess . at_least_rust_2018 ( ) {
170
+ continue ;
171
+ }
172
+
173
+ // If the extern crate has any attributes, they may have funky
174
+ // semantics we can't faithfully represent using `use` (most
175
+ // notably `#[macro_use]`). Ignore it.
176
+ if extern_crate. has_attrs {
177
+ continue ;
178
+ }
179
+
180
+ // If the extern crate is renamed, then we cannot suggest replacing it with a use as this
181
+ // would not insert the new name into the prelude, where other imports in the crate may be
182
+ // expecting it.
183
+ if extern_crate. renames {
184
+ continue ;
185
+ }
186
+
187
+ // If the extern crate isn't in the extern prelude,
188
+ // there is no way it can be written as a `use`.
189
+ if !self
190
+ . r
191
+ . extern_prelude
192
+ . get ( & extern_crate. ident )
193
+ . is_some_and ( |entry| !entry. introduced_by_item )
194
+ {
195
+ continue ;
196
+ }
197
+
198
+ let vis_span = extern_crate
199
+ . vis_span
200
+ . find_ancestor_inside ( extern_crate. span )
201
+ . unwrap_or ( extern_crate. vis_span ) ;
202
+ let ident_span = extern_crate
203
+ . ident
204
+ . span
205
+ . find_ancestor_inside ( extern_crate. span )
206
+ . unwrap_or ( extern_crate. ident . span ) ;
207
+ self . r . lint_buffer . buffer_lint_with_diagnostic (
208
+ UNUSED_EXTERN_CRATES ,
209
+ extern_crate. id ,
210
+ extern_crate. span ,
211
+ "`extern crate` is not idiomatic in the new edition" ,
212
+ BuiltinLintDiag :: ExternCrateNotIdiomatic { vis_span, ident_span } ,
213
+ ) ;
214
+ }
215
+ }
140
216
}
141
217
142
218
impl < ' a , ' b , ' tcx > Visitor < ' a > for UnusedImportCheckVisitor < ' a , ' b , ' tcx > {
@@ -335,6 +411,8 @@ impl Resolver<'_, '_> {
335
411
} ;
336
412
visit:: walk_crate ( & mut visitor, krate) ;
337
413
414
+ visitor. report_unused_extern_crate_items ( maybe_unused_extern_crates) ;
415
+
338
416
for unused in visitor. unused_imports . values ( ) {
339
417
let mut fixes = Vec :: new ( ) ;
340
418
let spans = match calc_unused_spans ( unused, & unused. use_tree , unused. use_tree_id ) {
@@ -416,75 +494,6 @@ impl Resolver<'_, '_> {
416
494
) ;
417
495
}
418
496
419
- for extern_crate in visitor. extern_crate_items {
420
- let warn_if_unused = !extern_crate. ident . name . as_str ( ) . starts_with ( '_' ) ;
421
-
422
- // If the crate is fully unused, we suggest removing it altogether.
423
- // We do this in any edition.
424
- if warn_if_unused {
425
- if let Some ( & span) = maybe_unused_extern_crates. get ( & extern_crate. id ) {
426
- visitor. r . lint_buffer . buffer_lint_with_diagnostic (
427
- UNUSED_EXTERN_CRATES ,
428
- extern_crate. id ,
429
- span,
430
- "unused extern crate" ,
431
- BuiltinLintDiag :: UnusedExternCrate {
432
- removal_span : extern_crate. span_with_attributes ,
433
- } ,
434
- ) ;
435
- continue ;
436
- }
437
- }
438
-
439
- // If we are not in Rust 2018 edition, then we don't make any further
440
- // suggestions.
441
- if !tcx. sess . at_least_rust_2018 ( ) {
442
- continue ;
443
- }
444
-
445
- // If the extern crate has any attributes, they may have funky
446
- // semantics we can't faithfully represent using `use` (most
447
- // notably `#[macro_use]`). Ignore it.
448
- if extern_crate. has_attrs {
449
- continue ;
450
- }
451
-
452
- // If the extern crate is renamed, then we cannot suggest replacing it with a use as this
453
- // would not insert the new name into the prelude, where other imports in the crate may be
454
- // expecting it.
455
- if extern_crate. renames {
456
- continue ;
457
- }
458
-
459
- // If the extern crate isn't in the extern prelude,
460
- // there is no way it can be written as a `use`.
461
- if !visitor
462
- . r
463
- . extern_prelude
464
- . get ( & extern_crate. ident )
465
- . is_some_and ( |entry| !entry. introduced_by_item )
466
- {
467
- continue ;
468
- }
469
-
470
- let vis_span = extern_crate
471
- . vis_span
472
- . find_ancestor_inside ( extern_crate. span )
473
- . unwrap_or ( extern_crate. vis_span ) ;
474
- let ident_span = extern_crate
475
- . ident
476
- . span
477
- . find_ancestor_inside ( extern_crate. span )
478
- . unwrap_or ( extern_crate. ident . span ) ;
479
- visitor. r . lint_buffer . buffer_lint_with_diagnostic (
480
- UNUSED_EXTERN_CRATES ,
481
- extern_crate. id ,
482
- extern_crate. span ,
483
- "`extern crate` is not idiomatic in the new edition" ,
484
- BuiltinLintDiag :: ExternCrateNotIdiomatic { vis_span, ident_span } ,
485
- ) ;
486
- }
487
-
488
497
let unused_imports = visitor. unused_imports ;
489
498
let mut check_redundant_imports = FxIndexSet :: default ( ) ;
490
499
for module in self . arenas . local_modules ( ) . iter ( ) {
0 commit comments