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.rs56
-rw-r--r--crates/hir_def/src/nameres.rs17
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs2
-rw-r--r--crates/hir_def/src/resolver.rs18
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.
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,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#"
901fn main() {
902 let _ = 22_i32.as_name$0();
903}
904
905pub 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
628impl HasResolver for ModuleId { 628impl 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