Unnamed repository; edit this file 'description' to name the repository.
Fix `expand_macro` not working for derive attributes
Lukas Wirth 2022-02-22
parent 7b89d5e · commit be3168d
-rw-r--r--crates/hir_expand/src/lib.rs36
-rw-r--r--crates/ide/src/expand_macro.rs24
2 files changed, 42 insertions, 18 deletions
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 2ccf4c56ee..2c6378cd3e 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -219,9 +219,18 @@ impl HirFileId {
let arg_tt = loc.kind.arg(db)?;
+ let macro_def = db.macro_def(loc.def).ok()?;
+ let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?;
+ let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
+
let def = loc.def.ast_id().left().and_then(|id| {
let def_tt = match id.to_node(db) {
ast::Macro::MacroRules(mac) => mac.token_tree()?,
+ ast::Macro::MacroDef(_)
+ if matches!(*macro_def, TokenExpander::BuiltinAttr(_)) =>
+ {
+ return None
+ }
ast::Macro::MacroDef(mac) => mac.body()?,
};
Some(InFile::new(id.file_id, def_tt))
@@ -239,10 +248,6 @@ impl HirFileId {
_ => None,
});
- let macro_def = db.macro_def(loc.def).ok()?;
- let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?;
- let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
-
Some(ExpansionInfo {
expanded: InFile::new(self, parse.syntax_node()),
arg: InFile::new(loc.kind.file_id(), arg_tt),
@@ -292,7 +297,7 @@ impl HirFileId {
}
}
- /// Return whether this file is an include macro
+ /// Return whether this file is an attr macro
pub fn is_attr_macro(&self, db: &dyn db::AstDatabase) -> bool {
match self.0 {
HirFileIdRepr::MacroFile(macro_file) => {
@@ -303,6 +308,17 @@ impl HirFileId {
}
}
+ /// Return whether this file is the pseudo expansion of the derive attribute.
+ pub fn is_derive_attr_macro(&self, db: &dyn db::AstDatabase) -> bool {
+ match self.0 {
+ HirFileIdRepr::MacroFile(macro_file) => {
+ let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
+ matches!(loc.kind, MacroCallKind::Attr { is_derive: true, .. })
+ }
+ _ => false,
+ }
+ }
+
pub fn is_macro(self) -> bool {
matches!(self.0, HirFileIdRepr::MacroFile(_))
}
@@ -567,6 +583,9 @@ impl ExpansionInfo {
// Attributes are a bit special for us, they have two inputs, the input tokentree and the annotated item.
let (token_map, tt) = match &loc.kind {
+ MacroCallKind::Attr { attr_args, is_derive: true, .. } => {
+ (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned())
+ }
MacroCallKind::Attr { attr_args, .. } => {
// try unshifting the the token id, if unshifting fails, the token resides in the non-item attribute input
// note that the `TokenExpander::map_id_up` earlier only unshifts for declarative macros, so we don't double unshift with this
@@ -722,6 +741,13 @@ impl<'a> InFile<&'a SyntaxNode> {
}
}
+impl InFile<SyntaxToken> {
+ pub fn upmap(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxToken>> {
+ let expansion = self.file_id.expansion_info(db)?;
+ expansion.map_token_up(db, self.as_ref()).map(|(it, _)| it)
+ }
+}
+
fn ascend_node_border_tokens(
db: &dyn db::AstDatabase,
InFile { file_id, value: node }: InFile<&SyntaxNode>,
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 32dbd9070b..c234eb3db6 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -41,20 +41,18 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
// struct Bar;
// ```
- let derive = sema.descend_into_macros(tok.clone()).iter().find_map(|descended| {
- let attr = descended.ancestors().find_map(ast::Attr::cast)?;
- let (path, tt) = attr.as_simple_call()?;
- if path == "derive" {
- let mut tt = tt.syntax().children_with_tokens().skip(1).join("");
- tt.pop();
- let expansions = sema.expand_derive_macro(&attr)?;
- Some(ExpandedMacro {
- name: tt,
- expansion: expansions.into_iter().map(insert_ws_into).join(""),
- })
- } else {
- None
+ let derive = sema.descend_into_macros(tok.clone()).into_iter().find_map(|descended| {
+ let hir_file = sema.hir_file_for(&descended.parent()?);
+ if !hir_file.is_derive_attr_macro(db) {
+ return None;
}
+
+ let name = descended.ancestors().filter_map(ast::Path::cast).last()?.to_string();
+ // up map out of the #[derive] expansion
+ let token = hir::InFile::new(hir_file, descended).upmap(db)?.value;
+ let attr = token.ancestors().find_map(ast::Attr::cast)?;
+ let expansions = sema.expand_derive_macro(&attr)?;
+ Some(ExpandedMacro { name, expansion: expansions.into_iter().map(insert_ws_into).join("") })
});
if derive.is_some() {