aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-09-17 13:48:17 +0100
committerJonas Schievink <[email protected]>2020-09-17 13:48:17 +0100
commit0dca7acf0fb65545f0c46f0c604bb15400aa6d91 (patch)
tree7130de110e002f66618a6bc0329200a659f655d9
parentf792bc7ddd2616c0bb1fcdffda204151fc40b3d6 (diff)
Don't diagnose imports whose base crate is missing
-rw-r--r--crates/hir_def/src/nameres/collector.rs57
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs24
2 files changed, 64 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};
17use rustc_hash::FxHashMap; 17use rustc_hash::FxHashMap;
18use rustc_hash::FxHashSet;
18use syntax::ast; 19use syntax::ast;
19use test_utils::mark; 20use 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
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index cd0eb1a4b..576b813d2 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -93,6 +93,30 @@ fn unresolved_extern_crate() {
93} 93}
94 94
95#[test] 95#[test]
96fn dedup_unresolved_import_from_unresolved_crate() {
97 check_diagnostics(
98 r"
99 //- /main.rs crate:main
100 mod a {
101 extern crate doesnotexist;
102 //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
103
104 // Should not error, since we already errored for the missing crate.
105 use doesnotexist::{self, bla, *};
106
107 use crate::doesnotexist;
108 //^^^^^^^^^^^^^^^^^^^ unresolved import
109 }
110
111 mod m {
112 use super::doesnotexist;
113 //^^^^^^^^^^^^^^^^^^^ unresolved import
114 }
115 ",
116 );
117}
118
119#[test]
96fn unresolved_module() { 120fn unresolved_module() {
97 check_diagnostics( 121 check_diagnostics(
98 r" 122 r"