Skip to content

Commit 666144e

Browse files
authored
Merge pull request #19823 from github/aibaars/rust-expand-assoc-items
Rust: expand attribute macros on `AssocItem` and `ExternItem`
2 parents 9605eb0 + e3e8880 commit 666144e

File tree

3 files changed

+213
-50
lines changed

3 files changed

+213
-50
lines changed

rust/extractor/src/translate/base.rs

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,38 @@ use ra_ap_syntax::{
2626
macro_rules! pre_emit {
2727
(Item, $self:ident, $node:ident) => {
2828
if let Some(label) = $self.prepare_item_expansion($node) {
29-
return Some(label);
29+
return Some(label.into());
30+
}
31+
};
32+
(AssocItem, $self:ident, $node:ident) => {
33+
if let Some(label) = $self.prepare_item_expansion(&$node.clone().into()) {
34+
return Some(label.into());
35+
}
36+
};
37+
(ExternItem, $self:ident, $node:ident) => {
38+
if let Some(label) = $self.prepare_item_expansion(&$node.clone().into()) {
39+
return Some(label.into());
3040
}
3141
};
3242
($($_:tt)*) => {};
3343
}
3444

45+
// TODO: remove the mannually written Label conversions. These can be auto-generated by
46+
// changing the base class of AssocItem from AstNode to Item
47+
impl From<crate::trap::Label<generated::AssocItem>> for crate::trap::Label<generated::Item> {
48+
fn from(value: crate::trap::Label<generated::AssocItem>) -> Self {
49+
// SAFETY: this is safe because every concrete instance of `@assoc_item` is also an instance of `@item`
50+
unsafe { Self::from_untyped(value.as_untyped()) }
51+
}
52+
}
53+
// TODO: remove the mannually written Label conversions. These can be auto-generated by
54+
// changing the base class of ExternItem from AstNode to Item
55+
impl From<crate::trap::Label<generated::ExternItem>> for crate::trap::Label<generated::Item> {
56+
fn from(value: crate::trap::Label<generated::ExternItem>) -> Self {
57+
// SAFETY: this is safe because every concrete instance of `@extern_item` is also an instance of `@item`
58+
unsafe { Self::from_untyped(value.as_untyped()) }
59+
}
60+
}
3561
#[macro_export]
3662
macro_rules! post_emit {
3763
(MacroCall, $self:ident, $node:ident, $label:ident) => {
@@ -62,6 +88,18 @@ macro_rules! post_emit {
6288
(Item, $self:ident, $node:ident, $label:ident) => {
6389
$self.emit_item_expansion($node, $label);
6490
};
91+
(AssocItem, $self:ident, $node:ident, $label:ident) => {
92+
$self.emit_item_expansion(
93+
&$node.clone().into(),
94+
From::<Label<generated::AssocItem>>::from($label),
95+
);
96+
};
97+
(ExternItem, $self:ident, $node:ident, $label:ident) => {
98+
$self.emit_item_expansion(
99+
&$node.clone().into(),
100+
From::<Label<generated::ExternItem>>::from($label),
101+
);
102+
};
65103
// TODO canonical origin of other items
66104
(PathExpr, $self:ident, $node:ident, $label:ident) => {
67105
$self.extract_path_canonical_destination($node, $label.into());
@@ -728,10 +766,21 @@ impl<'a> Translator<'a> {
728766
}
729767
}
730768

769+
fn is_attribute_macro_target(&self, node: &ast::Item) -> bool {
770+
// rust-analyzer considers as an `attr_macro_call` also a plain macro call, but we want to
771+
// process that differently (in `extract_macro_call_expanded`)
772+
!matches!(node, ast::Item::MacroCall(_))
773+
&& self.semantics.is_some_and(|semantics| {
774+
let file = semantics.hir_file_for(node.syntax());
775+
let node = InFile::new(file, node);
776+
semantics.is_attr_macro_call(node)
777+
})
778+
}
779+
731780
pub(crate) fn prepare_item_expansion(
732781
&mut self,
733782
node: &ast::Item,
734-
) -> Option<Label<generated::Item>> {
783+
) -> Option<Label<generated::MacroCall>> {
735784
if self.source_kind == SourceKind::Library {
736785
// if the item expands via an attribute macro, we want to only emit the expansion
737786
if let Some(expanded) = self.emit_attribute_macro_expansion(node) {
@@ -748,13 +797,10 @@ impl<'a> Translator<'a> {
748797
expanded.into(),
749798
&mut self.trap.writer,
750799
);
751-
return Some(label.into());
800+
return Some(label);
752801
}
753802
}
754-
let semantics = self.semantics.as_ref()?;
755-
let file = semantics.hir_file_for(node.syntax());
756-
let node = InFile::new(file, node);
757-
if semantics.is_attr_macro_call(node) {
803+
if self.is_attribute_macro_target(node) {
758804
self.macro_context_depth += 1;
759805
}
760806
None
@@ -764,10 +810,7 @@ impl<'a> Translator<'a> {
764810
&mut self,
765811
node: &ast::Item,
766812
) -> Option<Label<generated::MacroItems>> {
767-
let semantics = self.semantics?;
768-
let file = semantics.hir_file_for(node.syntax());
769-
let infile_node = InFile::new(file, node);
770-
if !semantics.is_attr_macro_call(infile_node) {
813+
if !self.is_attribute_macro_target(node) {
771814
return None;
772815
}
773816
self.macro_context_depth -= 1;
@@ -777,7 +820,7 @@ impl<'a> Translator<'a> {
777820
}
778821
let ExpandResult {
779822
value: expanded, ..
780-
} = semantics.expand_attr_macro(node)?;
823+
} = self.semantics.and_then(|s| s.expand_attr_macro(node))?;
781824
self.emit_macro_expansion_parse_errors(node, &expanded);
782825
let macro_items = ast::MacroItems::cast(expanded).or_else(|| {
783826
let message = "attribute macro expansion cannot be cast to MacroItems".to_owned();

rust/ql/test/extractor-tests/macro-expansion/PrintAst.expected

Lines changed: 145 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,151 @@ macro_expansion.rs:
406406
# 30| getItem(6): [Impl] impl S { ... }
407407
# 30| getAssocItemList(): [AssocItemList] AssocItemList
408408
# 31| getAssocItem(0): [Function] fn bzz
409+
# 32| getAttributeMacroExpansion(): [MacroItems] MacroItems
410+
# 32| getItem(0): [Function] fn bzz_0
411+
# 32| getParamList(): [ParamList] ParamList
412+
# 32| getBody(): [BlockExpr] { ... }
413+
# 32| getStmtList(): [StmtList] StmtList
414+
# 33| getStatement(0): [ExprStmt] ExprStmt
415+
# 33| getExpr(): [MacroExpr] MacroExpr
416+
# 33| getMacroCall(): [MacroCall] hello!...
417+
# 33| getPath(): [Path] hello
418+
# 33| getSegment(): [PathSegment] hello
419+
# 33| getIdentifier(): [NameRef] hello
420+
# 33| getTokenTree(): [TokenTree] TokenTree
421+
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
422+
# 31| getStatement(0): [ExprStmt] ExprStmt
423+
# 31| getExpr(): [MacroExpr] MacroExpr
424+
# 31| getMacroCall(): [MacroCall] println!...
425+
# 31| getPath(): [Path] println
426+
# 31| getSegment(): [PathSegment] println
427+
# 31| getIdentifier(): [NameRef] println
428+
# 31| getTokenTree(): [TokenTree] TokenTree
429+
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
430+
# 31| getTailExpr(): [BlockExpr] { ... }
431+
# 31| getStmtList(): [StmtList] StmtList
432+
# 31| getStatement(0): [ExprStmt] ExprStmt
433+
# 31| getExpr(): [CallExpr] ...::_print(...)
434+
# 31| getArgList(): [ArgList] ArgList
435+
# 31| getArg(0): [MacroExpr] MacroExpr
436+
# 31| getMacroCall(): [MacroCall] ...::format_args_nl!...
437+
# 31| getPath(): [Path] ...::format_args_nl
438+
# 31| getQualifier(): [Path] $crate
439+
# 31| getSegment(): [PathSegment] $crate
440+
# 31| getIdentifier(): [NameRef] $crate
441+
# 31| getSegment(): [PathSegment] format_args_nl
442+
# 31| getIdentifier(): [NameRef] format_args_nl
443+
# 31| getTokenTree(): [TokenTree] TokenTree
444+
# 31| getMacroCallExpansion(): [FormatArgsExpr] FormatArgsExpr
445+
# 31| getTemplate(): [StringLiteralExpr] "hello!\n"
446+
# 31| getFunction(): [PathExpr] ...::_print
447+
# 31| getPath(): [Path] ...::_print
448+
# 31| getQualifier(): [Path] ...::io
449+
# 31| getQualifier(): [Path] $crate
450+
# 31| getSegment(): [PathSegment] $crate
451+
# 31| getIdentifier(): [NameRef] $crate
452+
# 31| getSegment(): [PathSegment] io
453+
# 31| getIdentifier(): [NameRef] io
454+
# 31| getSegment(): [PathSegment] _print
455+
# 31| getIdentifier(): [NameRef] _print
456+
# 32| getName(): [Name] bzz_0
457+
# 32| getVisibility(): [Visibility] Visibility
458+
# 32| getItem(1): [Function] fn bzz_1
459+
# 32| getParamList(): [ParamList] ParamList
460+
# 32| getBody(): [BlockExpr] { ... }
461+
# 32| getStmtList(): [StmtList] StmtList
462+
# 33| getStatement(0): [ExprStmt] ExprStmt
463+
# 33| getExpr(): [MacroExpr] MacroExpr
464+
# 33| getMacroCall(): [MacroCall] hello!...
465+
# 33| getPath(): [Path] hello
466+
# 33| getSegment(): [PathSegment] hello
467+
# 33| getIdentifier(): [NameRef] hello
468+
# 33| getTokenTree(): [TokenTree] TokenTree
469+
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
470+
# 31| getStatement(0): [ExprStmt] ExprStmt
471+
# 31| getExpr(): [MacroExpr] MacroExpr
472+
# 31| getMacroCall(): [MacroCall] println!...
473+
# 31| getPath(): [Path] println
474+
# 31| getSegment(): [PathSegment] println
475+
# 31| getIdentifier(): [NameRef] println
476+
# 31| getTokenTree(): [TokenTree] TokenTree
477+
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
478+
# 31| getTailExpr(): [BlockExpr] { ... }
479+
# 31| getStmtList(): [StmtList] StmtList
480+
# 31| getStatement(0): [ExprStmt] ExprStmt
481+
# 31| getExpr(): [CallExpr] ...::_print(...)
482+
# 31| getArgList(): [ArgList] ArgList
483+
# 31| getArg(0): [MacroExpr] MacroExpr
484+
# 31| getMacroCall(): [MacroCall] ...::format_args_nl!...
485+
# 31| getPath(): [Path] ...::format_args_nl
486+
# 31| getQualifier(): [Path] $crate
487+
# 31| getSegment(): [PathSegment] $crate
488+
# 31| getIdentifier(): [NameRef] $crate
489+
# 31| getSegment(): [PathSegment] format_args_nl
490+
# 31| getIdentifier(): [NameRef] format_args_nl
491+
# 31| getTokenTree(): [TokenTree] TokenTree
492+
# 31| getMacroCallExpansion(): [FormatArgsExpr] FormatArgsExpr
493+
# 31| getTemplate(): [StringLiteralExpr] "hello!\n"
494+
# 31| getFunction(): [PathExpr] ...::_print
495+
# 31| getPath(): [Path] ...::_print
496+
# 31| getQualifier(): [Path] ...::io
497+
# 31| getQualifier(): [Path] $crate
498+
# 31| getSegment(): [PathSegment] $crate
499+
# 31| getIdentifier(): [NameRef] $crate
500+
# 31| getSegment(): [PathSegment] io
501+
# 31| getIdentifier(): [NameRef] io
502+
# 31| getSegment(): [PathSegment] _print
503+
# 31| getIdentifier(): [NameRef] _print
504+
# 32| getName(): [Name] bzz_1
505+
# 32| getVisibility(): [Visibility] Visibility
506+
# 32| getItem(2): [Function] fn bzz_2
507+
# 32| getParamList(): [ParamList] ParamList
508+
# 32| getBody(): [BlockExpr] { ... }
509+
# 32| getStmtList(): [StmtList] StmtList
510+
# 33| getStatement(0): [ExprStmt] ExprStmt
511+
# 33| getExpr(): [MacroExpr] MacroExpr
512+
# 33| getMacroCall(): [MacroCall] hello!...
513+
# 33| getPath(): [Path] hello
514+
# 33| getSegment(): [PathSegment] hello
515+
# 33| getIdentifier(): [NameRef] hello
516+
# 33| getTokenTree(): [TokenTree] TokenTree
517+
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
518+
# 31| getStatement(0): [ExprStmt] ExprStmt
519+
# 31| getExpr(): [MacroExpr] MacroExpr
520+
# 31| getMacroCall(): [MacroCall] println!...
521+
# 31| getPath(): [Path] println
522+
# 31| getSegment(): [PathSegment] println
523+
# 31| getIdentifier(): [NameRef] println
524+
# 31| getTokenTree(): [TokenTree] TokenTree
525+
# 31| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
526+
# 31| getTailExpr(): [BlockExpr] { ... }
527+
# 31| getStmtList(): [StmtList] StmtList
528+
# 31| getStatement(0): [ExprStmt] ExprStmt
529+
# 31| getExpr(): [CallExpr] ...::_print(...)
530+
# 31| getArgList(): [ArgList] ArgList
531+
# 31| getArg(0): [MacroExpr] MacroExpr
532+
# 31| getMacroCall(): [MacroCall] ...::format_args_nl!...
533+
# 31| getPath(): [Path] ...::format_args_nl
534+
# 31| getQualifier(): [Path] $crate
535+
# 31| getSegment(): [PathSegment] $crate
536+
# 31| getIdentifier(): [NameRef] $crate
537+
# 31| getSegment(): [PathSegment] format_args_nl
538+
# 31| getIdentifier(): [NameRef] format_args_nl
539+
# 31| getTokenTree(): [TokenTree] TokenTree
540+
# 31| getMacroCallExpansion(): [FormatArgsExpr] FormatArgsExpr
541+
# 31| getTemplate(): [StringLiteralExpr] "hello!\n"
542+
# 31| getFunction(): [PathExpr] ...::_print
543+
# 31| getPath(): [Path] ...::_print
544+
# 31| getQualifier(): [Path] ...::io
545+
# 31| getQualifier(): [Path] $crate
546+
# 31| getSegment(): [PathSegment] $crate
547+
# 31| getIdentifier(): [NameRef] $crate
548+
# 31| getSegment(): [PathSegment] io
549+
# 31| getIdentifier(): [NameRef] io
550+
# 31| getSegment(): [PathSegment] _print
551+
# 31| getIdentifier(): [NameRef] _print
552+
# 32| getName(): [Name] bzz_2
553+
# 32| getVisibility(): [Visibility] Visibility
409554
# 32| getParamList(): [ParamList] ParamList
410555
# 31| getAttr(0): [Attr] Attr
411556
# 31| getMeta(): [Meta] Meta
@@ -422,41 +567,6 @@ macro_expansion.rs:
422567
# 33| getSegment(): [PathSegment] hello
423568
# 33| getIdentifier(): [NameRef] hello
424569
# 33| getTokenTree(): [TokenTree] TokenTree
425-
# 33| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
426-
# 33| getStatement(0): [ExprStmt] ExprStmt
427-
# 33| getExpr(): [MacroExpr] MacroExpr
428-
# 33| getMacroCall(): [MacroCall] println!...
429-
# 33| getPath(): [Path] println
430-
# 33| getSegment(): [PathSegment] println
431-
# 33| getIdentifier(): [NameRef] println
432-
# 33| getTokenTree(): [TokenTree] TokenTree
433-
# 33| getMacroCallExpansion(): [MacroBlockExpr] MacroBlockExpr
434-
# 33| getTailExpr(): [BlockExpr] { ... }
435-
# 33| getStmtList(): [StmtList] StmtList
436-
# 33| getStatement(0): [ExprStmt] ExprStmt
437-
# 33| getExpr(): [CallExpr] ...::_print(...)
438-
# 33| getArgList(): [ArgList] ArgList
439-
# 33| getArg(0): [MacroExpr] MacroExpr
440-
# 33| getMacroCall(): [MacroCall] ...::format_args_nl!...
441-
# 33| getPath(): [Path] ...::format_args_nl
442-
# 33| getQualifier(): [Path] $crate
443-
# 33| getSegment(): [PathSegment] $crate
444-
# 33| getIdentifier(): [NameRef] $crate
445-
# 33| getSegment(): [PathSegment] format_args_nl
446-
# 33| getIdentifier(): [NameRef] format_args_nl
447-
# 33| getTokenTree(): [TokenTree] TokenTree
448-
# 33| getMacroCallExpansion(): [FormatArgsExpr] FormatArgsExpr
449-
# 33| getTemplate(): [StringLiteralExpr] "hello!\n"
450-
# 33| getFunction(): [PathExpr] ...::_print
451-
# 33| getPath(): [Path] ...::_print
452-
# 33| getQualifier(): [Path] ...::io
453-
# 33| getQualifier(): [Path] $crate
454-
# 33| getSegment(): [PathSegment] $crate
455-
# 33| getIdentifier(): [NameRef] $crate
456-
# 33| getSegment(): [PathSegment] io
457-
# 33| getIdentifier(): [NameRef] io
458-
# 33| getSegment(): [PathSegment] _print
459-
# 33| getIdentifier(): [NameRef] _print
460570
# 32| getName(): [Name] bzz
461571
# 32| getVisibility(): [Visibility] Visibility
462572
# 30| getSelfTy(): [PathTypeRepr] S

0 commit comments

Comments
 (0)