@@ -137,6 +137,81 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
137137 self . check_import_as_underscore ( item, * id) ;
138138 }
139139 }
140+
141+ fn report_unused_extern_crate_items (
142+ & mut self ,
143+ maybe_unused_extern_crates : FxHashMap < ast:: NodeId , Span > ,
144+ ) {
145+ let tcx = self . r . tcx ( ) ;
146+ for extern_crate in & self . extern_crate_items {
147+ let warn_if_unused = !extern_crate. ident . name . as_str ( ) . starts_with ( '_' ) ;
148+
149+ // If the crate is fully unused, we suggest removing it altogether.
150+ // We do this in any edition.
151+ if warn_if_unused {
152+ if let Some ( & span) = maybe_unused_extern_crates. get ( & extern_crate. id ) {
153+ self . r . lint_buffer . buffer_lint_with_diagnostic (
154+ UNUSED_EXTERN_CRATES ,
155+ extern_crate. id ,
156+ span,
157+ "unused extern crate" ,
158+ BuiltinLintDiag :: UnusedExternCrate {
159+ removal_span : extern_crate. span_with_attributes ,
160+ } ,
161+ ) ;
162+ continue ;
163+ }
164+ }
165+
166+ // If we are not in Rust 2018 edition, then we don't make any further
167+ // suggestions.
168+ if !tcx. sess . at_least_rust_2018 ( ) {
169+ continue ;
170+ }
171+
172+ // If the extern crate has any attributes, they may have funky
173+ // semantics we can't faithfully represent using `use` (most
174+ // notably `#[macro_use]`). Ignore it.
175+ if extern_crate. has_attrs {
176+ continue ;
177+ }
178+
179+ // If the extern crate is renamed, then we cannot suggest replacing it with a use as this
180+ // would not insert the new name into the prelude, where other imports in the crate may be
181+ // expecting it.
182+ if extern_crate. renames {
183+ continue ;
184+ }
185+
186+ // If the extern crate isn't in the extern prelude,
187+ // there is no way it can be written as a `use`.
188+ if !self
189+ . r
190+ . extern_prelude
191+ . get ( & extern_crate. ident )
192+ . is_some_and ( |entry| !entry. introduced_by_item )
193+ {
194+ continue ;
195+ }
196+
197+ let vis_span = extern_crate
198+ . vis_span
199+ . find_ancestor_inside ( extern_crate. span )
200+ . unwrap_or ( extern_crate. vis_span ) ;
201+ let ident_span = extern_crate
202+ . ident
203+ . span
204+ . find_ancestor_inside ( extern_crate. span )
205+ . unwrap_or ( extern_crate. ident . span ) ;
206+ self . r . lint_buffer . buffer_lint_with_diagnostic (
207+ UNUSED_EXTERN_CRATES ,
208+ extern_crate. id ,
209+ extern_crate. span ,
210+ "`extern crate` is not idiomatic in the new edition" ,
211+ BuiltinLintDiag :: ExternCrateNotIdiomatic { vis_span, ident_span } ,
212+ ) ;
213+ }
214+ }
140215}
141216
142217impl < ' a , ' b , ' tcx > Visitor < ' a > for UnusedImportCheckVisitor < ' a , ' b , ' tcx > {
@@ -335,6 +410,8 @@ impl Resolver<'_, '_> {
335410 } ;
336411 visit:: walk_crate ( & mut visitor, krate) ;
337412
413+ visitor. report_unused_extern_crate_items ( maybe_unused_extern_crates) ;
414+
338415 for unused in visitor. unused_imports . values ( ) {
339416 let mut fixes = Vec :: new ( ) ;
340417 let spans = match calc_unused_spans ( unused, & unused. use_tree , unused. use_tree_id ) {
@@ -416,75 +493,6 @@ impl Resolver<'_, '_> {
416493 ) ;
417494 }
418495
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-
488496 let unused_imports = visitor. unused_imports ;
489497 let mut check_redundant_imports = FxIndexSet :: default ( ) ;
490498 for module in self . arenas . local_modules ( ) . iter ( ) {
0 commit comments