aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-06-23 12:46:38 +0100
committerJonas Schievink <[email protected]>2020-06-24 15:53:54 +0100
commit689e147c9dc416027fd36e94673431533df545f9 (patch)
treefe8c4d6937134388bd23416706c08a4de046cf06 /crates
parent5a81427304114d2c6ada9e9258ffe31e715c25bc (diff)
Collect inner items in expression macros
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_def/src/body/lower.rs4
-rw-r--r--crates/ra_hir_def/src/body/scope.rs20
-rw-r--r--crates/ra_hir_def/src/item_tree.rs27
-rw-r--r--crates/ra_hir_def/src/item_tree/lower.rs7
4 files changed, 44 insertions, 14 deletions
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index e7cf80676..bbde0b802 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -564,12 +564,14 @@ impl ExprCollector<'_> {
564 }); 564 });
565 let tree = &self.item_trees[index].1; 565 let tree = &self.item_trees[index].1;
566 566
567 // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes
568
567 // Root file (non-macro). 569 // Root file (non-macro).
568 tree.all_inner_items() 570 tree.all_inner_items()
569 .chain(tree.top_level_items().iter().copied()) 571 .chain(tree.top_level_items().iter().copied())
570 .filter_map(|mod_item| mod_item.downcast::<S>()) 572 .filter_map(|mod_item| mod_item.downcast::<S>())
571 .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value) 573 .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value)
572 .unwrap() 574 .unwrap_or_else(|| panic!("couldn't find inner item for {:?}", id))
573 } 575 }
574 576
575 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { 577 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index 0b74199d9..81397b063 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -317,6 +317,26 @@ fn foo() {
317 ); 317 );
318 } 318 }
319 319
320 #[test]
321 fn macro_inner_item() {
322 do_check(
323 r"
324 macro_rules! mac {
325 () => {{
326 fn inner() {}
327 inner();
328 }};
329 }
330
331 fn foo() {
332 mac!();
333 <|>
334 }
335 ",
336 &[],
337 );
338 }
339
320 fn do_check_local_name(ra_fixture: &str, expected_offset: u32) { 340 fn do_check_local_name(ra_fixture: &str, expected_offset: u32) {
321 let (db, position) = TestDB::with_position(ra_fixture); 341 let (db, position) = TestDB::with_position(ra_fixture);
322 let file_id = position.file_id; 342 let file_id = position.file_id;
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
index efcb5dc60..a1a78fc5c 100644
--- a/crates/ra_hir_def/src/item_tree.rs
+++ b/crates/ra_hir_def/src/item_tree.rs
@@ -12,7 +12,7 @@ use std::{
12 sync::Arc, 12 sync::Arc,
13}; 13};
14 14
15use ast::{AstNode, AttrsOwner, ModuleItemOwner, NameOwner, StructKind, TypeAscriptionOwner}; 15use ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner};
16use either::Either; 16use either::Either;
17use hir_expand::{ 17use hir_expand::{
18 ast_id_map::FileAstId, 18 ast_id_map::FileAstId,
@@ -73,25 +73,28 @@ impl ItemTree {
73 }; 73 };
74 74
75 let hygiene = Hygiene::new(db.upcast(), file_id); 75 let hygiene = Hygiene::new(db.upcast(), file_id);
76 let ctx = lower::Ctx::new(db, hygiene.clone(), file_id);
76 let mut top_attrs = None; 77 let mut top_attrs = None;
77 let (macro_storage, file_storage); 78 let mut item_tree = match_ast! {
78 let item_owner = match_ast! {
79 match syntax { 79 match syntax {
80 ast::MacroItems(items) => {
81 macro_storage = items;
82 &macro_storage as &dyn ModuleItemOwner
83 },
84 ast::SourceFile(file) => { 80 ast::SourceFile(file) => {
85 top_attrs = Some(Attrs::new(&file, &hygiene)); 81 top_attrs = Some(Attrs::new(&file, &hygiene));
86 file_storage = file; 82 ctx.lower_module_items(&file)
87 &file_storage 83 },
84 ast::MacroItems(items) => {
85 ctx.lower_module_items(&items)
86 },
87 // Macros can expand to expressions. We return an empty item tree in this case, but
88 // still need to collect inner items.
89 ast::Expr(e) => {
90 ctx.lower_inner_items(e.syntax())
91 },
92 _ => {
93 panic!("cannot create item tree from {:?}", syntax);
88 }, 94 },
89 _ => return Arc::new(Self::empty(file_id)),
90 } 95 }
91 }; 96 };
92 97
93 let ctx = lower::Ctx::new(db, hygiene, file_id);
94 let mut item_tree = ctx.lower(item_owner);
95 item_tree.top_attrs = top_attrs.unwrap_or_default(); 98 item_tree.top_attrs = top_attrs.unwrap_or_default();
96 Arc::new(item_tree) 99 Arc::new(item_tree)
97 } 100 }
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
index 841c7a852..3bb437e81 100644
--- a/crates/ra_hir_def/src/item_tree/lower.rs
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -52,7 +52,7 @@ impl Ctx {
52 } 52 }
53 } 53 }
54 54
55 pub(super) fn lower(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { 55 pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree {
56 self.tree.top_level = item_owner 56 self.tree.top_level = item_owner
57 .items() 57 .items()
58 .flat_map(|item| self.lower_mod_item(&item, false)) 58 .flat_map(|item| self.lower_mod_item(&item, false))
@@ -61,6 +61,11 @@ impl Ctx {
61 self.tree 61 self.tree
62 } 62 }
63 63
64 pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree {
65 self.collect_inner_items(within);
66 self.tree
67 }
68
64 fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> { 69 fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> {
65 assert!(inner || self.inner_items.is_empty()); 70 assert!(inner || self.inner_items.is_empty());
66 71