Skip to content

Rust: turn off macro expansion in code to be expanded by attribute macros #19572

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions rust/ast-generator/templates/extractor.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use super::base::Translator;
use super::mappings::TextValue;
use crate::emit_detached;
use crate::{pre_emit,post_emit};
use crate::generated;
use crate::trap::{Label, TrapId};
use ra_ap_syntax::ast::{
Expand All @@ -22,18 +22,20 @@ impl Translator<'_> {
{{#enums}}

pub(crate) fn emit_{{snake_case_name}}(&mut self, node: &ast::{{ast_name}}) -> Option<Label<generated::{{name}}>> {
pre_emit!({{name}}, self, node);
let label = match node {
{{#variants}}
ast::{{ast_name}}::{{variant_ast_name}}(inner) => self.emit_{{snake_case_name}}(inner).map(Into::into),
{{/variants}}
}?;
emit_detached!({{name}}, self, node, label);
post_emit!({{name}}, self, node, label);
Some(label)
}
{{/enums}}
{{#nodes}}

pub(crate) fn emit_{{snake_case_name}}(&mut self, node: &ast::{{ast_name}}) -> Option<Label<generated::{{name}}>> {
pre_emit!({{name}}, self, node);
if self.should_be_excluded(node) { return None; }
{{#has_attrs}}
if self.should_be_excluded_attrs(node) { return None; }
Expand All @@ -59,7 +61,7 @@ impl Translator<'_> {
{{/fields}}
});
self.emit_location(label, node);
emit_detached!({{name}}, self, node, label);
post_emit!({{name}}, self, node, label);
self.emit_tokens(node, label.into(), node.syntax().children_with_tokens());
Some(label)
}
Expand Down
51 changes: 43 additions & 8 deletions rust/extractor/src/translate/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use ra_ap_hir::{
};
use ra_ap_hir_def::ModuleId;
use ra_ap_hir_def::type_ref::Mutability;
use ra_ap_hir_expand::{ExpandResult, ExpandTo};
use ra_ap_hir_expand::{ExpandResult, ExpandTo, InFile};
use ra_ap_ide_db::RootDatabase;
use ra_ap_ide_db::line_index::{LineCol, LineIndex};
use ra_ap_parser::SyntaxKind;
Expand All @@ -23,7 +23,15 @@ use ra_ap_syntax::{
};

#[macro_export]
macro_rules! emit_detached {
macro_rules! pre_emit {
(Item, $self:ident, $node:ident) => {
$self.setup_item_expansion($node);
};
($($_:tt)*) => {};
}

#[macro_export]
macro_rules! post_emit {
(MacroCall, $self:ident, $node:ident, $label:ident) => {
$self.extract_macro_call_expanded($node, $label);
};
Expand Down Expand Up @@ -106,8 +114,9 @@ pub struct Translator<'a> {
line_index: LineIndex,
file_id: Option<EditionedFileId>,
pub semantics: Option<&'a Semantics<'a, RootDatabase>>,
resolve_paths: ResolvePaths,
resolve_paths: bool,
source_kind: SourceKind,
macro_context_depth: usize,
}

const UNKNOWN_LOCATION: (LineCol, LineCol) =
Expand All @@ -130,8 +139,9 @@ impl<'a> Translator<'a> {
line_index,
file_id: semantic_info.map(|i| i.file_id),
semantics: semantic_info.map(|i| i.semantics),
resolve_paths,
resolve_paths: resolve_paths == ResolvePaths::Yes,
source_kind,
macro_context_depth: 0,
}
}
fn location(&self, range: TextRange) -> Option<(LineCol, LineCol)> {
Expand Down Expand Up @@ -337,6 +347,11 @@ impl<'a> Translator<'a> {
mcall: &ast::MacroCall,
label: Label<generated::MacroCall>,
) {
if self.macro_context_depth > 0 {
// we are in an attribute macro, don't emit anything: we would be failing to expand any
// way as from version 0.0.274 rust-analyser only expands in the context of an expansion
return;
}
if let Some(expanded) = self
.semantics
.as_ref()
Expand Down Expand Up @@ -537,7 +552,7 @@ impl<'a> Translator<'a> {
item: &T,
label: Label<generated::Addressable>,
) {
if self.resolve_paths == ResolvePaths::No {
if !self.resolve_paths {
return;
}
(|| {
Expand All @@ -560,7 +575,7 @@ impl<'a> Translator<'a> {
item: &ast::Variant,
label: Label<generated::Variant>,
) {
if self.resolve_paths == ResolvePaths::No {
if !self.resolve_paths {
return;
}
(|| {
Expand All @@ -583,7 +598,7 @@ impl<'a> Translator<'a> {
item: &impl PathAst,
label: Label<generated::Resolvable>,
) {
if self.resolve_paths == ResolvePaths::No {
if !self.resolve_paths {
return;
}
(|| {
Expand All @@ -606,7 +621,7 @@ impl<'a> Translator<'a> {
item: &ast::MethodCallExpr,
label: Label<generated::MethodCallExpr>,
) {
if self.resolve_paths == ResolvePaths::No {
if !self.resolve_paths {
return;
}
(|| {
Expand Down Expand Up @@ -708,13 +723,33 @@ impl<'a> Translator<'a> {
}
}

pub(crate) fn setup_item_expansion(&mut self, node: &ast::Item) {
if self.semantics.is_some_and(|s| {
let file = s.hir_file_for(node.syntax());
let node = InFile::new(file, node);
s.is_attr_macro_call(node)
}) {
self.macro_context_depth += 1;
}
}

pub(crate) fn emit_item_expansion(&mut self, node: &ast::Item, label: Label<generated::Item>) {
// TODO: remove this after fixing exponential expansion on libraries like funty-2.0.0
if self.source_kind == SourceKind::Library {
return;
}
(|| {
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) {
return None;
}
self.macro_context_depth -= 1;
if self.macro_context_depth > 0 {
// only expand the outermost attribute macro
return None;
}
let ExpandResult {
value: expanded, ..
} = semantics.expand_attr_macro(node)?;
Expand Down
Loading