diff options
Diffstat (limited to 'crates/ra_hir_def/src/body.rs')
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 65 |
1 files changed, 59 insertions, 6 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 4f2350915..2fe04db2b 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -14,6 +14,7 @@ use ra_db::CrateId; | |||
14 | use ra_prof::profile; | 14 | use ra_prof::profile; |
15 | use ra_syntax::{ast, AstNode, AstPtr}; | 15 | use ra_syntax::{ast, AstNode, AstPtr}; |
16 | use rustc_hash::FxHashMap; | 16 | use rustc_hash::FxHashMap; |
17 | use test_utils::mark; | ||
17 | 18 | ||
18 | pub(crate) use lower::LowerCtx; | 19 | pub(crate) use lower::LowerCtx; |
19 | 20 | ||
@@ -42,9 +43,15 @@ pub(crate) struct Expander { | |||
42 | current_file_id: HirFileId, | 43 | current_file_id: HirFileId, |
43 | ast_id_map: Arc<AstIdMap>, | 44 | ast_id_map: Arc<AstIdMap>, |
44 | module: ModuleId, | 45 | module: ModuleId, |
45 | recursive_limit: usize, | 46 | recursion_limit: usize, |
46 | } | 47 | } |
47 | 48 | ||
49 | #[cfg(test)] | ||
50 | const EXPANSION_RECURSION_LIMIT: usize = 32; | ||
51 | |||
52 | #[cfg(not(test))] | ||
53 | const EXPANSION_RECURSION_LIMIT: usize = 128; | ||
54 | |||
48 | impl CfgExpander { | 55 | impl CfgExpander { |
49 | pub(crate) fn new( | 56 | pub(crate) fn new( |
50 | db: &dyn DefDatabase, | 57 | db: &dyn DefDatabase, |
@@ -81,7 +88,7 @@ impl Expander { | |||
81 | current_file_id, | 88 | current_file_id, |
82 | ast_id_map, | 89 | ast_id_map, |
83 | module, | 90 | module, |
84 | recursive_limit: 0, | 91 | recursion_limit: 0, |
85 | } | 92 | } |
86 | } | 93 | } |
87 | 94 | ||
@@ -91,7 +98,9 @@ impl Expander { | |||
91 | local_scope: Option<&ItemScope>, | 98 | local_scope: Option<&ItemScope>, |
92 | macro_call: ast::MacroCall, | 99 | macro_call: ast::MacroCall, |
93 | ) -> Option<(Mark, T)> { | 100 | ) -> Option<(Mark, T)> { |
94 | if self.recursive_limit > 1024 { | 101 | self.recursion_limit += 1; |
102 | if self.recursion_limit > EXPANSION_RECURSION_LIMIT { | ||
103 | mark::hit!(your_stack_belongs_to_me); | ||
95 | return None; | 104 | return None; |
96 | } | 105 | } |
97 | 106 | ||
@@ -118,8 +127,6 @@ impl Expander { | |||
118 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); | 127 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); |
119 | self.current_file_id = file_id; | 128 | self.current_file_id = file_id; |
120 | self.ast_id_map = db.ast_id_map(file_id); | 129 | self.ast_id_map = db.ast_id_map(file_id); |
121 | self.recursive_limit += 1; | ||
122 | |||
123 | return Some((mark, expr)); | 130 | return Some((mark, expr)); |
124 | } | 131 | } |
125 | } | 132 | } |
@@ -134,7 +141,7 @@ impl Expander { | |||
134 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); | 141 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); |
135 | self.current_file_id = mark.file_id; | 142 | self.current_file_id = mark.file_id; |
136 | self.ast_id_map = mem::take(&mut mark.ast_id_map); | 143 | self.ast_id_map = mem::take(&mut mark.ast_id_map); |
137 | self.recursive_limit -= 1; | 144 | self.recursion_limit -= 1; |
138 | mark.bomb.defuse(); | 145 | mark.bomb.defuse(); |
139 | } | 146 | } |
140 | 147 | ||
@@ -302,7 +309,53 @@ impl BodySourceMap { | |||
302 | self.pat_map.get(&src).cloned() | 309 | self.pat_map.get(&src).cloned() |
303 | } | 310 | } |
304 | 311 | ||
312 | pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> { | ||
313 | let src = node.map(|it| Either::Right(AstPtr::new(it))); | ||
314 | self.pat_map.get(&src).cloned() | ||
315 | } | ||
316 | |||
305 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> { | 317 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> { |
306 | self.field_map[&(expr, field)].clone() | 318 | self.field_map[&(expr, field)].clone() |
307 | } | 319 | } |
308 | } | 320 | } |
321 | |||
322 | #[cfg(test)] | ||
323 | mod tests { | ||
324 | use ra_db::{fixture::WithFixture, SourceDatabase}; | ||
325 | use test_utils::mark; | ||
326 | |||
327 | use crate::ModuleDefId; | ||
328 | |||
329 | use super::*; | ||
330 | |||
331 | fn lower(ra_fixture: &str) -> Arc<Body> { | ||
332 | let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture); | ||
333 | |||
334 | let krate = db.crate_graph().iter().next().unwrap(); | ||
335 | let def_map = db.crate_def_map(krate); | ||
336 | let module = def_map.modules_for_file(file_id).next().unwrap(); | ||
337 | let module = &def_map[module]; | ||
338 | let fn_def = match module.scope.declarations().next().unwrap() { | ||
339 | ModuleDefId::FunctionId(it) => it, | ||
340 | _ => panic!(), | ||
341 | }; | ||
342 | |||
343 | db.body(fn_def.into()) | ||
344 | } | ||
345 | |||
346 | #[test] | ||
347 | fn your_stack_belongs_to_me() { | ||
348 | mark::check!(your_stack_belongs_to_me); | ||
349 | lower( | ||
350 | " | ||
351 | macro_rules! n_nuple { | ||
352 | ($e:tt) => (); | ||
353 | ($($rest:tt)*) => {{ | ||
354 | (n_nuple!($($rest)*)None,) | ||
355 | }}; | ||
356 | } | ||
357 | fn main() { n_nuple!(1,2,3); } | ||
358 | ", | ||
359 | ); | ||
360 | } | ||
361 | } | ||