Skip to main content

hir_expand/
lib.rs

1//! `hir_expand` deals with macro expansion.
2//!
3//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax
4//! tree originates not from the text of some `FileId`, but from some macro
5//! expansion.
6#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
7// It's useful to refer to code that is private in doc comments.
8#![allow(rustdoc::private_intra_doc_links)]
9
10pub use intern;
11
12pub mod attrs;
13pub mod builtin;
14pub mod change;
15pub mod declarative;
16pub mod eager;
17pub mod files;
18pub mod hygiene;
19pub mod inert_attr_macro;
20pub mod mod_path;
21pub mod name;
22pub mod proc_macro;
23pub mod span_map;
24
25mod cfg_process;
26mod fixup;
27mod prettify_macro_expansion_;
28
29use salsa::plumbing::{AsId, FromId};
30use thin_vec::ThinVec;
31use triomphe::Arc;
32
33use core::fmt;
34use std::{borrow::Cow, ops};
35
36use base_db::{Crate, SourceDatabase};
37use either::Either;
38use mbe::MatchedArmIndex;
39use span::{
40    AstIdMap, Edition, ErasedFileAstId, FileAstId, NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER, Span,
41    SyntaxContext,
42};
43use syntax::{
44    Parse, SyntaxError, SyntaxNode, SyntaxToken, T, TextRange, TextSize,
45    ast::{self, AstNode},
46};
47use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree};
48
49use crate::{
50    attrs::AttrId,
51    builtin::{
52        BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander,
53        include_input_to_file_id, pseudo_derive_attr_expansion,
54    },
55    cfg_process::attr_macro_input_to_token_tree,
56    fixup::SyntaxFixupUndoInfo,
57    hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt},
58    proc_macro::{CustomProcMacroExpander, ProcMacroKind, ProcMacros},
59    span_map::{ExpansionSpanMap, RealSpanMap, SpanMap},
60};
61
62pub use crate::{
63    files::{AstId, ErasedAstId, FileRange, InFile, InMacroFile, InRealFile},
64    prettify_macro_expansion_::prettify_macro_expansion,
65};
66
67pub use base_db::EditionedFileId;
68pub use mbe::{DeclarativeMacro, MacroCallStyle, MacroCallStyles, ValueResult};
69
70pub use tt;
71
72/// This is just to ensure the types of [`MacroCallId::macro_arg_considering_derives`]
73/// and [`MacroCallId::macro_arg`] are the same.
74type MacroArgResult = (tt::TopSubtree, SyntaxFixupUndoInfo, Span);
75
76/// Total limit on the number of tokens produced by any macro invocation.
77///
78/// If an invocation produces more tokens than this limit, it will not be stored in the database and
79/// an error will be emitted.
80///
81/// Actual max for `analysis-stats .` at some point: 30672.
82const TOKEN_LIMIT: usize = 2_097_152;
83
84#[macro_export]
85macro_rules! impl_intern_lookup {
86    ($id:ident, $loc:ident) => {
87        impl $crate::Intern for $loc {
88            type ID = $id;
89            fn intern(self, db: &dyn ::base_db::SourceDatabase) -> Self::ID {
90                $id::new(db, self)
91            }
92        }
93
94        impl $crate::Lookup for $id {
95            type Data = $loc;
96            fn lookup<'db>(&self, db: &'db dyn ::base_db::SourceDatabase) -> &'db Self::Data {
97                self.loc(db)
98            }
99        }
100    };
101}
102
103// ideally these would be defined in base-db, but the orphan rule doesn't let us
104pub trait Intern {
105    type ID;
106    fn intern(self, db: &dyn SourceDatabase) -> Self::ID;
107}
108
109pub trait Lookup {
110    type Data;
111    fn lookup<'db>(&self, db: &'db dyn SourceDatabase) -> &'db Self::Data;
112}
113
114impl_intern_lookup!(MacroCallId, MacroCallLoc);
115
116pub type ExpandResult<T> = ValueResult<T, ExpandError>;
117
118#[derive(Debug, PartialEq, Eq, Clone, Hash)]
119pub struct ExpandError {
120    inner: Arc<(ExpandErrorKind, Span)>,
121}
122
123impl ExpandError {
124    pub fn new(span: Span, kind: ExpandErrorKind) -> Self {
125        ExpandError { inner: Arc::new((kind, span)) }
126    }
127    pub fn other(span: Span, msg: impl Into<Box<str>>) -> Self {
128        ExpandError { inner: Arc::new((ExpandErrorKind::Other(msg.into()), span)) }
129    }
130    pub fn kind(&self) -> &ExpandErrorKind {
131        &self.inner.0
132    }
133    pub fn span(&self) -> Span {
134        self.inner.1
135    }
136
137    pub fn render_to_string(&self, db: &dyn SourceDatabase) -> RenderedExpandError {
138        self.inner.0.render_to_string(db)
139    }
140}
141
142#[derive(Debug, PartialEq, Eq, Clone, Hash)]
143pub enum ExpandErrorKind {
144    /// Attribute macro expansion is disabled.
145    ProcMacroAttrExpansionDisabled,
146    MissingProcMacroExpander(Crate),
147    /// The macro for this call is disabled.
148    MacroDisabled,
149    /// The macro definition has errors.
150    MacroDefinition,
151    Mbe(mbe::ExpandErrorKind),
152    RecursionOverflow,
153    Other(Box<str>),
154    ProcMacroPanic(Box<str>),
155}
156
157pub struct RenderedExpandError {
158    pub message: String,
159    pub error: bool,
160    pub kind: &'static str,
161}
162
163impl fmt::Display for RenderedExpandError {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        write!(f, "{}", self.message)
166    }
167}
168
169impl RenderedExpandError {
170    const GENERAL_KIND: &str = "macro-error";
171    const DISABLED: &str = "proc-macro-disabled";
172    const ATTR_EXP_DISABLED: &str = "attribute-expansion-disabled";
173}
174
175impl ExpandErrorKind {
176    pub fn render_to_string(&self, db: &dyn SourceDatabase) -> RenderedExpandError {
177        match self {
178            ExpandErrorKind::ProcMacroAttrExpansionDisabled => RenderedExpandError {
179                message: "procedural attribute macro expansion is disabled".to_owned(),
180                error: false,
181                kind: RenderedExpandError::ATTR_EXP_DISABLED,
182            },
183            ExpandErrorKind::MacroDisabled => RenderedExpandError {
184                message: "proc-macro is explicitly disabled".to_owned(),
185                error: false,
186                kind: RenderedExpandError::DISABLED,
187            },
188            &ExpandErrorKind::MissingProcMacroExpander(def_crate) => {
189                match ProcMacros::get_for_crate(db, def_crate).and_then(|it| it.get_error()) {
190                    Some(e) => RenderedExpandError {
191                        message: e.to_string(),
192                        error: e.is_hard_error(),
193                        kind: RenderedExpandError::GENERAL_KIND,
194                    },
195                    None => RenderedExpandError {
196                        message: format!(
197                            "internal error: proc-macro map is missing error entry for crate {def_crate:?}"
198                        ),
199                        error: true,
200                        kind: RenderedExpandError::GENERAL_KIND,
201                    },
202                }
203            }
204            ExpandErrorKind::MacroDefinition => RenderedExpandError {
205                message: "macro definition has parse errors".to_owned(),
206                error: true,
207                kind: RenderedExpandError::GENERAL_KIND,
208            },
209            ExpandErrorKind::Mbe(e) => RenderedExpandError {
210                message: e.to_string(),
211                error: true,
212                kind: RenderedExpandError::GENERAL_KIND,
213            },
214            ExpandErrorKind::RecursionOverflow => RenderedExpandError {
215                message: "overflow expanding the original macro".to_owned(),
216                error: true,
217                kind: RenderedExpandError::GENERAL_KIND,
218            },
219            ExpandErrorKind::Other(e) => RenderedExpandError {
220                message: (**e).to_owned(),
221                error: true,
222                kind: RenderedExpandError::GENERAL_KIND,
223            },
224            ExpandErrorKind::ProcMacroPanic(e) => RenderedExpandError {
225                message: format!("proc-macro panicked: {e}"),
226                error: true,
227                kind: RenderedExpandError::GENERAL_KIND,
228            },
229        }
230    }
231}
232
233impl From<mbe::ExpandError> for ExpandError {
234    fn from(mbe: mbe::ExpandError) -> Self {
235        ExpandError { inner: Arc::new((ExpandErrorKind::Mbe(mbe.inner.1.clone()), mbe.inner.0)) }
236    }
237}
238#[derive(Debug, Clone, PartialEq, Eq, Hash)]
239pub struct MacroCallLoc {
240    pub def: MacroDefId,
241    pub krate: Crate,
242    pub kind: MacroCallKind,
243    pub ctxt: SyntaxContext,
244    /// The macro recursion depth of this expansion.
245    ///
246    /// Because macro expansions can cross `DefMap` boundaries, we must track this inside the expansion
247    /// to not recurse infinitely.
248    pub macro_depth: u32,
249}
250
251#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
252pub struct MacroDefId {
253    pub krate: Crate,
254    pub edition: Edition,
255    pub kind: MacroDefKind,
256    pub local_inner: bool,
257    pub allow_internal_unsafe: bool,
258}
259
260#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
261pub enum MacroDefKind {
262    Declarative(AstId<ast::Macro>, MacroCallStyles),
263    BuiltIn(AstId<ast::Macro>, BuiltinFnLikeExpander),
264    BuiltInAttr(AstId<ast::Macro>, BuiltinAttrExpander),
265    BuiltInDerive(AstId<ast::Macro>, BuiltinDeriveExpander),
266    BuiltInEager(AstId<ast::Macro>, EagerExpander),
267    UnimplementedBuiltIn(AstId<ast::Macro>),
268    ProcMacro(AstId<ast::Fn>, CustomProcMacroExpander, ProcMacroKind),
269}
270
271impl MacroDefKind {
272    #[inline]
273    pub fn is_declarative(&self) -> bool {
274        matches!(self, MacroDefKind::Declarative(..))
275    }
276
277    pub fn erased_ast_id(&self) -> ErasedAstId {
278        match *self {
279            MacroDefKind::ProcMacro(id, ..) => id.erase(),
280            MacroDefKind::BuiltIn(id, _)
281            | MacroDefKind::BuiltInAttr(id, _)
282            | MacroDefKind::BuiltInDerive(id, _)
283            | MacroDefKind::BuiltInEager(id, _)
284            | MacroDefKind::Declarative(id, ..)
285            | MacroDefKind::UnimplementedBuiltIn(id) => id.erase(),
286        }
287    }
288}
289
290#[derive(Debug, Clone, PartialEq, Eq, Hash)]
291pub struct EagerCallInfo {
292    /// The expanded argument of the eager macro.
293    arg: tt::TopSubtree,
294    /// Call id of the eager macro's input file (this is the macro file for its fully expanded input).
295    arg_id: MacroCallId,
296    error: Option<ExpandError>,
297    /// The call site span of the eager macro
298    span: Span,
299}
300
301#[derive(Debug, Clone, PartialEq, Eq, Hash)]
302pub enum MacroCallKind {
303    FnLike {
304        ast_id: AstId<ast::MacroCall>,
305        expand_to: ExpandTo,
306        /// Some if this is a macro call for an eager macro. Note that this is `None`
307        /// for the eager input macro file.
308        // FIXME: This is being interned, subtrees can vary quickly differing just slightly causing
309        // leakage problems here
310        eager: Option<Box<EagerCallInfo>>,
311    },
312    Derive {
313        ast_id: AstId<ast::Adt>,
314        /// Syntactical index of the invoking `#[derive]` attribute.
315        derive_attr_index: AttrId,
316        /// Index of the derive macro in the derive attribute
317        derive_index: u32,
318        /// The "parent" macro call.
319        /// We will resolve the same token tree for all derive macros in the same derive attribute.
320        derive_macro_id: MacroCallId,
321    },
322    Attr {
323        ast_id: AstId<ast::Item>,
324        // FIXME: This shouldn't be here, we can derive this from `invoc_attr_index`.
325        attr_args: Option<Box<tt::TopSubtree>>,
326        /// This contains the list of all *active* attributes (derives and attr macros) preceding this
327        /// attribute, including this attribute. You can retrieve the [`AttrId`] of the current attribute
328        /// by calling [`invoc_attr()`] on this.
329        ///
330        /// The macro should not see the attributes here.
331        ///
332        /// [`invoc_attr()`]: AttrMacroAttrIds::invoc_attr
333        censored_attr_ids: AttrMacroAttrIds,
334    },
335}
336
337#[derive(Debug, Clone, PartialEq, Eq, Hash)]
338pub struct AttrMacroAttrIds(AttrMacroAttrIdsRepr);
339
340impl AttrMacroAttrIds {
341    #[inline]
342    pub fn from_one(id: AttrId) -> Self {
343        Self(AttrMacroAttrIdsRepr::One(id))
344    }
345
346    #[inline]
347    pub fn from_many(ids: &[AttrId]) -> Self {
348        if let &[id] = ids {
349            Self(AttrMacroAttrIdsRepr::One(id))
350        } else {
351            Self(AttrMacroAttrIdsRepr::ManyDerives(ids.iter().copied().collect()))
352        }
353    }
354}
355
356#[derive(Debug, Clone, PartialEq, Eq, Hash)]
357enum AttrMacroAttrIdsRepr {
358    One(AttrId),
359    ManyDerives(ThinVec<AttrId>),
360}
361
362impl ops::Deref for AttrMacroAttrIds {
363    type Target = [AttrId];
364
365    #[inline]
366    fn deref(&self) -> &Self::Target {
367        match &self.0 {
368            AttrMacroAttrIdsRepr::One(one) => std::slice::from_ref(one),
369            AttrMacroAttrIdsRepr::ManyDerives(many) => many,
370        }
371    }
372}
373
374impl AttrMacroAttrIds {
375    #[inline]
376    pub fn invoc_attr(&self) -> AttrId {
377        match &self.0 {
378            AttrMacroAttrIdsRepr::One(it) => *it,
379            AttrMacroAttrIdsRepr::ManyDerives(it) => {
380                *it.last().expect("should always have at least one `AttrId`")
381            }
382        }
383    }
384}
385
386impl MacroCallKind {
387    pub(crate) fn call_style(&self) -> MacroCallStyle {
388        match self {
389            MacroCallKind::FnLike { .. } => MacroCallStyle::FnLike,
390            MacroCallKind::Derive { .. } => MacroCallStyle::Derive,
391            MacroCallKind::Attr { .. } => MacroCallStyle::Attr,
392        }
393    }
394}
395
396#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
397pub enum MacroKind {
398    /// `macro_rules!` or Macros 2.0 macro.
399    Declarative,
400    /// A built-in function-like macro.
401    DeclarativeBuiltIn,
402    /// A custom derive.
403    Derive,
404    /// A builtin-in derive.
405    DeriveBuiltIn,
406    /// A procedural attribute macro.
407    Attr,
408    /// A built-in attribute macro.
409    AttrBuiltIn,
410    /// A function-like procedural macro.
411    ProcMacro,
412}
413
414impl MacroCallId {
415    pub fn call_node(self, db: &dyn SourceDatabase) -> InFile<SyntaxNode> {
416        self.loc(db).to_node(db)
417    }
418    pub fn expansion_level(self, db: &dyn SourceDatabase) -> u32 {
419        let mut level = 0;
420        let mut macro_file = self;
421        loop {
422            let loc = macro_file.loc(db);
423
424            level += 1;
425            macro_file = match loc.kind.file_id() {
426                HirFileId::FileId(_) => break level,
427                HirFileId::MacroFile(it) => it,
428            };
429        }
430    }
431    pub fn parent(self, db: &dyn SourceDatabase) -> HirFileId {
432        self.loc(db).kind.file_id()
433    }
434
435    /// Return expansion information if it is a macro-expansion file
436    pub fn expansion_info(self, db: &dyn SourceDatabase) -> ExpansionInfo<'_> {
437        ExpansionInfo::new(db, self)
438    }
439
440    pub fn kind(self, db: &dyn SourceDatabase) -> MacroKind {
441        match self.loc(db).def.kind {
442            MacroDefKind::Declarative(..) => MacroKind::Declarative,
443            MacroDefKind::BuiltIn(..) | MacroDefKind::BuiltInEager(..) => {
444                MacroKind::DeclarativeBuiltIn
445            }
446            MacroDefKind::BuiltInDerive(..) => MacroKind::DeriveBuiltIn,
447            MacroDefKind::ProcMacro(_, _, ProcMacroKind::CustomDerive) => MacroKind::Derive,
448            MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr) => MacroKind::Attr,
449            MacroDefKind::ProcMacro(_, _, ProcMacroKind::Bang) => MacroKind::ProcMacro,
450            MacroDefKind::BuiltInAttr(..) => MacroKind::AttrBuiltIn,
451            MacroDefKind::UnimplementedBuiltIn(..) => MacroKind::Declarative,
452        }
453    }
454
455    pub fn is_include_macro(self, db: &dyn SourceDatabase) -> bool {
456        self.loc(db).def.is_include()
457    }
458
459    pub fn is_include_like_macro(self, db: &dyn SourceDatabase) -> bool {
460        self.loc(db).def.is_include_like()
461    }
462
463    pub fn is_env_or_option_env(self, db: &dyn SourceDatabase) -> bool {
464        self.loc(db).def.is_env_or_option_env()
465    }
466
467    pub fn is_eager(self, db: &dyn SourceDatabase) -> bool {
468        let loc = self.loc(db);
469        matches!(loc.def.kind, MacroDefKind::BuiltInEager(..))
470    }
471
472    pub fn eager_arg(self, db: &dyn SourceDatabase) -> Option<MacroCallId> {
473        let loc = self.loc(db);
474        match &loc.kind {
475            MacroCallKind::FnLike { eager, .. } => eager.as_ref().map(|it| it.arg_id),
476            _ => None,
477        }
478    }
479
480    pub fn is_derive_attr_pseudo_expansion(self, db: &dyn SourceDatabase) -> bool {
481        let loc = self.loc(db);
482        loc.def.is_attribute_derive()
483    }
484}
485
486#[salsa::tracked]
487impl MacroCallId {
488    /// Implementation of [`HirFileId::parse_or_expand`] for the macro case.
489    // FIXME: We should verify that the parsed node is one of the many macro node variants we expect
490    // instead of having it be untyped
491    #[salsa::tracked(returns(ref), lru = 512)]
492    pub fn parse_macro_expansion(
493        self,
494        db: &dyn SourceDatabase,
495    ) -> ExpandResult<(Parse<SyntaxNode>, ExpansionSpanMap)> {
496        let _p = tracing::info_span!("parse_macro_expansion").entered();
497        let loc = self.loc(db);
498        let expand_to = loc.expand_to();
499        let mbe::ValueResult { value: (tt, matched_arm), err } = self.macro_expand(db, loc);
500
501        let (parse, mut rev_token_map) = token_tree_to_syntax_node(db, &tt, expand_to);
502        rev_token_map.matched_arm = matched_arm;
503
504        ExpandResult { value: (parse, rev_token_map), err }
505    }
506
507    pub fn parse_macro_expansion_error(
508        self,
509        db: &dyn SourceDatabase,
510    ) -> Option<ExpandResult<Arc<[SyntaxError]>>> {
511        let e: ExpandResult<Arc<[SyntaxError]>> =
512            self.parse_macro_expansion(db).as_ref().map(|it| Arc::from(it.0.errors()));
513        if e.value.is_empty() && e.err.is_none() { None } else { Some(e) }
514    }
515
516    /// This resolves the [MacroCallId] to check if it is a derive macro if so get the [macro_arg] for the derive.
517    /// Other wise return the [macro_arg] for the macro_call_id.
518    ///
519    /// This is not connected to the database so it does not cache the result. However, the inner [macro_arg] query is
520    ///
521    /// [macro_arg]: Self::macro_arg
522    #[expect(deprecated, reason = "we are `macro_arg_considering_derives`")]
523    pub fn macro_arg_considering_derives<'db>(
524        self,
525        db: &'db dyn SourceDatabase,
526        kind: &MacroCallKind,
527    ) -> &'db MacroArgResult {
528        match kind {
529            // Get the macro arg for the derive macro
530            MacroCallKind::Derive { derive_macro_id, .. } => derive_macro_id.macro_arg(db),
531            // Normal macro arg
532            _ => self.macro_arg(db),
533        }
534    }
535
536    /// Lowers syntactic macro call to a token tree representation. That's a firewall
537    /// query, only typing in the macro call itself changes the returned
538    /// subtree.
539    #[salsa::tracked(returns(ref))]
540    #[deprecated = "calling this is incorrect, call `macro_arg_considering_derives` instead"]
541    fn macro_arg(self, db: &dyn SourceDatabase) -> MacroArgResult {
542        let loc = self.loc(db);
543
544        if let MacroCallLoc {
545            def: MacroDefId { kind: MacroDefKind::BuiltInEager(..), .. },
546            kind: MacroCallKind::FnLike { eager: Some(eager), .. },
547            ..
548        } = &loc
549        {
550            return (eager.arg.clone(), SyntaxFixupUndoInfo::NONE, eager.span);
551        }
552
553        let (parse, map) = loc.kind.file_id().parse_with_map(db);
554        let root = parse.syntax_node();
555
556        let (is_derive, censor_item_tree_attr_ids, item_node, span) = match &loc.kind {
557            MacroCallKind::FnLike { ast_id, .. } => {
558                let node = &ast_id.to_ptr(db).to_node(&root);
559                let path_range = node
560                    .path()
561                    .map_or_else(|| node.syntax().text_range(), |path| path.syntax().text_range());
562                let span = map.span_for_range(path_range);
563
564                let dummy_tt = |kind| {
565                    (
566                        tt::TopSubtree::from_token_trees(
567                            tt::Delimiter { open: span, close: span, kind },
568                            tt::TokenTreesView::empty(),
569                        ),
570                        SyntaxFixupUndoInfo::default(),
571                        span,
572                    )
573                };
574
575                let Some(tt) = node.token_tree() else {
576                    return dummy_tt(tt::DelimiterKind::Invisible);
577                };
578                let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']);
579                let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]);
580
581                let mismatched_delimiters = !matches!(
582                    (first, last),
583                    (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}'])
584                );
585                if mismatched_delimiters {
586                    // Don't expand malformed (unbalanced) macro invocations. This is
587                    // less than ideal, but trying to expand unbalanced  macro calls
588                    // sometimes produces pathological, deeply nested code which breaks
589                    // all kinds of things.
590                    //
591                    // So instead, we'll return an empty subtree here
592                    cov_mark::hit!(issue9358_bad_macro_stack_overflow);
593
594                    let kind = match first {
595                        _ if loc.def.is_proc_macro() => tt::DelimiterKind::Invisible,
596                        T!['('] => tt::DelimiterKind::Parenthesis,
597                        T!['['] => tt::DelimiterKind::Bracket,
598                        T!['{'] => tt::DelimiterKind::Brace,
599                        _ => tt::DelimiterKind::Invisible,
600                    };
601                    return dummy_tt(kind);
602                }
603
604                let mut tt = syntax_bridge::syntax_node_to_token_tree(
605                    tt.syntax(),
606                    map,
607                    span,
608                    if loc.def.is_proc_macro() {
609                        DocCommentDesugarMode::ProcMacro
610                    } else {
611                        DocCommentDesugarMode::Mbe
612                    },
613                );
614                if loc.def.is_proc_macro() {
615                    // proc macros expect their inputs without parentheses, MBEs expect it with them included
616                    tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
617                }
618                return (tt, SyntaxFixupUndoInfo::NONE, span);
619            }
620            // MacroCallKind::Derive should not be here. As we are getting the argument for the derive macro
621            MacroCallKind::Derive { .. } => {
622                unreachable!("`MacroCallId::macro_arg` called with `MacroCallKind::Derive`")
623            }
624            MacroCallKind::Attr { ast_id, censored_attr_ids: attr_ids, .. } => {
625                let node = ast_id.to_ptr(db).to_node(&root);
626                let (_, attr) =
627                    attr_ids.invoc_attr().find_attr_range_with_source(db, loc.krate, &node);
628                let range = attr
629                    .path()
630                    .map(|path| path.syntax().text_range())
631                    .unwrap_or_else(|| attr.syntax().text_range());
632                let span = map.span_for_range(range);
633
634                let is_derive = matches!(loc.def.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive());
635                (is_derive, &**attr_ids, node, span)
636            }
637        };
638
639        let (mut tt, undo_info) = attr_macro_input_to_token_tree(
640            db,
641            item_node.syntax(),
642            map,
643            span,
644            is_derive,
645            censor_item_tree_attr_ids,
646            loc.krate,
647        );
648
649        if loc.def.is_proc_macro() {
650            // proc macros expect their inputs without parentheses, MBEs expect it with them included
651            tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
652        }
653
654        (tt, undo_info, span)
655    }
656
657    fn macro_expand<'db>(
658        self,
659        db: &'db dyn SourceDatabase,
660        loc: &MacroCallLoc,
661    ) -> ExpandResult<(Cow<'db, tt::TopSubtree>, MatchedArmIndex)> {
662        let _p = tracing::info_span!("macro_expand").entered();
663
664        let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind {
665            MacroDefKind::ProcMacro(..) => {
666                return self.expand_proc_macro(db).as_ref().map(|it| (Cow::Borrowed(it), None));
667            }
668            _ => {
669                let (macro_arg, undo_info, span) =
670                    self.macro_arg_considering_derives(db, &loc.kind);
671                let span = *span;
672
673                let arg = macro_arg;
674                let res = match loc.def.kind {
675                    MacroDefKind::Declarative(id, _) => {
676                        id.decl_macro_expander(db, loc.def.krate).expand(db, arg, self, span)
677                    }
678                    MacroDefKind::BuiltIn(_, it) => {
679                        it.expand(db, self, arg, span).map_err(Into::into).zip_val(None)
680                    }
681                    MacroDefKind::BuiltInDerive(_, it) => {
682                        it.expand(db, self, arg, span).map_err(Into::into).zip_val(None)
683                    }
684                    MacroDefKind::UnimplementedBuiltIn(_) => {
685                        expand_unimplemented_builtin_macro(span).zip_val(None)
686                    }
687                    MacroDefKind::BuiltInEager(_, it) => {
688                        // This might look a bit odd, but we do not expand the inputs to eager macros here.
689                        // Eager macros inputs are expanded, well, eagerly when we collect the macro calls.
690                        // That kind of expansion uses the ast id map of an eager macros input though which goes through
691                        // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query
692                        // will end up going through here again, whereas we want to just want to inspect the raw input.
693                        // As such we just return the input subtree here.
694                        let eager = match &loc.kind {
695                            MacroCallKind::FnLike { eager: None, .. } => {
696                                return ExpandResult::ok(Cow::Borrowed(macro_arg)).zip_val(None);
697                            }
698                            MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
699                            _ => None,
700                        };
701
702                        let mut res = it.expand(db, self, arg, span).map_err(Into::into);
703
704                        if let Some(EagerCallInfo { error, .. }) = eager {
705                            // FIXME: We should report both errors!
706                            res.err = error.clone().or(res.err);
707                        }
708                        res.zip_val(None)
709                    }
710                    MacroDefKind::BuiltInAttr(_, it) => {
711                        let mut res = it.expand(db, self, arg, span);
712                        fixup::reverse_fixups(&mut res.value, undo_info);
713                        res.zip_val(None)
714                    }
715                    MacroDefKind::ProcMacro(_, _, _) => unreachable!(),
716                };
717                (res, span)
718            }
719        };
720
721        // Skip checking token tree limit for include! macro call
722        if !loc.def.is_include() {
723            // Set a hard limit for the expanded tt
724            if let Err(value) = check_tt_count(&tt) {
725                return value
726                    .map(|()| Cow::Owned(tt::TopSubtree::empty(tt::DelimSpan::from_single(span))))
727                    .zip_val(matched_arm);
728            }
729        }
730
731        ExpandResult { value: (Cow::Owned(tt), matched_arm), err }
732    }
733
734    /// Special case of [`Self::macro_expand`] for procedural macros. We can't LRU
735    /// proc macros, since they are not deterministic in general, and
736    /// non-determinism breaks salsa in a very, very, very bad way.
737    /// @edwin0cheng heroically debugged this once! See #4315 for details
738    #[salsa::tracked(returns(ref))]
739    fn expand_proc_macro(self, db: &dyn SourceDatabase) -> ExpandResult<tt::TopSubtree> {
740        let loc = self.loc(db);
741        let (macro_arg, undo_info, span) = self.macro_arg_considering_derives(db, &loc.kind);
742
743        let (ast, expander) = match loc.def.kind {
744            MacroDefKind::ProcMacro(ast, expander, _) => (ast, expander),
745            _ => unreachable!(),
746        };
747
748        let attr_arg = match &loc.kind {
749            MacroCallKind::Attr { attr_args: Some(attr_args), .. } => Some(&**attr_args),
750            _ => None,
751        };
752
753        let ExpandResult { value: mut tt, err } = {
754            let span = proc_macro_span(db, ast);
755            expander.expand(
756                db,
757                loc.def.krate,
758                loc.krate,
759                macro_arg,
760                attr_arg,
761                span_with_def_site_ctxt(db, span, self.into(), loc.def.edition),
762                span_with_call_site_ctxt(db, span, self.into(), loc.def.edition),
763                span_with_mixed_site_ctxt(db, span, self.into(), loc.def.edition),
764            )
765        };
766
767        // Set a hard limit for the expanded tt
768        if let Err(value) = check_tt_count(&tt) {
769            return value.map(|()| tt::TopSubtree::empty(tt::DelimSpan::from_single(*span)));
770        }
771
772        fixup::reverse_fixups(&mut tt, undo_info);
773
774        ExpandResult { value: tt, err }
775    }
776}
777
778impl MacroCallId {
779    /// This expands the given macro call, but with different arguments. This is
780    /// used for completion, where we want to see what 'would happen' if we insert a
781    /// token. The `token_to_map` mapped down into the expansion, with the mapped
782    /// token(s) returned with their priority.
783    pub fn expand_speculative(
784        self,
785        db: &dyn SourceDatabase,
786        speculative_args: &SyntaxNode,
787        token_to_map: SyntaxToken,
788    ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
789        let loc = self.loc(db);
790        let (_, _, span) = *self.macro_arg_considering_derives(db, &loc.kind);
791
792        let span_map = RealSpanMap::absolute(span.anchor.file_id);
793        let span_map = SpanMap::RealSpanMap(&span_map);
794
795        // Build the subtree and token mapping for the speculative args
796        let (mut tt, undo_info) = match &loc.kind {
797            MacroCallKind::FnLike { .. } => (
798                syntax_bridge::syntax_node_to_token_tree(
799                    speculative_args,
800                    span_map,
801                    span,
802                    if loc.def.is_proc_macro() {
803                        DocCommentDesugarMode::ProcMacro
804                    } else {
805                        DocCommentDesugarMode::Mbe
806                    },
807                ),
808                SyntaxFixupUndoInfo::NONE,
809            ),
810            MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => (
811                syntax_bridge::syntax_node_to_token_tree(
812                    speculative_args,
813                    span_map,
814                    span,
815                    DocCommentDesugarMode::ProcMacro,
816                ),
817                SyntaxFixupUndoInfo::NONE,
818            ),
819            MacroCallKind::Derive { derive_macro_id, .. } => {
820                let MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } =
821                    &derive_macro_id.loc(db).kind
822                else {
823                    unreachable!("`derive_macro_id` should be `MacroCallKind::Attr`");
824                };
825                attr_macro_input_to_token_tree(
826                    db,
827                    speculative_args,
828                    span_map,
829                    span,
830                    true,
831                    attr_ids,
832                    loc.krate,
833                )
834            }
835            MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => {
836                attr_macro_input_to_token_tree(
837                    db,
838                    speculative_args,
839                    span_map,
840                    span,
841                    false,
842                    attr_ids,
843                    loc.krate,
844                )
845            }
846        };
847
848        let attr_arg = match &loc.kind {
849            MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => {
850                if loc.def.is_attribute_derive() {
851                    // for pseudo-derive expansion we actually pass the attribute itself only
852                    ast::Attr::cast(speculative_args.clone())
853                        .and_then(|attr| {
854                            if let ast::Meta::TokenTreeMeta(meta) = attr.meta()? {
855                                meta.token_tree()
856                            } else {
857                                None
858                            }
859                        })
860                        .map(|token_tree| {
861                            let mut tree = syntax_node_to_token_tree(
862                                token_tree.syntax(),
863                                span_map,
864                                span,
865                                DocCommentDesugarMode::ProcMacro,
866                            );
867                            tree.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
868                            tree.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span));
869                            tree
870                        })
871                } else {
872                    // Attributes may have an input token tree, build the subtree and map for this as well
873                    // then try finding a token id for our token if it is inside this input subtree.
874                    let item = ast::Item::cast(speculative_args.clone())?;
875                    let (_, meta) = attr_ids
876                        .invoc_attr()
877                        .find_attr_range_with_source_opt(db, loc.krate, &item)?;
878                    if let ast::Meta::TokenTreeMeta(meta) = meta
879                        && let Some(tt) = meta.token_tree()
880                    {
881                        let mut attr_arg = syntax_bridge::syntax_node_to_token_tree(
882                            tt.syntax(),
883                            span_map,
884                            span,
885                            DocCommentDesugarMode::ProcMacro,
886                        );
887                        attr_arg.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
888                        Some(attr_arg)
889                    } else {
890                        None
891                    }
892                }
893            }
894            _ => None,
895        };
896
897        // Do the actual expansion, we need to directly expand the proc macro due to the attribute args
898        // Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
899        let mut speculative_expansion = match loc.def.kind {
900            MacroDefKind::ProcMacro(ast, expander, _) => {
901                let span = proc_macro_span(db, ast);
902                tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
903                tt.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span));
904                expander.expand(
905                    db,
906                    loc.def.krate,
907                    loc.krate,
908                    &tt,
909                    attr_arg.as_ref(),
910                    span_with_def_site_ctxt(db, span, self.into(), loc.def.edition),
911                    span_with_call_site_ctxt(db, span, self.into(), loc.def.edition),
912                    span_with_mixed_site_ctxt(db, span, self.into(), loc.def.edition),
913                )
914            }
915            MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => {
916                pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span)
917            }
918            MacroDefKind::Declarative(it, _) => it
919                .decl_macro_expander(db, loc.krate)
920                .expand_unhygienic(db, &tt, loc.kind.call_style(), span),
921            MacroDefKind::BuiltIn(_, it) => it.expand(db, self, &tt, span).map_err(Into::into),
922            MacroDefKind::BuiltInDerive(_, it) => {
923                it.expand(db, self, &tt, span).map_err(Into::into)
924            }
925            MacroDefKind::BuiltInEager(_, it) => it.expand(db, self, &tt, span).map_err(Into::into),
926            MacroDefKind::BuiltInAttr(_, it) => it.expand(db, self, &tt, span),
927            MacroDefKind::UnimplementedBuiltIn(_) => expand_unimplemented_builtin_macro(span),
928        };
929
930        let expand_to = loc.expand_to();
931
932        fixup::reverse_fixups(&mut speculative_expansion.value, &undo_info);
933        let (node, rev_tmap) =
934            token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to);
935
936        let syntax_node = node.syntax_node();
937        let token = rev_tmap
938            .ranges_with_span(span_map.span_for_range(token_to_map.text_range()))
939            .filter_map(|(range, ctx)| {
940                syntax_node.covering_element(range).into_token().zip(Some(ctx))
941            })
942            .map(|(t, ctx)| {
943                // prefer tokens of the same kind and text, as well as non opaque marked ones
944                // Note the inversion of the score here, as we want to prefer the first token in case
945                // of all tokens having the same score
946                let ranking = ctx.is_opaque(db) as u8
947                    + 2 * (t.kind() != token_to_map.kind()) as u8
948                    + 4 * ((t.text() != token_to_map.text()) as u8);
949                (t, ranking)
950            })
951            .collect();
952        Some((node.syntax_node(), token))
953    }
954}
955
956fn expand_unimplemented_builtin_macro(span: Span) -> ExpandResult<tt::TopSubtree> {
957    ExpandResult::new(
958        tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
959        ExpandError::other(span, "this built-in macro is not implemented"),
960    )
961}
962
963/// Retrieves the span to be used for a proc-macro expansions spans.
964/// This is a firewall query as it requires parsing the file, which we don't want proc-macros to
965/// directly depend on as that would cause to frequent invalidations, mainly because of the
966/// parse queries being LRU cached. If they weren't the invalidations would only happen if the
967/// user wrote in the file that defines the proc-macro.
968fn proc_macro_span(db: &dyn SourceDatabase, ast: AstId<ast::Fn>) -> Span {
969    #[salsa::tracked(returns(copy))]
970    fn proc_macro_span(db: &dyn SourceDatabase, ast: AstId<ast::Fn>, _: ()) -> Span {
971        let (parse, span_map) = ast.file_id.parse_with_map(db);
972        let root = parse.syntax_node();
973        let ast_id_map = ast.file_id.ast_id_map(db);
974
975        let node = ast_id_map.get(ast.value).to_node(&root);
976        let range = ast::HasName::name(&node)
977            .map_or_else(|| node.syntax().text_range(), |name| name.syntax().text_range());
978        span_map.span_for_range(range)
979    }
980    proc_macro_span(db, ast, ())
981}
982
983pub(crate) fn token_tree_to_syntax_node(
984    db: &dyn SourceDatabase,
985    tt: &tt::TopSubtree,
986    expand_to: ExpandTo,
987) -> (Parse<SyntaxNode>, ExpansionSpanMap) {
988    let entry_point = match expand_to {
989        ExpandTo::Statements => syntax_bridge::TopEntryPoint::MacroStmts,
990        ExpandTo::Items => syntax_bridge::TopEntryPoint::MacroItems,
991        ExpandTo::Pattern => syntax_bridge::TopEntryPoint::Pattern,
992        ExpandTo::Type => syntax_bridge::TopEntryPoint::Type,
993        ExpandTo::Expr => syntax_bridge::TopEntryPoint::Expr,
994    };
995    syntax_bridge::token_tree_to_syntax_node(tt, entry_point, &mut |ctx| ctx.edition(db))
996}
997
998fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> {
999    let tt = tt.top_subtree();
1000    let count = tt.count();
1001    if count <= TOKEN_LIMIT {
1002        Ok(())
1003    } else {
1004        Err(ExpandResult {
1005            value: (),
1006            err: Some(ExpandError::other(
1007                tt.delimiter.open,
1008                format!(
1009                    "macro invocation exceeds token limit: produced {count} tokens, limit is {TOKEN_LIMIT}",
1010                ),
1011            )),
1012        })
1013    }
1014}
1015
1016impl MacroDefId {
1017    pub fn make_call(
1018        self,
1019        db: &dyn SourceDatabase,
1020        krate: Crate,
1021        kind: MacroCallKind,
1022        ctxt: SyntaxContext,
1023        macro_depth: u32,
1024    ) -> MacroCallId {
1025        MacroCallId::new(db, MacroCallLoc { def: self, krate, kind, ctxt, macro_depth })
1026    }
1027
1028    pub fn definition_range(&self, db: &dyn SourceDatabase) -> InFile<TextRange> {
1029        match self.kind {
1030            MacroDefKind::Declarative(id, _)
1031            | MacroDefKind::BuiltIn(id, _)
1032            | MacroDefKind::BuiltInAttr(id, _)
1033            | MacroDefKind::BuiltInDerive(id, _)
1034            | MacroDefKind::BuiltInEager(id, _)
1035            | MacroDefKind::UnimplementedBuiltIn(id) => {
1036                id.with_value(id.file_id.ast_id_map(db).get(id.value).text_range())
1037            }
1038            MacroDefKind::ProcMacro(id, _, _) => {
1039                id.with_value(id.file_id.ast_id_map(db).get(id.value).text_range())
1040            }
1041        }
1042    }
1043
1044    pub fn ast_id(&self) -> Either<AstId<ast::Macro>, AstId<ast::Fn>> {
1045        match self.kind {
1046            MacroDefKind::ProcMacro(id, ..) => Either::Right(id),
1047            MacroDefKind::Declarative(id, _)
1048            | MacroDefKind::BuiltIn(id, _)
1049            | MacroDefKind::BuiltInAttr(id, _)
1050            | MacroDefKind::BuiltInDerive(id, _)
1051            | MacroDefKind::BuiltInEager(id, _)
1052            | MacroDefKind::UnimplementedBuiltIn(id) => Either::Left(id),
1053        }
1054    }
1055
1056    pub fn is_proc_macro(&self) -> bool {
1057        matches!(self.kind, MacroDefKind::ProcMacro(..))
1058    }
1059
1060    pub fn is_attribute(&self) -> bool {
1061        match self.kind {
1062            MacroDefKind::BuiltInAttr(..)
1063            | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr)
1064            | MacroDefKind::UnimplementedBuiltIn(_) => true,
1065            MacroDefKind::Declarative(_, styles) => styles.contains(MacroCallStyles::ATTR),
1066            _ => false,
1067        }
1068    }
1069
1070    pub fn is_derive(&self) -> bool {
1071        match self.kind {
1072            MacroDefKind::BuiltInDerive(..)
1073            | MacroDefKind::ProcMacro(_, _, ProcMacroKind::CustomDerive)
1074            | MacroDefKind::UnimplementedBuiltIn(_) => true,
1075            MacroDefKind::Declarative(_, styles) => styles.contains(MacroCallStyles::DERIVE),
1076            _ => false,
1077        }
1078    }
1079
1080    pub fn is_fn_like(&self) -> bool {
1081        matches!(
1082            self.kind,
1083            MacroDefKind::BuiltIn(..)
1084                | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Bang)
1085                | MacroDefKind::BuiltInEager(..)
1086                | MacroDefKind::Declarative(..)
1087                | MacroDefKind::UnimplementedBuiltIn(_)
1088        )
1089    }
1090
1091    pub fn is_attribute_derive(&self) -> bool {
1092        matches!(self.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive())
1093    }
1094
1095    pub fn is_include(&self) -> bool {
1096        matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_include())
1097    }
1098
1099    pub fn is_include_like(&self) -> bool {
1100        matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_include_like())
1101    }
1102
1103    pub fn is_env_or_option_env(&self) -> bool {
1104        matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_env_or_option_env())
1105    }
1106}
1107
1108impl MacroCallLoc {
1109    pub fn to_node(&self, db: &dyn SourceDatabase) -> InFile<SyntaxNode> {
1110        match &self.kind {
1111            MacroCallKind::FnLike { ast_id, .. } => {
1112                ast_id.with_value(ast_id.to_node(db).syntax().clone())
1113            }
1114            MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
1115                let (_, attr) = derive_attr_index.find_attr_range(db, self.krate, *ast_id);
1116                ast_id.with_value(attr.syntax().clone())
1117            }
1118            MacroCallKind::Attr { ast_id, censored_attr_ids: attr_ids, .. } => {
1119                if self.def.is_attribute_derive() {
1120                    let (_, attr) = attr_ids.invoc_attr().find_attr_range(db, self.krate, *ast_id);
1121                    ast_id.with_value(attr.syntax().clone())
1122                } else {
1123                    ast_id.with_value(ast_id.to_node(db).syntax().clone())
1124                }
1125            }
1126        }
1127    }
1128
1129    pub fn to_node_item(&self, db: &dyn SourceDatabase) -> InFile<ast::Item> {
1130        match self.kind {
1131            MacroCallKind::FnLike { ast_id, .. } => {
1132                InFile::new(ast_id.file_id, ast_id.map(FileAstId::upcast).to_node(db))
1133            }
1134            MacroCallKind::Derive { ast_id, .. } => {
1135                InFile::new(ast_id.file_id, ast_id.map(FileAstId::upcast).to_node(db))
1136            }
1137            MacroCallKind::Attr { ast_id, .. } => InFile::new(ast_id.file_id, ast_id.to_node(db)),
1138        }
1139    }
1140
1141    fn expand_to(&self) -> ExpandTo {
1142        match self.kind {
1143            MacroCallKind::FnLike { expand_to, .. } => expand_to,
1144            MacroCallKind::Derive { .. } => ExpandTo::Items,
1145            MacroCallKind::Attr { .. } if self.def.is_attribute_derive() => ExpandTo::Items,
1146            MacroCallKind::Attr { .. } => {
1147                // FIXME(stmt_expr_attributes)
1148                ExpandTo::Items
1149            }
1150        }
1151    }
1152
1153    pub fn include_file_id(
1154        &self,
1155        db: &dyn SourceDatabase,
1156        macro_call_id: MacroCallId,
1157    ) -> Option<EditionedFileId> {
1158        if self.def.is_include()
1159            && let MacroCallKind::FnLike { eager: Some(eager), .. } = &self.kind
1160            && let Ok(it) = include_input_to_file_id(db, macro_call_id, &eager.arg)
1161        {
1162            return Some(it);
1163        }
1164
1165        None
1166    }
1167}
1168
1169impl MacroCallKind {
1170    pub fn descr(&self) -> &'static str {
1171        match self {
1172            MacroCallKind::FnLike { .. } => "macro call",
1173            MacroCallKind::Derive { .. } => "derive macro",
1174            MacroCallKind::Attr { .. } => "attribute macro",
1175        }
1176    }
1177
1178    /// Returns the file containing the macro invocation.
1179    pub fn file_id(&self) -> HirFileId {
1180        match *self {
1181            MacroCallKind::FnLike { ast_id: InFile { file_id, .. }, .. }
1182            | MacroCallKind::Derive { ast_id: InFile { file_id, .. }, .. }
1183            | MacroCallKind::Attr { ast_id: InFile { file_id, .. }, .. } => file_id,
1184        }
1185    }
1186
1187    pub fn erased_ast_id(&self) -> ErasedFileAstId {
1188        match *self {
1189            MacroCallKind::FnLike { ast_id: InFile { value, .. }, .. } => value.erase(),
1190            MacroCallKind::Derive { ast_id: InFile { value, .. }, .. } => value.erase(),
1191            MacroCallKind::Attr { ast_id: InFile { value, .. }, .. } => value.erase(),
1192        }
1193    }
1194
1195    /// Returns the original file range that best describes the location of this macro call.
1196    ///
1197    /// This spans the entire macro call, including its input. That is for
1198    /// - fn_like! {}, it spans the path and token tree
1199    /// - #\[derive], it spans the `#[derive(...)]` attribute and the annotated item
1200    /// - #\[attr], it spans the `#[attr(...)]` attribute and the annotated item
1201    pub fn original_call_range_with_input(&self, db: &dyn SourceDatabase) -> FileRange {
1202        let get_range = |kind: &_| match kind {
1203            MacroCallKind::FnLike { ast_id, .. } => ast_id.erase(),
1204            MacroCallKind::Derive { ast_id, .. } => ast_id.erase(),
1205            MacroCallKind::Attr { ast_id, .. } => ast_id.erase(),
1206        };
1207
1208        let mut ast_id = get_range(self);
1209        let mut file_id = self.file_id();
1210        let file_id = loop {
1211            match file_id {
1212                HirFileId::MacroFile(file) => {
1213                    let kind = &file.loc(db).kind;
1214                    ast_id = get_range(kind);
1215                    file_id = kind.file_id();
1216                }
1217                HirFileId::FileId(file_id) => break file_id,
1218            }
1219        };
1220
1221        FileRange { range: ast_id.to_ptr(db).text_range(), file_id }
1222    }
1223
1224    /// Returns the original file range that best describes the location of this macro call.
1225    ///
1226    /// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros
1227    /// get the macro path (rustc shows the whole `ast::MacroCall`), attribute macros get the
1228    /// attribute's range, and derives get only the specific derive that is being referred to.
1229    pub fn original_call_range(&self, db: &dyn SourceDatabase, krate: Crate) -> FileRange {
1230        let get_range = |kind: &_| match kind {
1231            MacroCallKind::FnLike { ast_id, .. } => {
1232                let node = ast_id.to_node(db);
1233                node.path()
1234                    .unwrap()
1235                    .syntax()
1236                    .text_range()
1237                    .cover(node.excl_token().unwrap().text_range())
1238            }
1239            MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
1240                // FIXME: should be the range of the macro name, not the whole derive
1241                derive_attr_index.find_attr_range(db, krate, *ast_id).1.syntax().text_range()
1242            }
1243            // FIXME: handle `cfg_attr`
1244            MacroCallKind::Attr { ast_id, censored_attr_ids: attr_ids, .. } => {
1245                attr_ids.invoc_attr().find_attr_range(db, krate, *ast_id).1.syntax().text_range()
1246            }
1247        };
1248
1249        let mut range = get_range(self);
1250        let mut file_id = self.file_id();
1251        let file_id = loop {
1252            match file_id {
1253                HirFileId::MacroFile(file) => {
1254                    let kind = &file.loc(db).kind;
1255                    range = get_range(kind);
1256                    file_id = kind.file_id();
1257                }
1258                HirFileId::FileId(file_id) => break file_id,
1259            }
1260        };
1261
1262        FileRange { range, file_id }
1263    }
1264
1265    fn arg(&self, db: &dyn SourceDatabase) -> InFile<Option<SyntaxNode>> {
1266        match self {
1267            MacroCallKind::FnLike { ast_id, .. } => {
1268                ast_id.to_in_file_node(db).map(|it| Some(it.token_tree()?.syntax().clone()))
1269            }
1270            MacroCallKind::Derive { ast_id, .. } => {
1271                ast_id.to_in_file_node(db).syntax().cloned().map(Some)
1272            }
1273            MacroCallKind::Attr { ast_id, .. } => {
1274                ast_id.to_in_file_node(db).syntax().cloned().map(Some)
1275            }
1276        }
1277    }
1278}
1279
1280/// ExpansionInfo mainly describes how to map text range between src and expanded macro
1281// FIXME: can be expensive to create, we should check the use sites and maybe replace them with
1282// simpler function calls if the map is only used once
1283#[derive(Clone, Debug, PartialEq, Eq)]
1284pub struct ExpansionInfo<'db> {
1285    expanded: InMacroFile<SyntaxNode>,
1286    /// The argument TokenTree or item for attributes
1287    arg: InFile<Option<SyntaxNode>>,
1288    exp_map: &'db ExpansionSpanMap,
1289    arg_map: SpanMap<'db>,
1290    loc: &'db MacroCallLoc,
1291}
1292
1293impl<'db> ExpansionInfo<'db> {
1294    pub fn expanded(&self) -> InMacroFile<SyntaxNode> {
1295        self.expanded.clone()
1296    }
1297
1298    pub fn arg(&self) -> InFile<Option<&SyntaxNode>> {
1299        self.arg.as_ref().map(|it| it.as_ref())
1300    }
1301
1302    pub fn call_file(&self) -> HirFileId {
1303        self.arg.file_id
1304    }
1305
1306    pub fn is_attr(&self) -> bool {
1307        matches!(
1308            self.loc.def.kind,
1309            MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr)
1310        )
1311    }
1312
1313    /// Maps the passed in file range down into a macro expansion if it is the input to a macro call.
1314    ///
1315    /// Note this does a linear search through the entire backing vector of the spanmap.
1316    // FIXME: Consider adding a reverse map to ExpansionInfo to get rid of the linear search which
1317    // potentially results in quadratic look ups (notably this might improve semantic highlighting perf)
1318    pub fn map_range_down_exact(
1319        &self,
1320        span: Span,
1321    ) -> Option<InMacroFile<impl Iterator<Item = (SyntaxToken, SyntaxContext)> + '_>> {
1322        if span.anchor.ast_id == NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER {
1323            return None;
1324        }
1325
1326        let tokens = self.exp_map.ranges_with_span_exact(span).flat_map(move |(range, ctx)| {
1327            self.expanded.value.covering_element(range).into_token().zip(Some(ctx))
1328        });
1329
1330        Some(InMacroFile::new(self.expanded.file_id, tokens))
1331    }
1332
1333    /// Maps the passed in file range down into a macro expansion if it is the input to a macro call.
1334    /// Unlike [`ExpansionInfo::map_range_down_exact`], this will consider spans that contain the given span.
1335    ///
1336    /// Note this does a linear search through the entire backing vector of the spanmap.
1337    pub fn map_range_down(
1338        &self,
1339        span: Span,
1340    ) -> Option<InMacroFile<impl Iterator<Item = (SyntaxToken, SyntaxContext)> + '_>> {
1341        if span.anchor.ast_id == NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER {
1342            return None;
1343        }
1344
1345        let tokens = self.exp_map.ranges_with_span(span).flat_map(move |(range, ctx)| {
1346            self.expanded.value.covering_element(range).into_token().zip(Some(ctx))
1347        });
1348
1349        Some(InMacroFile::new(self.expanded.file_id, tokens))
1350    }
1351
1352    /// Looks up the span at the given offset.
1353    pub fn span_for_offset(
1354        &self,
1355        db: &dyn SourceDatabase,
1356        offset: TextSize,
1357    ) -> (FileRange, SyntaxContext) {
1358        debug_assert!(self.expanded.value.text_range().contains(offset));
1359        span_for_offset(db, self.exp_map, offset)
1360    }
1361
1362    /// Maps up the text range out of the expansion hierarchy back into the original file its from.
1363    pub fn map_node_range_up(
1364        &self,
1365        db: &dyn SourceDatabase,
1366        range: TextRange,
1367    ) -> Option<(FileRange, SyntaxContext)> {
1368        debug_assert!(self.expanded.value.text_range().contains_range(range));
1369        map_node_range_up(db, self.exp_map, range)
1370    }
1371
1372    /// Maps up the text range out of the expansion into its macro call.
1373    ///
1374    /// Note that this may return multiple ranges as we lose the precise association between input to output
1375    /// and as such we may consider inputs that are unrelated.
1376    pub fn map_range_up_once(
1377        &self,
1378        db: &dyn SourceDatabase,
1379        token: TextRange,
1380    ) -> InFile<smallvec::SmallVec<[TextRange; 1]>> {
1381        debug_assert!(self.expanded.value.text_range().contains_range(token));
1382        let span = self.exp_map.span_at(token.start());
1383        match &self.arg_map {
1384            SpanMap::RealSpanMap(_) => {
1385                let range = resolve_span(db, span);
1386                InFile { file_id: range.file_id.into(), value: smallvec::smallvec![range.range] }
1387            }
1388            SpanMap::ExpansionSpanMap(arg_map) => {
1389                let Some(arg_node) = &self.arg.value else {
1390                    return InFile::new(self.arg.file_id, smallvec::smallvec![]);
1391                };
1392                let arg_range = arg_node.text_range();
1393                InFile::new(
1394                    self.arg.file_id,
1395                    arg_map
1396                        .ranges_with_span_exact(span)
1397                        .map(|(range, _)| range)
1398                        .filter(|range| range.intersect(arg_range).is_some())
1399                        .collect(),
1400                )
1401            }
1402        }
1403    }
1404
1405    pub fn new(db: &'db dyn SourceDatabase, macro_file: MacroCallId) -> ExpansionInfo<'db> {
1406        let _p = tracing::info_span!("ExpansionInfo::new").entered();
1407        let loc = macro_file.loc(db);
1408
1409        let arg_tt = loc.kind.arg(db);
1410        let arg_map = arg_tt.file_id.span_map(db);
1411
1412        let (parse, exp_map) = &macro_file.parse_macro_expansion(db).value;
1413        let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() };
1414
1415        ExpansionInfo { expanded, loc, arg: arg_tt, exp_map, arg_map }
1416    }
1417}
1418
1419/// Maps up the text range out of the expansion hierarchy back into the original file its from only
1420/// considering the root spans contained.
1421/// Unlike [`map_node_range_up`], this will not return `None` if any anchors or syntax contexts differ.
1422pub fn map_node_range_up_rooted(
1423    db: &dyn SourceDatabase,
1424    exp_map: &ExpansionSpanMap,
1425    range: TextRange,
1426) -> Option<FileRange> {
1427    let mut spans = exp_map.spans_for_range(range).filter(|span| span.ctx.is_root());
1428    let Span { range, anchor, ctx } = spans.next()?;
1429    let mut start = range.start();
1430    let mut end = range.end();
1431
1432    for span in spans {
1433        if span.anchor != anchor {
1434            return None;
1435        }
1436        start = start.min(span.range.start());
1437        end = end.max(span.range.end());
1438    }
1439    Some(resolve_span(db, Span { range: TextRange::new(start, end), anchor, ctx }))
1440}
1441
1442/// Maps up the text range out of the expansion hierarchy back into the original file its from.
1443///
1444/// this will return `None` if any anchors or syntax contexts differ.
1445pub fn map_node_range_up(
1446    db: &dyn SourceDatabase,
1447    exp_map: &ExpansionSpanMap,
1448    range: TextRange,
1449) -> Option<(FileRange, SyntaxContext)> {
1450    let mut spans = exp_map.spans_for_range(range);
1451    let Span { range, anchor, ctx } = spans.next()?;
1452    let mut start = range.start();
1453    let mut end = range.end();
1454
1455    for span in spans {
1456        if span.anchor != anchor || span.ctx != ctx {
1457            return None;
1458        }
1459        start = start.min(span.range.start());
1460        end = end.max(span.range.end());
1461    }
1462    Some((resolve_span(db, Span { range: TextRange::new(start, end), anchor, ctx }), ctx))
1463}
1464
1465/// Looks up the span at the given offset.
1466pub fn span_for_offset(
1467    db: &dyn SourceDatabase,
1468    exp_map: &ExpansionSpanMap,
1469    offset: TextSize,
1470) -> (FileRange, SyntaxContext) {
1471    let span = exp_map.span_at(offset);
1472    (resolve_span(db, span), span.ctx)
1473}
1474
1475// FIXME: This is only public because of its use in `load_cargo` (which we should consider removing
1476// by moving the implementations of the subrequests to `hir_expand`, and calling within `load-cargo`).
1477// Avoid adding any more outside uses.
1478pub fn resolve_span(db: &dyn SourceDatabase, Span { range, anchor, ctx: _ }: Span) -> FileRange {
1479    let file_id = EditionedFileId::from_span_file_id(db, anchor.file_id);
1480    let anchor_offset =
1481        HirFileId::from(file_id).ast_id_map(db).get_erased(anchor.ast_id).text_range().start();
1482    FileRange { file_id, range: range + anchor_offset }
1483}
1484
1485/// In Rust, macros expand token trees to token trees. When we want to turn a
1486/// token tree into an AST node, we need to figure out what kind of AST node we
1487/// want: something like `foo` can be a type, an expression, or a pattern.
1488///
1489/// Naively, one would think that "what this expands to" is a property of a
1490/// particular macro: macro `m1` returns an item, while macro `m2` returns an
1491/// expression, etc. That's not the case -- macros are polymorphic in the
1492/// result, and can expand to any type of the AST node.
1493///
1494/// What defines the actual AST node is the syntactic context of the macro
1495/// invocation. As a contrived example, in `let T![*] = T![*];` the first `T`
1496/// expands to a pattern, while the second one expands to an expression.
1497///
1498/// `ExpandTo` captures this bit of information about a particular macro call
1499/// site.
1500#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1501pub enum ExpandTo {
1502    Statements,
1503    Items,
1504    Pattern,
1505    Type,
1506    Expr,
1507}
1508
1509impl ExpandTo {
1510    pub fn from_call_site(call: &ast::MacroCall) -> ExpandTo {
1511        use syntax::SyntaxKind::*;
1512
1513        let syn = call.syntax();
1514
1515        let parent = match syn.parent() {
1516            Some(it) => it,
1517            None => return ExpandTo::Statements,
1518        };
1519
1520        // FIXME: macros in statement position are treated as expression statements, they should
1521        // probably be their own statement kind. The *grand*parent indicates what's valid.
1522        if parent.kind() == MACRO_EXPR
1523            && parent
1524                .parent()
1525                .is_some_and(|p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
1526        {
1527            return ExpandTo::Statements;
1528        }
1529
1530        match parent.kind() {
1531            MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => ExpandTo::Items,
1532            MACRO_STMTS | EXPR_STMT | STMT_LIST => ExpandTo::Statements,
1533            MACRO_PAT => ExpandTo::Pattern,
1534            MACRO_TYPE => ExpandTo::Type,
1535
1536            ARG_LIST | ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BREAK_EXPR | CALL_EXPR | CAST_EXPR
1537            | CLOSURE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR | INDEX_EXPR | LET_EXPR
1538            | MATCH_ARM | MATCH_EXPR | MATCH_GUARD | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR
1539            | PREFIX_EXPR | RANGE_EXPR | RECORD_EXPR_FIELD | REF_EXPR | RETURN_EXPR | TRY_EXPR
1540            | TUPLE_EXPR | WHILE_EXPR | MACRO_EXPR => ExpandTo::Expr,
1541            _ => {
1542                // Unknown , Just guess it is `Items`
1543                ExpandTo::Items
1544            }
1545        }
1546    }
1547}
1548
1549/// Macro ids. That's probably the tricksiest bit in rust-analyzer, and the
1550/// reason why we use salsa at all.
1551///
1552/// We encode macro definitions into ids of macro calls, this what allows us
1553/// to be incremental.
1554#[salsa::interned(unsafe(no_lifetime), debug, revisions = usize::MAX)]
1555#[doc(alias = "MacroFileId")]
1556pub struct MacroCallId {
1557    #[returns(ref)]
1558    pub loc: MacroCallLoc,
1559}
1560
1561impl From<span::MacroCallId> for MacroCallId {
1562    #[inline]
1563    fn from(value: span::MacroCallId) -> Self {
1564        MacroCallId::from_id(value.0)
1565    }
1566}
1567
1568impl From<MacroCallId> for span::MacroCallId {
1569    #[inline]
1570    fn from(value: MacroCallId) -> span::MacroCallId {
1571        span::MacroCallId(value.as_id())
1572    }
1573}
1574
1575#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)]
1576pub enum HirFileId {
1577    FileId(EditionedFileId),
1578    MacroFile(MacroCallId),
1579}
1580
1581impl From<EditionedFileId> for HirFileId {
1582    #[inline]
1583    fn from(file_id: EditionedFileId) -> Self {
1584        HirFileId::FileId(file_id)
1585    }
1586}
1587
1588impl From<MacroCallId> for HirFileId {
1589    #[inline]
1590    fn from(file_id: MacroCallId) -> Self {
1591        HirFileId::MacroFile(file_id)
1592    }
1593}
1594
1595impl PartialEq<EditionedFileId> for HirFileId {
1596    fn eq(&self, &other: &EditionedFileId) -> bool {
1597        *self == HirFileId::from(other)
1598    }
1599}
1600impl PartialEq<HirFileId> for EditionedFileId {
1601    fn eq(&self, &other: &HirFileId) -> bool {
1602        other == HirFileId::from(*self)
1603    }
1604}
1605
1606impl HirFileId {
1607    #[inline]
1608    pub fn macro_file(self) -> Option<MacroCallId> {
1609        match self {
1610            HirFileId::FileId(_) => None,
1611            HirFileId::MacroFile(it) => Some(it),
1612        }
1613    }
1614
1615    #[inline]
1616    pub fn is_macro(self) -> bool {
1617        matches!(self, HirFileId::MacroFile(_))
1618    }
1619
1620    #[inline]
1621    pub fn file_id(self) -> Option<EditionedFileId> {
1622        match self {
1623            HirFileId::FileId(it) => Some(it),
1624            HirFileId::MacroFile(_) => None,
1625        }
1626    }
1627
1628    pub fn syntax_context(self, db: &dyn SourceDatabase, edition: Edition) -> SyntaxContext {
1629        match self {
1630            HirFileId::FileId(_) => SyntaxContext::root(edition),
1631            HirFileId::MacroFile(m) => {
1632                let kind = &m.loc(db).kind;
1633                m.macro_arg_considering_derives(db, kind).2.ctx
1634            }
1635        }
1636    }
1637
1638    pub fn edition(self, db: &dyn SourceDatabase) -> Edition {
1639        match self {
1640            HirFileId::FileId(file_id) => file_id.edition(db),
1641            HirFileId::MacroFile(m) => m.loc(db).def.edition,
1642        }
1643    }
1644
1645    pub fn original_file(self, db: &dyn SourceDatabase) -> EditionedFileId {
1646        let mut file_id = self;
1647        loop {
1648            match file_id {
1649                HirFileId::FileId(id) => break id,
1650                HirFileId::MacroFile(macro_call_id) => {
1651                    file_id = macro_call_id.loc(db).kind.file_id()
1652                }
1653            }
1654        }
1655    }
1656
1657    pub fn original_file_respecting_includes(mut self, db: &dyn SourceDatabase) -> EditionedFileId {
1658        loop {
1659            match self {
1660                HirFileId::FileId(id) => break id,
1661                HirFileId::MacroFile(file) => {
1662                    let loc = file.loc(db);
1663                    if loc.def.is_include()
1664                        && let MacroCallKind::FnLike { eager: Some(eager), .. } = &loc.kind
1665                        && let Ok(it) = include_input_to_file_id(db, file, &eager.arg)
1666                    {
1667                        break it;
1668                    }
1669                    self = loc.kind.file_id();
1670                }
1671            }
1672        }
1673    }
1674
1675    pub fn original_call_node(self, db: &dyn SourceDatabase) -> Option<InRealFile<SyntaxNode>> {
1676        let mut call = self.macro_file()?.loc(db).to_node(db);
1677        loop {
1678            match call.file_id {
1679                HirFileId::FileId(file_id) => {
1680                    break Some(InRealFile { file_id, value: call.value });
1681                }
1682                HirFileId::MacroFile(macro_call_id) => {
1683                    call = macro_call_id.loc(db).to_node(db);
1684                }
1685            }
1686        }
1687    }
1688
1689    pub fn call_node(self, db: &dyn SourceDatabase) -> Option<InFile<SyntaxNode>> {
1690        Some(self.macro_file()?.loc(db).to_node(db))
1691    }
1692
1693    pub fn as_builtin_derive_attr_node(
1694        &self,
1695        db: &dyn SourceDatabase,
1696    ) -> Option<InFile<ast::Attr>> {
1697        let macro_file = self.macro_file()?;
1698        let loc = macro_file.loc(db);
1699        let attr = match loc.def.kind {
1700            MacroDefKind::BuiltInDerive(..) => loc.to_node(db),
1701            _ => return None,
1702        };
1703        Some(attr.with_value(ast::Attr::cast(attr.value.clone())?))
1704    }
1705
1706    /// Main public API -- parses a hir file, not caring whether it's a real
1707    /// file or a macro expansion.
1708    pub fn parse_or_expand(self, db: &dyn SourceDatabase) -> SyntaxNode {
1709        match self {
1710            HirFileId::FileId(file_id) => file_id.parse(db).syntax_node(),
1711            HirFileId::MacroFile(macro_file) => {
1712                macro_file.parse_macro_expansion(db).value.0.syntax_node()
1713            }
1714        }
1715    }
1716
1717    pub(crate) fn parse_with_map(
1718        self,
1719        db: &dyn SourceDatabase,
1720    ) -> (Parse<SyntaxNode>, SpanMap<'_>) {
1721        match self {
1722            HirFileId::FileId(file_id) => (
1723                file_id.parse(db).to_syntax(),
1724                SpanMap::RealSpanMap(crate::span_map::real_span_map(db, file_id)),
1725            ),
1726            HirFileId::MacroFile(macro_file) => {
1727                let (parse, map) = &macro_file.parse_macro_expansion(db).value;
1728                (parse.clone(), SpanMap::ExpansionSpanMap(map))
1729            }
1730        }
1731    }
1732
1733    /// How many macro expansions separate this file from the real file it originates from.
1734    ///
1735    /// `Expander` and `DefCollector` seed their expansion depth counters from this. Both otherwise
1736    /// start at zero for every body and every block, so a macro expanding to an item that invokes
1737    /// the macro again advances neither counter past one and never reaches the recursion limit.
1738    ///
1739    /// Written recursively rather than as a loop so that salsa memoizes each file's depth. Callers
1740    /// ask for this once per body, and the bodies of one expansion chain sit at depths 1..n, so a
1741    /// loop would walk 1 + 2 + ... + n steps for that chain. Reusing the parent's memoized depth
1742    /// makes each file O(1) once computed, and the chain linear.
1743    #[inline]
1744    pub fn macro_expansion_depth(self, db: &dyn SourceDatabase) -> u32 {
1745        match self {
1746            HirFileId::MacroFile(macro_call) => macro_call.loc(db).macro_depth,
1747            HirFileId::FileId(_) => 0,
1748        }
1749    }
1750}
1751
1752#[salsa::tracked]
1753impl HirFileId {
1754    #[salsa::tracked(lru = 1024, returns(ref))]
1755    pub fn ast_id_map(self, db: &dyn SourceDatabase) -> AstIdMap {
1756        AstIdMap::from_source(&self.parse_or_expand(db))
1757    }
1758}