aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/nameres/mod_resolution.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/nameres/mod_resolution.rs')
-rw-r--r--crates/hir_def/src/nameres/mod_resolution.rs23
1 files changed, 19 insertions, 4 deletions
diff --git a/crates/hir_def/src/nameres/mod_resolution.rs b/crates/hir_def/src/nameres/mod_resolution.rs
index e8389b484..c0c789cae 100644
--- a/crates/hir_def/src/nameres/mod_resolution.rs
+++ b/crates/hir_def/src/nameres/mod_resolution.rs
@@ -2,9 +2,12 @@
2use base_db::FileId; 2use base_db::FileId;
3use hir_expand::name::Name; 3use hir_expand::name::Name;
4use syntax::SmolStr; 4use syntax::SmolStr;
5use test_utils::mark;
5 6
6use crate::{db::DefDatabase, HirFileId}; 7use crate::{db::DefDatabase, HirFileId};
7 8
9const MOD_DEPTH_LIMIT: u32 = 32;
10
8#[derive(Clone, Debug)] 11#[derive(Clone, Debug)]
9pub(super) struct ModDir { 12pub(super) struct ModDir {
10 /// `` for `mod.rs`, `lib.rs` 13 /// `` for `mod.rs`, `lib.rs`
@@ -14,18 +17,28 @@ pub(super) struct ModDir {
14 dir_path: DirPath, 17 dir_path: DirPath,
15 /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/` 18 /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/`
16 root_non_dir_owner: bool, 19 root_non_dir_owner: bool,
20 depth: u32,
17} 21}
18 22
19impl ModDir { 23impl ModDir {
20 pub(super) fn root() -> ModDir { 24 pub(super) fn root() -> ModDir {
21 ModDir { dir_path: DirPath::empty(), root_non_dir_owner: false } 25 ModDir { dir_path: DirPath::empty(), root_non_dir_owner: false, depth: 0 }
26 }
27 fn child(&self, dir_path: DirPath, root_non_dir_owner: bool) -> Option<ModDir> {
28 let depth = self.depth + 1;
29 if depth > MOD_DEPTH_LIMIT {
30 log::error!("MOD_DEPTH_LIMIT exceeded");
31 mark::hit!(circular_mods);
32 return None;
33 }
34 Some(ModDir { dir_path, root_non_dir_owner, depth })
22 } 35 }
23 36
24 pub(super) fn descend_into_definition( 37 pub(super) fn descend_into_definition(
25 &self, 38 &self,
26 name: &Name, 39 name: &Name,
27 attr_path: Option<&SmolStr>, 40 attr_path: Option<&SmolStr>,
28 ) -> ModDir { 41 ) -> Option<ModDir> {
29 let path = match attr_path.map(|it| it.as_str()) { 42 let path = match attr_path.map(|it| it.as_str()) {
30 None => { 43 None => {
31 let mut path = self.dir_path.clone(); 44 let mut path = self.dir_path.clone();
@@ -40,7 +53,7 @@ impl ModDir {
40 DirPath::new(path) 53 DirPath::new(path)
41 } 54 }
42 }; 55 };
43 ModDir { dir_path: path, root_non_dir_owner: false } 56 self.child(path, false)
44 } 57 }
45 58
46 pub(super) fn resolve_declaration( 59 pub(super) fn resolve_declaration(
@@ -72,7 +85,9 @@ impl ModDir {
72 } else { 85 } else {
73 (DirPath::new(format!("{}/", name)), true) 86 (DirPath::new(format!("{}/", name)), true)
74 }; 87 };
75 return Ok((file_id, is_mod_rs, ModDir { dir_path, root_non_dir_owner })); 88 if let Some(mod_dir) = self.child(dir_path, root_non_dir_owner) {
89 return Ok((file_id, is_mod_rs, mod_dir));
90 }
76 } 91 }
77 } 92 }
78 Err(candidate_files.remove(0)) 93 Err(candidate_files.remove(0))