Collect inner items in expression macros

This commit is contained in:
Jonas Schievink 2020-06-23 13:46:38 +02:00
parent 5a81427304
commit 689e147c9d
4 changed files with 44 additions and 14 deletions

View File

@ -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::<S>())
.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<ast::Expr>) -> ExprId {

View File

@ -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;

View File

@ -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;
&macro_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)
}

View File

@ -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<ModItems> {
assert!(inner || self.inner_items.is_empty());