Skip to content

Commit 0dca7ac

Browse files
author
Jonas Schievink
committed
Don't diagnose imports whose base crate is missing
1 parent f792bc7 commit 0dca7ac

File tree

2 files changed

+64
-17
lines changed

2 files changed

+64
-17
lines changed

crates/hir_def/src/nameres/collector.rs

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use hir_expand::{
1515
HirFileId, MacroCallId, MacroDefId, MacroDefKind,
1616
};
1717
use rustc_hash::FxHashMap;
18+
use rustc_hash::FxHashSet;
1819
use syntax::ast;
1920
use test_utils::mark;
2021

@@ -788,25 +789,47 @@ impl DefCollector<'_> {
788789
}
789790

790791
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();
791800
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+
_ => {}
809826
}
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+
));
810833
}
811834
}
812835

crates/hir_def/src/nameres/tests/diagnostics.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,30 @@ fn unresolved_extern_crate() {
9292
);
9393
}
9494

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+
95119
#[test]
96120
fn unresolved_module() {
97121
check_diagnostics(

0 commit comments

Comments
 (0)