diff options
author | Jonas Schievink <[email protected]> | 2020-09-17 13:48:17 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2020-09-17 13:48:17 +0100 |
commit | 0dca7acf0fb65545f0c46f0c604bb15400aa6d91 (patch) | |
tree | 7130de110e002f66618a6bc0329200a659f655d9 | |
parent | f792bc7ddd2616c0bb1fcdffda204151fc40b3d6 (diff) |
Don't diagnose imports whose base crate is missing
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 57 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 24 |
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 | }; |
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 | ||
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] |
96 | fn 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] | ||
96 | fn unresolved_module() { | 120 | fn unresolved_module() { |
97 | check_diagnostics( | 121 | check_diagnostics( |
98 | r" | 122 | r" |