Rust: Rust: expand attribute macros on AssocItem and ExternItem

This commit is contained in:
Arthur Baars
2025-06-19 16:57:27 +02:00
parent 8b3137626c
commit b7f66f8653
3 changed files with 209 additions and 51 deletions

View File

@@ -26,12 +26,33 @@ use ra_ap_syntax::{
macro_rules! pre_emit {
(Item, $self:ident, $node:ident) => {
if let Some(label) = $self.prepare_item_expansion($node) {
return Some(label);
return Some(label.into());
}
};
(AssocItem, $self:ident, $node:ident) => {
if let Some(label) = $self.prepare_item_expansion(&$node.clone().into()) {
return Some(label.into());
}
};
(ExternItem, $self:ident, $node:ident) => {
if let Some(label) = $self.prepare_item_expansion(&$node.clone().into()) {
return Some(label.into());
}
};
($($_:tt)*) => {};
}
impl From<crate::trap::Label<generated::AssocItem>> for crate::trap::Label<generated::Item> {
fn from(value: crate::trap::Label<generated::AssocItem>) -> Self {
// SAFETY: this is safe because in the dbscheme Item is a subclass of Stmt
unsafe { Self::from_untyped(value.as_untyped()) }
}
}
impl From<crate::trap::Label<generated::ExternItem>> for crate::trap::Label<generated::Item> {
fn from(value: crate::trap::Label<generated::ExternItem>) -> Self {
// SAFETY: this is safe because in the dbscheme Item is a subclass of Stmt
unsafe { Self::from_untyped(value.as_untyped()) }
}
}
#[macro_export]
macro_rules! post_emit {
(MacroCall, $self:ident, $node:ident, $label:ident) => {
@@ -62,6 +83,18 @@ macro_rules! post_emit {
(Item, $self:ident, $node:ident, $label:ident) => {
$self.emit_item_expansion($node, $label);
};
(AssocItem, $self:ident, $node:ident, $label:ident) => {
$self.emit_item_expansion(
&$node.clone().into(),
From::<Label<generated::AssocItem>>::from($label),
);
};
(ExternItem, $self:ident, $node:ident, $label:ident) => {
$self.emit_item_expansion(
&$node.clone().into(),
From::<Label<generated::ExternItem>>::from($label),
);
};
// TODO canonical origin of other items
(PathExpr, $self:ident, $node:ident, $label:ident) => {
$self.extract_path_canonical_destination($node, $label.into());
@@ -694,10 +727,21 @@ impl<'a> Translator<'a> {
}
}
fn is_attribute_macro_target(&self, node: &ast::Item) -> bool {
// rust-analyzer considers as an `attr_macro_call` also a plain macro call, but we want to
// process that differently (in `extract_macro_call_expanded`)
!matches!(node, ast::Item::MacroCall(_))
&& self.semantics.is_some_and(|semantics| {
let file = semantics.hir_file_for(node.syntax());
let node = InFile::new(file, node);
semantics.is_attr_macro_call(node)
})
}
pub(crate) fn prepare_item_expansion(
&mut self,
node: &ast::Item,
) -> Option<Label<generated::Item>> {
) -> Option<Label<generated::MacroCall>> {
if self.source_kind == SourceKind::Library {
// if the item expands via an attribute macro, we want to only emit the expansion
if let Some(expanded) = self.emit_attribute_macro_expansion(node) {
@@ -714,13 +758,10 @@ impl<'a> Translator<'a> {
expanded.into(),
&mut self.trap.writer,
);
return Some(label.into());
return Some(label);
}
}
let semantics = self.semantics.as_ref()?;
let file = semantics.hir_file_for(node.syntax());
let node = InFile::new(file, node);
if semantics.is_attr_macro_call(node) {
if self.is_attribute_macro_target(node) {
self.macro_context_depth += 1;
}
None
@@ -730,10 +771,7 @@ impl<'a> Translator<'a> {
&mut self,
node: &ast::Item,
) -> Option<Label<generated::MacroItems>> {
let semantics = self.semantics?;
let file = semantics.hir_file_for(node.syntax());
let infile_node = InFile::new(file, node);
if !semantics.is_attr_macro_call(infile_node) {
if !self.is_attribute_macro_target(node) {
return None;
}
self.macro_context_depth -= 1;
@@ -743,7 +781,7 @@ impl<'a> Translator<'a> {
}
let ExpandResult {
value: expanded, ..
} = semantics.expand_attr_macro(node)?;
} = self.semantics.and_then(|s| s.expand_attr_macro(node))?;
self.emit_macro_expansion_parse_errors(node, &expanded);
let macro_items = ast::MacroItems::cast(expanded).or_else(|| {
let message = "attribute macro expansion cannot be cast to MacroItems".to_owned();

View File

@@ -406,6 +406,151 @@ macro_expansion.rs:
# 30| getItem(6): [Impl] impl S { ... }
# 30| getAssocItemList(): [AssocItemList] AssocItemList
# 31| getAssocItem(0): [Function] fn bzz
# 32| getAttributeMacroExpansion(): [MacroItems] MacroItems
# 32| getItem(0): [Function] fn bzz_0
# 32| getParamList(): [ParamList] ParamList
# 32| getBody(): [BlockExpr] { ... }
# 32| getStmtList(): [StmtList] StmtList
# 33| getStatement(0): [ExprStmt] ExprStmt
# 33| getExpr(): [MacroExpr] MacroExpr
# 33| getMacroCall(): [MacroCall] hello!...
# 33| getPath(): [Path] hello
# 33| getSegment(): [PathSegment] hello
# 33| getIdentifier(): [NameRef] hello
# 33| getTokenTree(): [TokenTree] TokenTree
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 31| getStatement(0): [ExprStmt] ExprStmt
# 31| getExpr(): [MacroExpr] MacroExpr
# 31| getMacroCall(): [MacroCall] println!...
# 31| getPath(): [Path] println
# 31| getSegment(): [PathSegment] println
# 31| getIdentifier(): [NameRef] println
# 31| getTokenTree(): [TokenTree] TokenTree
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 31| getTailExpr(): [BlockExpr] { ... }
# 31| getStmtList(): [StmtList] StmtList
# 31| getStatement(0): [ExprStmt] ExprStmt
# 31| getExpr(): [CallExpr] ...::_print(...)
# 31| getArgList(): [ArgList] ArgList
# 31| getArg(0): [MacroExpr] MacroExpr
# 31| getMacroCall(): [MacroCall] ...::format_args_nl!...
# 31| getPath(): [Path] ...::format_args_nl
# 31| getQualifier(): [Path] $crate
# 31| getSegment(): [PathSegment] $crate
# 31| getIdentifier(): [NameRef] $crate
# 31| getSegment(): [PathSegment] format_args_nl
# 31| getIdentifier(): [NameRef] format_args_nl
# 31| getTokenTree(): [TokenTree] TokenTree
# 31| getMacroCallExpansion(): [FormatArgsExpr] FormatArgsExpr
# 31| getTemplate(): [StringLiteralExpr] "hello!\n"
# 31| getFunction(): [PathExpr] ...::_print
# 31| getPath(): [Path] ...::_print
# 31| getQualifier(): [Path] ...::io
# 31| getQualifier(): [Path] $crate
# 31| getSegment(): [PathSegment] $crate
# 31| getIdentifier(): [NameRef] $crate
# 31| getSegment(): [PathSegment] io
# 31| getIdentifier(): [NameRef] io
# 31| getSegment(): [PathSegment] _print
# 31| getIdentifier(): [NameRef] _print
# 32| getName(): [Name] bzz_0
# 32| getVisibility(): [Visibility] Visibility
# 32| getItem(1): [Function] fn bzz_1
# 32| getParamList(): [ParamList] ParamList
# 32| getBody(): [BlockExpr] { ... }
# 32| getStmtList(): [StmtList] StmtList
# 33| getStatement(0): [ExprStmt] ExprStmt
# 33| getExpr(): [MacroExpr] MacroExpr
# 33| getMacroCall(): [MacroCall] hello!...
# 33| getPath(): [Path] hello
# 33| getSegment(): [PathSegment] hello
# 33| getIdentifier(): [NameRef] hello
# 33| getTokenTree(): [TokenTree] TokenTree
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 31| getStatement(0): [ExprStmt] ExprStmt
# 31| getExpr(): [MacroExpr] MacroExpr
# 31| getMacroCall(): [MacroCall] println!...
# 31| getPath(): [Path] println
# 31| getSegment(): [PathSegment] println
# 31| getIdentifier(): [NameRef] println
# 31| getTokenTree(): [TokenTree] TokenTree
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 31| getTailExpr(): [BlockExpr] { ... }
# 31| getStmtList(): [StmtList] StmtList
# 31| getStatement(0): [ExprStmt] ExprStmt
# 31| getExpr(): [CallExpr] ...::_print(...)
# 31| getArgList(): [ArgList] ArgList
# 31| getArg(0): [MacroExpr] MacroExpr
# 31| getMacroCall(): [MacroCall] ...::format_args_nl!...
# 31| getPath(): [Path] ...::format_args_nl
# 31| getQualifier(): [Path] $crate
# 31| getSegment(): [PathSegment] $crate
# 31| getIdentifier(): [NameRef] $crate
# 31| getSegment(): [PathSegment] format_args_nl
# 31| getIdentifier(): [NameRef] format_args_nl
# 31| getTokenTree(): [TokenTree] TokenTree
# 31| getMacroCallExpansion(): [FormatArgsExpr] FormatArgsExpr
# 31| getTemplate(): [StringLiteralExpr] "hello!\n"
# 31| getFunction(): [PathExpr] ...::_print
# 31| getPath(): [Path] ...::_print
# 31| getQualifier(): [Path] ...::io
# 31| getQualifier(): [Path] $crate
# 31| getSegment(): [PathSegment] $crate
# 31| getIdentifier(): [NameRef] $crate
# 31| getSegment(): [PathSegment] io
# 31| getIdentifier(): [NameRef] io
# 31| getSegment(): [PathSegment] _print
# 31| getIdentifier(): [NameRef] _print
# 32| getName(): [Name] bzz_1
# 32| getVisibility(): [Visibility] Visibility
# 32| getItem(2): [Function] fn bzz_2
# 32| getParamList(): [ParamList] ParamList
# 32| getBody(): [BlockExpr] { ... }
# 32| getStmtList(): [StmtList] StmtList
# 33| getStatement(0): [ExprStmt] ExprStmt
# 33| getExpr(): [MacroExpr] MacroExpr
# 33| getMacroCall(): [MacroCall] hello!...
# 33| getPath(): [Path] hello
# 33| getSegment(): [PathSegment] hello
# 33| getIdentifier(): [NameRef] hello
# 33| getTokenTree(): [TokenTree] TokenTree
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 31| getStatement(0): [ExprStmt] ExprStmt
# 31| getExpr(): [MacroExpr] MacroExpr
# 31| getMacroCall(): [MacroCall] println!...
# 31| getPath(): [Path] println
# 31| getSegment(): [PathSegment] println
# 31| getIdentifier(): [NameRef] println
# 31| getTokenTree(): [TokenTree] TokenTree
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 31| getTailExpr(): [BlockExpr] { ... }
# 31| getStmtList(): [StmtList] StmtList
# 31| getStatement(0): [ExprStmt] ExprStmt
# 31| getExpr(): [CallExpr] ...::_print(...)
# 31| getArgList(): [ArgList] ArgList
# 31| getArg(0): [MacroExpr] MacroExpr
# 31| getMacroCall(): [MacroCall] ...::format_args_nl!...
# 31| getPath(): [Path] ...::format_args_nl
# 31| getQualifier(): [Path] $crate
# 31| getSegment(): [PathSegment] $crate
# 31| getIdentifier(): [NameRef] $crate
# 31| getSegment(): [PathSegment] format_args_nl
# 31| getIdentifier(): [NameRef] format_args_nl
# 31| getTokenTree(): [TokenTree] TokenTree
# 31| getMacroCallExpansion(): [FormatArgsExpr] FormatArgsExpr
# 31| getTemplate(): [StringLiteralExpr] "hello!\n"
# 31| getFunction(): [PathExpr] ...::_print
# 31| getPath(): [Path] ...::_print
# 31| getQualifier(): [Path] ...::io
# 31| getQualifier(): [Path] $crate
# 31| getSegment(): [PathSegment] $crate
# 31| getIdentifier(): [NameRef] $crate
# 31| getSegment(): [PathSegment] io
# 31| getIdentifier(): [NameRef] io
# 31| getSegment(): [PathSegment] _print
# 31| getIdentifier(): [NameRef] _print
# 32| getName(): [Name] bzz_2
# 32| getVisibility(): [Visibility] Visibility
# 32| getParamList(): [ParamList] ParamList
# 31| getAttr(0): [Attr] Attr
# 31| getMeta(): [Meta] Meta
@@ -422,41 +567,6 @@ macro_expansion.rs:
# 33| getSegment(): [PathSegment] hello
# 33| getIdentifier(): [NameRef] hello
# 33| getTokenTree(): [TokenTree] TokenTree
# 33| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 33| getStatement(0): [ExprStmt] ExprStmt
# 33| getExpr(): [MacroExpr] MacroExpr
# 33| getMacroCall(): [MacroCall] println!...
# 33| getPath(): [Path] println
# 33| getSegment(): [PathSegment] println
# 33| getIdentifier(): [NameRef] println
# 33| getTokenTree(): [TokenTree] TokenTree
# 33| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
# 33| getTailExpr(): [BlockExpr] { ... }
# 33| getStmtList(): [StmtList] StmtList
# 33| getStatement(0): [ExprStmt] ExprStmt
# 33| getExpr(): [CallExpr] ...::_print(...)
# 33| getArgList(): [ArgList] ArgList
# 33| getArg(0): [MacroExpr] MacroExpr
# 33| getMacroCall(): [MacroCall] ...::format_args_nl!...
# 33| getPath(): [Path] ...::format_args_nl
# 33| getQualifier(): [Path] $crate
# 33| getSegment(): [PathSegment] $crate
# 33| getIdentifier(): [NameRef] $crate
# 33| getSegment(): [PathSegment] format_args_nl
# 33| getIdentifier(): [NameRef] format_args_nl
# 33| getTokenTree(): [TokenTree] TokenTree
# 33| getMacroCallExpansion(): [FormatArgsExpr] FormatArgsExpr
# 33| getTemplate(): [StringLiteralExpr] "hello!\n"
# 33| getFunction(): [PathExpr] ...::_print
# 33| getPath(): [Path] ...::_print
# 33| getQualifier(): [Path] ...::io
# 33| getQualifier(): [Path] $crate
# 33| getSegment(): [PathSegment] $crate
# 33| getIdentifier(): [NameRef] $crate
# 33| getSegment(): [PathSegment] io
# 33| getIdentifier(): [NameRef] io
# 33| getSegment(): [PathSegment] _print
# 33| getIdentifier(): [NameRef] _print
# 32| getName(): [Name] bzz
# 32| getVisibility(): [Visibility] Visibility
# 30| getSelfTy(): [PathTypeRepr] S

View File

@@ -11,13 +11,22 @@ attribute_macros
| macro_expansion.rs:15:1:16:14 | fn bar_0 | 1 | macro_expansion.rs:16:1:16:14 | fn bar_0_new |
| macro_expansion.rs:15:1:16:14 | fn bar_1 | 0 | macro_expansion.rs:16:1:16:14 | fn bar_1 |
| macro_expansion.rs:15:1:16:14 | fn bar_1 | 1 | macro_expansion.rs:16:1:16:14 | fn bar_1_new |
| macro_expansion.rs:31:5:34:5 | fn bzz | 0 | macro_expansion.rs:32:5:33:17 | fn bzz_0 |
| macro_expansion.rs:31:5:34:5 | fn bzz | 1 | macro_expansion.rs:32:5:33:17 | fn bzz_1 |
| macro_expansion.rs:31:5:34:5 | fn bzz | 2 | macro_expansion.rs:32:5:33:17 | fn bzz_2 |
macro_calls
| included/included.rs:2:9:2:39 | concat!... | included/included.rs:2:17:2:38 | "Hello world!" |
| macro_expansion.rs:5:9:5:34 | concat!... | macro_expansion.rs:5:17:5:34 | "Hello world!" |
| macro_expansion.rs:5:9:5:34 | concat!... | macro_expansion.rs:5:17:5:34 | "Hello world!" |
| macro_expansion.rs:33:9:33:16 | ...::format_args_nl!... | macro_expansion.rs:33:9:33:16 | FormatArgsExpr |
| macro_expansion.rs:33:9:33:16 | hello!... | macro_expansion.rs:33:9:33:16 | MacroBlockExpr |
| macro_expansion.rs:33:9:33:16 | println!... | macro_expansion.rs:33:9:33:16 | MacroBlockExpr |
| macro_expansion.rs:31:5:31:16 | ...::format_args_nl!... | macro_expansion.rs:31:5:31:16 | FormatArgsExpr |
| macro_expansion.rs:31:5:31:16 | ...::format_args_nl!... | macro_expansion.rs:31:5:31:16 | FormatArgsExpr |
| macro_expansion.rs:31:5:31:16 | ...::format_args_nl!... | macro_expansion.rs:31:5:31:16 | FormatArgsExpr |
| macro_expansion.rs:31:5:31:16 | println!... | macro_expansion.rs:31:5:31:16 | MacroBlockExpr |
| macro_expansion.rs:31:5:31:16 | println!... | macro_expansion.rs:31:5:31:16 | MacroBlockExpr |
| macro_expansion.rs:31:5:31:16 | println!... | macro_expansion.rs:31:5:31:16 | MacroBlockExpr |
| macro_expansion.rs:33:9:33:15 | hello!... | macro_expansion.rs:31:5:31:16 | MacroBlockExpr |
| macro_expansion.rs:33:9:33:15 | hello!... | macro_expansion.rs:31:5:31:16 | MacroBlockExpr |
| macro_expansion.rs:33:9:33:15 | hello!... | macro_expansion.rs:31:5:31:16 | MacroBlockExpr |
| macro_expansion.rs:44:5:44:13 | def_x!... | macro_expansion.rs:44:5:44:13 | MacroItems |
| macro_expansion.rs:53:9:53:25 | concat!... | macro_expansion.rs:53:17:53:24 | "xy" |
| macro_expansion.rs:55:9:58:5 | my_macro!... | macro_expansion.rs:56:9:57:13 | MacroExpr |
@@ -34,4 +43,5 @@ macro_calls
| macro_expansion.rs:79:12:79:20 | my_int!... | macro_expansion.rs:79:12:79:20 | i32 |
unexpanded_macro_calls
| macro_expansion.rs:5:9:5:35 | concat!... |
| macro_expansion.rs:33:9:33:16 | hello!... |
warnings