Do not revisit recursively imported modules

This commit is contained in:
Kirill Bulatov 2021-03-21 23:45:00 +02:00
parent 858ad55437
commit 3a4e99115d

View file

@ -18,7 +18,8 @@ use crate::{
/// *from where* you're referring to the item, hence the `from` parameter. /// *from where* you're referring to the item, hence the `from` parameter.
pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
let _p = profile::span("find_path"); let _p = profile::span("find_path");
find_path_inner(db, item, from, MAX_PATH_LEN, None) let mut visited_modules = FxHashSet::default();
find_path_inner(db, item, from, MAX_PATH_LEN, None, &mut visited_modules)
} }
pub fn find_path_prefixed( pub fn find_path_prefixed(
@ -28,7 +29,8 @@ pub fn find_path_prefixed(
prefix_kind: PrefixKind, prefix_kind: PrefixKind,
) -> Option<ModPath> { ) -> Option<ModPath> {
let _p = profile::span("find_path_prefixed"); let _p = profile::span("find_path_prefixed");
find_path_inner(db, item, from, MAX_PATH_LEN, Some(prefix_kind)) let mut visited_modules = FxHashSet::default();
find_path_inner(db, item, from, MAX_PATH_LEN, Some(prefix_kind), &mut visited_modules)
} }
const MAX_PATH_LEN: usize = 15; const MAX_PATH_LEN: usize = 15;
@ -97,6 +99,7 @@ fn find_path_inner(
from: ModuleId, from: ModuleId,
max_len: usize, max_len: usize,
mut prefixed: Option<PrefixKind>, mut prefixed: Option<PrefixKind>,
visited_modules: &mut FxHashSet<ModuleId>,
) -> Option<ModPath> { ) -> Option<ModPath> {
if max_len == 0 { if max_len == 0 {
return None; return None;
@ -176,15 +179,17 @@ fn find_path_inner(
if item.krate(db) == Some(from.krate) { if item.krate(db) == Some(from.krate) {
// Item was defined in the same crate that wants to import it. It cannot be found in any // Item was defined in the same crate that wants to import it. It cannot be found in any
// dependency in this case. // dependency in this case.
for (module_id, name) in find_local_import_locations(db, item, from) {
let local_imports = find_local_import_locations(db, item, from); if !visited_modules.insert(module_id) {
for (module_id, name) in local_imports { continue;
}
if let Some(mut path) = find_path_inner( if let Some(mut path) = find_path_inner(
db, db,
ItemInNs::Types(ModuleDefId::ModuleId(module_id)), ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
from, from,
best_path_len - 1, best_path_len - 1,
prefixed, prefixed,
visited_modules,
) { ) {
path.push_segment(name); path.push_segment(name);
@ -213,6 +218,7 @@ fn find_path_inner(
from, from,
best_path_len - 1, best_path_len - 1,
prefixed, prefixed,
visited_modules,
)?; )?;
cov_mark::hit!(partially_imported); cov_mark::hit!(partially_imported);
path.push_segment(info.path.segments.last().unwrap().clone()); path.push_segment(info.path.segments.last().unwrap().clone());
@ -391,8 +397,15 @@ mod tests {
.take_types() .take_types()
.unwrap(); .unwrap();
let found_path = let mut visited_modules = FxHashSet::default();
find_path_inner(&db, ItemInNs::Types(resolved), module, MAX_PATH_LEN, prefix_kind); let found_path = find_path_inner(
&db,
ItemInNs::Types(resolved),
module,
MAX_PATH_LEN,
prefix_kind,
&mut visited_modules,
);
assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind); assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
} }
@ -878,4 +891,31 @@ mod tests {
"self::module::CompleteMe", "self::module::CompleteMe",
) )
} }
#[test]
fn recursive_pub_mod_reexport() {
check_found_path(
r#"
fn main() {
let _ = 22_i32.as_name$0();
}
pub mod name {
pub trait AsName {
fn as_name(&self) -> String;
}
impl AsName for i32 {
fn as_name(&self) -> String {
format!("Name: {}", self)
}
}
pub use crate::name;
}
"#,
"name::AsName",
"name::AsName",
"crate::name::AsName",
"self::name::AsName",
);
}
} }