Skip to content

Commit ebaa05a

Browse files
bors[bot]hasali19
andauthored
Merge #4472
4472: Fix path resolution for module and function with same name r=hasali19 a=hasali19 This fixes #3970 and also fixes completion for the same issue. Co-authored-by: Hasan Ali <[email protected]>
2 parents 9322790 + bb78d31 commit ebaa05a

File tree

4 files changed

+115
-2
lines changed

4 files changed

+115
-2
lines changed

crates/ra_hir/src/semantics.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::{
2323
db::HirDatabase,
2424
diagnostics::Diagnostic,
2525
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
26-
source_analyzer::{resolve_hir_path, SourceAnalyzer},
26+
source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
2727
AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef,
2828
Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam,
2929
};
@@ -451,6 +451,23 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> {
451451
pub fn resolve_hir_path(&self, path: &Path) -> Option<PathResolution> {
452452
resolve_hir_path(self.db, &self.resolver, path)
453453
}
454+
455+
/// Resolves a path where we know it is a qualifier of another path.
456+
///
457+
/// For example, if we have:
458+
/// ```
459+
/// mod my {
460+
/// pub mod foo {
461+
/// struct Bar;
462+
/// }
463+
///
464+
/// pub fn foo() {}
465+
/// }
466+
/// ```
467+
/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
468+
pub fn resolve_hir_path_qualifier(&self, path: &Path) -> Option<PathResolution> {
469+
resolve_hir_path_qualifier(self.db, &self.resolver, path)
470+
}
454471
}
455472

456473
// FIXME: Change `HasSource` trait to work with `Semantics` and remove this?

crates/ra_hir/src/source_analyzer.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,17 @@ impl SourceAnalyzer {
226226
// This must be a normal source file rather than macro file.
227227
let hir_path =
228228
crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?;
229+
230+
// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
231+
// trying to resolve foo::bar.
232+
if let Some(outer_path) = path.syntax().parent().and_then(ast::Path::cast) {
233+
if let Some(qualifier) = outer_path.qualifier() {
234+
if path == &qualifier {
235+
return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
236+
}
237+
}
238+
}
239+
229240
resolve_hir_path(db, &self.resolver, &hir_path)
230241
}
231242

@@ -404,6 +415,7 @@ pub(crate) fn resolve_hir_path(
404415
TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
405416
TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
406417
});
418+
407419
let body_owner = resolver.body_owner();
408420
let values =
409421
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(
426438
.resolve_module_path_in_items(db.upcast(), path.mod_path())
427439
.take_types()
428440
.map(|it| PathResolution::Def(it.into()));
441+
429442
types.or(values).or(items).or_else(|| {
430443
resolver
431444
.resolve_path_as_macro(db.upcast(), path.mod_path())
432445
.map(|def| PathResolution::Macro(def.into()))
433446
})
434447
}
448+
449+
/// Resolves a path where we know it is a qualifier of another path.
450+
///
451+
/// For example, if we have:
452+
/// ```
453+
/// mod my {
454+
/// pub mod foo {
455+
/// struct Bar;
456+
/// }
457+
///
458+
/// pub fn foo() {}
459+
/// }
460+
/// ```
461+
/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
462+
pub(crate) fn resolve_hir_path_qualifier(
463+
db: &dyn HirDatabase,
464+
resolver: &Resolver,
465+
path: &crate::Path,
466+
) -> Option<PathResolution> {
467+
let items = resolver
468+
.resolve_module_path_in_items(db.upcast(), path.mod_path())
469+
.take_types()
470+
.map(|it| PathResolution::Def(it.into()));
471+
472+
if items.is_some() {
473+
return items;
474+
}
475+
476+
resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty {
477+
TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
478+
TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
479+
TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => PathResolution::Def(Adt::from(it).into()),
480+
TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
481+
TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
482+
TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
483+
TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
484+
})
485+
}

crates/ra_ide/src/completion/complete_qualified_path.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
2020
let scope = ctx.scope();
2121
let context_module = scope.module();
2222

23-
let res = match scope.resolve_hir_path(&path) {
23+
let res = match scope.resolve_hir_path_qualifier(&path) {
2424
Some(res) => res,
2525
None => return,
2626
};
@@ -225,6 +225,34 @@ mod tests {
225225
);
226226
}
227227

228+
#[test]
229+
fn completes_mod_with_same_name_as_function() {
230+
assert_debug_snapshot!(
231+
do_reference_completion(
232+
r"
233+
use self::my::<|>;
234+
235+
mod my {
236+
pub struct Bar;
237+
}
238+
239+
fn my() {}
240+
"
241+
),
242+
@r###"
243+
[
244+
CompletionItem {
245+
label: "Bar",
246+
source_range: 31..31,
247+
delete: 31..31,
248+
insert: "Bar",
249+
kind: Struct,
250+
},
251+
]
252+
"###
253+
);
254+
}
255+
228256
#[test]
229257
fn path_visibility() {
230258
assert_debug_snapshot!(

crates/ra_ide/src/hover.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,4 +921,21 @@ fn func(foo: i32) { if true { <|>foo; }; }
921921
&["unsafe trait foo"],
922922
);
923923
}
924+
925+
#[test]
926+
fn test_hover_mod_with_same_name_as_function() {
927+
check_hover_result(
928+
"
929+
//- /lib.rs
930+
use self::m<|>y::Bar;
931+
932+
mod my {
933+
pub struct Bar;
934+
}
935+
936+
fn my() {}
937+
",
938+
&["mod my"],
939+
);
940+
}
924941
}

0 commit comments

Comments
 (0)