summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-def/src/find_path.rs')
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs93
1 files changed, 77 insertions, 16 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index c70e6fdcc..ddd7ad99e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -107,7 +107,7 @@ fn find_path_inner(
}
// - if the item is in the prelude, return the name from there
- if let Some(value) = find_in_prelude(db, &crate_root.def_map(db), item, from) {
+ if let value @ Some(_) = find_in_prelude(db, &crate_root.def_map(db), &def_map, item, from) {
return value;
}
@@ -176,7 +176,7 @@ fn find_path_for_module(
// - if relative paths are fine, check if we are searching for a parent
if prefixed.filter(PrefixKind::is_absolute).is_none() {
- if let modpath @ Some(_) = find_self_super(&def_map, module_id, from) {
+ if let modpath @ Some(_) = find_self_super(def_map, module_id, from) {
return modpath;
}
}
@@ -205,7 +205,8 @@ fn find_path_for_module(
}
}
- if let Some(value) = find_in_prelude(db, &root_def_map, ItemInNs::Types(module_id.into()), from)
+ if let value @ Some(_) =
+ find_in_prelude(db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from)
{
return value;
}
@@ -234,23 +235,41 @@ fn find_in_scope(
})
}
+/// Returns single-segment path (i.e. without any prefix) if `item` is found in prelude and its
+/// name doesn't clash in current scope.
fn find_in_prelude(
db: &dyn DefDatabase,
root_def_map: &DefMap,
+ local_def_map: &DefMap,
item: ItemInNs,
from: ModuleId,
-) -> Option<Option<ModPath>> {
- if let Some(prelude_module) = root_def_map.prelude() {
- // Preludes in block DefMaps are ignored, only the crate DefMap is searched
- let prelude_def_map = prelude_module.def_map(db);
- let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
- if let Some((name, vis)) = prelude_scope.name_of(item) {
- if vis.is_visible_from(db, from) {
- return Some(Some(ModPath::from_segments(PathKind::Plain, Some(name.clone()))));
- }
- }
+) -> Option<ModPath> {
+ let prelude_module = root_def_map.prelude()?;
+ // Preludes in block DefMaps are ignored, only the crate DefMap is searched
+ let prelude_def_map = prelude_module.def_map(db);
+ let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
+ let (name, vis) = prelude_scope.name_of(item)?;
+ if !vis.is_visible_from(db, from) {
+ return None;
+ }
+
+ // Check if the name is in current scope and it points to the same def.
+ let found_and_same_def =
+ local_def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
+ let per_ns = def_map[local_id].scope.get(name);
+ let same_def = match item {
+ ItemInNs::Types(it) => per_ns.take_types()? == it,
+ ItemInNs::Values(it) => per_ns.take_values()? == it,
+ ItemInNs::Macros(it) => per_ns.take_macros()? == it,
+ };
+ Some(same_def)
+ });
+
+ if found_and_same_def.unwrap_or(true) {
+ Some(ModPath::from_segments(PathKind::Plain, Some(name.clone())))
+ } else {
+ None
}
- None
}
fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<ModPath> {
@@ -512,7 +531,7 @@ mod tests {
fn check_found_path_(ra_fixture: &str, path: &str, prefix_kind: Option<PrefixKind>) {
let (db, pos) = TestDB::with_position(ra_fixture);
let module = db.module_at_position(pos);
- let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path));
+ let parsed_path_file = syntax::SourceFile::parse(&format!("use {path};"));
let ast_path =
parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap();
let mod_path = ModPath::from_src(&db, ast_path, &Hygiene::new_unhygienic()).unwrap();
@@ -531,7 +550,7 @@ mod tests {
let found_path =
find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false);
- assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
+ assert_eq!(found_path, Some(mod_path), "{prefix_kind:?}");
}
fn check_found_path(
@@ -809,6 +828,48 @@ pub mod prelude {
}
#[test]
+ fn shadowed_prelude() {
+ check_found_path(
+ r#"
+//- /main.rs crate:main deps:std
+struct S;
+$0
+//- /std.rs crate:std
+pub mod prelude {
+ pub mod rust_2018 {
+ pub struct S;
+ }
+}
+"#,
+ "std::prelude::rust_2018::S",
+ "std::prelude::rust_2018::S",
+ "std::prelude::rust_2018::S",
+ "std::prelude::rust_2018::S",
+ );
+ }
+
+ #[test]
+ fn imported_prelude() {
+ check_found_path(
+ r#"
+//- /main.rs crate:main deps:std
+use S;
+$0
+//- /std.rs crate:std
+pub mod prelude {
+ pub mod rust_2018 {
+ pub struct S;
+ }
+}
+"#,
+ "S",
+ "S",
+ "S",
+ "S",
+ );
+ }
+
+ #[test]
fn enum_variant_from_prelude() {
let code = r#"
//- /main.rs crate:main deps:std