hir_expand/
db.rs

1//! Defines database & queries for macro expansion.
2
3use base_db::{Crate, RootQueryDb};
4use either::Either;
5use mbe::MatchedArmIndex;
6use rustc_hash::FxHashSet;
7use span::{AstIdMap, Edition, Span, SyntaxContext};
8use syntax::{AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T, ast};
9use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree};
10use triomphe::Arc;
11
12use crate::{
13    AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo,
14    EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, HirFileId, MacroCallId,
15    MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
16    attrs::{AttrId, AttrInput, RawAttrs, collect_attrs},
17    builtin::pseudo_derive_attr_expansion,
18    cfg_process,
19    declarative::DeclarativeMacroExpander,
20    fixup::{self, SyntaxFixupUndoInfo},
21    hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt},
22    proc_macro::{CrateProcMacros, CustomProcMacroExpander, ProcMacros},
23    span_map::{ExpansionSpanMap, RealSpanMap, SpanMap, SpanMapRef},
24    tt,
25};
26/// This is just to ensure the types of smart_macro_arg and macro_arg are the same
27type MacroArgResult = (Arc<tt::TopSubtree>, SyntaxFixupUndoInfo, Span);
28/// Total limit on the number of tokens produced by any macro invocation.
29///
30/// If an invocation produces more tokens than this limit, it will not be stored in the database and
31/// an error will be emitted.
32///
33/// Actual max for `analysis-stats .` at some point: 30672.
34const TOKEN_LIMIT: usize = 2_097_152;
35
36#[derive(Debug, Clone, Eq, PartialEq)]
37pub enum TokenExpander {
38    /// Old-style `macro_rules` or the new macros 2.0
39    DeclarativeMacro(Arc<DeclarativeMacroExpander>),
40    /// Stuff like `line!` and `file!`.
41    BuiltIn(BuiltinFnLikeExpander),
42    /// Built-in eagerly expanded fn-like macros (`include!`, `concat!`, etc.)
43    BuiltInEager(EagerExpander),
44    /// `global_allocator` and such.
45    BuiltInAttr(BuiltinAttrExpander),
46    /// `derive(Copy)` and such.
47    BuiltInDerive(BuiltinDeriveExpander),
48    /// The thing we love the most here in rust-analyzer -- procedural macros.
49    ProcMacro(CustomProcMacroExpander),
50}
51
52#[query_group::query_group]
53pub trait ExpandDatabase: RootQueryDb {
54    /// The proc macros. Do not use this! Use `proc_macros_for_crate()` instead.
55    #[salsa::input]
56    fn proc_macros(&self) -> Arc<ProcMacros>;
57
58    /// Incrementality query to prevent queries from directly depending on `ExpandDatabase::proc_macros`.
59    #[salsa::invoke(crate::proc_macro::proc_macros_for_crate)]
60    fn proc_macros_for_crate(&self, krate: Crate) -> Option<Arc<CrateProcMacros>>;
61
62    #[salsa::invoke(ast_id_map)]
63    #[salsa::lru(1024)]
64    fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
65
66    #[salsa::transparent]
67    fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode;
68
69    /// Implementation for the macro case.
70    #[salsa::lru(512)]
71    fn parse_macro_expansion(
72        &self,
73        macro_file: MacroCallId,
74    ) -> ExpandResult<(Parse<SyntaxNode>, Arc<ExpansionSpanMap>)>;
75
76    #[salsa::transparent]
77    #[salsa::invoke(SpanMap::new)]
78    fn span_map(&self, file_id: HirFileId) -> SpanMap;
79
80    #[salsa::transparent]
81    #[salsa::invoke(crate::span_map::expansion_span_map)]
82    fn expansion_span_map(&self, file_id: MacroCallId) -> Arc<ExpansionSpanMap>;
83    #[salsa::invoke(crate::span_map::real_span_map)]
84    fn real_span_map(&self, file_id: EditionedFileId) -> Arc<RealSpanMap>;
85
86    /// Macro ids. That's probably the tricksiest bit in rust-analyzer, and the
87    /// reason why we use salsa at all.
88    ///
89    /// We encode macro definitions into ids of macro calls, this what allows us
90    /// to be incremental.
91    #[salsa::transparent]
92    fn intern_macro_call(&self, macro_call: MacroCallLoc) -> MacroCallId;
93    #[salsa::transparent]
94    fn lookup_intern_macro_call(&self, macro_call: MacroCallId) -> MacroCallLoc;
95
96    /// Lowers syntactic macro call to a token tree representation. That's a firewall
97    /// query, only typing in the macro call itself changes the returned
98    /// subtree.
99    #[deprecated = "calling this is incorrect, call `macro_arg_considering_derives` instead"]
100    #[salsa::invoke(macro_arg)]
101    fn macro_arg(&self, id: MacroCallId) -> MacroArgResult;
102
103    #[salsa::transparent]
104    fn macro_arg_considering_derives(
105        &self,
106        id: MacroCallId,
107        kind: &MacroCallKind,
108    ) -> MacroArgResult;
109
110    /// Fetches the expander for this macro.
111    #[salsa::transparent]
112    #[salsa::invoke(TokenExpander::macro_expander)]
113    fn macro_expander(&self, id: MacroDefId) -> TokenExpander;
114
115    /// Fetches (and compiles) the expander of this decl macro.
116    #[salsa::invoke(DeclarativeMacroExpander::expander)]
117    fn decl_macro_expander(
118        &self,
119        def_crate: Crate,
120        id: AstId<ast::Macro>,
121    ) -> Arc<DeclarativeMacroExpander>;
122
123    /// Special case of the previous query for procedural macros. We can't LRU
124    /// proc macros, since they are not deterministic in general, and
125    /// non-determinism breaks salsa in a very, very, very bad way.
126    /// @edwin0cheng heroically debugged this once! See #4315 for details
127    #[salsa::invoke(expand_proc_macro)]
128    fn expand_proc_macro(&self, call: MacroCallId) -> ExpandResult<Arc<tt::TopSubtree>>;
129    /// Retrieves the span to be used for a proc-macro expansions spans.
130    /// This is a firewall query as it requires parsing the file, which we don't want proc-macros to
131    /// directly depend on as that would cause to frequent invalidations, mainly because of the
132    /// parse queries being LRU cached. If they weren't the invalidations would only happen if the
133    /// user wrote in the file that defines the proc-macro.
134    #[salsa::invoke_interned(proc_macro_span)]
135    fn proc_macro_span(&self, fun: AstId<ast::Fn>) -> Span;
136
137    /// Firewall query that returns the errors from the `parse_macro_expansion` query.
138    #[salsa::invoke(parse_macro_expansion_error)]
139    fn parse_macro_expansion_error(
140        &self,
141        macro_call: MacroCallId,
142    ) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>>;
143
144    #[salsa::transparent]
145    fn syntax_context(&self, file: HirFileId, edition: Edition) -> SyntaxContext;
146}
147
148#[salsa_macros::interned(no_lifetime, id = span::SyntaxContext, revisions = usize::MAX)]
149pub struct SyntaxContextWrapper {
150    pub data: SyntaxContext,
151}
152
153fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId, edition: Edition) -> SyntaxContext {
154    match file {
155        HirFileId::FileId(_) => SyntaxContext::root(edition),
156        HirFileId::MacroFile(m) => {
157            let kind = db.lookup_intern_macro_call(m).kind;
158            db.macro_arg_considering_derives(m, &kind).2.ctx
159        }
160    }
161}
162
163/// This expands the given macro call, but with different arguments. This is
164/// used for completion, where we want to see what 'would happen' if we insert a
165/// token. The `token_to_map` mapped down into the expansion, with the mapped
166/// token(s) returned with their priority.
167pub fn expand_speculative(
168    db: &dyn ExpandDatabase,
169    actual_macro_call: MacroCallId,
170    speculative_args: &SyntaxNode,
171    token_to_map: SyntaxToken,
172) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
173    let loc = db.lookup_intern_macro_call(actual_macro_call);
174    let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
175
176    let span_map = RealSpanMap::absolute(span.anchor.file_id);
177    let span_map = SpanMapRef::RealSpanMap(&span_map);
178
179    // Build the subtree and token mapping for the speculative args
180    let (mut tt, undo_info) = match loc.kind {
181        MacroCallKind::FnLike { .. } => (
182            syntax_bridge::syntax_node_to_token_tree(
183                speculative_args,
184                span_map,
185                span,
186                if loc.def.is_proc_macro() {
187                    DocCommentDesugarMode::ProcMacro
188                } else {
189                    DocCommentDesugarMode::Mbe
190                },
191            ),
192            SyntaxFixupUndoInfo::NONE,
193        ),
194        MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => (
195            syntax_bridge::syntax_node_to_token_tree(
196                speculative_args,
197                span_map,
198                span,
199                DocCommentDesugarMode::ProcMacro,
200            ),
201            SyntaxFixupUndoInfo::NONE,
202        ),
203        MacroCallKind::Derive { derive_attr_index: index, .. }
204        | MacroCallKind::Attr { invoc_attr_index: index, .. } => {
205            let censor = if let MacroCallKind::Derive { .. } = loc.kind {
206                censor_derive_input(index, &ast::Adt::cast(speculative_args.clone())?)
207            } else {
208                attr_source(index, &ast::Item::cast(speculative_args.clone())?)
209                    .into_iter()
210                    .map(|it| it.syntax().clone().into())
211                    .collect()
212            };
213
214            let censor_cfg =
215                cfg_process::process_cfg_attrs(db, speculative_args, &loc).unwrap_or_default();
216            let mut fixups = fixup::fixup_syntax(
217                span_map,
218                speculative_args,
219                span,
220                DocCommentDesugarMode::ProcMacro,
221            );
222            fixups.append.retain(|it, _| match it {
223                syntax::NodeOrToken::Token(_) => true,
224                it => !censor.contains(it) && !censor_cfg.contains(it),
225            });
226            fixups.remove.extend(censor);
227            fixups.remove.extend(censor_cfg);
228
229            (
230                syntax_bridge::syntax_node_to_token_tree_modified(
231                    speculative_args,
232                    span_map,
233                    fixups.append,
234                    fixups.remove,
235                    span,
236                    DocCommentDesugarMode::ProcMacro,
237                ),
238                fixups.undo_info,
239            )
240        }
241    };
242
243    let attr_arg = match loc.kind {
244        MacroCallKind::Attr { invoc_attr_index, .. } => {
245            if loc.def.is_attribute_derive() {
246                // for pseudo-derive expansion we actually pass the attribute itself only
247                ast::Attr::cast(speculative_args.clone()).and_then(|attr| attr.token_tree()).map(
248                    |token_tree| {
249                        let mut tree = syntax_node_to_token_tree(
250                            token_tree.syntax(),
251                            span_map,
252                            span,
253                            DocCommentDesugarMode::ProcMacro,
254                        );
255                        *tree.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span);
256                        tree
257                    },
258                )
259            } else {
260                // Attributes may have an input token tree, build the subtree and map for this as well
261                // then try finding a token id for our token if it is inside this input subtree.
262                let item = ast::Item::cast(speculative_args.clone())?;
263                let attrs = RawAttrs::new_expanded(db, &item, span_map, loc.krate.cfg_options(db));
264                attrs.iter().find(|attr| attr.id == invoc_attr_index).and_then(|attr| {
265                    match attr.input.as_deref()? {
266                        AttrInput::TokenTree(tt) => {
267                            let mut attr_arg = tt.clone();
268                            attr_arg.top_subtree_delimiter_mut().kind =
269                                tt::DelimiterKind::Invisible;
270                            Some(attr_arg)
271                        }
272                        AttrInput::Literal(_) => None,
273                    }
274                })
275            }
276        }
277        _ => None,
278    };
279
280    // Do the actual expansion, we need to directly expand the proc macro due to the attribute args
281    // Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
282    let mut speculative_expansion = match loc.def.kind {
283        MacroDefKind::ProcMacro(ast, expander, _) => {
284            let span = db.proc_macro_span(ast);
285            *tt.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span);
286            expander.expand(
287                db,
288                loc.def.krate,
289                loc.krate,
290                &tt,
291                attr_arg.as_ref(),
292                span_with_def_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition),
293                span_with_call_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition),
294                span_with_mixed_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition),
295            )
296        }
297        MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => {
298            pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span)
299        }
300        MacroDefKind::Declarative(it) => {
301            db.decl_macro_expander(loc.krate, it).expand_unhygienic(tt, span, loc.def.edition)
302        }
303        MacroDefKind::BuiltIn(_, it) => {
304            it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
305        }
306        MacroDefKind::BuiltInDerive(_, it) => {
307            it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
308        }
309        MacroDefKind::BuiltInEager(_, it) => {
310            it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
311        }
312        MacroDefKind::BuiltInAttr(_, it) => it.expand(db, actual_macro_call, &tt, span),
313    };
314
315    let expand_to = loc.expand_to();
316
317    fixup::reverse_fixups(&mut speculative_expansion.value, &undo_info);
318    let (node, rev_tmap) =
319        token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to, loc.def.edition);
320
321    let syntax_node = node.syntax_node();
322    let token = rev_tmap
323        .ranges_with_span(span_map.span_for_range(token_to_map.text_range()))
324        .filter_map(|(range, ctx)| syntax_node.covering_element(range).into_token().zip(Some(ctx)))
325        .map(|(t, ctx)| {
326            // prefer tokens of the same kind and text, as well as non opaque marked ones
327            // Note the inversion of the score here, as we want to prefer the first token in case
328            // of all tokens having the same score
329            let ranking = ctx.is_opaque(db) as u8
330                + 2 * (t.kind() != token_to_map.kind()) as u8
331                + 4 * ((t.text() != token_to_map.text()) as u8);
332            (t, ranking)
333        })
334        .collect();
335    Some((node.syntax_node(), token))
336}
337
338fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> triomphe::Arc<AstIdMap> {
339    triomphe::Arc::new(AstIdMap::from_source(&db.parse_or_expand(file_id)))
340}
341
342/// Main public API -- parses a hir file, not caring whether it's a real
343/// file or a macro expansion.
344fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> SyntaxNode {
345    match file_id {
346        HirFileId::FileId(file_id) => db.parse(file_id).syntax_node(),
347        HirFileId::MacroFile(macro_file) => {
348            db.parse_macro_expansion(macro_file).value.0.syntax_node()
349        }
350    }
351}
352
353// FIXME: We should verify that the parsed node is one of the many macro node variants we expect
354// instead of having it be untyped
355fn parse_macro_expansion(
356    db: &dyn ExpandDatabase,
357    macro_file: MacroCallId,
358) -> ExpandResult<(Parse<SyntaxNode>, Arc<ExpansionSpanMap>)> {
359    let _p = tracing::info_span!("parse_macro_expansion").entered();
360    let loc = db.lookup_intern_macro_call(macro_file);
361    let def_edition = loc.def.edition;
362    let expand_to = loc.expand_to();
363    let mbe::ValueResult { value: (tt, matched_arm), err } = macro_expand(db, macro_file, loc);
364
365    let (parse, mut rev_token_map) = token_tree_to_syntax_node(
366        db,
367        match &tt {
368            CowArc::Arc(it) => it,
369            CowArc::Owned(it) => it,
370        },
371        expand_to,
372        def_edition,
373    );
374    rev_token_map.matched_arm = matched_arm;
375
376    ExpandResult { value: (parse, Arc::new(rev_token_map)), err }
377}
378
379fn parse_macro_expansion_error(
380    db: &dyn ExpandDatabase,
381    macro_call_id: MacroCallId,
382) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>> {
383    let e: ExpandResult<Arc<[SyntaxError]>> =
384        db.parse_macro_expansion(macro_call_id).map(|it| Arc::from(it.0.errors()));
385    if e.value.is_empty() && e.err.is_none() { None } else { Some(Arc::new(e)) }
386}
387
388pub(crate) fn parse_with_map(
389    db: &dyn ExpandDatabase,
390    file_id: HirFileId,
391) -> (Parse<SyntaxNode>, SpanMap) {
392    match file_id {
393        HirFileId::FileId(file_id) => {
394            (db.parse(file_id).to_syntax(), SpanMap::RealSpanMap(db.real_span_map(file_id)))
395        }
396        HirFileId::MacroFile(macro_file) => {
397            let (parse, map) = db.parse_macro_expansion(macro_file).value;
398            (parse, SpanMap::ExpansionSpanMap(map))
399        }
400    }
401}
402
403/// This resolves the [MacroCallId] to check if it is a derive macro if so get the [macro_arg] for the derive.
404/// Other wise return the [macro_arg] for the macro_call_id.
405///
406/// This is not connected to the database so it does not cached the result. However, the inner [macro_arg] query is
407#[allow(deprecated)] // we are macro_arg_considering_derives
408fn macro_arg_considering_derives(
409    db: &dyn ExpandDatabase,
410    id: MacroCallId,
411    kind: &MacroCallKind,
412) -> MacroArgResult {
413    match kind {
414        // Get the macro arg for the derive macro
415        MacroCallKind::Derive { derive_macro_id, .. } => db.macro_arg(*derive_macro_id),
416        // Normal macro arg
417        _ => db.macro_arg(id),
418    }
419}
420
421fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
422    let loc = db.lookup_intern_macro_call(id);
423
424    if let MacroCallLoc {
425        def: MacroDefId { kind: MacroDefKind::BuiltInEager(..), .. },
426        kind: MacroCallKind::FnLike { eager: Some(eager), .. },
427        ..
428    } = &loc
429    {
430        return (eager.arg.clone(), SyntaxFixupUndoInfo::NONE, eager.span);
431    }
432
433    let (parse, map) = parse_with_map(db, loc.kind.file_id());
434    let root = parse.syntax_node();
435
436    let (censor, item_node, span) = match loc.kind {
437        MacroCallKind::FnLike { ast_id, .. } => {
438            let node = &ast_id.to_ptr(db).to_node(&root);
439            let path_range = node
440                .path()
441                .map_or_else(|| node.syntax().text_range(), |path| path.syntax().text_range());
442            let span = map.span_for_range(path_range);
443
444            let dummy_tt = |kind| {
445                (
446                    Arc::new(tt::TopSubtree::from_token_trees(
447                        tt::Delimiter { open: span, close: span, kind },
448                        tt::TokenTreesView::new(&[]),
449                    )),
450                    SyntaxFixupUndoInfo::default(),
451                    span,
452                )
453            };
454
455            let Some(tt) = node.token_tree() else {
456                return dummy_tt(tt::DelimiterKind::Invisible);
457            };
458            let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']);
459            let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]);
460
461            let mismatched_delimiters = !matches!(
462                (first, last),
463                (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}'])
464            );
465            if mismatched_delimiters {
466                // Don't expand malformed (unbalanced) macro invocations. This is
467                // less than ideal, but trying to expand unbalanced  macro calls
468                // sometimes produces pathological, deeply nested code which breaks
469                // all kinds of things.
470                //
471                // So instead, we'll return an empty subtree here
472                cov_mark::hit!(issue9358_bad_macro_stack_overflow);
473
474                let kind = match first {
475                    _ if loc.def.is_proc_macro() => tt::DelimiterKind::Invisible,
476                    T!['('] => tt::DelimiterKind::Parenthesis,
477                    T!['['] => tt::DelimiterKind::Bracket,
478                    T!['{'] => tt::DelimiterKind::Brace,
479                    _ => tt::DelimiterKind::Invisible,
480                };
481                return dummy_tt(kind);
482            }
483
484            let mut tt = syntax_bridge::syntax_node_to_token_tree(
485                tt.syntax(),
486                map.as_ref(),
487                span,
488                if loc.def.is_proc_macro() {
489                    DocCommentDesugarMode::ProcMacro
490                } else {
491                    DocCommentDesugarMode::Mbe
492                },
493            );
494            if loc.def.is_proc_macro() {
495                // proc macros expect their inputs without parentheses, MBEs expect it with them included
496                tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Invisible;
497            }
498            return (Arc::new(tt), SyntaxFixupUndoInfo::NONE, span);
499        }
500        // MacroCallKind::Derive should not be here. As we are getting the argument for the derive macro
501        MacroCallKind::Derive { .. } => {
502            unreachable!("`ExpandDatabase::macro_arg` called with `MacroCallKind::Derive`")
503        }
504        MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
505            let node = ast_id.to_ptr(db).to_node(&root);
506            let attr_source = attr_source(invoc_attr_index, &node);
507
508            let span = map.span_for_range(
509                attr_source
510                    .as_ref()
511                    .and_then(|it| it.path())
512                    .map_or_else(|| node.syntax().text_range(), |it| it.syntax().text_range()),
513            );
514            // If derive attribute we need to censor the derive input
515            if matches!(loc.def.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive())
516                && ast::Adt::can_cast(node.syntax().kind())
517            {
518                let adt = ast::Adt::cast(node.syntax().clone()).unwrap();
519                let censor_derive_input = censor_derive_input(invoc_attr_index, &adt);
520                (censor_derive_input, node, span)
521            } else {
522                (attr_source.into_iter().map(|it| it.syntax().clone().into()).collect(), node, span)
523            }
524        }
525    };
526
527    let (mut tt, undo_info) = {
528        let syntax = item_node.syntax();
529        let censor_cfg = cfg_process::process_cfg_attrs(db, syntax, &loc).unwrap_or_default();
530        let mut fixups =
531            fixup::fixup_syntax(map.as_ref(), syntax, span, DocCommentDesugarMode::ProcMacro);
532        fixups.append.retain(|it, _| match it {
533            syntax::NodeOrToken::Token(_) => true,
534            it => !censor.contains(it) && !censor_cfg.contains(it),
535        });
536        fixups.remove.extend(censor);
537        fixups.remove.extend(censor_cfg);
538
539        (
540            syntax_bridge::syntax_node_to_token_tree_modified(
541                syntax,
542                map,
543                fixups.append,
544                fixups.remove,
545                span,
546                DocCommentDesugarMode::ProcMacro,
547            ),
548            fixups.undo_info,
549        )
550    };
551
552    if loc.def.is_proc_macro() {
553        // proc macros expect their inputs without parentheses, MBEs expect it with them included
554        tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Invisible;
555    }
556
557    (Arc::new(tt), undo_info, span)
558}
559
560// FIXME: Censoring info should be calculated by the caller! Namely by name resolution
561/// Derives expect all `#[derive(..)]` invocations up to (and including) the currently invoked one to be stripped
562fn censor_derive_input(derive_attr_index: AttrId, node: &ast::Adt) -> FxHashSet<SyntaxElement> {
563    // FIXME: handle `cfg_attr`
564    cov_mark::hit!(derive_censoring);
565    collect_attrs(node)
566        .take(derive_attr_index.ast_index() + 1)
567        .filter_map(|(_, attr)| Either::left(attr))
568        // FIXME, this resolution should not be done syntactically
569        // derive is a proper macro now, no longer builtin
570        // But we do not have resolution at this stage, this means
571        // we need to know about all macro calls for the given ast item here
572        // so we require some kind of mapping...
573        .filter(|attr| attr.simple_name().as_deref() == Some("derive"))
574        .map(|it| it.syntax().clone().into())
575        .collect()
576}
577
578/// Attributes expect the invoking attribute to be stripped
579fn attr_source(invoc_attr_index: AttrId, node: &ast::Item) -> Option<ast::Attr> {
580    // FIXME: handle `cfg_attr`
581    cov_mark::hit!(attribute_macro_attr_censoring);
582    collect_attrs(node).nth(invoc_attr_index.ast_index()).and_then(|(_, attr)| Either::left(attr))
583}
584
585impl TokenExpander {
586    fn macro_expander(db: &dyn ExpandDatabase, id: MacroDefId) -> TokenExpander {
587        match id.kind {
588            MacroDefKind::Declarative(ast_id) => {
589                TokenExpander::DeclarativeMacro(db.decl_macro_expander(id.krate, ast_id))
590            }
591            MacroDefKind::BuiltIn(_, expander) => TokenExpander::BuiltIn(expander),
592            MacroDefKind::BuiltInAttr(_, expander) => TokenExpander::BuiltInAttr(expander),
593            MacroDefKind::BuiltInDerive(_, expander) => TokenExpander::BuiltInDerive(expander),
594            MacroDefKind::BuiltInEager(_, expander) => TokenExpander::BuiltInEager(expander),
595            MacroDefKind::ProcMacro(_, expander, _) => TokenExpander::ProcMacro(expander),
596        }
597    }
598}
599
600enum CowArc<T> {
601    Arc(Arc<T>),
602    Owned(T),
603}
604
605fn macro_expand(
606    db: &dyn ExpandDatabase,
607    macro_call_id: MacroCallId,
608    loc: MacroCallLoc,
609) -> ExpandResult<(CowArc<tt::TopSubtree>, MatchedArmIndex)> {
610    let _p = tracing::info_span!("macro_expand").entered();
611
612    let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind {
613        MacroDefKind::ProcMacro(..) => {
614            return db.expand_proc_macro(macro_call_id).map(CowArc::Arc).zip_val(None);
615        }
616        _ => {
617            let (macro_arg, undo_info, span) =
618                db.macro_arg_considering_derives(macro_call_id, &loc.kind);
619
620            let arg = &*macro_arg;
621            let res =
622                match loc.def.kind {
623                    MacroDefKind::Declarative(id) => db
624                        .decl_macro_expander(loc.def.krate, id)
625                        .expand(db, arg.clone(), macro_call_id, span),
626                    MacroDefKind::BuiltIn(_, it) => {
627                        it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
628                    }
629                    MacroDefKind::BuiltInDerive(_, it) => {
630                        it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
631                    }
632                    MacroDefKind::BuiltInEager(_, it) => {
633                        // This might look a bit odd, but we do not expand the inputs to eager macros here.
634                        // Eager macros inputs are expanded, well, eagerly when we collect the macro calls.
635                        // That kind of expansion uses the ast id map of an eager macros input though which goes through
636                        // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query
637                        // will end up going through here again, whereas we want to just want to inspect the raw input.
638                        // As such we just return the input subtree here.
639                        let eager = match &loc.kind {
640                            MacroCallKind::FnLike { eager: None, .. } => {
641                                return ExpandResult::ok(CowArc::Arc(macro_arg.clone()))
642                                    .zip_val(None);
643                            }
644                            MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
645                            _ => None,
646                        };
647
648                        let mut res = it.expand(db, macro_call_id, arg, span).map_err(Into::into);
649
650                        if let Some(EagerCallInfo { error, .. }) = eager {
651                            // FIXME: We should report both errors!
652                            res.err = error.clone().or(res.err);
653                        }
654                        res.zip_val(None)
655                    }
656                    MacroDefKind::BuiltInAttr(_, it) => {
657                        let mut res = it.expand(db, macro_call_id, arg, span);
658                        fixup::reverse_fixups(&mut res.value, &undo_info);
659                        res.zip_val(None)
660                    }
661                    MacroDefKind::ProcMacro(_, _, _) => unreachable!(),
662                };
663            (ExpandResult { value: res.value, err: res.err }, span)
664        }
665    };
666
667    // Skip checking token tree limit for include! macro call
668    if !loc.def.is_include() {
669        // Set a hard limit for the expanded tt
670        if let Err(value) = check_tt_count(&tt) {
671            return value
672                .map(|()| CowArc::Owned(tt::TopSubtree::empty(tt::DelimSpan::from_single(span))))
673                .zip_val(matched_arm);
674        }
675    }
676
677    ExpandResult { value: (CowArc::Owned(tt), matched_arm), err }
678}
679
680fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
681    let root = db.parse_or_expand(ast.file_id);
682    let ast_id_map = &db.ast_id_map(ast.file_id);
683    let span_map = &db.span_map(ast.file_id);
684
685    let node = ast_id_map.get(ast.value).to_node(&root);
686    let range = ast::HasName::name(&node)
687        .map_or_else(|| node.syntax().text_range(), |name| name.syntax().text_range());
688    span_map.span_for_range(range)
689}
690
691fn expand_proc_macro(
692    db: &dyn ExpandDatabase,
693    id: MacroCallId,
694) -> ExpandResult<Arc<tt::TopSubtree>> {
695    let loc = db.lookup_intern_macro_call(id);
696    let (macro_arg, undo_info, span) = db.macro_arg_considering_derives(id, &loc.kind);
697
698    let (ast, expander) = match loc.def.kind {
699        MacroDefKind::ProcMacro(ast, expander, _) => (ast, expander),
700        _ => unreachable!(),
701    };
702
703    let attr_arg = match &loc.kind {
704        MacroCallKind::Attr { attr_args: Some(attr_args), .. } => Some(&**attr_args),
705        _ => None,
706    };
707
708    let ExpandResult { value: mut tt, err } = {
709        let span = db.proc_macro_span(ast);
710        expander.expand(
711            db,
712            loc.def.krate,
713            loc.krate,
714            &macro_arg,
715            attr_arg,
716            span_with_def_site_ctxt(db, span, id.into(), loc.def.edition),
717            span_with_call_site_ctxt(db, span, id.into(), loc.def.edition),
718            span_with_mixed_site_ctxt(db, span, id.into(), loc.def.edition),
719        )
720    };
721
722    // Set a hard limit for the expanded tt
723    if let Err(value) = check_tt_count(&tt) {
724        return value.map(|()| Arc::new(tt::TopSubtree::empty(tt::DelimSpan::from_single(span))));
725    }
726
727    fixup::reverse_fixups(&mut tt, &undo_info);
728
729    ExpandResult { value: Arc::new(tt), err }
730}
731
732pub(crate) fn token_tree_to_syntax_node(
733    db: &dyn ExpandDatabase,
734    tt: &tt::TopSubtree,
735    expand_to: ExpandTo,
736    edition: parser::Edition,
737) -> (Parse<SyntaxNode>, ExpansionSpanMap) {
738    let entry_point = match expand_to {
739        ExpandTo::Statements => syntax_bridge::TopEntryPoint::MacroStmts,
740        ExpandTo::Items => syntax_bridge::TopEntryPoint::MacroItems,
741        ExpandTo::Pattern => syntax_bridge::TopEntryPoint::Pattern,
742        ExpandTo::Type => syntax_bridge::TopEntryPoint::Type,
743        ExpandTo::Expr => syntax_bridge::TopEntryPoint::Expr,
744    };
745    syntax_bridge::token_tree_to_syntax_node(tt, entry_point, &mut |ctx| ctx.edition(db), edition)
746}
747
748fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> {
749    let tt = tt.top_subtree();
750    let count = tt.count();
751    if count <= TOKEN_LIMIT {
752        Ok(())
753    } else {
754        Err(ExpandResult {
755            value: (),
756            err: Some(ExpandError::other(
757                tt.delimiter.open,
758                format!(
759                    "macro invocation exceeds token limit: produced {count} tokens, limit is {TOKEN_LIMIT}",
760                ),
761            )),
762        })
763    }
764}
765
766fn intern_macro_call(db: &dyn ExpandDatabase, macro_call: MacroCallLoc) -> MacroCallId {
767    MacroCallId::new(db, macro_call)
768}
769
770fn lookup_intern_macro_call(db: &dyn ExpandDatabase, macro_call: MacroCallId) -> MacroCallLoc {
771    macro_call.loc(db)
772}