Expand attributes recursively in expand_macro

This commit is contained in:
Lukas Wirth 2021-08-21 23:24:12 +02:00
parent 9e3517f8f3
commit 2f179adc41
2 changed files with 29 additions and 8 deletions

View file

@ -278,6 +278,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.resolve_macro_call(macro_call)
}
pub fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<MacroDef> {
self.imp.resolve_attr_macro_call(item)
}
pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
self.imp.resolve_path(path)
}
@ -634,6 +638,12 @@ impl<'db> SemanticsImpl<'db> {
sa.resolve_macro_call(self.db, macro_call)
}
fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<MacroDef> {
let item_in_file = self.find_file(item.syntax().clone()).with_value(item.clone());
let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(item_in_file))?;
Some(MacroDef { id: self.db.lookup_intern_macro(macro_call_id).def })
}
fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
self.analyze(path.syntax()).resolve_path(self.db, path)
}

View file

@ -34,11 +34,9 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
let mut name = None;
for node in tok.ancestors() {
if let Some(item) = ast::Item::cast(node.clone()) {
expanded = sema.expand_attr_macro(&item);
if expanded.is_some() {
// FIXME: add the macro name
// FIXME: make this recursive too
name = Some("?".to_string());
if let Some(def) = sema.resolve_attr_macro_call(&item) {
name = def.name(db).map(|name| name.to_string());
expanded = expand_attr_macro_recur(&sema, &item);
break;
}
}
@ -54,7 +52,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
// macro expansion may lose all white space information
// But we hope someday we can use ra_fmt for that
let expansion = insert_whitespaces(expanded?);
Some(ExpandedMacro { name: name?, expansion })
Some(ExpandedMacro { name: name.unwrap_or_else(|| "???".to_owned()), expansion })
}
fn expand_macro_recur(
@ -62,12 +60,25 @@ fn expand_macro_recur(
macro_call: &ast::MacroCall,
) -> Option<SyntaxNode> {
let expanded = sema.expand(macro_call)?.clone_for_update();
expand(sema, expanded, ast::MacroCall::cast, expand_macro_recur)
}
let children = expanded.descendants().filter_map(ast::MacroCall::cast);
fn expand_attr_macro_recur(sema: &Semantics<RootDatabase>, item: &ast::Item) -> Option<SyntaxNode> {
let expanded = sema.expand_attr_macro(item)?.clone_for_update();
expand(sema, expanded, ast::Item::cast, expand_attr_macro_recur)
}
fn expand<T: AstNode>(
sema: &Semantics<RootDatabase>,
expanded: SyntaxNode,
f: impl FnMut(SyntaxNode) -> Option<T>,
exp: impl Fn(&Semantics<RootDatabase>, &T) -> Option<SyntaxNode>,
) -> Option<SyntaxNode> {
let children = expanded.descendants().filter_map(f);
let mut replacements = Vec::new();
for child in children {
if let Some(new_node) = expand_macro_recur(sema, &child) {
if let Some(new_node) = exp(sema, &child) {
// check if the whole original syntax is replaced
if expanded == *child.syntax() {
return Some(new_node);