@@ -39,6 +39,7 @@ use rustc_session::lint::BuiltinLintDiag;
3939use rustc_span:: symbol:: { kw, Ident } ;
4040use rustc_span:: { Span , DUMMY_SP } ;
4141
42+ #[ derive( Debug ) ]
4243struct UnusedImport {
4344 use_tree : ast:: UseTree ,
4445 use_tree_id : ast:: NodeId ,
@@ -137,6 +138,81 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
137138 self . check_import_as_underscore ( item, * id) ;
138139 }
139140 }
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+ }
140216}
141217
142218impl < ' a , ' b , ' tcx > Visitor < ' a > for UnusedImportCheckVisitor < ' a , ' b , ' tcx > {
@@ -335,6 +411,8 @@ impl Resolver<'_, '_> {
335411 } ;
336412 visit:: walk_crate ( & mut visitor, krate) ;
337413
414+ visitor. report_unused_extern_crate_items ( maybe_unused_extern_crates) ;
415+
338416 for unused in visitor. unused_imports . values ( ) {
339417 let mut fixes = Vec :: new ( ) ;
340418 let spans = match calc_unused_spans ( unused, & unused. use_tree , unused. use_tree_id ) {
@@ -416,75 +494,6 @@ impl Resolver<'_, '_> {
416494 ) ;
417495 }
418496
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-
488497 let unused_imports = visitor. unused_imports ;
489498 let mut check_redundant_imports = FxIndexSet :: default ( ) ;
490499 for module in self . arenas . local_modules ( ) . iter ( ) {
0 commit comments