Fix find_path
when inner items are present
This commit is contained in:
parent
5efb7f85eb
commit
0dcec31553
@ -1,5 +1,7 @@
|
|||||||
//! An algorithm to find a path to refer to a certain item.
|
//! An algorithm to find a path to refer to a certain item.
|
||||||
|
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
use hir_expand::name::{known, AsName, Name};
|
use hir_expand::name::{known, AsName, Name};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
@ -95,7 +97,7 @@ fn find_path_inner(
|
|||||||
item: ItemInNs,
|
item: ItemInNs,
|
||||||
from: ModuleId,
|
from: ModuleId,
|
||||||
max_len: usize,
|
max_len: usize,
|
||||||
prefixed: Option<PrefixKind>,
|
mut prefixed: Option<PrefixKind>,
|
||||||
) -> Option<ModPath> {
|
) -> Option<ModPath> {
|
||||||
if max_len == 0 {
|
if max_len == 0 {
|
||||||
return None;
|
return None;
|
||||||
@ -114,8 +116,9 @@ fn find_path_inner(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - if the item is the crate root, return `crate`
|
// - if the item is the crate root, return `crate`
|
||||||
let root = def_map.module_id(def_map.root());
|
let root = def_map.crate_root(db);
|
||||||
if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) && def_map.block_id().is_none() {
|
if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) && def_map.block_id().is_none() {
|
||||||
|
// FIXME: the `block_id()` check should be unnecessary, but affects the result
|
||||||
return Some(ModPath::from_segments(PathKind::Crate, Vec::new()));
|
return Some(ModPath::from_segments(PathKind::Crate, Vec::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +168,7 @@ fn find_path_inner(
|
|||||||
|
|
||||||
// - otherwise, look for modules containing (reexporting) it and import it from one of those
|
// - otherwise, look for modules containing (reexporting) it and import it from one of those
|
||||||
|
|
||||||
let crate_root = def_map.module_id(def_map.root());
|
let crate_root = def_map.crate_root(db);
|
||||||
let crate_attrs = db.attrs(crate_root.into());
|
let crate_attrs = db.attrs(crate_root.into());
|
||||||
let prefer_no_std = crate_attrs.by_key("no_std").exists();
|
let prefer_no_std = crate_attrs.by_key("no_std").exists();
|
||||||
let mut best_path = None;
|
let mut best_path = None;
|
||||||
@ -228,12 +231,16 @@ fn find_path_inner(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut prefix) = prefixed.map(PrefixKind::prefix) {
|
// If the item is declared inside a block expression, don't use a prefix, as we don't handle
|
||||||
if matches!(prefix, PathKind::Crate | PathKind::Super(0)) && def_map.block_id().is_some() {
|
// that correctly (FIXME).
|
||||||
// Inner items cannot be referred to via `crate::` or `self::` paths.
|
if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) {
|
||||||
prefix = PathKind::Plain;
|
if item_module.def_map(db).block_id().is_some() && prefixed.is_some() {
|
||||||
|
mark::hit!(prefixed_in_block_expression);
|
||||||
|
prefixed = Some(PrefixKind::Plain);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(prefix) = prefixed.map(PrefixKind::prefix) {
|
||||||
best_path.or_else(|| {
|
best_path.or_else(|| {
|
||||||
scope_name.map(|scope_name| ModPath::from_segments(prefix, vec![scope_name]))
|
scope_name.map(|scope_name| ModPath::from_segments(prefix, vec![scope_name]))
|
||||||
})
|
})
|
||||||
@ -285,12 +292,12 @@ fn find_local_import_locations(
|
|||||||
let data = &def_map[from.local_id];
|
let data = &def_map[from.local_id];
|
||||||
let mut worklist =
|
let mut worklist =
|
||||||
data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>();
|
data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>();
|
||||||
let mut parent = data.parent;
|
for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) {
|
||||||
while let Some(p) = parent {
|
worklist.push(ancestor);
|
||||||
worklist.push(def_map.module_id(p));
|
|
||||||
parent = def_map[p].parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let def_map = def_map.crate_root(db).def_map(db);
|
||||||
|
|
||||||
let mut seen: FxHashSet<_> = FxHashSet::default();
|
let mut seen: FxHashSet<_> = FxHashSet::default();
|
||||||
|
|
||||||
let mut locations = Vec::new();
|
let mut locations = Vec::new();
|
||||||
@ -301,7 +308,14 @@ fn find_local_import_locations(
|
|||||||
|
|
||||||
let ext_def_map;
|
let ext_def_map;
|
||||||
let data = if module.krate == from.krate {
|
let data = if module.krate == from.krate {
|
||||||
&def_map[module.local_id]
|
if module.block.is_some() {
|
||||||
|
// Re-query the block's DefMap
|
||||||
|
ext_def_map = module.def_map(db);
|
||||||
|
&ext_def_map[module.local_id]
|
||||||
|
} else {
|
||||||
|
// Reuse the root DefMap
|
||||||
|
&def_map[module.local_id]
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// The crate might reexport a module defined in another crate.
|
// The crate might reexport a module defined in another crate.
|
||||||
ext_def_map = module.def_map(db);
|
ext_def_map = module.def_map(db);
|
||||||
@ -828,6 +842,7 @@ struct Struct {}
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn inner_items_from_inner_module() {
|
fn inner_items_from_inner_module() {
|
||||||
|
mark::check!(prefixed_in_block_expression);
|
||||||
check_found_path(
|
check_found_path(
|
||||||
r#"
|
r#"
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -869,4 +884,24 @@ mod module {
|
|||||||
"super::Struct",
|
"super::Struct",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn outer_items_with_inner_items_present() {
|
||||||
|
check_found_path(
|
||||||
|
r#"
|
||||||
|
mod module {
|
||||||
|
pub struct CompleteMe;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
fn inner() {}
|
||||||
|
$0
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
"module::CompleteMe",
|
||||||
|
"module::CompleteMe",
|
||||||
|
"crate::module::CompleteMe",
|
||||||
|
"self::module::CompleteMe",
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId,
|
db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId,
|
||||||
LocalModuleId, Lookup, MacroDefId, ModuleDefId, ModuleId, TraitId,
|
LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
@ -375,19 +375,9 @@ pub fn as_module_def_id(self) -> Option<ModuleDefId> {
|
|||||||
|
|
||||||
/// Returns the crate defining this item (or `None` if `self` is built-in).
|
/// Returns the crate defining this item (or `None` if `self` is built-in).
|
||||||
pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
|
pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
|
||||||
Some(match self {
|
match self {
|
||||||
ItemInNs::Types(did) | ItemInNs::Values(did) => match did {
|
ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate),
|
||||||
ModuleDefId::ModuleId(id) => id.krate,
|
ItemInNs::Macros(id) => Some(id.krate),
|
||||||
ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate,
|
}
|
||||||
ModuleDefId::AdtId(id) => id.module(db).krate,
|
|
||||||
ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate,
|
|
||||||
ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate,
|
|
||||||
ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate,
|
|
||||||
ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate,
|
|
||||||
ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate,
|
|
||||||
ModuleDefId::BuiltinType(_) => return None,
|
|
||||||
},
|
|
||||||
ItemInNs::Macros(id) => return Some(id.krate),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,10 @@ pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc<DefMap> {
|
|||||||
pub fn krate(&self) -> CrateId {
|
pub fn krate(&self) -> CrateId {
|
||||||
self.krate
|
self.krate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
|
||||||
|
self.def_map(db).containing_module(self.local_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An ID of a module, **local** to a specific crate
|
/// An ID of a module, **local** to a specific crate
|
||||||
@ -529,6 +533,25 @@ fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ModuleDefId {
|
||||||
|
/// Returns the module containing `self` (or `self`, if `self` is itself a module).
|
||||||
|
///
|
||||||
|
/// Returns `None` if `self` refers to a primitive type.
|
||||||
|
pub fn module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
|
||||||
|
Some(match self {
|
||||||
|
ModuleDefId::ModuleId(id) => *id,
|
||||||
|
ModuleDefId::FunctionId(id) => id.lookup(db).module(db),
|
||||||
|
ModuleDefId::AdtId(id) => id.module(db),
|
||||||
|
ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db),
|
||||||
|
ModuleDefId::ConstId(id) => id.lookup(db).container.module(db),
|
||||||
|
ModuleDefId::StaticId(id) => id.lookup(db).container.module(db),
|
||||||
|
ModuleDefId::TraitId(id) => id.lookup(db).container.module(db),
|
||||||
|
ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db),
|
||||||
|
ModuleDefId::BuiltinType(_) => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AttrDefId {
|
impl AttrDefId {
|
||||||
pub fn krate(&self, db: &dyn db::DefDatabase) -> CrateId {
|
pub fn krate(&self, db: &dyn db::DefDatabase) -> CrateId {
|
||||||
match self {
|
match self {
|
||||||
|
@ -343,6 +343,18 @@ pub fn parent(&self) -> Option<ModuleId> {
|
|||||||
Some(self.block?.parent)
|
Some(self.block?.parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the module containing `local_mod`, either the parent `mod`, or the module containing
|
||||||
|
/// the block, if `self` corresponds to a block expression.
|
||||||
|
pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
|
||||||
|
match &self[local_mod].parent {
|
||||||
|
Some(parent) => Some(self.module_id(*parent)),
|
||||||
|
None => match &self.block {
|
||||||
|
Some(block) => Some(block.parent),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: this can use some more human-readable format (ideally, an IR
|
// FIXME: this can use some more human-readable format (ideally, an IR
|
||||||
// even), as this should be a great debugging aid.
|
// even), as this should be a great debugging aid.
|
||||||
pub fn dump(&self, db: &dyn DefDatabase) -> String {
|
pub fn dump(&self, db: &dyn DefDatabase) -> String {
|
||||||
|
Loading…
Reference in New Issue
Block a user