Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-expand/src/db.rs')
-rw-r--r--crates/hir-expand/src/db.rs191
1 files changed, 140 insertions, 51 deletions
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index 935669d49b..f7a26e436d 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -1,14 +1,16 @@
//! Defines database & queries for macro expansion.
+use std::sync::OnceLock;
+
use base_db::{
salsa::{self, debug::DebugQueryTable},
- span::SyntaxContextId,
- CrateId, Edition, FileId, SourceDatabase,
+ CrateId, Edition, FileId, SourceDatabase, VersionReq,
};
use either::Either;
use limit::Limit;
use mbe::{syntax_node_to_token_tree, ValueResult};
use rustc_hash::FxHashSet;
+use span::{Span, SyntaxContextId};
use syntax::{
ast::{self, HasAttrs},
AstNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T,
@@ -21,11 +23,16 @@ use crate::{
builtin_attr_macro::pseudo_derive_attr_expansion,
builtin_fn_macro::EagerExpander,
fixup::{self, reverse_fixups, SyntaxFixupUndoInfo},
- hygiene::{apply_mark, SyntaxContextData, Transparency},
- span::{RealSpanMap, SpanMap, SpanMapRef},
- tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo,
- ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap, HirFileId, HirFileIdRepr, MacroCallId,
- MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFileId, ProcMacroExpander,
+ hygiene::{
+ apply_mark, span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt,
+ SyntaxContextData, Transparency,
+ },
+ proc_macro::ProcMacros,
+ span_map::{RealSpanMap, SpanMap, SpanMapRef},
+ tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
+ CustomProcMacroExpander, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap,
+ HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
+ MacroFileId,
};
/// Total limit on the number of tokens produced by any macro invocation.
@@ -39,10 +46,13 @@ static TOKEN_LIMIT: Limit = Limit::new(1_048_576);
#[derive(Debug, Clone, Eq, PartialEq)]
/// Old-style `macro_rules` or the new macros 2.0
pub struct DeclarativeMacroExpander {
- pub mac: mbe::DeclarativeMacro<base_db::span::SpanData>,
+ pub mac: mbe::DeclarativeMacro<span::Span>,
pub transparency: Transparency,
}
+// FIXME: Remove this once we drop support for 1.76
+static REQUIREMENT: OnceLock<VersionReq> = OnceLock::new();
+
impl DeclarativeMacroExpander {
pub fn expand(
&self,
@@ -50,25 +60,61 @@ impl DeclarativeMacroExpander {
tt: tt::Subtree,
call_id: MacroCallId,
) -> ExpandResult<tt::Subtree> {
+ let loc = db.lookup_intern_macro_call(call_id);
+ let toolchain = &db.crate_graph()[loc.def.krate].toolchain;
+ let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
+ REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
+ &base_db::Version {
+ pre: base_db::Prerelease::EMPTY,
+ build: base_db::BuildMetadata::EMPTY,
+ major: version.major,
+ minor: version.minor,
+ patch: version.patch,
+ },
+ )
+ });
match self.mac.err() {
Some(e) => ExpandResult::new(
- tt::Subtree::empty(tt::DelimSpan::DUMMY),
+ tt::Subtree::empty(tt::DelimSpan { open: loc.call_site, close: loc.call_site }),
ExpandError::other(format!("invalid macro definition: {e}")),
),
None => self
.mac
- .expand(&tt, |s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency))
+ .expand(
+ &tt,
+ |s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency),
+ new_meta_vars,
+ loc.call_site,
+ )
.map_err(Into::into),
}
}
- pub fn expand_unhygienic(&self, tt: tt::Subtree) -> ExpandResult<tt::Subtree> {
+ pub fn expand_unhygienic(
+ &self,
+ db: &dyn ExpandDatabase,
+ tt: tt::Subtree,
+ krate: CrateId,
+ call_site: Span,
+ ) -> ExpandResult<tt::Subtree> {
+ let toolchain = &db.crate_graph()[krate].toolchain;
+ let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
+ REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
+ &base_db::Version {
+ pre: base_db::Prerelease::EMPTY,
+ build: base_db::BuildMetadata::EMPTY,
+ major: version.major,
+ minor: version.minor,
+ patch: version.patch,
+ },
+ )
+ });
match self.mac.err() {
Some(e) => ExpandResult::new(
- tt::Subtree::empty(tt::DelimSpan::DUMMY),
+ tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
ExpandError::other(format!("invalid macro definition: {e}")),
),
- None => self.mac.expand(&tt, |_| ()).map_err(Into::into),
+ None => self.mac.expand(&tt, |_| (), new_meta_vars, call_site).map_err(Into::into),
}
}
}
@@ -86,11 +132,15 @@ pub enum TokenExpander {
/// `derive(Copy)` and such.
BuiltInDerive(BuiltinDeriveExpander),
/// The thing we love the most here in rust-analyzer -- procedural macros.
- ProcMacro(ProcMacroExpander),
+ ProcMacro(CustomProcMacroExpander),
}
#[salsa::query_group(ExpandDatabaseStorage)]
pub trait ExpandDatabase: SourceDatabase {
+ /// The proc macros.
+ #[salsa::input]
+ fn proc_macros(&self) -> Arc<ProcMacros>;
+
fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
/// Main public API -- parses a hir file, not caring whether it's a real
@@ -164,7 +214,20 @@ pub fn span_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> SpanMap {
}
pub fn real_span_map(db: &dyn ExpandDatabase, file_id: FileId) -> Arc<RealSpanMap> {
- Arc::new(RealSpanMap::from_file(db, file_id))
+ use syntax::ast::HasModuleItem;
+ let mut pairs = vec![(syntax::TextSize::new(0), span::ROOT_ERASED_FILE_AST_ID)];
+ let ast_id_map = db.ast_id_map(file_id.into());
+ let tree = db.parse(file_id).tree();
+ pairs.extend(
+ tree.items()
+ .map(|item| (item.syntax().text_range().start(), ast_id_map.ast_id(&item).erase())),
+ );
+
+ Arc::new(RealSpanMap::from_file(
+ file_id,
+ pairs.into_boxed_slice(),
+ tree.syntax().text_range().end(),
+ ))
}
/// This expands the given macro call, but with different arguments. This is
@@ -184,12 +247,13 @@ pub fn expand_speculative(
// Build the subtree and token mapping for the speculative args
let (mut tt, undo_info) = match loc.kind {
- MacroCallKind::FnLike { .. } => {
- (mbe::syntax_node_to_token_tree(speculative_args, span_map), SyntaxFixupUndoInfo::NONE)
- }
+ MacroCallKind::FnLike { .. } => (
+ mbe::syntax_node_to_token_tree(speculative_args, span_map, loc.call_site),
+ SyntaxFixupUndoInfo::NONE,
+ ),
MacroCallKind::Derive { .. } | MacroCallKind::Attr { .. } => {
let censor = censor_for_macro_input(&loc, speculative_args);
- let mut fixups = fixup::fixup_syntax(span_map, speculative_args);
+ let mut fixups = fixup::fixup_syntax(span_map, speculative_args, loc.call_site);
fixups.append.retain(|it, _| match it {
syntax::NodeOrToken::Node(it) => !censor.contains(it),
syntax::NodeOrToken::Token(_) => true,
@@ -201,6 +265,7 @@ pub fn expand_speculative(
span_map,
fixups.append,
fixups.remove,
+ loc.call_site,
),
fixups.undo_info,
)
@@ -222,8 +287,9 @@ pub fn expand_speculative(
}?;
match attr.token_tree() {
Some(token_tree) => {
- let mut tree = syntax_node_to_token_tree(token_tree.syntax(), span_map);
- tree.delimiter = tt::Delimiter::DUMMY_INVISIBLE;
+ let mut tree =
+ syntax_node_to_token_tree(token_tree.syntax(), span_map, loc.call_site);
+ tree.delimiter = tt::Delimiter::invisible_spanned(loc.call_site);
Some(tree)
}
@@ -237,17 +303,16 @@ 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(expander, ..) => {
- tt.delimiter = tt::Delimiter::DUMMY_INVISIBLE;
- let call_site = loc.span(db);
+ tt.delimiter = tt::Delimiter::invisible_spanned(loc.call_site);
expander.expand(
db,
loc.def.krate,
loc.krate,
&tt,
attr_arg.as_ref(),
- call_site,
- call_site,
- call_site,
+ span_with_def_site_ctxt(db, loc.def.span, actual_macro_call),
+ span_with_call_site_ctxt(db, loc.def.span, actual_macro_call),
+ span_with_mixed_site_ctxt(db, loc.def.span, actual_macro_call),
)
}
MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
@@ -258,9 +323,12 @@ pub fn expand_speculative(
let adt = ast::Adt::cast(speculative_args.clone()).unwrap();
expander.expand(db, actual_macro_call, &adt, span_map)
}
- MacroDefKind::Declarative(it) => {
- db.decl_macro_expander(loc.krate, it).expand_unhygienic(tt)
- }
+ MacroDefKind::Declarative(it) => db.decl_macro_expander(loc.krate, it).expand_unhygienic(
+ db,
+ tt,
+ loc.def.krate,
+ loc.call_site,
+ ),
MacroDefKind::BuiltIn(it, _) => it.expand(db, actual_macro_call, &tt).map_err(Into::into),
MacroDefKind::BuiltInEager(it, _) => {
it.expand(db, actual_macro_call, &tt).map_err(Into::into)
@@ -410,12 +478,13 @@ fn macro_arg(
MacroCallKind::Attr { ast_id, .. } => ast_id.to_ptr(db).to_node(&root).syntax().clone(),
};
let (mut tt, undo_info) = match loc.kind {
- MacroCallKind::FnLike { .. } => {
- (mbe::syntax_node_to_token_tree(&syntax, map.as_ref()), SyntaxFixupUndoInfo::NONE)
- }
+ MacroCallKind::FnLike { .. } => (
+ mbe::syntax_node_to_token_tree(&syntax, map.as_ref(), loc.call_site),
+ SyntaxFixupUndoInfo::NONE,
+ ),
MacroCallKind::Derive { .. } | MacroCallKind::Attr { .. } => {
let censor = censor_for_macro_input(&loc, &syntax);
- let mut fixups = fixup::fixup_syntax(map.as_ref(), &syntax);
+ let mut fixups = fixup::fixup_syntax(map.as_ref(), &syntax, loc.call_site);
fixups.append.retain(|it, _| match it {
syntax::NodeOrToken::Node(it) => !censor.contains(it),
syntax::NodeOrToken::Token(_) => true,
@@ -427,6 +496,7 @@ fn macro_arg(
map.as_ref(),
fixups.append.clone(),
fixups.remove.clone(),
+ loc.call_site,
);
reverse_fixups(&mut tt, &fixups.undo_info);
}
@@ -436,6 +506,7 @@ fn macro_arg(
map,
fixups.append,
fixups.remove,
+ loc.call_site,
),
fixups.undo_info,
)
@@ -444,7 +515,7 @@ fn macro_arg(
if loc.def.is_proc_macro() {
// proc macros expect their inputs without parentheses, MBEs expect it with them included
- tt.delimiter = tt::Delimiter::DUMMY_INVISIBLE;
+ tt.delimiter.kind = tt::DelimiterKind::Invisible;
}
if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) {
@@ -506,7 +577,8 @@ fn decl_macro_expander(
def_crate: CrateId,
id: AstId<ast::Macro>,
) -> Arc<DeclarativeMacroExpander> {
- let is_2021 = db.crate_graph()[def_crate].edition >= Edition::Edition2021;
+ let crate_data = &db.crate_graph()[def_crate];
+ let is_2021 = crate_data.edition >= Edition::Edition2021;
let (root, map) = parse_with_map(db, id.file_id);
let root = root.syntax_node();
@@ -530,13 +602,29 @@ fn decl_macro_expander(
_ => None,
}
};
+ let toolchain = crate_data.toolchain.as_ref();
+ let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
+ REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
+ &base_db::Version {
+ pre: base_db::Prerelease::EMPTY,
+ build: base_db::BuildMetadata::EMPTY,
+ major: version.major,
+ minor: version.minor,
+ patch: version.patch,
+ },
+ )
+ });
let (mac, transparency) = match id.to_ptr(db).to_node(&root) {
ast::Macro::MacroRules(macro_rules) => (
match macro_rules.token_tree() {
Some(arg) => {
- let tt = mbe::syntax_node_to_token_tree(arg.syntax(), map.as_ref());
- let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021);
+ let tt = mbe::syntax_node_to_token_tree(
+ arg.syntax(),
+ map.as_ref(),
+ map.span_for_range(macro_rules.macro_rules_token().unwrap().text_range()),
+ );
+ let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021, new_meta_vars);
mac
}
None => mbe::DeclarativeMacro::from_err(
@@ -549,8 +637,12 @@ fn decl_macro_expander(
ast::Macro::MacroDef(macro_def) => (
match macro_def.body() {
Some(arg) => {
- let tt = mbe::syntax_node_to_token_tree(arg.syntax(), map.as_ref());
- let mac = mbe::DeclarativeMacro::parse_macro2(&tt, is_2021);
+ let tt = mbe::syntax_node_to_token_tree(
+ arg.syntax(),
+ map.as_ref(),
+ map.span_for_range(macro_def.macro_token().unwrap().text_range()),
+ );
+ let mac = mbe::DeclarativeMacro::parse_macro2(&tt, is_2021, new_meta_vars);
mac
}
None => mbe::DeclarativeMacro::from_err(
@@ -601,7 +693,7 @@ fn macro_expand(
let Some((macro_arg, undo_info)) = value else {
return ExpandResult {
value: Arc::new(tt::Subtree {
- delimiter: tt::Delimiter::DUMMY_INVISIBLE,
+ delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
token_trees: Vec::new(),
}),
// FIXME: We should make sure to enforce an invariant that invalid macro
@@ -660,7 +752,7 @@ fn macro_expand(
// 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) {
+ if let Err(value) = check_tt_count(&tt, loc.call_site) {
return value;
}
}
@@ -673,7 +765,7 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<A
let Some((macro_arg, undo_info)) = db.macro_arg(id).value else {
return ExpandResult {
value: Arc::new(tt::Subtree {
- delimiter: tt::Delimiter::DUMMY_INVISIBLE,
+ delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
token_trees: Vec::new(),
}),
// FIXME: We should make sure to enforce an invariant that invalid macro
@@ -692,22 +784,19 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<A
_ => None,
};
- let call_site = loc.span(db);
let ExpandResult { value: mut tt, err } = expander.expand(
db,
loc.def.krate,
loc.krate,
&macro_arg,
attr_arg,
- // FIXME
- call_site,
- call_site,
- // FIXME
- call_site,
+ span_with_def_site_ctxt(db, loc.def.span, id),
+ span_with_call_site_ctxt(db, loc.def.span, id),
+ span_with_mixed_site_ctxt(db, loc.def.span, id),
);
// Set a hard limit for the expanded tt
- if let Err(value) = check_tt_count(&tt) {
+ if let Err(value) = check_tt_count(&tt, loc.call_site) {
return value;
}
@@ -730,12 +819,12 @@ fn token_tree_to_syntax_node(
mbe::token_tree_to_syntax_node(tt, entry_point)
}
-fn check_tt_count(tt: &tt::Subtree) -> Result<(), ExpandResult<Arc<tt::Subtree>>> {
+fn check_tt_count(tt: &tt::Subtree, call_site: Span) -> Result<(), ExpandResult<Arc<tt::Subtree>>> {
let count = tt.count();
if TOKEN_LIMIT.check(count).is_err() {
Err(ExpandResult {
value: Arc::new(tt::Subtree {
- delimiter: tt::Delimiter::DUMMY_INVISIBLE,
+ delimiter: tt::Delimiter::invisible_spanned(call_site),
token_trees: vec![],
}),
err: Some(ExpandError::other(format!(