aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/semantics.rs19
-rw-r--r--crates/ra_hir/src/source_analyzer.rs51
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.
462pub(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}