@@ -15,6 +15,7 @@ use hir_expand::{
15
15
HirFileId , MacroCallId , MacroDefId , MacroDefKind ,
16
16
} ;
17
17
use rustc_hash:: FxHashMap ;
18
+ use rustc_hash:: FxHashSet ;
18
19
use syntax:: ast;
19
20
use test_utils:: mark;
20
21
@@ -788,25 +789,47 @@ impl DefCollector<'_> {
788
789
}
789
790
790
791
fn finish ( mut self ) -> CrateDefMap {
792
+ // Emit diagnostics for all remaining unresolved imports.
793
+
794
+ // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
795
+ // resolve. We first emit diagnostics for unresolved extern crates and collect the missing
796
+ // crate names. Then we emit diagnostics for unresolved imports, but only if the import
797
+ // doesn't start with an unresolved crate's name. Due to renaming and reexports, this is a
798
+ // heuristic, but it works in practice.
799
+ let mut diagnosed_extern_crates = FxHashSet :: default ( ) ;
791
800
for directive in & self . unresolved_imports {
792
- match directive. import . source {
793
- ImportSource :: Import ( import) => {
794
- let item_tree = self . db . item_tree ( import. file_id ) ;
795
- let import_data = & item_tree[ import. value ] ;
796
- self . def_map . diagnostics . push ( DefDiagnostic :: unresolved_import (
797
- directive. module_id ,
798
- InFile :: new ( import. file_id , import_data. ast_id ) ,
799
- import_data. index ,
800
- ) ) ;
801
- }
802
- ImportSource :: ExternCrate ( krate) => {
803
- let item_tree = self . db . item_tree ( krate. file_id ) ;
804
- let extern_crate = & item_tree[ krate. value ] ;
805
- self . def_map . diagnostics . push ( DefDiagnostic :: unresolved_extern_crate (
806
- directive. module_id ,
807
- InFile :: new ( krate. file_id , extern_crate. ast_id ) ,
808
- ) ) ;
801
+ if let ImportSource :: ExternCrate ( krate) = directive. import . source {
802
+ let item_tree = self . db . item_tree ( krate. file_id ) ;
803
+ let extern_crate = & item_tree[ krate. value ] ;
804
+
805
+ diagnosed_extern_crates. insert ( extern_crate. path . segments [ 0 ] . clone ( ) ) ;
806
+
807
+ self . def_map . diagnostics . push ( DefDiagnostic :: unresolved_extern_crate (
808
+ directive. module_id ,
809
+ InFile :: new ( krate. file_id , extern_crate. ast_id ) ,
810
+ ) ) ;
811
+ }
812
+ }
813
+
814
+ for directive in & self . unresolved_imports {
815
+ if let ImportSource :: Import ( import) = & directive. import . source {
816
+ let item_tree = self . db . item_tree ( import. file_id ) ;
817
+ let import_data = & item_tree[ import. value ] ;
818
+
819
+ match ( import_data. path . segments . first ( ) , & import_data. path . kind ) {
820
+ ( Some ( krate) , PathKind :: Plain ) | ( Some ( krate) , PathKind :: Abs ) => {
821
+ if diagnosed_extern_crates. contains ( krate) {
822
+ continue ;
823
+ }
824
+ }
825
+ _ => { }
809
826
}
827
+
828
+ self . def_map . diagnostics . push ( DefDiagnostic :: unresolved_import (
829
+ directive. module_id ,
830
+ InFile :: new ( import. file_id , import_data. ast_id ) ,
831
+ import_data. index ,
832
+ ) ) ;
810
833
}
811
834
}
812
835
0 commit comments