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