aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/semantics.rs19
-rw-r--r--crates/ra_hir/src/source_analyzer.rs51
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs30
-rw-r--r--crates/ra_ide/src/hover.rs17
4 files changed, 115 insertions, 2 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}
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs
index 7fcd22525..db7430454 100644
--- a/crates/ra_ide/src/completion/complete_qualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_qualified_path.rs
@@ -20,7 +20,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
20 let scope = ctx.scope(); 20 let scope = ctx.scope();
21 let context_module = scope.module(); 21 let context_module = scope.module();
22 22
23 let res = match scope.resolve_hir_path(&path) { 23 let res = match scope.resolve_hir_path_qualifier(&path) {
24 Some(res) => res, 24 Some(res) => res,
25 None => return, 25 None => return,
26 }; 26 };
@@ -226,6 +226,34 @@ mod tests {
226 } 226 }
227 227
228 #[test] 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
256 #[test]
229 fn path_visibility() { 257 fn path_visibility() {
230 assert_debug_snapshot!( 258 assert_debug_snapshot!(
231 do_reference_completion( 259 do_reference_completion(
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 06d4f1c63..befa977c7 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -921,4 +921,21 @@ fn func(foo: i32) { if true { <|>foo; }; }
921 &["unsafe trait foo"], 921 &["unsafe trait foo"],
922 ); 922 );
923 } 923 }
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 }
924} 941}