diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-05-16 20:49:01 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-05-16 20:49:01 +0100 |
commit | ebaa05a4478096aaf3bc2a48d0d171a287422c7c (patch) | |
tree | 3a28337d2213a819b241d9d950ca64f6dcaf2345 /crates/ra_hir/src | |
parent | 9322790066fe86056965332078bed74ff7f77293 (diff) | |
parent | bb78d314e15999a68f5eb865486824966c13402f (diff) |
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]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir/src/source_analyzer.rs | 51 |
2 files changed, 69 insertions, 1 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 515e5eb17..7c1f79f27 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -23,7 +23,7 @@ use crate::{ | |||
23 | db::HirDatabase, | 23 | db::HirDatabase, |
24 | diagnostics::Diagnostic, | 24 | diagnostics::Diagnostic, |
25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 25 | 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}, |
27 | AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, | 27 | AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, |
28 | Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, | 28 | Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, |
29 | }; | 29 | }; |
@@ -451,6 +451,23 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> { | |||
451 | pub fn resolve_hir_path(&self, path: &Path) -> Option<PathResolution> { | 451 | pub fn resolve_hir_path(&self, path: &Path) -> Option<PathResolution> { |
452 | resolve_hir_path(self.db, &self.resolver, path) | 452 | resolve_hir_path(self.db, &self.resolver, path) |
453 | } | 453 | } |
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 | } | ||
454 | } | 471 | } |
455 | 472 | ||
456 | // FIXME: Change `HasSource` trait to work with `Semantics` and remove this? | 473 | // 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 { | |||
226 | // This must be a normal source file rather than macro file. | 226 | // This must be a normal source file rather than macro file. |
227 | let hir_path = | 227 | let hir_path = |
228 | crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; | 228 | 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 | |||
229 | resolve_hir_path(db, &self.resolver, &hir_path) | 240 | resolve_hir_path(db, &self.resolver, &hir_path) |
230 | } | 241 | } |
231 | 242 | ||
@@ -404,6 +415,7 @@ pub(crate) fn resolve_hir_path( | |||
404 | TypeNs::BuiltinType(it) => PathResolution::Def(it.into()), | 415 | TypeNs::BuiltinType(it) => PathResolution::Def(it.into()), |
405 | TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), | 416 | TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), |
406 | }); | 417 | }); |
418 | |||
407 | let body_owner = resolver.body_owner(); | 419 | let body_owner = resolver.body_owner(); |
408 | let values = | 420 | let values = |
409 | resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| { | 421 | 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( | |||
426 | .resolve_module_path_in_items(db.upcast(), path.mod_path()) | 438 | .resolve_module_path_in_items(db.upcast(), path.mod_path()) |
427 | .take_types() | 439 | .take_types() |
428 | .map(|it| PathResolution::Def(it.into())); | 440 | .map(|it| PathResolution::Def(it.into())); |
441 | |||
429 | types.or(values).or(items).or_else(|| { | 442 | types.or(values).or(items).or_else(|| { |
430 | resolver | 443 | resolver |
431 | .resolve_path_as_macro(db.upcast(), path.mod_path()) | 444 | .resolve_path_as_macro(db.upcast(), path.mod_path()) |
432 | .map(|def| PathResolution::Macro(def.into())) | 445 | .map(|def| PathResolution::Macro(def.into())) |
433 | }) | 446 | }) |
434 | } | 447 | } |
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 | } | ||