From 58ed8ee6650058d5dc4ce511e2d9c04fdfa09aaf Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 11 Feb 2019 15:39:26 +0300 Subject: use extern prelude in Resolver This fixes two bugs: - completion for paths works again - we handle extern prelude shadowing more correctly --- crates/ra_hir/src/nameres.rs | 22 ++++++--------- crates/ra_hir/src/nameres/tests.rs | 32 ++++++++++++++++++++++ crates/ra_hir/src/resolve.rs | 7 ++--- crates/ra_ide_api/src/completion/complete_path.rs | 16 +++++++++++ ...on_item__completes_use_paths_across_crates.snap | 22 +++++++++++++++ 5 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 crates/ra_ide_api/src/completion/snapshots/completion_item__completes_use_paths_across_crates.snap diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 94f7db024..4b8097235 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -434,6 +434,14 @@ impl ItemMap { self.resolve_path_fp(db, original_module, path).0 } + pub(crate) fn resolve_name_in_module(&self, module: Module, name: &Name) -> PerNs { + let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def); + let from_extern_prelude = + self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); + + from_scope.combine(from_extern_prelude) + } + // Returns Yes if we are sure that additions to `ItemMap` wouldn't change // the result. fn resolve_path_fp( @@ -451,19 +459,7 @@ impl ItemMap { Some((_, segment)) => segment, None => return (PerNs::none(), ReachedFixedPoint::Yes), }; - // Resolve in: - // - current module / scope - // - extern prelude - match self[original_module.module_id].items.get(&segment.name) { - Some(res) if !res.def.is_none() => res.def, - _ => { - if let Some(def) = self.extern_prelude.get(&segment.name) { - PerNs::types(*def) - } else { - return (PerNs::none(), ReachedFixedPoint::No); - } - } - } + self.resolve_name_in_module(original_module, &segment.name) } PathKind::Super => { if let Some(p) = original_module.parent(db) { diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 9b621fbc2..f1a1f5b76 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs @@ -536,6 +536,38 @@ fn reexport_across_crates() { ); } +#[test] +fn values_dont_shadow_extern_crates() { + let mut db = MockDatabase::with_files( + " + //- /main.rs + fn foo() {} + use foo::Bar; + + //- /foo/lib.rs + pub struct Bar; + ", + ); + db.set_crate_graph_from_fixture(crate_graph! { + "main": ("/main.rs", ["foo"]), + "foo": ("/foo/lib.rs", []), + }); + let main_id = db.file_id_of("/main.rs"); + + let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); + let krate = module.krate(&db).unwrap(); + let item_map = db.item_map(krate); + + check_module_item_map( + &item_map, + module.module_id, + " + Bar: t v + foo: v + ", + ); +} + fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) { let (mut db, pos) = MockDatabase::with_position(initial); let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap(); diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 3d7ec5683..e8abac5bc 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -149,10 +149,7 @@ impl Scope { if let Some(KnownName::SelfParam) = name.as_known_name() { PerNs::types(Resolution::Def(m.module.into())) } else { - match m.item_map[m.module.module_id].get(name) { - Some(res) => res.def.map(Resolution::Def), - None => PerNs::none(), - } + m.item_map.resolve_name_in_module(m.module, name).map(Resolution::Def) } } Scope::GenericParams(gp) => match gp.find_by_name(name) { @@ -177,7 +174,7 @@ impl Scope { } } - fn collect_names(&self, f: &mut FnMut(Name, PerNs)) { + fn collect_names(&self, f: &mut dyn FnMut(Name, PerNs)) { match self { Scope::ModuleScope(m) => { // TODO: should we provide `self` here? diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index c47a14e9f..39aefdb13 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs @@ -186,4 +186,20 @@ mod tests { ", ); } + + #[test] + fn completes_use_paths_across_crates() { + check_reference_completion( + "completes_use_paths_across_crates", + " + //- /main.rs + use foo::<|>; + + //- /foo/lib.rs + pub mod bar { + pub struct S; + } + ", + ); + } } diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_use_paths_across_crates.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_use_paths_across_crates.snap new file mode 100644 index 000000000..4b40fcf27 --- /dev/null +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_use_paths_across_crates.snap @@ -0,0 +1,22 @@ +--- +created: "2019-02-11T11:53:02.410665254Z" +creator: insta@0.6.1 +source: crates/ra_ide_api/src/completion/completion_item.rs +expression: kind_completions +--- +[ + CompletionItem { + completion_kind: Reference, + label: "bar", + kind: Some( + Module + ), + detail: None, + documentation: None, + lookup: None, + insert_text: None, + insert_text_format: PlainText, + source_range: [9; 9), + text_edit: None + } +] -- cgit v1.2.3