Unnamed repository; edit this file 'description' to name the repository.
turn queries into methods on `MacroCallId`
Ada Alakbarova 9 days ago
parent 1e3698f · commit 492420d
-rw-r--r--crates/hir-def/src/attrs/docs.rs2
-rw-r--r--crates/hir-def/src/expr_store/expander.rs4
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mod.rs4
-rw-r--r--crates/hir-def/src/nameres/assoc.rs2
-rw-r--r--crates/hir-def/src/nameres/tests/incremental.rs58
-rw-r--r--crates/hir-expand/src/builtin/derive_macro.rs2
-rw-r--r--crates/hir-expand/src/db.rs406
-rw-r--r--crates/hir-expand/src/eager.rs8
-rw-r--r--crates/hir-expand/src/files.rs2
-rw-r--r--crates/hir-expand/src/lib.rs376
-rw-r--r--crates/hir-expand/src/span_map.rs4
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/hir/src/semantics.rs7
13 files changed, 429 insertions, 448 deletions
diff --git a/crates/hir-def/src/attrs/docs.rs b/crates/hir-def/src/attrs/docs.rs
index 0d01d54786..cb91f08af3 100644
--- a/crates/hir-def/src/attrs/docs.rs
+++ b/crates/hir-def/src/attrs/docs.rs
@@ -390,7 +390,7 @@ fn expand_doc_macro_call<'db>(
.value?;
expander.recursion_depth += 1;
- let parse = expander.db.parse_macro_expansion(call_id).value.0.clone();
+ let parse = call_id.parse_macro_expansion(expander.db).value.0.clone();
let expr = parse.cast::<ast::Expr>().map(|parse| parse.tree())?;
expander.recursion_depth -= 1;
diff --git a/crates/hir-def/src/expr_store/expander.rs b/crates/hir-def/src/expr_store/expander.rs
index c79a1db847..35cf1c9681 100644
--- a/crates/hir-def/src/expr_store/expander.rs
+++ b/crates/hir-def/src/expr_store/expander.rs
@@ -184,12 +184,12 @@ impl<'db> Expander<'db> {
self.recursion_depth = u32::MAX;
cov_mark::hit!(your_stack_belongs_to_me);
return ExpandResult::only_err(ExpandError::new(
- db.macro_arg_considering_derives(call_id, &call_id.lookup(db).kind).2,
+ call_id.macro_arg_considering_derives(db, &call_id.lookup(db).kind).2,
ExpandErrorKind::RecursionOverflow,
));
}
- let res = db.parse_macro_expansion(call_id);
+ let res = call_id.parse_macro_expansion(db);
let err = err.or_else(|| res.err.clone());
ExpandResult {
diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs
index 1d6812ad56..88f41274e4 100644
--- a/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -62,7 +62,7 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect)
.modules()
.flat_map(|module| module.1.scope.all_macro_calls())
.filter_map(|macro_call| {
- let errors = db.parse_macro_expansion_error(macro_call)?;
+ let errors = macro_call.parse_macro_expansion_error(&db)?;
let errors = errors.err.as_ref()?.render_to_string(&db);
let macro_loc = macro_call.loc(&db);
let ast_id = match macro_loc.kind {
@@ -125,7 +125,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
let ptr = InFile::new(source.file_id, AstPtr::new(&macro_call_node));
let macro_call_id = resolve_macro_call_id(&db, def_map, ast_id, ptr)
.unwrap_or_else(|| panic!("unable to find semantic macro call {macro_call_node}"));
- let expansion_result = db.parse_macro_expansion(macro_call_id);
+ let expansion_result = macro_call_id.parse_macro_expansion(&db);
expansions.push((macro_call_node.clone(), expansion_result));
}
diff --git a/crates/hir-def/src/nameres/assoc.rs b/crates/hir-def/src/nameres/assoc.rs
index 7b5b39cb08..cc88d21fbf 100644
--- a/crates/hir-def/src/nameres/assoc.rs
+++ b/crates/hir-def/src/nameres/assoc.rs
@@ -356,7 +356,7 @@ impl<'db> AssocItemCollector<'db> {
return;
}
- let (syntax, span_map) = &self.db.parse_macro_expansion(macro_call_id).value;
+ let (syntax, span_map) = &macro_call_id.parse_macro_expansion(self.db).value;
let old_file_id = mem::replace(&mut self.file_id, macro_call_id.into());
let old_ast_id_map = mem::replace(&mut self.ast_id_map, self.db.ast_id_map(self.file_id));
let old_span_map = mem::replace(&mut self.span_map, SpanMap::ExpansionSpanMap(span_map));
diff --git a/crates/hir-def/src/nameres/tests/incremental.rs b/crates/hir-def/src/nameres/tests/incremental.rs
index bb19456f46..e7aa994c07 100644
--- a/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/crates/hir-def/src/nameres/tests/incremental.rs
@@ -239,8 +239,8 @@ pub struct S {}
"macro_def_shim",
"file_item_tree_query",
"ast_id_map",
- "parse_macro_expansion",
- "macro_arg",
+ "MacroCallId::parse_macro_expansion_",
+ "MacroCallId::macro_arg_",
]
"#]],
expect![[r#"
@@ -249,8 +249,8 @@ pub struct S {}
"ast_id_map",
"file_item_tree_query",
"real_span_map",
- "macro_arg",
- "parse_macro_expansion",
+ "MacroCallId::macro_arg_",
+ "MacroCallId::parse_macro_expansion_",
"ast_id_map",
"file_item_tree_query",
]
@@ -302,9 +302,9 @@ fn f() { foo }
"macro_def_shim",
"file_item_tree_query",
"ast_id_map",
- "parse_macro_expansion",
- "expand_proc_macro",
- "macro_arg",
+ "MacroCallId::parse_macro_expansion_",
+ "MacroCallId::expand_proc_macro_",
+ "MacroCallId::macro_arg_",
"proc_macro_span",
]
"#]],
@@ -314,9 +314,9 @@ fn f() { foo }
"ast_id_map",
"file_item_tree_query",
"real_span_map",
- "macro_arg",
- "expand_proc_macro",
- "parse_macro_expansion",
+ "MacroCallId::macro_arg_",
+ "MacroCallId::expand_proc_macro_",
+ "MacroCallId::parse_macro_expansion_",
"ast_id_map",
"file_item_tree_query",
]
@@ -427,20 +427,20 @@ pub struct S {}
"macro_def_shim",
"file_item_tree_query",
"ast_id_map",
- "parse_macro_expansion",
- "macro_arg",
+ "MacroCallId::parse_macro_expansion_",
+ "MacroCallId::macro_arg_",
"DeclarativeMacroExpander::expander_",
"macro_def_shim",
"file_item_tree_query",
"ast_id_map",
- "parse_macro_expansion",
- "macro_arg",
+ "MacroCallId::parse_macro_expansion_",
+ "MacroCallId::macro_arg_",
"macro_def_shim",
"file_item_tree_query",
"ast_id_map",
- "parse_macro_expansion",
- "expand_proc_macro",
- "macro_arg",
+ "MacroCallId::parse_macro_expansion_",
+ "MacroCallId::expand_proc_macro_",
+ "MacroCallId::macro_arg_",
"proc_macro_span",
]
"#]],
@@ -450,10 +450,10 @@ pub struct S {}
"ast_id_map",
"file_item_tree_query",
"real_span_map",
- "macro_arg",
+ "MacroCallId::macro_arg_",
"DeclarativeMacroExpander::expander_",
- "macro_arg",
- "macro_arg",
+ "MacroCallId::macro_arg_",
+ "MacroCallId::macro_arg_",
]
"#]],
);
@@ -538,16 +538,16 @@ m!(Z);
"macro_def_shim",
"file_item_tree_query",
"ast_id_map",
- "parse_macro_expansion",
- "macro_arg",
+ "MacroCallId::parse_macro_expansion_",
+ "MacroCallId::macro_arg_",
"file_item_tree_query",
"ast_id_map",
- "parse_macro_expansion",
- "macro_arg",
+ "MacroCallId::parse_macro_expansion_",
+ "MacroCallId::macro_arg_",
"file_item_tree_query",
"ast_id_map",
- "parse_macro_expansion",
- "macro_arg",
+ "MacroCallId::parse_macro_expansion_",
+ "MacroCallId::macro_arg_",
]
"#]],
);
@@ -575,9 +575,9 @@ m!(Z);
"ast_id_map",
"file_item_tree_query",
"real_span_map",
- "macro_arg",
- "macro_arg",
- "macro_arg",
+ "MacroCallId::macro_arg_",
+ "MacroCallId::macro_arg_",
+ "MacroCallId::macro_arg_",
]
"#]],
);
diff --git a/crates/hir-expand/src/builtin/derive_macro.rs b/crates/hir-expand/src/builtin/derive_macro.rs
index c4da558fda..86ee3f153b 100644
--- a/crates/hir-expand/src/builtin/derive_macro.rs
+++ b/crates/hir-expand/src/builtin/derive_macro.rs
@@ -391,7 +391,7 @@ fn to_adt_syntax(
tt: &tt::TopSubtree,
call_site: Span,
) -> Result<(ast::Adt, span::SpanMap), ExpandError> {
- let (parsed, tm) = crate::db::token_tree_to_syntax_node(db, tt, crate::ExpandTo::Items);
+ let (parsed, tm) = crate::token_tree_to_syntax_node(db, tt, crate::ExpandTo::Items);
let macro_items = ast::MacroItems::cast(parsed.syntax_node())
.ok_or_else(|| ExpandError::other(call_site, "invalid item definition"))?;
let item =
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index ffa64fe01b..c8a8be4311 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -1,17 +1,13 @@
//! Defines database & queries for macro expansion.
use base_db::{Crate, SourceDatabase};
-use mbe::MatchedArmIndex;
use span::{AstIdMap, Span};
-use std::borrow::Cow;
-use syntax::{AstNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T, ast};
+use syntax::{AstNode, Parse, SyntaxNode, SyntaxToken, ast};
use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree};
-use triomphe::Arc;
use crate::{
- AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo,
- EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, FileRange, HirFileId,
- MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
+ AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander,
+ EditionedFileId, FileRange, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
builtin::pseudo_derive_attr_expansion,
cfg_process::attr_macro_input_to_token_tree,
declarative::DeclarativeMacroExpander,
@@ -22,17 +18,6 @@ use crate::{
tt,
};
-/// This is just to ensure the types of [`macro_arg_considering_derives`] and [`macro_arg`] are the same.
-type MacroArgResult = (tt::TopSubtree, SyntaxFixupUndoInfo, Span);
-
-/// Total limit on the number of tokens produced by any macro invocation.
-///
-/// If an invocation produces more tokens than this limit, it will not be stored in the database and
-/// an error will be emitted.
-///
-/// Actual max for `analysis-stats .` at some point: 30672.
-const TOKEN_LIMIT: usize = 2_097_152;
-
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum TokenExpander<'db> {
/// Old-style `macro_rules` or the new macros 2.0
@@ -62,13 +47,6 @@ pub trait ExpandDatabase: SourceDatabase {
#[salsa::transparent]
fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode;
- /// Implementation for the macro case.
- #[salsa::transparent]
- fn parse_macro_expansion(
- &self,
- macro_file: MacroCallId,
- ) -> &ExpandResult<(Parse<SyntaxNode>, ExpansionSpanMap)>;
-
#[salsa::transparent]
#[salsa::invoke(SpanMap::new)]
fn span_map(&self, file_id: HirFileId) -> SpanMap<'_>;
@@ -80,21 +58,6 @@ pub trait ExpandDatabase: SourceDatabase {
#[salsa::transparent]
fn real_span_map(&self, file_id: EditionedFileId) -> &RealSpanMap;
- /// Lowers syntactic macro call to a token tree representation. That's a firewall
- /// query, only typing in the macro call itself changes the returned
- /// subtree.
- #[deprecated = "calling this is incorrect, call `macro_arg_considering_derives` instead"]
- #[salsa::invoke(macro_arg)]
- #[salsa::transparent]
- fn macro_arg(&self, id: MacroCallId) -> &MacroArgResult;
-
- #[salsa::transparent]
- fn macro_arg_considering_derives<'db>(
- &'db self,
- id: MacroCallId,
- kind: &MacroCallKind,
- ) -> &'db MacroArgResult;
-
/// Fetches the expander for this macro.
#[salsa::transparent]
#[salsa::invoke(TokenExpander::macro_expander)]
@@ -108,13 +71,6 @@ pub trait ExpandDatabase: SourceDatabase {
def_crate: Crate,
id: AstId<ast::Macro>,
) -> &DeclarativeMacroExpander;
-
- #[salsa::invoke(parse_macro_expansion_error)]
- #[salsa::transparent]
- fn parse_macro_expansion_error(
- &self,
- macro_call: MacroCallId,
- ) -> Option<ExpandResult<Arc<[SyntaxError]>>>;
}
fn resolve_span(db: &dyn ExpandDatabase, Span { range, anchor, ctx: _ }: Span) -> FileRange {
@@ -135,7 +91,7 @@ pub fn expand_speculative(
token_to_map: SyntaxToken,
) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
let loc = actual_macro_call.loc(db);
- let (_, _, span) = *db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
+ let (_, _, span) = *actual_macro_call.macro_arg_considering_derives(db, &loc.kind);
let span_map = RealSpanMap::absolute(span.anchor.file_id);
let span_map = SpanMap::RealSpanMap(&span_map);
@@ -243,7 +199,7 @@ pub fn expand_speculative(
// Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
let mut speculative_expansion = match loc.def.kind {
MacroDefKind::ProcMacro(ast, expander, _) => {
- let span = proc_macro_span(db, ast);
+ let span = crate::proc_macro_span(db, ast);
tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
tt.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span));
expander.expand(
@@ -273,13 +229,14 @@ pub fn expand_speculative(
it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
}
MacroDefKind::BuiltInAttr(_, it) => it.expand(db, actual_macro_call, &tt, span),
- MacroDefKind::UnimplementedBuiltIn(_) => expand_unimplemented_builtin_macro(span),
+ MacroDefKind::UnimplementedBuiltIn(_) => crate::expand_unimplemented_builtin_macro(span),
};
let expand_to = loc.expand_to();
fixup::reverse_fixups(&mut speculative_expansion.value, &undo_info);
- let (node, rev_tmap) = token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to);
+ let (node, rev_tmap) =
+ crate::token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to);
let syntax_node = node.syntax_node();
let token = rev_tmap
@@ -298,13 +255,6 @@ pub fn expand_speculative(
Some((node.syntax_node(), token))
}
-fn expand_unimplemented_builtin_macro(span: Span) -> ExpandResult<tt::TopSubtree> {
- ExpandResult::new(
- tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
- ExpandError::other(span, "this built-in macro is not implemented"),
- )
-}
-
#[salsa::tracked(lru = 1024, returns(ref))]
fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> AstIdMap {
AstIdMap::from_source(&db.parse_or_expand(file_id))
@@ -316,38 +266,11 @@ fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> SyntaxNode {
match file_id {
HirFileId::FileId(file_id) => file_id.parse(db).syntax_node(),
HirFileId::MacroFile(macro_file) => {
- db.parse_macro_expansion(macro_file).value.0.syntax_node()
+ macro_file.parse_macro_expansion(db).value.0.syntax_node()
}
}
}
-// FIXME: We should verify that the parsed node is one of the many macro node variants we expect
-// instead of having it be untyped
-#[salsa_macros::tracked(returns(ref), lru = 512)]
-fn parse_macro_expansion(
- db: &dyn ExpandDatabase,
- macro_file: MacroCallId,
-) -> ExpandResult<(Parse<SyntaxNode>, ExpansionSpanMap)> {
- let _p = tracing::info_span!("parse_macro_expansion").entered();
- let loc = macro_file.loc(db);
- let expand_to = loc.expand_to();
- let mbe::ValueResult { value: (tt, matched_arm), err } = macro_expand(db, macro_file, loc);
-
- let (parse, mut rev_token_map) = token_tree_to_syntax_node(db, &tt, expand_to);
- rev_token_map.matched_arm = matched_arm;
-
- ExpandResult { value: (parse, rev_token_map), err }
-}
-
-fn parse_macro_expansion_error(
- db: &dyn ExpandDatabase,
- macro_call_id: MacroCallId,
-) -> Option<ExpandResult<Arc<[SyntaxError]>>> {
- let e: ExpandResult<Arc<[SyntaxError]>> =
- db.parse_macro_expansion(macro_call_id).as_ref().map(|it| Arc::from(it.0.errors()));
- if e.value.is_empty() && e.err.is_none() { None } else { Some(e) }
-}
-
pub(crate) fn parse_with_map(
db: &dyn ExpandDatabase,
file_id: HirFileId,
@@ -357,146 +280,12 @@ pub(crate) fn parse_with_map(
(file_id.parse(db).to_syntax(), SpanMap::RealSpanMap(db.real_span_map(file_id)))
}
HirFileId::MacroFile(macro_file) => {
- let (parse, map) = &db.parse_macro_expansion(macro_file).value;
+ let (parse, map) = &macro_file.parse_macro_expansion(db).value;
(parse.clone(), SpanMap::ExpansionSpanMap(map))
}
}
}
-/// This resolves the [MacroCallId] to check if it is a derive macro if so get the [macro_arg] for the derive.
-/// Other wise return the [macro_arg] for the macro_call_id.
-///
-/// This is not connected to the database so it does not cache the result. However, the inner [macro_arg] query is
-#[allow(deprecated)] // we are macro_arg_considering_derives
-fn macro_arg_considering_derives<'db>(
- db: &'db dyn ExpandDatabase,
- id: MacroCallId,
- kind: &MacroCallKind,
-) -> &'db MacroArgResult {
- match kind {
- // Get the macro arg for the derive macro
- MacroCallKind::Derive { derive_macro_id, .. } => db.macro_arg(*derive_macro_id),
- // Normal macro arg
- _ => db.macro_arg(id),
- }
-}
-
-#[salsa_macros::tracked(returns(ref))]
-fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
- let loc = id.loc(db);
-
- if let MacroCallLoc {
- def: MacroDefId { kind: MacroDefKind::BuiltInEager(..), .. },
- kind: MacroCallKind::FnLike { eager: Some(eager), .. },
- ..
- } = &loc
- {
- return (eager.arg.clone(), SyntaxFixupUndoInfo::NONE, eager.span);
- }
-
- let (parse, map) = parse_with_map(db, loc.kind.file_id());
- let root = parse.syntax_node();
-
- let (is_derive, censor_item_tree_attr_ids, item_node, span) = match &loc.kind {
- MacroCallKind::FnLike { ast_id, .. } => {
- let node = &ast_id.to_ptr(db).to_node(&root);
- let path_range = node
- .path()
- .map_or_else(|| node.syntax().text_range(), |path| path.syntax().text_range());
- let span = map.span_for_range(path_range);
-
- let dummy_tt = |kind| {
- (
- tt::TopSubtree::from_token_trees(
- tt::Delimiter { open: span, close: span, kind },
- tt::TokenTreesView::empty(),
- ),
- SyntaxFixupUndoInfo::default(),
- span,
- )
- };
-
- let Some(tt) = node.token_tree() else {
- return dummy_tt(tt::DelimiterKind::Invisible);
- };
- let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']);
- let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]);
-
- let mismatched_delimiters = !matches!(
- (first, last),
- (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}'])
- );
- if mismatched_delimiters {
- // Don't expand malformed (unbalanced) macro invocations. This is
- // less than ideal, but trying to expand unbalanced macro calls
- // sometimes produces pathological, deeply nested code which breaks
- // all kinds of things.
- //
- // So instead, we'll return an empty subtree here
- cov_mark::hit!(issue9358_bad_macro_stack_overflow);
-
- let kind = match first {
- _ if loc.def.is_proc_macro() => tt::DelimiterKind::Invisible,
- T!['('] => tt::DelimiterKind::Parenthesis,
- T!['['] => tt::DelimiterKind::Bracket,
- T!['{'] => tt::DelimiterKind::Brace,
- _ => tt::DelimiterKind::Invisible,
- };
- return dummy_tt(kind);
- }
-
- let mut tt = syntax_bridge::syntax_node_to_token_tree(
- tt.syntax(),
- map,
- span,
- if loc.def.is_proc_macro() {
- DocCommentDesugarMode::ProcMacro
- } else {
- DocCommentDesugarMode::Mbe
- },
- );
- if loc.def.is_proc_macro() {
- // proc macros expect their inputs without parentheses, MBEs expect it with them included
- tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
- }
- return (tt, SyntaxFixupUndoInfo::NONE, span);
- }
- // MacroCallKind::Derive should not be here. As we are getting the argument for the derive macro
- MacroCallKind::Derive { .. } => {
- unreachable!("`ExpandDatabase::macro_arg` called with `MacroCallKind::Derive`")
- }
- MacroCallKind::Attr { ast_id, censored_attr_ids: attr_ids, .. } => {
- let node = ast_id.to_ptr(db).to_node(&root);
- let (_, attr) = attr_ids.invoc_attr().find_attr_range_with_source(db, loc.krate, &node);
- let range = attr
- .path()
- .map(|path| path.syntax().text_range())
- .unwrap_or_else(|| attr.syntax().text_range());
- let span = map.span_for_range(range);
-
- let is_derive = matches!(loc.def.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive());
- (is_derive, &**attr_ids, node, span)
- }
- };
-
- let (mut tt, undo_info) = attr_macro_input_to_token_tree(
- db,
- item_node.syntax(),
- map,
- span,
- is_derive,
- censor_item_tree_attr_ids,
- loc.krate,
- );
-
- if loc.def.is_proc_macro() {
- // proc macros expect their inputs without parentheses, MBEs expect it with them included
- tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
- }
-
- (tt, undo_info, span)
-}
-
impl<'db> TokenExpander<'db> {
fn macro_expander(db: &'db dyn ExpandDatabase, id: MacroDefId) -> TokenExpander<'db> {
match id.kind {
@@ -512,178 +301,3 @@ impl<'db> TokenExpander<'db> {
}
}
}
-
-fn macro_expand<'db>(
- db: &'db dyn ExpandDatabase,
- macro_call_id: MacroCallId,
- loc: &MacroCallLoc,
-) -> ExpandResult<(Cow<'db, tt::TopSubtree>, MatchedArmIndex)> {
- let _p = tracing::info_span!("macro_expand").entered();
-
- let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind {
- MacroDefKind::ProcMacro(..) => {
- return expand_proc_macro(db, macro_call_id)
- .as_ref()
- .map(|it| (Cow::Borrowed(it), None));
- }
- _ => {
- let (macro_arg, undo_info, span) =
- db.macro_arg_considering_derives(macro_call_id, &loc.kind);
- let span = *span;
-
- let arg = macro_arg;
- let res = match loc.def.kind {
- MacroDefKind::Declarative(id, _) => {
- db.decl_macro_expander(loc.def.krate, id).expand(db, arg, macro_call_id, span)
- }
- MacroDefKind::BuiltIn(_, it) => {
- it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
- }
- MacroDefKind::BuiltInDerive(_, it) => {
- it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
- }
- MacroDefKind::UnimplementedBuiltIn(_) => {
- expand_unimplemented_builtin_macro(span).zip_val(None)
- }
- MacroDefKind::BuiltInEager(_, it) => {
- // This might look a bit odd, but we do not expand the inputs to eager macros here.
- // Eager macros inputs are expanded, well, eagerly when we collect the macro calls.
- // That kind of expansion uses the ast id map of an eager macros input though which goes through
- // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query
- // will end up going through here again, whereas we want to just want to inspect the raw input.
- // As such we just return the input subtree here.
- let eager = match &loc.kind {
- MacroCallKind::FnLike { eager: None, .. } => {
- return ExpandResult::ok(Cow::Borrowed(macro_arg)).zip_val(None);
- }
- MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
- _ => None,
- };
-
- let mut res = it.expand(db, macro_call_id, arg, span).map_err(Into::into);
-
- if let Some(EagerCallInfo { error, .. }) = eager {
- // FIXME: We should report both errors!
- res.err = error.clone().or(res.err);
- }
- res.zip_val(None)
- }
- MacroDefKind::BuiltInAttr(_, it) => {
- let mut res = it.expand(db, macro_call_id, arg, span);
- fixup::reverse_fixups(&mut res.value, undo_info);
- res.zip_val(None)
- }
- MacroDefKind::ProcMacro(_, _, _) => unreachable!(),
- };
- (res, span)
- }
- };
-
- // Skip checking token tree limit for include! macro call
- if !loc.def.is_include() {
- // Set a hard limit for the expanded tt
- if let Err(value) = check_tt_count(&tt) {
- return value
- .map(|()| Cow::Owned(tt::TopSubtree::empty(tt::DelimSpan::from_single(span))))
- .zip_val(matched_arm);
- }
- }
-
- ExpandResult { value: (Cow::Owned(tt), matched_arm), err }
-}
-
-/// Retrieves the span to be used for a proc-macro expansions spans.
-/// This is a firewall query as it requires parsing the file, which we don't want proc-macros to
-/// directly depend on as that would cause to frequent invalidations, mainly because of the
-/// parse queries being LRU cached. If they weren't the invalidations would only happen if the
-/// user wrote in the file that defines the proc-macro.
-fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
- #[salsa::tracked]
- fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>, _: ()) -> Span {
- let root = db.parse_or_expand(ast.file_id);
- let ast_id_map = db.ast_id_map(ast.file_id);
- let span_map = db.span_map(ast.file_id);
-
- let node = ast_id_map.get(ast.value).to_node(&root);
- let range = ast::HasName::name(&node)
- .map_or_else(|| node.syntax().text_range(), |name| name.syntax().text_range());
- span_map.span_for_range(range)
- }
- proc_macro_span(db, ast, ())
-}
-
-/// Special case of [`macro_expand`] for procedural macros. We can't LRU
-/// proc macros, since they are not deterministic in general, and
-/// non-determinism breaks salsa in a very, very, very bad way.
-/// @edwin0cheng heroically debugged this once! See #4315 for details
-#[salsa_macros::tracked(returns(ref))]
-fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<tt::TopSubtree> {
- let loc = id.loc(db);
- let (macro_arg, undo_info, span) = db.macro_arg_considering_derives(id, &loc.kind);
-
- let (ast, expander) = match loc.def.kind {
- MacroDefKind::ProcMacro(ast, expander, _) => (ast, expander),
- _ => unreachable!(),
- };
-
- let attr_arg = match &loc.kind {
- MacroCallKind::Attr { attr_args: Some(attr_args), .. } => Some(&**attr_args),
- _ => None,
- };
-
- let ExpandResult { value: mut tt, err } = {
- let span = proc_macro_span(db, ast);
- expander.expand(
- db,
- loc.def.krate,
- loc.krate,
- macro_arg,
- attr_arg,
- span_with_def_site_ctxt(db, span, id.into(), loc.def.edition),
- span_with_call_site_ctxt(db, span, id.into(), loc.def.edition),
- span_with_mixed_site_ctxt(db, span, id.into(), loc.def.edition),
- )
- };
-
- // Set a hard limit for the expanded tt
- if let Err(value) = check_tt_count(&tt) {
- return value.map(|()| tt::TopSubtree::empty(tt::DelimSpan::from_single(*span)));
- }
-
- fixup::reverse_fixups(&mut tt, undo_info);
-
- ExpandResult { value: tt, err }
-}
-
-pub(crate) fn token_tree_to_syntax_node(
- db: &dyn ExpandDatabase,
- tt: &tt::TopSubtree,
- expand_to: ExpandTo,
-) -> (Parse<SyntaxNode>, ExpansionSpanMap) {
- let entry_point = match expand_to {
- ExpandTo::Statements => syntax_bridge::TopEntryPoint::MacroStmts,
- ExpandTo::Items => syntax_bridge::TopEntryPoint::MacroItems,
- ExpandTo::Pattern => syntax_bridge::TopEntryPoint::Pattern,
- ExpandTo::Type => syntax_bridge::TopEntryPoint::Type,
- ExpandTo::Expr => syntax_bridge::TopEntryPoint::Expr,
- };
- syntax_bridge::token_tree_to_syntax_node(tt, entry_point, &mut |ctx| ctx.edition(db))
-}
-
-fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> {
- let tt = tt.top_subtree();
- let count = tt.count();
- if count <= TOKEN_LIMIT {
- Ok(())
- } else {
- Err(ExpandResult {
- value: (),
- err: Some(ExpandError::other(
- tt.delimiter.open,
- format!(
- "macro invocation exceeds token limit: produced {count} tokens, limit is {TOKEN_LIMIT}",
- ),
- )),
- })
- }
-}
diff --git a/crates/hir-expand/src/eager.rs b/crates/hir-expand/src/eager.rs
index f8a560834a..30e9624b2b 100644
--- a/crates/hir-expand/src/eager.rs
+++ b/crates/hir-expand/src/eager.rs
@@ -62,9 +62,9 @@ pub fn expand_eager_macro_input(
};
let arg_id = MacroCallId::new(db, loc);
#[allow(deprecated)] // builtin eager macros are never derives
- let (_, _, span) = db.macro_arg(arg_id);
+ let (_, _, span) = arg_id.macro_arg(db);
let ExpandResult { value: (arg_exp, arg_exp_map), err: parse_err } =
- db.parse_macro_expansion(arg_id);
+ arg_id.parse_macro_expansion(db);
let mut arg_map = ExpansionSpanMap::empty();
@@ -136,7 +136,7 @@ fn lazy_expand<'db>(
);
eager_callback(ast_id.map(|ast_id| (AstPtr::new(macro_call), ast_id)), id);
- db.parse_macro_expansion(id)
+ id.parse_macro_expansion(db)
.as_ref()
.map(|parse| (InFile::new(id.into(), parse.0.clone()), &parse.1))
}
@@ -226,7 +226,7 @@ fn eager_macro_recur(
call_id,
);
let ExpandResult { value: (parse, map), err: err2 } =
- db.parse_macro_expansion(call_id);
+ call_id.parse_macro_expansion(db);
map.iter().for_each(|(o, span)| expanded_map.push(o + offset, span));
diff --git a/crates/hir-expand/src/files.rs b/crates/hir-expand/src/files.rs
index a4c206156d..5f03e1b6b3 100644
--- a/crates/hir-expand/src/files.rs
+++ b/crates/hir-expand/src/files.rs
@@ -213,7 +213,7 @@ impl FileIdToSyntax for EditionedFileId {
}
impl FileIdToSyntax for MacroCallId {
fn file_syntax(self, db: &dyn db::ExpandDatabase) -> SyntaxNode {
- db.parse_macro_expansion(self).value.0.syntax_node()
+ self.parse_macro_expansion(db).value.0.syntax_node()
}
}
impl FileIdToSyntax for HirFileId {
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index a8933a424e..73647d0ece 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -33,17 +33,19 @@ use thin_vec::ThinVec;
use triomphe::Arc;
use core::fmt;
-use std::ops;
+use std::{borrow::Cow, ops};
use base_db::Crate;
use either::Either;
+use mbe::MatchedArmIndex;
use span::{
Edition, ErasedFileAstId, FileAstId, NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER, Span, SyntaxContext,
};
use syntax::{
- SyntaxNode, SyntaxToken, TextRange, TextSize,
+ Parse, SyntaxError, SyntaxNode, SyntaxToken, T, TextRange, TextSize,
ast::{self, AstNode},
};
+use syntax_bridge::DocCommentDesugarMode;
use crate::{
attrs::AttrId,
@@ -51,7 +53,10 @@ use crate::{
BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander,
include_input_to_file_id,
},
+ cfg_process::attr_macro_input_to_token_tree,
db::ExpandDatabase,
+ fixup::SyntaxFixupUndoInfo,
+ hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt},
proc_macro::{CustomProcMacroExpander, ProcMacroKind, ProcMacros},
span_map::{ExpansionSpanMap, SpanMap},
};
@@ -66,6 +71,18 @@ pub use mbe::{DeclarativeMacro, MacroCallStyle, MacroCallStyles, ValueResult};
pub use tt;
+/// This is just to ensure the types of [`MacroCallId::macro_arg_considering_derives`]
+/// and [`MacroCallId::macro_arg`] are the same.
+type MacroArgResult = (tt::TopSubtree, SyntaxFixupUndoInfo, Span);
+
+/// Total limit on the number of tokens produced by any macro invocation.
+///
+/// If an invocation produces more tokens than this limit, it will not be stored in the database and
+/// an error will be emitted.
+///
+/// Actual max for `analysis-stats .` at some point: 30672.
+const TOKEN_LIMIT: usize = 2_097_152;
+
#[macro_export]
macro_rules! impl_intern_lookup {
($db:ident, $id:ident, $loc:ident) => {
@@ -467,6 +484,357 @@ impl MacroCallId {
}
}
+#[salsa::tracked]
+impl MacroCallId {
+ /// Implementation of [`crate::db::parse_or_expand`] for the macro case.
+ // FIXME: We should verify that the parsed node is one of the many macro node variants we expect
+ // instead of having it be untyped
+ #[salsa::tracked(returns(ref), lru = 512)]
+ pub fn parse_macro_expansion(
+ self,
+ db: &dyn ExpandDatabase,
+ ) -> ExpandResult<(Parse<SyntaxNode>, ExpansionSpanMap)> {
+ let _p = tracing::info_span!("parse_macro_expansion").entered();
+ let loc = self.loc(db);
+ let expand_to = loc.expand_to();
+ let mbe::ValueResult { value: (tt, matched_arm), err } = self.macro_expand(db, loc);
+
+ let (parse, mut rev_token_map) = token_tree_to_syntax_node(db, &tt, expand_to);
+ rev_token_map.matched_arm = matched_arm;
+
+ ExpandResult { value: (parse, rev_token_map), err }
+ }
+
+ pub fn parse_macro_expansion_error(
+ self,
+ db: &dyn ExpandDatabase,
+ ) -> Option<ExpandResult<Arc<[SyntaxError]>>> {
+ let e: ExpandResult<Arc<[SyntaxError]>> =
+ self.parse_macro_expansion(db).as_ref().map(|it| Arc::from(it.0.errors()));
+ if e.value.is_empty() && e.err.is_none() { None } else { Some(e) }
+ }
+
+ /// This resolves the [MacroCallId] to check if it is a derive macro if so get the [macro_arg] for the derive.
+ /// Other wise return the [macro_arg] for the macro_call_id.
+ ///
+ /// This is not connected to the database so it does not cache the result. However, the inner [macro_arg] query is
+ ///
+ /// [macro_arg]: Self::macro_arg
+ #[allow(deprecated)] // we are macro_arg_considering_derives
+ pub fn macro_arg_considering_derives<'db>(
+ self,
+ db: &'db dyn ExpandDatabase,
+ kind: &MacroCallKind,
+ ) -> &'db MacroArgResult {
+ match kind {
+ // Get the macro arg for the derive macro
+ MacroCallKind::Derive { derive_macro_id, .. } => derive_macro_id.macro_arg(db),
+ // Normal macro arg
+ _ => self.macro_arg(db),
+ }
+ }
+
+ /// Lowers syntactic macro call to a token tree representation. That's a firewall
+ /// query, only typing in the macro call itself changes the returned
+ /// subtree.
+ #[salsa::tracked(returns(ref))]
+ fn macro_arg(self, db: &dyn ExpandDatabase) -> MacroArgResult {
+ let loc = self.loc(db);
+
+ if let MacroCallLoc {
+ def: MacroDefId { kind: MacroDefKind::BuiltInEager(..), .. },
+ kind: MacroCallKind::FnLike { eager: Some(eager), .. },
+ ..
+ } = &loc
+ {
+ return (eager.arg.clone(), SyntaxFixupUndoInfo::NONE, eager.span);
+ }
+
+ let (parse, map) = crate::db::parse_with_map(db, loc.kind.file_id());
+ let root = parse.syntax_node();
+
+ let (is_derive, censor_item_tree_attr_ids, item_node, span) = match &loc.kind {
+ MacroCallKind::FnLike { ast_id, .. } => {
+ let node = &ast_id.to_ptr(db).to_node(&root);
+ let path_range = node
+ .path()
+ .map_or_else(|| node.syntax().text_range(), |path| path.syntax().text_range());
+ let span = map.span_for_range(path_range);
+
+ let dummy_tt = |kind| {
+ (
+ tt::TopSubtree::from_token_trees(
+ tt::Delimiter { open: span, close: span, kind },
+ tt::TokenTreesView::empty(),
+ ),
+ SyntaxFixupUndoInfo::default(),
+ span,
+ )
+ };
+
+ let Some(tt) = node.token_tree() else {
+ return dummy_tt(tt::DelimiterKind::Invisible);
+ };
+ let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']);
+ let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]);
+
+ let mismatched_delimiters = !matches!(
+ (first, last),
+ (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}'])
+ );
+ if mismatched_delimiters {
+ // Don't expand malformed (unbalanced) macro invocations. This is
+ // less than ideal, but trying to expand unbalanced macro calls
+ // sometimes produces pathological, deeply nested code which breaks
+ // all kinds of things.
+ //
+ // So instead, we'll return an empty subtree here
+ cov_mark::hit!(issue9358_bad_macro_stack_overflow);
+
+ let kind = match first {
+ _ if loc.def.is_proc_macro() => tt::DelimiterKind::Invisible,
+ T!['('] => tt::DelimiterKind::Parenthesis,
+ T!['['] => tt::DelimiterKind::Bracket,
+ T!['{'] => tt::DelimiterKind::Brace,
+ _ => tt::DelimiterKind::Invisible,
+ };
+ return dummy_tt(kind);
+ }
+
+ let mut tt = syntax_bridge::syntax_node_to_token_tree(
+ tt.syntax(),
+ map,
+ span,
+ if loc.def.is_proc_macro() {
+ DocCommentDesugarMode::ProcMacro
+ } else {
+ DocCommentDesugarMode::Mbe
+ },
+ );
+ if loc.def.is_proc_macro() {
+ // proc macros expect their inputs without parentheses, MBEs expect it with them included
+ tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
+ }
+ return (tt, SyntaxFixupUndoInfo::NONE, span);
+ }
+ // MacroCallKind::Derive should not be here. As we are getting the argument for the derive macro
+ MacroCallKind::Derive { .. } => {
+ unreachable!("`ExpandDatabase::macro_arg` called with `MacroCallKind::Derive`")
+ }
+ MacroCallKind::Attr { ast_id, censored_attr_ids: attr_ids, .. } => {
+ let node = ast_id.to_ptr(db).to_node(&root);
+ let (_, attr) =
+ attr_ids.invoc_attr().find_attr_range_with_source(db, loc.krate, &node);
+ let range = attr
+ .path()
+ .map(|path| path.syntax().text_range())
+ .unwrap_or_else(|| attr.syntax().text_range());
+ let span = map.span_for_range(range);
+
+ let is_derive = matches!(loc.def.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive());
+ (is_derive, &**attr_ids, node, span)
+ }
+ };
+
+ let (mut tt, undo_info) = attr_macro_input_to_token_tree(
+ db,
+ item_node.syntax(),
+ map,
+ span,
+ is_derive,
+ censor_item_tree_attr_ids,
+ loc.krate,
+ );
+
+ if loc.def.is_proc_macro() {
+ // proc macros expect their inputs without parentheses, MBEs expect it with them included
+ tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
+ }
+
+ (tt, undo_info, span)
+ }
+
+ fn macro_expand<'db>(
+ self,
+ db: &'db dyn ExpandDatabase,
+ loc: &MacroCallLoc,
+ ) -> ExpandResult<(Cow<'db, tt::TopSubtree>, MatchedArmIndex)> {
+ let _p = tracing::info_span!("macro_expand").entered();
+
+ let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind {
+ MacroDefKind::ProcMacro(..) => {
+ return self.expand_proc_macro(db).as_ref().map(|it| (Cow::Borrowed(it), None));
+ }
+ _ => {
+ let (macro_arg, undo_info, span) =
+ self.macro_arg_considering_derives(db, &loc.kind);
+ let span = *span;
+
+ let arg = macro_arg;
+ let res = match loc.def.kind {
+ MacroDefKind::Declarative(id, _) => {
+ db.decl_macro_expander(loc.def.krate, id).expand(db, arg, self, span)
+ }
+ MacroDefKind::BuiltIn(_, it) => {
+ it.expand(db, self, arg, span).map_err(Into::into).zip_val(None)
+ }
+ MacroDefKind::BuiltInDerive(_, it) => {
+ it.expand(db, self, arg, span).map_err(Into::into).zip_val(None)
+ }
+ MacroDefKind::UnimplementedBuiltIn(_) => {
+ expand_unimplemented_builtin_macro(span).zip_val(None)
+ }
+ MacroDefKind::BuiltInEager(_, it) => {
+ // This might look a bit odd, but we do not expand the inputs to eager macros here.
+ // Eager macros inputs are expanded, well, eagerly when we collect the macro calls.
+ // That kind of expansion uses the ast id map of an eager macros input though which goes through
+ // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query
+ // will end up going through here again, whereas we want to just want to inspect the raw input.
+ // As such we just return the input subtree here.
+ let eager = match &loc.kind {
+ MacroCallKind::FnLike { eager: None, .. } => {
+ return ExpandResult::ok(Cow::Borrowed(macro_arg)).zip_val(None);
+ }
+ MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
+ _ => None,
+ };
+
+ let mut res = it.expand(db, self, arg, span).map_err(Into::into);
+
+ if let Some(EagerCallInfo { error, .. }) = eager {
+ // FIXME: We should report both errors!
+ res.err = error.clone().or(res.err);
+ }
+ res.zip_val(None)
+ }
+ MacroDefKind::BuiltInAttr(_, it) => {
+ let mut res = it.expand(db, self, arg, span);
+ fixup::reverse_fixups(&mut res.value, undo_info);
+ res.zip_val(None)
+ }
+ MacroDefKind::ProcMacro(_, _, _) => unreachable!(),
+ };
+ (res, span)
+ }
+ };
+
+ // Skip checking token tree limit for include! macro call
+ if !loc.def.is_include() {
+ // Set a hard limit for the expanded tt
+ if let Err(value) = check_tt_count(&tt) {
+ return value
+ .map(|()| Cow::Owned(tt::TopSubtree::empty(tt::DelimSpan::from_single(span))))
+ .zip_val(matched_arm);
+ }
+ }
+
+ ExpandResult { value: (Cow::Owned(tt), matched_arm), err }
+ }
+
+ /// Special case of [`Self::macro_expand`] for procedural macros. We can't LRU
+ /// proc macros, since they are not deterministic in general, and
+ /// non-determinism breaks salsa in a very, very, very bad way.
+ /// @edwin0cheng heroically debugged this once! See #4315 for details
+ #[salsa::tracked(returns(ref))]
+ fn expand_proc_macro(self, db: &dyn ExpandDatabase) -> ExpandResult<tt::TopSubtree> {
+ let loc = self.loc(db);
+ let (macro_arg, undo_info, span) = self.macro_arg_considering_derives(db, &loc.kind);
+
+ let (ast, expander) = match loc.def.kind {
+ MacroDefKind::ProcMacro(ast, expander, _) => (ast, expander),
+ _ => unreachable!(),
+ };
+
+ let attr_arg = match &loc.kind {
+ MacroCallKind::Attr { attr_args: Some(attr_args), .. } => Some(&**attr_args),
+ _ => None,
+ };
+
+ let ExpandResult { value: mut tt, err } = {
+ let span = proc_macro_span(db, ast);
+ expander.expand(
+ db,
+ loc.def.krate,
+ loc.krate,
+ macro_arg,
+ attr_arg,
+ span_with_def_site_ctxt(db, span, self.into(), loc.def.edition),
+ span_with_call_site_ctxt(db, span, self.into(), loc.def.edition),
+ span_with_mixed_site_ctxt(db, span, self.into(), loc.def.edition),
+ )
+ };
+
+ // Set a hard limit for the expanded tt
+ if let Err(value) = check_tt_count(&tt) {
+ return value.map(|()| tt::TopSubtree::empty(tt::DelimSpan::from_single(*span)));
+ }
+
+ fixup::reverse_fixups(&mut tt, undo_info);
+
+ ExpandResult { value: tt, err }
+ }
+}
+
+fn expand_unimplemented_builtin_macro(span: Span) -> ExpandResult<tt::TopSubtree> {
+ ExpandResult::new(
+ tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
+ ExpandError::other(span, "this built-in macro is not implemented"),
+ )
+}
+
+/// Retrieves the span to be used for a proc-macro expansions spans.
+/// This is a firewall query as it requires parsing the file, which we don't want proc-macros to
+/// directly depend on as that would cause to frequent invalidations, mainly because of the
+/// parse queries being LRU cached. If they weren't the invalidations would only happen if the
+/// user wrote in the file that defines the proc-macro.
+fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
+ #[salsa::tracked]
+ fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>, _: ()) -> Span {
+ let root = db.parse_or_expand(ast.file_id);
+ let ast_id_map = db.ast_id_map(ast.file_id);
+ let span_map = db.span_map(ast.file_id);
+
+ let node = ast_id_map.get(ast.value).to_node(&root);
+ let range = ast::HasName::name(&node)
+ .map_or_else(|| node.syntax().text_range(), |name| name.syntax().text_range());
+ span_map.span_for_range(range)
+ }
+ proc_macro_span(db, ast, ())
+}
+
+pub(crate) fn token_tree_to_syntax_node(
+ db: &dyn ExpandDatabase,
+ tt: &tt::TopSubtree,
+ expand_to: ExpandTo,
+) -> (Parse<SyntaxNode>, ExpansionSpanMap) {
+ let entry_point = match expand_to {
+ ExpandTo::Statements => syntax_bridge::TopEntryPoint::MacroStmts,
+ ExpandTo::Items => syntax_bridge::TopEntryPoint::MacroItems,
+ ExpandTo::Pattern => syntax_bridge::TopEntryPoint::Pattern,
+ ExpandTo::Type => syntax_bridge::TopEntryPoint::Type,
+ ExpandTo::Expr => syntax_bridge::TopEntryPoint::Expr,
+ };
+ syntax_bridge::token_tree_to_syntax_node(tt, entry_point, &mut |ctx| ctx.edition(db))
+}
+
+fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> {
+ let tt = tt.top_subtree();
+ let count = tt.count();
+ if count <= TOKEN_LIMIT {
+ Ok(())
+ } else {
+ Err(ExpandResult {
+ value: (),
+ err: Some(ExpandError::other(
+ tt.delimiter.open,
+ format!(
+ "macro invocation exceeds token limit: produced {count} tokens, limit is {TOKEN_LIMIT}",
+ ),
+ )),
+ })
+ }
+}
+
impl MacroDefId {
pub fn make_call(
self,
@@ -862,7 +1230,7 @@ impl<'db> ExpansionInfo<'db> {
let arg_tt = loc.kind.arg(db);
let arg_map = db.span_map(arg_tt.file_id);
- let (parse, exp_map) = &db.parse_macro_expansion(macro_file).value;
+ let (parse, exp_map) = &macro_file.parse_macro_expansion(db).value;
let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() };
ExpansionInfo { expanded, loc, arg: arg_tt, exp_map, arg_map }
@@ -1073,7 +1441,7 @@ impl HirFileId {
HirFileId::FileId(_) => SyntaxContext::root(edition),
HirFileId::MacroFile(m) => {
let kind = &m.loc(db).kind;
- db.macro_arg_considering_derives(m, kind).2.ctx
+ m.macro_arg_considering_derives(db, kind).2.ctx
}
}
}
diff --git a/crates/hir-expand/src/span_map.rs b/crates/hir-expand/src/span_map.rs
index 6a94df8b5a..d19eead4a8 100644
--- a/crates/hir-expand/src/span_map.rs
+++ b/crates/hir-expand/src/span_map.rs
@@ -41,7 +41,7 @@ impl<'db> SpanMap<'db> {
match file_id {
HirFileId::FileId(file_id) => SpanMap::RealSpanMap(db.real_span_map(file_id)),
HirFileId::MacroFile(m) => {
- SpanMap::ExpansionSpanMap(&db.parse_macro_expansion(m).value.1)
+ SpanMap::ExpansionSpanMap(&m.parse_macro_expansion(db).value.1)
}
}
}
@@ -115,5 +115,5 @@ pub(crate) fn expansion_span_map(
db: &dyn ExpandDatabase,
file_id: MacroCallId,
) -> &ExpansionSpanMap {
- &db.parse_macro_expansion(file_id).value.1
+ &file_id.parse_macro_expansion(db).value.1
}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 8d21b351e4..ceac3f0876 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1159,7 +1159,7 @@ fn macro_call_diagnostics<'db>(
macro_call_id: MacroCallId,
acc: &mut Vec<AnyDiagnostic<'db>>,
) {
- let Some(e) = db.parse_macro_expansion_error(macro_call_id) else {
+ let Some(e) = macro_call_id.parse_macro_expansion_error(db) else {
return;
};
let ValueResult { value: parse_errors, err } = e;
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index dcbd6c37af..8fc08abef1 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -564,7 +564,7 @@ impl<'db> SemanticsImpl<'db> {
}
pub fn expand(&self, file_id: MacroCallId) -> ExpandResult<SyntaxNode> {
- let res = self.db.parse_macro_expansion(file_id).as_ref().map(|it| it.0.syntax_node());
+ let res = file_id.parse_macro_expansion(self.db).as_ref().map(|it| it.0.syntax_node());
self.cache(res.value.clone(), file_id.into());
res
}
@@ -661,7 +661,7 @@ impl<'db> SemanticsImpl<'db> {
.into_iter()
.map(|call| {
let file_id = call?.left()?;
- let ExpandResult { value, err } = self.db.parse_macro_expansion(file_id);
+ let ExpandResult { value, err } = file_id.parse_macro_expansion(self.db);
let root_node = value.0.syntax_node();
self.cache(root_node.clone(), file_id.into());
Some(ExpandResult { value: root_node, err: err.clone() })
@@ -1979,8 +1979,7 @@ impl<'db> SemanticsImpl<'db> {
}
pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option<u32> {
- let file_id = self.to_def(macro_call)?;
- self.db.parse_macro_expansion(file_id).value.1.matched_arm
+ self.to_def(macro_call)?.parse_macro_expansion(self.db).value.1.matched_arm
}
pub fn get_unsafe_ops(&self, def: ExpressionStoreOwner) -> FxHashSet<ExprOrPatSource> {