mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Merge #2626
2626: Recursive collect macros in impl items r=matklad a=edwin0cheng Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
commit
3ebf15c9b2
2 changed files with 59 additions and 10 deletions
|
@ -225,22 +225,48 @@ fn collect_impl_items_in_macros(
|
|||
let mut expander = Expander::new(db, impl_block.file_id, module_id);
|
||||
let mut res = Vec::new();
|
||||
|
||||
// We set a limit to protect against infinite recursion
|
||||
let limit = 100;
|
||||
|
||||
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, limit))
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn collect_impl_items_in_macro(
|
||||
db: &impl DefDatabase,
|
||||
expander: &mut Expander,
|
||||
m: ast::MacroCall,
|
||||
id: ImplId,
|
||||
limit: usize,
|
||||
) -> Vec<AssocItemId> {
|
||||
if limit == 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
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, limit - 1))
|
||||
}
|
||||
expander.exit(db, mark);
|
||||
res
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_impl_items(
|
||||
db: &impl DefDatabase,
|
||||
impl_items: impl Iterator<Item = ImplItem>,
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue