From 001a86dc03104b75df732d69257d22526cf422b7 Mon Sep 17 00:00:00 2001 From: Hasan Ali Date: Fri, 15 May 2020 22:23:49 +0100 Subject: Fix completion and hover for module and function of same name --- crates/ra_hir/src/semantics.rs | 6 ++++- crates/ra_hir/src/source_analyzer.rs | 51 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 515e5eb17..c1129a494 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -23,7 +23,7 @@ use crate::{ db::HirDatabase, diagnostics::Diagnostic, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, - source_analyzer::{resolve_hir_path, SourceAnalyzer}, + source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, }; @@ -451,6 +451,10 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> { pub fn resolve_hir_path(&self, path: &Path) -> Option { resolve_hir_path(self.db, &self.resolver, path) } + + pub fn resolve_hir_path_qualifier(&self, path: &Path) -> Option { + resolve_hir_path_qualifier(self.db, &self.resolver, path) + } } // FIXME: Change `HasSource` trait to work with `Semantics` and remove this? diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index c862a4f48..4b509f07c 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs @@ -226,6 +226,17 @@ impl SourceAnalyzer { // This must be a normal source file rather than macro file. let hir_path = crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; + + // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we + // trying to resolve foo::bar. + if let Some(outer_path) = path.syntax().parent().and_then(ast::Path::cast) { + if let Some(qualifier) = outer_path.qualifier() { + if path == &qualifier { + return resolve_hir_path_qualifier(db, &self.resolver, &hir_path); + } + } + } + resolve_hir_path(db, &self.resolver, &hir_path) } @@ -404,6 +415,7 @@ pub(crate) fn resolve_hir_path( TypeNs::BuiltinType(it) => PathResolution::Def(it.into()), TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), }); + let body_owner = resolver.body_owner(); let values = resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| { @@ -426,9 +438,48 @@ pub(crate) fn resolve_hir_path( .resolve_module_path_in_items(db.upcast(), path.mod_path()) .take_types() .map(|it| PathResolution::Def(it.into())); + types.or(values).or(items).or_else(|| { resolver .resolve_path_as_macro(db.upcast(), path.mod_path()) .map(|def| PathResolution::Macro(def.into())) }) } + +/// Resolves a path where we know it is a qualifier of another path. +/// +/// For example, if we have: +/// ``` +/// mod my { +/// pub mod foo { +/// struct Bar; +/// } +/// +/// pub fn foo() {} +/// } +/// ``` +/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function. +pub(crate) fn resolve_hir_path_qualifier( + db: &dyn HirDatabase, + resolver: &Resolver, + path: &crate::Path, +) -> Option { + let items = resolver + .resolve_module_path_in_items(db.upcast(), path.mod_path()) + .take_types() + .map(|it| PathResolution::Def(it.into())); + + if items.is_some() { + return items; + } + + resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty { + TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), + TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }), + TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => PathResolution::Def(Adt::from(it).into()), + TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), + TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), + TypeNs::BuiltinType(it) => PathResolution::Def(it.into()), + TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), + }) +} -- cgit v1.2.3