aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-11-04 14:31:35 +0000
committerAleksey Kladov <[email protected]>2020-11-04 14:31:35 +0000
commit2b108133ac35b6886c0bd2c7e7bda83e18ba3b79 (patch)
tree139e5981758b0ba10270167f30598cb8882d2ec8 /crates/hir_def
parentbdfffa372be37cc57facc2fbead920fcf3134a91 (diff)
Don't stack overflow on circular modules
closes #6453
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/nameres/collector.rs25
-rw-r--r--crates/hir_def/src/nameres/mod_resolution.rs23
-rw-r--r--crates/hir_def/src/nameres/tests.rs5
-rw-r--r--crates/hir_def/src/nameres/tests/mod_resolution.rs27
4 files changed, 62 insertions, 18 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 59b6644c3..386287518 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -1116,17 +1116,20 @@ impl ModCollector<'_, '_> {
1116 &self.item_tree[module.visibility], 1116 &self.item_tree[module.visibility],
1117 ); 1117 );
1118 1118
1119 ModCollector { 1119 if let Some(mod_dir) = self.mod_dir.descend_into_definition(&module.name, path_attr)
1120 def_collector: &mut *self.def_collector, 1120 {
1121 macro_depth: self.macro_depth, 1121 ModCollector {
1122 module_id, 1122 def_collector: &mut *self.def_collector,
1123 file_id: self.file_id, 1123 macro_depth: self.macro_depth,
1124 item_tree: self.item_tree, 1124 module_id,
1125 mod_dir: self.mod_dir.descend_into_definition(&module.name, path_attr), 1125 file_id: self.file_id,
1126 } 1126 item_tree: self.item_tree,
1127 .collect(&*items); 1127 mod_dir,
1128 if is_macro_use { 1128 }
1129 self.import_all_legacy_macros(module_id); 1129 .collect(&*items);
1130 if is_macro_use {
1131 self.import_all_legacy_macros(module_id);
1132 }
1130 } 1133 }
1131 } 1134 }
1132 // out of line module, resolve, parse and recurse 1135 // out of line module, resolve, parse and recurse
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))
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index 9c19bf572..a4d1fb8f3 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -20,9 +20,8 @@ fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> {
20} 20}
21 21
22fn check(ra_fixture: &str, expect: Expect) { 22fn check(ra_fixture: &str, expect: Expect) {
23 let db = TestDB::with_files(ra_fixture); 23 let def_map = compute_crate_def_map(ra_fixture);
24 let krate = db.crate_graph().iter().next().unwrap(); 24 let actual = def_map.dump();
25 let actual = db.crate_def_map(krate).dump();
26 expect.assert_eq(&actual); 25 expect.assert_eq(&actual);
27} 26}
28 27
diff --git a/crates/hir_def/src/nameres/tests/mod_resolution.rs b/crates/hir_def/src/nameres/tests/mod_resolution.rs
index ec9d589a3..ba295fd9e 100644
--- a/crates/hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/hir_def/src/nameres/tests/mod_resolution.rs
@@ -771,3 +771,30 @@ struct X;
771 "#]], 771 "#]],
772 ); 772 );
773} 773}
774
775#[test]
776fn circular_mods() {
777 mark::check!(circular_mods);
778 compute_crate_def_map(
779 r#"
780//- /lib.rs
781mod foo;
782//- /foo.rs
783#[path = "./foo.rs"]
784mod foo;
785"#,
786 );
787
788 compute_crate_def_map(
789 r#"
790//- /lib.rs
791mod foo;
792//- /foo.rs
793#[path = "./bar.rs"]
794mod bar;
795//- /bar.rs
796#[path = "./foo.rs"]
797mod foo;
798"#,
799 );
800}