mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 20:42:04 +00:00
fix: prefix prelude items whose name collides in current scope
This commit is contained in:
parent
643bc02ded
commit
cf2fa14db5
1 changed files with 74 additions and 13 deletions
|
@ -107,7 +107,7 @@ fn find_path_inner(
|
||||||
}
|
}
|
||||||
|
|
||||||
// - if the item is in the prelude, return the name from there
|
// - 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;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
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(
|
fn find_in_prelude(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
root_def_map: &DefMap,
|
root_def_map: &DefMap,
|
||||||
|
local_def_map: &DefMap,
|
||||||
item: ItemInNs,
|
item: ItemInNs,
|
||||||
from: ModuleId,
|
from: ModuleId,
|
||||||
) -> Option<Option<ModPath>> {
|
) -> Option<ModPath> {
|
||||||
if let Some(prelude_module) = root_def_map.prelude() {
|
let prelude_module = root_def_map.prelude()?;
|
||||||
// Preludes in block DefMaps are ignored, only the crate DefMap is searched
|
// Preludes in block DefMaps are ignored, only the crate DefMap is searched
|
||||||
let prelude_def_map = prelude_module.def_map(db);
|
let prelude_def_map = prelude_module.def_map(db);
|
||||||
let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
|
let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
|
||||||
if let Some((name, vis)) = prelude_scope.name_of(item) {
|
let (name, vis) = prelude_scope.name_of(item)?;
|
||||||
if vis.is_visible_from(db, from) {
|
if !vis.is_visible_from(db, from) {
|
||||||
return Some(Some(ModPath::from_segments(PathKind::Plain, Some(name.clone()))));
|
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> {
|
fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<ModPath> {
|
||||||
|
@ -808,6 +827,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]
|
#[test]
|
||||||
fn enum_variant_from_prelude() {
|
fn enum_variant_from_prelude() {
|
||||||
let code = r#"
|
let code = r#"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue