diff options
Diffstat (limited to 'crates/hir_def/src/nameres/collector.rs')
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 57 |
1 files changed, 40 insertions, 17 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index deb3885f9..818008169 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -15,6 +15,7 @@ use hir_expand::{ | |||
15 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, | 15 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, |
16 | }; | 16 | }; |
17 | use rustc_hash::FxHashMap; | 17 | use rustc_hash::FxHashMap; |
18 | use rustc_hash::FxHashSet; | ||
18 | use syntax::ast; | 19 | use syntax::ast; |
19 | use test_utils::mark; | 20 | use test_utils::mark; |
20 | 21 | ||
@@ -788,25 +789,47 @@ impl DefCollector<'_> { | |||
788 | } | 789 | } |
789 | 790 | ||
790 | fn finish(mut self) -> CrateDefMap { | 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 | for directive in &self.unresolved_imports { | 800 | for directive in &self.unresolved_imports { |
792 | match directive.import.source { | 801 | if let ImportSource::ExternCrate(krate) = directive.import.source { |
793 | ImportSource::Import(import) => { | 802 | let item_tree = self.db.item_tree(krate.file_id); |
794 | let item_tree = self.db.item_tree(import.file_id); | 803 | let extern_crate = &item_tree[krate.value]; |
795 | let import_data = &item_tree[import.value]; | 804 | |
796 | self.def_map.diagnostics.push(DefDiagnostic::unresolved_import( | 805 | diagnosed_extern_crates.insert(extern_crate.path.segments[0].clone()); |
797 | directive.module_id, | 806 | |
798 | InFile::new(import.file_id, import_data.ast_id), | 807 | self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate( |
799 | import_data.index, | 808 | directive.module_id, |
800 | )); | 809 | InFile::new(krate.file_id, extern_crate.ast_id), |
801 | } | 810 | )); |
802 | ImportSource::ExternCrate(krate) => { | 811 | } |
803 | let item_tree = self.db.item_tree(krate.file_id); | 812 | } |
804 | let extern_crate = &item_tree[krate.value]; | 813 | |
805 | self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate( | 814 | for directive in &self.unresolved_imports { |
806 | directive.module_id, | 815 | if let ImportSource::Import(import) = &directive.import.source { |
807 | InFile::new(krate.file_id, extern_crate.ast_id), | 816 | let item_tree = self.db.item_tree(import.file_id); |
808 | )); | 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 | ||