@@ -31,20 +31,18 @@ use crate::NameBindingKind;
31
31
use rustc_ast as ast;
32
32
use rustc_ast:: visit:: { self , Visitor } ;
33
33
use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap , FxIndexSet } ;
34
- use rustc_data_structures:: unord:: UnordSet ;
35
34
use rustc_errors:: { pluralize, MultiSpan } ;
36
35
use rustc_hir:: def:: { DefKind , Res } ;
37
36
use rustc_session:: lint:: builtin:: { MACRO_USE_EXTERN_CRATE , UNUSED_EXTERN_CRATES , UNUSED_IMPORTS } ;
38
37
use rustc_session:: lint:: BuiltinLintDiag ;
39
38
use rustc_span:: symbol:: { kw, Ident } ;
40
39
use rustc_span:: { Span , DUMMY_SP } ;
41
40
42
- #[ derive( Debug ) ]
43
41
struct UnusedImport {
44
42
use_tree : ast:: UseTree ,
45
43
use_tree_id : ast:: NodeId ,
46
44
item_span : Span ,
47
- unused : UnordSet < ast:: NodeId > ,
45
+ unused : FxIndexSet < ast:: NodeId > ,
48
46
}
49
47
50
48
impl UnusedImport {
@@ -97,7 +95,7 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
97
95
// FIXME(#120456) - is `swap_remove` correct?
98
96
self . r . maybe_unused_trait_imports . swap_remove ( & def_id) ;
99
97
if let Some ( i) = self . unused_imports . get_mut ( & self . base_id ) {
100
- i. unused . remove ( & id) ;
98
+ i. unused . swap_remove ( & id) ;
101
99
}
102
100
}
103
101
}
@@ -139,6 +137,16 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
139
137
}
140
138
}
141
139
140
+ fn merge_unused_import ( & mut self , unused_import : UnusedImport ) {
141
+ if let Some ( import) = self . unused_imports . get_mut ( & unused_import. use_tree_id ) {
142
+ for id in unused_import. unused {
143
+ import. unused . insert ( id) ;
144
+ }
145
+ } else {
146
+ self . unused_imports . entry ( unused_import. use_tree_id ) . or_insert ( unused_import) ;
147
+ }
148
+ }
149
+
142
150
fn report_unused_extern_crate_items (
143
151
& mut self ,
144
152
maybe_unused_extern_crates : FxHashMap < ast:: NodeId , Span > ,
@@ -447,6 +455,46 @@ impl Resolver<'_, '_> {
447
455
448
456
visitor. report_unused_extern_crate_items ( maybe_unused_extern_crates) ;
449
457
458
+ let unused_imports = & visitor. unused_imports ;
459
+ let mut check_redundant_imports = FxIndexSet :: default ( ) ;
460
+ for module in visitor. r . arenas . local_modules ( ) . iter ( ) {
461
+ for ( _key, resolution) in visitor. r . resolutions ( * module) . borrow ( ) . iter ( ) {
462
+ let resolution = resolution. borrow ( ) ;
463
+
464
+ if let Some ( binding) = resolution. binding
465
+ && let NameBindingKind :: Import { import, .. } = binding. kind
466
+ && let ImportKind :: Single { id, .. } = import. kind
467
+ {
468
+ if let Some ( unused_import) = unused_imports. get ( & import. root_id )
469
+ && unused_import. unused . contains ( & id)
470
+ {
471
+ continue ;
472
+ }
473
+
474
+ check_redundant_imports. insert ( import) ;
475
+ }
476
+ }
477
+ }
478
+
479
+ let mut redundant_source_spans = FxHashMap :: default ( ) ;
480
+ for import in check_redundant_imports {
481
+ if let Some ( redundant_spans) = visitor. r . check_for_redundant_imports ( import)
482
+ && let ImportKind :: Single { source, id, .. } = import. kind
483
+ {
484
+ let mut finder = ImportFinderVisitor {
485
+ node_id : id,
486
+ root_node_id : import. root_id ,
487
+ unused_import : None ,
488
+ item_span : Span :: default ( ) ,
489
+ } ;
490
+ visit:: walk_crate ( & mut finder, krate) ;
491
+ if let Some ( unused) = finder. unused_import {
492
+ visitor. merge_unused_import ( unused) ;
493
+ redundant_source_spans. insert ( id, ( source, redundant_spans) ) ;
494
+ }
495
+ }
496
+ }
497
+
450
498
for unused in visitor. unused_imports . values ( ) {
451
499
let mut fixes = Vec :: new ( ) ;
452
500
let spans = match calc_unused_spans ( unused, & unused. use_tree , unused. use_tree_id ) {
@@ -467,19 +515,34 @@ impl Resolver<'_, '_> {
467
515
}
468
516
} ;
469
517
470
- let ms = MultiSpan :: from_spans ( spans) ;
518
+ let mut redundant_sources = vec ! [ ] ;
519
+ for id in unused. unused . clone ( ) {
520
+ if let Some ( source) = redundant_source_spans. get ( & id) {
521
+ redundant_sources. push ( source. clone ( ) ) ;
522
+ }
523
+ }
471
524
472
- let mut span_snippets = ms
525
+ let multi_span = MultiSpan :: from_spans ( spans) ;
526
+ let mut span_snippets = multi_span
473
527
. primary_spans ( )
474
528
. iter ( )
475
529
. filter_map ( |span| tcx. sess . source_map ( ) . span_to_snippet ( * span) . ok ( ) )
476
530
. map ( |s| format ! ( "`{s}`" ) )
477
531
. collect :: < Vec < String > > ( ) ;
478
532
span_snippets. sort ( ) ;
479
533
534
+ let remove_type =
535
+ if unused. unused . iter ( ) . all ( |i| redundant_source_spans. get ( i) . is_none ( ) ) {
536
+ "unused import"
537
+ } else if unused. unused . iter ( ) . all ( |i| redundant_source_spans. get ( i) . is_some ( ) ) {
538
+ "redundant import"
539
+ } else {
540
+ "unused or redundant import"
541
+ } ;
480
542
let msg = format ! (
481
- "unused import{}{}" ,
482
- pluralize!( ms. primary_spans( ) . len( ) ) ,
543
+ "{}{}{}" ,
544
+ remove_type,
545
+ pluralize!( multi_span. primary_spans( ) . len( ) ) ,
483
546
if !span_snippets. is_empty( ) {
484
547
format!( ": {}" , span_snippets. join( ", " ) )
485
548
} else {
@@ -488,11 +551,11 @@ impl Resolver<'_, '_> {
488
551
) ;
489
552
490
553
let fix_msg = if fixes. len ( ) == 1 && fixes[ 0 ] . 0 == unused. item_span {
491
- "remove the whole `use` item"
492
- } else if ms . primary_spans ( ) . len ( ) > 1 {
493
- "remove the unused imports"
554
+ "remove the whole `use` item" . to_owned ( )
555
+ } else if multi_span . primary_spans ( ) . len ( ) > 1 {
556
+ format ! ( "remove the {}s" , remove_type )
494
557
} else {
495
- "remove the unused import"
558
+ format ! ( "remove the {}" , remove_type )
496
559
} ;
497
560
498
561
// If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]`
@@ -522,64 +585,15 @@ impl Resolver<'_, '_> {
522
585
visitor. r . lint_buffer . buffer_lint_with_diagnostic (
523
586
UNUSED_IMPORTS ,
524
587
unused. use_tree_id ,
525
- ms ,
588
+ multi_span ,
526
589
msg,
527
- BuiltinLintDiag :: UnusedImports ( fix_msg. into ( ) , fixes, test_module_span) ,
590
+ BuiltinLintDiag :: UnusedImports (
591
+ fix_msg. into ( ) ,
592
+ fixes,
593
+ test_module_span,
594
+ redundant_sources,
595
+ ) ,
528
596
) ;
529
597
}
530
-
531
- let unused_imports = visitor. unused_imports ;
532
- let mut check_redundant_imports = FxIndexSet :: default ( ) ;
533
- for module in self . arenas . local_modules ( ) . iter ( ) {
534
- for ( _key, resolution) in self . resolutions ( * module) . borrow ( ) . iter ( ) {
535
- let resolution = resolution. borrow ( ) ;
536
-
537
- if let Some ( binding) = resolution. binding
538
- && let NameBindingKind :: Import { import, .. } = binding. kind
539
- && let ImportKind :: Single { id, .. } = import. kind
540
- {
541
- if let Some ( unused_import) = unused_imports. get ( & import. root_id )
542
- && unused_import. unused . contains ( & id)
543
- {
544
- continue ;
545
- }
546
-
547
- check_redundant_imports. insert ( import) ;
548
- }
549
- }
550
- }
551
-
552
- for import in check_redundant_imports {
553
- if let Some ( redundant_spans) = self . check_for_redundant_imports ( import)
554
- && let ImportKind :: Single { source, id, .. } = import. kind
555
- {
556
- let mut visitor = ImportFinderVisitor {
557
- node_id : id,
558
- root_node_id : import. root_id ,
559
- unused_import : None ,
560
- item_span : Span :: default ( ) ,
561
- } ;
562
- visit:: walk_crate ( & mut visitor, krate) ;
563
- if let Some ( unused) = visitor. unused_import {
564
- let remove_span =
565
- match calc_unused_spans ( & unused, & unused. use_tree , unused. use_tree_id ) {
566
- UnusedSpanResult :: FlatUnused ( _, remove) => remove,
567
- UnusedSpanResult :: NestedFullUnused ( _, remove) => remove,
568
- UnusedSpanResult :: NestedPartialUnused ( _, removes) => {
569
- assert_eq ! ( removes. len( ) , 1 ) ;
570
- removes[ 0 ]
571
- }
572
- _ => import. use_span ,
573
- } ;
574
- self . lint_buffer . buffer_lint_with_diagnostic (
575
- UNUSED_IMPORTS ,
576
- id,
577
- import. span ,
578
- format ! ( "the item `{source}` is imported redundantly" ) ,
579
- BuiltinLintDiag :: RedundantImport ( redundant_spans, source, remove_span) ,
580
- ) ;
581
- }
582
- }
583
- }
584
598
}
585
599
}
0 commit comments