diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 68b52ddbc4..e790217993 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -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 { + self.imp.resolve_attr_macro_call(item) + } + pub fn resolve_path(&self, path: &ast::Path) -> Option { 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 { + 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 { self.analyze(path.syntax()).resolve_path(self.db, path) } diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index 854d54b711..814d28e7b6 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -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 { 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, item: &ast::Item) -> Option { + let expanded = sema.expand_attr_macro(item)?.clone_for_update(); + expand(sema, expanded, ast::Item::cast, expand_attr_macro_recur) +} + +fn expand( + sema: &Semantics, + expanded: SyntaxNode, + f: impl FnMut(SyntaxNode) -> Option, + exp: impl Fn(&Semantics, &T) -> Option, +) -> Option { + 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);