diff options
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r-- | crates/hir_def/src/find_path.rs | 56 | ||||
-rw-r--r-- | crates/hir_def/src/nameres.rs | 17 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/path_resolution.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/resolver.rs | 18 |
4 files changed, 81 insertions, 12 deletions
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index de08e2737..109d3552f 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. |
19 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | 19 | pub 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 | ||
24 | pub fn find_path_prefixed( | 25 | pub 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 | ||
34 | const MAX_PATH_LEN: usize = 15; | 36 | const 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,18 @@ 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 | cov_mark::hit!(recursive_imports); |
185 | continue; | ||
186 | } | ||
182 | if let Some(mut path) = find_path_inner( | 187 | if let Some(mut path) = find_path_inner( |
183 | db, | 188 | db, |
184 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), | 189 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), |
185 | from, | 190 | from, |
186 | best_path_len - 1, | 191 | best_path_len - 1, |
187 | prefixed, | 192 | prefixed, |
193 | visited_modules, | ||
188 | ) { | 194 | ) { |
189 | path.push_segment(name); | 195 | path.push_segment(name); |
190 | 196 | ||
@@ -213,6 +219,7 @@ fn find_path_inner( | |||
213 | from, | 219 | from, |
214 | best_path_len - 1, | 220 | best_path_len - 1, |
215 | prefixed, | 221 | prefixed, |
222 | visited_modules, | ||
216 | )?; | 223 | )?; |
217 | cov_mark::hit!(partially_imported); | 224 | cov_mark::hit!(partially_imported); |
218 | path.push_segment(info.path.segments.last().unwrap().clone()); | 225 | path.push_segment(info.path.segments.last().unwrap().clone()); |
@@ -391,8 +398,15 @@ mod tests { | |||
391 | .take_types() | 398 | .take_types() |
392 | .unwrap(); | 399 | .unwrap(); |
393 | 400 | ||
394 | let found_path = | 401 | let mut visited_modules = FxHashSet::default(); |
395 | find_path_inner(&db, ItemInNs::Types(resolved), module, MAX_PATH_LEN, prefix_kind); | 402 | let found_path = find_path_inner( |
403 | &db, | ||
404 | ItemInNs::Types(resolved), | ||
405 | module, | ||
406 | MAX_PATH_LEN, | ||
407 | prefix_kind, | ||
408 | &mut visited_modules, | ||
409 | ); | ||
396 | assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind); | 410 | assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind); |
397 | } | 411 | } |
398 | 412 | ||
@@ -878,4 +892,32 @@ mod tests { | |||
878 | "self::module::CompleteMe", | 892 | "self::module::CompleteMe", |
879 | ) | 893 | ) |
880 | } | 894 | } |
895 | |||
896 | #[test] | ||
897 | fn recursive_pub_mod_reexport() { | ||
898 | cov_mark::check!(recursive_imports); | ||
899 | check_found_path( | ||
900 | r#" | ||
901 | fn main() { | ||
902 | let _ = 22_i32.as_name$0(); | ||
903 | } | ||
904 | |||
905 | pub mod name { | ||
906 | pub trait AsName { | ||
907 | fn as_name(&self) -> String; | ||
908 | } | ||
909 | impl AsName for i32 { | ||
910 | fn as_name(&self) -> String { | ||
911 | format!("Name: {}", self) | ||
912 | } | ||
913 | } | ||
914 | pub use crate::name; | ||
915 | } | ||
916 | "#, | ||
917 | "name::AsName", | ||
918 | "name::AsName", | ||
919 | "crate::name::AsName", | ||
920 | "self::name::AsName", | ||
921 | ); | ||
922 | } | ||
881 | } | 923 | } |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 0d3a0b54f..9e8e4e9ec 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -322,6 +322,23 @@ impl DefMap { | |||
322 | (res.resolved_def, res.segment_index) | 322 | (res.resolved_def, res.segment_index) |
323 | } | 323 | } |
324 | 324 | ||
325 | pub(crate) fn resolve_path_locally( | ||
326 | &self, | ||
327 | db: &dyn DefDatabase, | ||
328 | original_module: LocalModuleId, | ||
329 | path: &ModPath, | ||
330 | shadow: BuiltinShadowMode, | ||
331 | ) -> (PerNs, Option<usize>) { | ||
332 | let res = self.resolve_path_fp_with_macro_single( | ||
333 | db, | ||
334 | ResolveMode::Other, | ||
335 | original_module, | ||
336 | path, | ||
337 | shadow, | ||
338 | ); | ||
339 | (res.resolved_def, res.segment_index) | ||
340 | } | ||
341 | |||
325 | /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module. | 342 | /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module. |
326 | /// | 343 | /// |
327 | /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns | 344 | /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns |
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs index db459b1ed..60471937c 100644 --- a/crates/hir_def/src/nameres/path_resolution.rs +++ b/crates/hir_def/src/nameres/path_resolution.rs | |||
@@ -156,7 +156,7 @@ impl DefMap { | |||
156 | } | 156 | } |
157 | } | 157 | } |
158 | 158 | ||
159 | fn resolve_path_fp_with_macro_single( | 159 | pub(super) fn resolve_path_fp_with_macro_single( |
160 | &self, | 160 | &self, |
161 | db: &dyn DefDatabase, | 161 | db: &dyn DefDatabase, |
162 | mode: ResolveMode, | 162 | mode: ResolveMode, |
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index 04ea9c5d7..a73585ee7 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -548,7 +548,7 @@ impl ModuleItemMap { | |||
548 | path: &ModPath, | 548 | path: &ModPath, |
549 | ) -> Option<ResolveValueResult> { | 549 | ) -> Option<ResolveValueResult> { |
550 | let (module_def, idx) = | 550 | let (module_def, idx) = |
551 | self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); | 551 | self.def_map.resolve_path_locally(db, self.module_id, &path, BuiltinShadowMode::Other); |
552 | match idx { | 552 | match idx { |
553 | None => { | 553 | None => { |
554 | let value = to_value_ns(module_def)?; | 554 | let value = to_value_ns(module_def)?; |
@@ -578,7 +578,7 @@ impl ModuleItemMap { | |||
578 | path: &ModPath, | 578 | path: &ModPath, |
579 | ) -> Option<(TypeNs, Option<usize>)> { | 579 | ) -> Option<(TypeNs, Option<usize>)> { |
580 | let (module_def, idx) = | 580 | let (module_def, idx) = |
581 | self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); | 581 | self.def_map.resolve_path_locally(db, self.module_id, &path, BuiltinShadowMode::Other); |
582 | let res = to_type_ns(module_def)?; | 582 | let res = to_type_ns(module_def)?; |
583 | Some((res, idx)) | 583 | Some((res, idx)) |
584 | } | 584 | } |
@@ -627,8 +627,18 @@ pub trait HasResolver: Copy { | |||
627 | 627 | ||
628 | impl HasResolver for ModuleId { | 628 | impl HasResolver for ModuleId { |
629 | fn resolver(self, db: &dyn DefDatabase) -> Resolver { | 629 | fn resolver(self, db: &dyn DefDatabase) -> Resolver { |
630 | let def_map = self.def_map(db); | 630 | let mut def_map = self.def_map(db); |
631 | Resolver::default().push_module_scope(def_map, self.local_id) | 631 | let mut modules = Vec::new(); |
632 | modules.push((def_map.clone(), self.local_id)); | ||
633 | while let Some(parent) = def_map.parent() { | ||
634 | def_map = parent.def_map(db); | ||
635 | modules.push((def_map.clone(), parent.local_id)); | ||
636 | } | ||
637 | let mut resolver = Resolver::default(); | ||
638 | for (def_map, module) in modules.into_iter().rev() { | ||
639 | resolver = resolver.push_module_scope(def_map, module); | ||
640 | } | ||
641 | resolver | ||
632 | } | 642 | } |
633 | } | 643 | } |
634 | 644 | ||