diff options
Diffstat (limited to 'crates/hir_def/src/nameres/mod_resolution.rs')
-rw-r--r-- | crates/hir_def/src/nameres/mod_resolution.rs | 23 |
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 @@ | |||
2 | use base_db::FileId; | 2 | use base_db::FileId; |
3 | use hir_expand::name::Name; | 3 | use hir_expand::name::Name; |
4 | use syntax::SmolStr; | 4 | use syntax::SmolStr; |
5 | use test_utils::mark; | ||
5 | 6 | ||
6 | use crate::{db::DefDatabase, HirFileId}; | 7 | use crate::{db::DefDatabase, HirFileId}; |
7 | 8 | ||
9 | const MOD_DEPTH_LIMIT: u32 = 32; | ||
10 | |||
8 | #[derive(Clone, Debug)] | 11 | #[derive(Clone, Debug)] |
9 | pub(super) struct ModDir { | 12 | pub(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 | ||
19 | impl ModDir { | 23 | impl 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)) |