Recursive collect macros in impl items

This commit is contained in:
Edwin Cheng 2019-12-21 05:02:31 +08:00
parent 6eab968c60
commit 360de5ba71
2 changed files with 51 additions and 10 deletions

View File

@ -226,21 +226,39 @@ fn collect_impl_items_in_macros(
let mut res = Vec::new();
for m in impl_block.value.syntax().children().filter_map(ast::MacroCall::cast) {
if let Some((mark, items)) = expander.enter_expand(db, m) {
let items: InFile<ast::MacroItems> = expander.to_source(items);
expander.exit(db, mark);
res.extend(collect_impl_items(
db,
items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())),
items.file_id,
id,
));
}
res.extend(collect_impl_items_in_macro(db, &mut expander, m, id))
}
res
}
fn collect_impl_items_in_macro(
db: &impl DefDatabase,
expander: &mut Expander,
m: ast::MacroCall,
id: ImplId,
) -> Vec<AssocItemId> {
if let Some((mark, items)) = expander.enter_expand(db, m) {
let items: InFile<ast::MacroItems> = expander.to_source(items);
let mut res = collect_impl_items(
db,
items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())),
items.file_id,
id,
);
// Recursive collect macros
// Note that ast::ModuleItem do not include ast::MacroCall
// We cannot use ModuleItemOwner::items here
for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) {
res.extend(collect_impl_items_in_macro(db, expander, it, id))
}
expander.exit(db, mark);
res
} else {
Vec::new()
}
}
fn collect_impl_items(
db: &impl DefDatabase,
impl_items: impl Iterator<Item = ImplItem>,

View File

@ -201,6 +201,29 @@ fn test() { S.foo()<|>; }
assert_eq!(t, "u128");
}
#[test]
fn infer_impl_items_generated_by_macros_chain() {
let t = type_at(
r#"
//- /main.rs
macro_rules! m_inner {
() => {fn foo(&self) -> u128 {0}}
}
macro_rules! m {
() => {m_inner!();}
}
struct S;
impl S {
m!();
}
fn test() { S.foo()<|>; }
"#,
);
assert_eq!(t, "u128");
}
#[test]
fn infer_macro_with_dollar_crate_is_correct_in_expr() {
let (db, pos) = TestDB::with_position(