aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r--crates/hir_def/src/find_path.rs54
1 files changed, 47 insertions, 7 deletions
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index de08e2737..b4362a5c4 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -18,7 +18,8 @@ use crate::{
18/// *from where* you're referring to the item, hence the `from` parameter. 18/// *from where* you're referring to the item, hence the `from` parameter.
19pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { 19pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
20 let _p = profile::span("find_path"); 20 let _p = profile::span("find_path");
21 find_path_inner(db, item, from, MAX_PATH_LEN, None) 21 let mut visited_modules = FxHashSet::default();
22 find_path_inner(db, item, from, MAX_PATH_LEN, None, &mut visited_modules)
22} 23}
23 24
24pub fn find_path_prefixed( 25pub fn find_path_prefixed(
@@ -28,7 +29,8 @@ pub fn find_path_prefixed(
28 prefix_kind: PrefixKind, 29 prefix_kind: PrefixKind,
29) -> Option<ModPath> { 30) -> Option<ModPath> {
30 let _p = profile::span("find_path_prefixed"); 31 let _p = profile::span("find_path_prefixed");
31 find_path_inner(db, item, from, MAX_PATH_LEN, Some(prefix_kind)) 32 let mut visited_modules = FxHashSet::default();
33 find_path_inner(db, item, from, MAX_PATH_LEN, Some(prefix_kind), &mut visited_modules)
32} 34}
33 35
34const MAX_PATH_LEN: usize = 15; 36const MAX_PATH_LEN: usize = 15;
@@ -97,6 +99,7 @@ fn find_path_inner(
97 from: ModuleId, 99 from: ModuleId,
98 max_len: usize, 100 max_len: usize,
99 mut prefixed: Option<PrefixKind>, 101 mut prefixed: Option<PrefixKind>,
102 visited_modules: &mut FxHashSet<ModuleId>,
100) -> Option<ModPath> { 103) -> Option<ModPath> {
101 if max_len == 0 { 104 if max_len == 0 {
102 return None; 105 return None;
@@ -176,15 +179,17 @@ fn find_path_inner(
176 if item.krate(db) == Some(from.krate) { 179 if item.krate(db) == Some(from.krate) {
177 // Item was defined in the same crate that wants to import it. It cannot be found in any 180 // Item was defined in the same crate that wants to import it. It cannot be found in any
178 // dependency in this case. 181 // dependency in this case.
179 182 for (module_id, name) in find_local_import_locations(db, item, from) {
180 let local_imports = find_local_import_locations(db, item, from); 183 if !visited_modules.insert(module_id) {
181 for (module_id, name) in local_imports { 184 continue;
185 }
182 if let Some(mut path) = find_path_inner( 186 if let Some(mut path) = find_path_inner(
183 db, 187 db,
184 ItemInNs::Types(ModuleDefId::ModuleId(module_id)), 188 ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
185 from, 189 from,
186 best_path_len - 1, 190 best_path_len - 1,
187 prefixed, 191 prefixed,
192 visited_modules,
188 ) { 193 ) {
189 path.push_segment(name); 194 path.push_segment(name);
190 195
@@ -213,6 +218,7 @@ fn find_path_inner(
213 from, 218 from,
214 best_path_len - 1, 219 best_path_len - 1,
215 prefixed, 220 prefixed,
221 visited_modules,
216 )?; 222 )?;
217 cov_mark::hit!(partially_imported); 223 cov_mark::hit!(partially_imported);
218 path.push_segment(info.path.segments.last().unwrap().clone()); 224 path.push_segment(info.path.segments.last().unwrap().clone());
@@ -391,8 +397,15 @@ mod tests {
391 .take_types() 397 .take_types()
392 .unwrap(); 398 .unwrap();
393 399
394 let found_path = 400 let mut visited_modules = FxHashSet::default();
395 find_path_inner(&db, ItemInNs::Types(resolved), module, MAX_PATH_LEN, prefix_kind); 401 let found_path = find_path_inner(
402 &db,
403 ItemInNs::Types(resolved),
404 module,
405 MAX_PATH_LEN,
406 prefix_kind,
407 &mut visited_modules,
408 );
396 assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind); 409 assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
397 } 410 }
398 411
@@ -878,4 +891,31 @@ mod tests {
878 "self::module::CompleteMe", 891 "self::module::CompleteMe",
879 ) 892 )
880 } 893 }
894
895 #[test]
896 fn recursive_pub_mod_reexport() {
897 check_found_path(
898 r#"
899fn main() {
900 let _ = 22_i32.as_name$0();
901}
902
903pub mod name {
904 pub trait AsName {
905 fn as_name(&self) -> String;
906 }
907 impl AsName for i32 {
908 fn as_name(&self) -> String {
909 format!("Name: {}", self)
910 }
911 }
912 pub use crate::name;
913}
914"#,
915 "name::AsName",
916 "name::AsName",
917 "crate::name::AsName",
918 "self::name::AsName",
919 );
920 }
881} 921}