Skip to content

Commit b7f66f8

Browse files
committed
Rust: Rust: expand attribute macros on AssocItem and ExternItem
1 parent 8b31376 commit b7f66f8

File tree

3 files changed

+209
-51
lines changed

3 files changed

+209
-51
lines changed

rust/extractor/src/translate/base.rs

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,33 @@ 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
}
34-
44+
impl From<crate::trap::Label<generated::AssocItem>> for crate::trap::Label<generated::Item> {
45+
fn from(value: crate::trap::Label<generated::AssocItem>) -> Self {
46+
// SAFETY: this is safe because in the dbscheme Item is a subclass of Stmt
47+
unsafe { Self::from_untyped(value.as_untyped()) }
48+
}
49+
}
50+
impl From<crate::trap::Label<generated::ExternItem>> for crate::trap::Label<generated::Item> {
51+
fn from(value: crate::trap::Label<generated::ExternItem>) -> Self {
52+
// SAFETY: this is safe because in the dbscheme Item is a subclass of Stmt
53+
unsafe { Self::from_untyped(value.as_untyped()) }
54+
}
55+
}
3556
#[macro_export]
3657
macro_rules! post_emit {
3758
(MacroCall, $self:ident, $node:ident, $label:ident) => {
@@ -62,6 +83,18 @@ macro_rules! post_emit {
6283
(Item, $self:ident, $node:ident, $label:ident) => {
6384
$self.emit_item_expansion($node, $label);
6485
};
86+
(AssocItem, $self:ident, $node:ident, $label:ident) => {
87+
$self.emit_item_expansion(
88+
&$node.clone().into(),
89+
From::<Label<generated::AssocItem>>::from($label),
90+
);
91+
};
92+
(ExternItem, $self:ident, $node:ident, $label:ident) => {
93+
$self.emit_item_expansion(
94+
&$node.clone().into(),
95+
From::<Label<generated::ExternItem>>::from($label),
96+
);
97+
};
6598
// TODO canonical origin of other items
6699
(PathExpr, $self:ident, $node:ident, $label:ident) => {
67100
$self.extract_path_canonical_destination($node, $label.into());
@@ -694,10 +727,21 @@ impl<'a> Translator<'a> {
694727
}
695728
}
696729

730+
fn is_attribute_macro_target(&self, node: &ast::Item) -> bool {
731+
// rust-analyzer considers as an `attr_macro_call` also a plain macro call, but we want to
732+
// process that differently (in `extract_macro_call_expanded`)
733+
!matches!(node, ast::Item::MacroCall(_))
734+
&& self.semantics.is_some_and(|semantics| {
735+
let file = semantics.hir_file_for(node.syntax());
736+
let node = InFile::new(file, node);
737+
semantics.is_attr_macro_call(node)
738+
})
739+
}
740+
697741
pub(crate) fn prepare_item_expansion(
698742
&mut self,
699743
node: &ast::Item,
700-
) -> Option<Label<generated::Item>> {
744+
) -> Option<Label<generated::MacroCall>> {
701745
if self.source_kind == SourceKind::Library {
702746
// if the item expands via an attribute macro, we want to only emit the expansion
703747
if let Some(expanded) = self.emit_attribute_macro_expansion(node) {
@@ -714,13 +758,10 @@ impl<'a> Translator<'a> {
714758
expanded.into(),
715759
&mut self.trap.writer,
716760
);
717-
return Some(label.into());
761+
return Some(label);
718762
}
719763
}
720-
let semantics = self.semantics.as_ref()?;
721-
let file = semantics.hir_file_for(node.syntax());
722-
let node = InFile::new(file, node);
723-
if semantics.is_attr_macro_call(node) {
764+
if self.is_attribute_macro_target(node) {
724765
self.macro_context_depth += 1;
725766
}
726767
None
@@ -730,10 +771,7 @@ impl<'a> Translator<'a> {
730771
&mut self,
731772
node: &ast::Item,
732773
) -> Option<Label<generated::MacroItems>> {
733-
let semantics = self.semantics?;
734-
let file = semantics.hir_file_for(node.syntax());
735-
let infile_node = InFile::new(file, node);
736-
if !semantics.is_attr_macro_call(infile_node) {
774+
if !self.is_attribute_macro_target(node) {
737775
return None;
738776
}
739777
self.macro_context_depth -= 1;
@@ -743,7 +781,7 @@ impl<'a> Translator<'a> {
743781
}
744782
let ExpandResult {
745783
value: expanded, ..
746-
} = semantics.expand_attr_macro(node)?;
784+
} = self.semantics.and_then(|s| s.expand_attr_macro(node))?;
747785
self.emit_macro_expansion_parse_errors(node, &expanded);
748786
let macro_items = ast::MacroItems::cast(expanded).or_else(|| {
749787
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)