Collect inner items in expression macros
This commit is contained in:
parent
5a81427304
commit
689e147c9d
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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());
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user