From 689e147c9dc416027fd36e94673431533df545f9 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jun 2020 13:46:38 +0200 Subject: Collect inner items in expression macros --- crates/ra_hir_def/src/body/lower.rs | 4 +++- crates/ra_hir_def/src/body/scope.rs | 20 ++++++++++++++++++++ crates/ra_hir_def/src/item_tree.rs | 27 +++++++++++++++------------ crates/ra_hir_def/src/item_tree/lower.rs | 7 ++++++- 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<'_> { }); let tree = &self.item_trees[index].1; + // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes + // Root file (non-macro). tree.all_inner_items() .chain(tree.top_level_items().iter().copied()) .filter_map(|mod_item| mod_item.downcast::()) .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value) - .unwrap() + .unwrap_or_else(|| panic!("couldn't find inner item for {:?}", id)) } fn collect_expr_opt(&mut self, expr: Option) -> 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() { ); } + #[test] + fn macro_inner_item() { + do_check( + r" + macro_rules! mac { + () => {{ + fn inner() {} + inner(); + }}; + } + + fn foo() { + mac!(); + <|> + } + ", + &[], + ); + } + fn do_check_local_name(ra_fixture: &str, expected_offset: u32) { let (db, position) = TestDB::with_position(ra_fixture); 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::{ sync::Arc, }; -use ast::{AstNode, AttrsOwner, ModuleItemOwner, NameOwner, StructKind, TypeAscriptionOwner}; +use ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner}; use either::Either; use hir_expand::{ ast_id_map::FileAstId, @@ -73,25 +73,28 @@ impl ItemTree { }; let hygiene = Hygiene::new(db.upcast(), file_id); + let ctx = lower::Ctx::new(db, hygiene.clone(), file_id); let mut top_attrs = None; - let (macro_storage, file_storage); - let item_owner = match_ast! { + let mut item_tree = match_ast! { match syntax { - ast::MacroItems(items) => { - macro_storage = items; - ¯o_storage as &dyn ModuleItemOwner - }, ast::SourceFile(file) => { top_attrs = Some(Attrs::new(&file, &hygiene)); - file_storage = file; - &file_storage + ctx.lower_module_items(&file) + }, + ast::MacroItems(items) => { + ctx.lower_module_items(&items) + }, + // Macros can expand to expressions. We return an empty item tree in this case, but + // still need to collect inner items. + ast::Expr(e) => { + ctx.lower_inner_items(e.syntax()) + }, + _ => { + panic!("cannot create item tree from {:?}", syntax); }, - _ => return Arc::new(Self::empty(file_id)), } }; - let ctx = lower::Ctx::new(db, hygiene, file_id); - let mut item_tree = ctx.lower(item_owner); item_tree.top_attrs = top_attrs.unwrap_or_default(); Arc::new(item_tree) } 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 { } } - pub(super) fn lower(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { + pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { self.tree.top_level = item_owner .items() .flat_map(|item| self.lower_mod_item(&item, false)) @@ -61,6 +61,11 @@ impl Ctx { self.tree } + pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { + self.collect_inner_items(within); + self.tree + } + fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option { assert!(inner || self.inner_items.is_empty()); -- cgit v1.2.3