• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
7 #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
8 
9 pub mod db;
10 pub mod ast_id_map;
11 pub mod name;
12 pub mod hygiene;
13 pub mod builtin_attr_macro;
14 pub mod builtin_derive_macro;
15 pub mod builtin_fn_macro;
16 pub mod proc_macro;
17 pub mod quote;
18 pub mod eager;
19 pub mod mod_path;
20 pub mod attrs;
21 mod fixup;
22 
23 use mbe::TokenMap;
24 pub use mbe::{Origin, ValueResult};
25 
26 use ::tt::token_id as tt;
27 use triomphe::Arc;
28 
29 use std::{fmt, hash::Hash, iter};
30 
31 use base_db::{
32     impl_intern_key,
33     salsa::{self, InternId},
34     CrateId, FileId, FileRange, ProcMacroKind,
35 };
36 use either::Either;
37 use syntax::{
38     algo::{self, skip_trivia_token},
39     ast::{self, AstNode, HasDocComments},
40     Direction, SyntaxNode, SyntaxToken,
41 };
42 
43 use crate::{
44     ast_id_map::FileAstId,
45     attrs::AttrId,
46     builtin_attr_macro::BuiltinAttrExpander,
47     builtin_derive_macro::BuiltinDeriveExpander,
48     builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
49     db::TokenExpander,
50     mod_path::ModPath,
51     proc_macro::ProcMacroExpander,
52 };
53 
54 pub type ExpandResult<T> = ValueResult<T, ExpandError>;
55 
56 #[derive(Debug, PartialEq, Eq, Clone, Hash)]
57 pub enum ExpandError {
58     UnresolvedProcMacro(CrateId),
59     Mbe(mbe::ExpandError),
60     RecursionOverflowPoisoned,
61     Other(Box<Box<str>>),
62 }
63 
64 impl ExpandError {
other(msg: impl Into<Box<str>>) -> Self65     pub fn other(msg: impl Into<Box<str>>) -> Self {
66         ExpandError::Other(Box::new(msg.into()))
67     }
68 }
69 
70 impl From<mbe::ExpandError> for ExpandError {
from(mbe: mbe::ExpandError) -> Self71     fn from(mbe: mbe::ExpandError) -> Self {
72         Self::Mbe(mbe)
73     }
74 }
75 
76 impl fmt::Display for ExpandError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result77     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78         match self {
79             ExpandError::UnresolvedProcMacro(_) => f.write_str("unresolved proc-macro"),
80             ExpandError::Mbe(it) => it.fmt(f),
81             ExpandError::RecursionOverflowPoisoned => {
82                 f.write_str("overflow expanding the original macro")
83             }
84             ExpandError::Other(it) => f.write_str(it),
85         }
86     }
87 }
88 
89 /// Input to the analyzer is a set of files, where each file is identified by
90 /// `FileId` and contains source code. However, another source of source code in
91 /// Rust are macros: each macro can be thought of as producing a "temporary
92 /// file". To assign an id to such a file, we use the id of the macro call that
93 /// produced the file. So, a `HirFileId` is either a `FileId` (source code
94 /// written by user), or a `MacroCallId` (source code produced by macro).
95 ///
96 /// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
97 /// containing the call plus the offset of the macro call in the file. Note that
98 /// this is a recursive definition! However, the size_of of `HirFileId` is
99 /// finite (because everything bottoms out at the real `FileId`) and small
100 /// (`MacroCallId` uses the location interning. You can check details here:
101 /// <https://en.wikipedia.org/wiki/String_interning>).
102 ///
103 /// The two variants are encoded in a single u32 which are differentiated by the MSB.
104 /// If the MSB is 0, the value represents a `FileId`, otherwise the remaining 31 bits represent a
105 /// `MacroCallId`.
106 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
107 pub struct HirFileId(u32);
108 
109 impl fmt::Debug for HirFileId {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result110     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111         self.repr().fmt(f)
112     }
113 }
114 
115 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
116 pub struct MacroFile {
117     pub macro_call_id: MacroCallId,
118 }
119 
120 /// `MacroCallId` identifies a particular macro invocation, like
121 /// `println!("Hello, {}", world)`.
122 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
123 pub struct MacroCallId(salsa::InternId);
124 impl_intern_key!(MacroCallId);
125 
126 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
127 pub struct MacroCallLoc {
128     pub def: MacroDefId,
129     pub(crate) krate: CrateId,
130     /// Some if `def` is a builtin eager macro.
131     eager: Option<Box<EagerCallInfo>>,
132     pub kind: MacroCallKind,
133 }
134 
135 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
136 pub struct MacroDefId {
137     pub krate: CrateId,
138     pub kind: MacroDefKind,
139     pub local_inner: bool,
140     pub allow_internal_unsafe: bool,
141 }
142 
143 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
144 pub enum MacroDefKind {
145     Declarative(AstId<ast::Macro>),
146     BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>),
147     BuiltInAttr(BuiltinAttrExpander, AstId<ast::Macro>),
148     BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>),
149     BuiltInEager(EagerExpander, AstId<ast::Macro>),
150     ProcMacro(ProcMacroExpander, ProcMacroKind, AstId<ast::Fn>),
151 }
152 
153 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
154 struct EagerCallInfo {
155     /// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro!
156     arg: Arc<(tt::Subtree, TokenMap)>,
157     /// call id of the eager macro's input file. If this is none, macro call containing this call info
158     /// is an eager macro's input, otherwise it is its output.
159     arg_id: Option<MacroCallId>,
160     error: Option<ExpandError>,
161 }
162 
163 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
164 pub enum MacroCallKind {
165     FnLike {
166         ast_id: AstId<ast::MacroCall>,
167         expand_to: ExpandTo,
168     },
169     Derive {
170         ast_id: AstId<ast::Adt>,
171         /// Syntactical index of the invoking `#[derive]` attribute.
172         ///
173         /// Outer attributes are counted first, then inner attributes. This does not support
174         /// out-of-line modules, which may have attributes spread across 2 files!
175         derive_attr_index: AttrId,
176         /// Index of the derive macro in the derive attribute
177         derive_index: u32,
178     },
179     Attr {
180         ast_id: AstId<ast::Item>,
181         attr_args: Arc<(tt::Subtree, mbe::TokenMap)>,
182         /// Syntactical index of the invoking `#[attribute]`.
183         ///
184         /// Outer attributes are counted first, then inner attributes. This does not support
185         /// out-of-line modules, which may have attributes spread across 2 files!
186         invoc_attr_index: AttrId,
187     },
188 }
189 
190 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
191 enum HirFileIdRepr {
192     FileId(FileId),
193     MacroFile(MacroFile),
194 }
195 
196 impl From<FileId> for HirFileId {
from(FileId(id): FileId) -> Self197     fn from(FileId(id): FileId) -> Self {
198         assert!(id < Self::MAX_FILE_ID);
199         HirFileId(id)
200     }
201 }
202 
203 impl From<MacroFile> for HirFileId {
204     fn from(MacroFile { macro_call_id: MacroCallId(id) }: MacroFile) -> Self {
205         let id = id.as_u32();
206         assert!(id < Self::MAX_FILE_ID);
207         HirFileId(id | Self::MACRO_FILE_TAG_MASK)
208     }
209 }
210 
211 impl HirFileId {
212     const MAX_FILE_ID: u32 = u32::MAX ^ Self::MACRO_FILE_TAG_MASK;
213     const MACRO_FILE_TAG_MASK: u32 = 1 << 31;
214 
215     /// For macro-expansion files, returns the file original source file the
216     /// expansion originated from.
original_file(self, db: &dyn db::ExpandDatabase) -> FileId217     pub fn original_file(self, db: &dyn db::ExpandDatabase) -> FileId {
218         let mut file_id = self;
219         loop {
220             match file_id.repr() {
221                 HirFileIdRepr::FileId(id) => break id,
222                 HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
223                     let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id);
224                     let is_include_expansion = loc.def.is_include()
225                         && matches!(
226                             loc.eager.as_deref(),
227                             Some(EagerCallInfo { arg_id: Some(_), .. })
228                         );
229                     file_id = match is_include_expansion.then(|| db.include_expand(macro_call_id)) {
230                         Some(Ok((_, file))) => file.into(),
231                         _ => loc.kind.file_id(),
232                     }
233                 }
234             }
235         }
236     }
237 
expansion_level(self, db: &dyn db::ExpandDatabase) -> u32238     pub fn expansion_level(self, db: &dyn db::ExpandDatabase) -> u32 {
239         let mut level = 0;
240         let mut curr = self;
241         while let Some(macro_file) = curr.macro_file() {
242             let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
243 
244             level += 1;
245             curr = loc.kind.file_id();
246         }
247         level
248     }
249 
250     /// If this is a macro call, returns the syntax node of the call.
call_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxNode>>251     pub fn call_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxNode>> {
252         let macro_file = self.macro_file()?;
253         let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
254         Some(loc.to_node(db))
255     }
256 
257     /// If this is a macro call, returns the syntax node of the very first macro call this file resides in.
original_call_node(self, db: &dyn db::ExpandDatabase) -> Option<(FileId, SyntaxNode)>258     pub fn original_call_node(self, db: &dyn db::ExpandDatabase) -> Option<(FileId, SyntaxNode)> {
259         let mut call = db.lookup_intern_macro_call(self.macro_file()?.macro_call_id).to_node(db);
260         loop {
261             match call.file_id.repr() {
262                 HirFileIdRepr::FileId(file_id) => break Some((file_id, call.value)),
263                 HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
264                     call = db.lookup_intern_macro_call(macro_call_id).to_node(db);
265                 }
266             }
267         }
268     }
269 
270     /// Return expansion information if it is a macro-expansion file
expansion_info(self, db: &dyn db::ExpandDatabase) -> Option<ExpansionInfo>271     pub fn expansion_info(self, db: &dyn db::ExpandDatabase) -> Option<ExpansionInfo> {
272         let macro_file = self.macro_file()?;
273         let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
274 
275         let arg_tt = loc.kind.arg(db)?;
276 
277         let macro_def = db.macro_def(loc.def).ok()?;
278         let (parse, exp_map) = db.parse_macro_expansion(macro_file).value;
279         let macro_arg = db.macro_arg(macro_file.macro_call_id).unwrap_or_else(|| {
280             Arc::new((
281                 tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: Vec::new() },
282                 Default::default(),
283                 Default::default(),
284             ))
285         });
286 
287         let def = loc.def.ast_id().left().and_then(|id| {
288             let def_tt = match id.to_node(db) {
289                 ast::Macro::MacroRules(mac) => mac.token_tree()?,
290                 ast::Macro::MacroDef(_) if matches!(*macro_def, TokenExpander::BuiltinAttr(_)) => {
291                     return None
292                 }
293                 ast::Macro::MacroDef(mac) => mac.body()?,
294             };
295             Some(InFile::new(id.file_id, def_tt))
296         });
297         let attr_input_or_mac_def = def.or_else(|| match loc.kind {
298             MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
299                 // FIXME: handle `cfg_attr`
300                 let tt = ast_id
301                     .to_node(db)
302                     .doc_comments_and_attrs()
303                     .nth(invoc_attr_index.ast_index())
304                     .and_then(Either::left)?
305                     .token_tree()?;
306                 Some(InFile::new(ast_id.file_id, tt))
307             }
308             _ => None,
309         });
310 
311         Some(ExpansionInfo {
312             expanded: InFile::new(self, parse.syntax_node()),
313             arg: InFile::new(loc.kind.file_id(), arg_tt),
314             attr_input_or_mac_def,
315             macro_arg_shift: mbe::Shift::new(&macro_arg.0),
316             macro_arg,
317             macro_def,
318             exp_map,
319         })
320     }
321 
322     /// Indicate it is macro file generated for builtin derive
is_builtin_derive(&self, db: &dyn db::ExpandDatabase) -> Option<InFile<ast::Attr>>323     pub fn is_builtin_derive(&self, db: &dyn db::ExpandDatabase) -> Option<InFile<ast::Attr>> {
324         let macro_file = self.macro_file()?;
325         let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
326         let attr = match loc.def.kind {
327             MacroDefKind::BuiltInDerive(..) => loc.to_node(db),
328             _ => return None,
329         };
330         Some(attr.with_value(ast::Attr::cast(attr.value.clone())?))
331     }
332 
is_custom_derive(&self, db: &dyn db::ExpandDatabase) -> bool333     pub fn is_custom_derive(&self, db: &dyn db::ExpandDatabase) -> bool {
334         match self.macro_file() {
335             Some(macro_file) => {
336                 let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
337                 matches!(loc.def.kind, MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _))
338             }
339             None => false,
340         }
341     }
342 
343     /// Return whether this file is an include macro
is_include_macro(&self, db: &dyn db::ExpandDatabase) -> bool344     pub fn is_include_macro(&self, db: &dyn db::ExpandDatabase) -> bool {
345         match self.macro_file() {
346             Some(macro_file) => {
347                 let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
348                 loc.def.is_include()
349             }
350             _ => false,
351         }
352     }
353 
is_eager(&self, db: &dyn db::ExpandDatabase) -> bool354     pub fn is_eager(&self, db: &dyn db::ExpandDatabase) -> bool {
355         match self.macro_file() {
356             Some(macro_file) => {
357                 let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
358                 matches!(loc.eager.as_deref(), Some(EagerCallInfo { .. }))
359             }
360             _ => false,
361         }
362     }
363 
364     /// Return whether this file is an attr macro
is_attr_macro(&self, db: &dyn db::ExpandDatabase) -> bool365     pub fn is_attr_macro(&self, db: &dyn db::ExpandDatabase) -> bool {
366         match self.macro_file() {
367             Some(macro_file) => {
368                 let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
369                 matches!(loc.kind, MacroCallKind::Attr { .. })
370             }
371             _ => false,
372         }
373     }
374 
375     /// Return whether this file is the pseudo expansion of the derive attribute.
376     /// See [`crate::builtin_attr_macro::derive_attr_expand`].
is_derive_attr_pseudo_expansion(&self, db: &dyn db::ExpandDatabase) -> bool377     pub fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::ExpandDatabase) -> bool {
378         match self.macro_file() {
379             Some(macro_file) => {
380                 let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
381                 loc.def.is_attribute_derive()
382             }
383             None => false,
384         }
385     }
386 
387     #[inline]
is_macro(self) -> bool388     pub fn is_macro(self) -> bool {
389         self.0 & Self::MACRO_FILE_TAG_MASK != 0
390     }
391 
392     #[inline]
macro_file(self) -> Option<MacroFile>393     pub fn macro_file(self) -> Option<MacroFile> {
394         match self.0 & Self::MACRO_FILE_TAG_MASK {
395             0 => None,
396             _ => Some(MacroFile {
397                 macro_call_id: MacroCallId(InternId::from(self.0 ^ Self::MACRO_FILE_TAG_MASK)),
398             }),
399         }
400     }
401 
402     #[inline]
file_id(self) -> Option<FileId>403     pub fn file_id(self) -> Option<FileId> {
404         match self.0 & Self::MACRO_FILE_TAG_MASK {
405             0 => Some(FileId(self.0)),
406             _ => None,
407         }
408     }
409 
repr(self) -> HirFileIdRepr410     fn repr(self) -> HirFileIdRepr {
411         match self.0 & Self::MACRO_FILE_TAG_MASK {
412             0 => HirFileIdRepr::FileId(FileId(self.0)),
413             _ => HirFileIdRepr::MacroFile(MacroFile {
414                 macro_call_id: MacroCallId(InternId::from(self.0 ^ Self::MACRO_FILE_TAG_MASK)),
415             }),
416         }
417     }
418 }
419 
420 impl MacroDefId {
as_lazy_macro( self, db: &dyn db::ExpandDatabase, krate: CrateId, kind: MacroCallKind, ) -> MacroCallId421     pub fn as_lazy_macro(
422         self,
423         db: &dyn db::ExpandDatabase,
424         krate: CrateId,
425         kind: MacroCallKind,
426     ) -> MacroCallId {
427         db.intern_macro_call(MacroCallLoc { def: self, krate, eager: None, kind })
428     }
429 
ast_id(&self) -> Either<AstId<ast::Macro>, AstId<ast::Fn>>430     pub fn ast_id(&self) -> Either<AstId<ast::Macro>, AstId<ast::Fn>> {
431         let id = match self.kind {
432             MacroDefKind::ProcMacro(.., id) => return Either::Right(id),
433             MacroDefKind::Declarative(id)
434             | MacroDefKind::BuiltIn(_, id)
435             | MacroDefKind::BuiltInAttr(_, id)
436             | MacroDefKind::BuiltInDerive(_, id)
437             | MacroDefKind::BuiltInEager(_, id) => id,
438         };
439         Either::Left(id)
440     }
441 
is_proc_macro(&self) -> bool442     pub fn is_proc_macro(&self) -> bool {
443         matches!(self.kind, MacroDefKind::ProcMacro(..))
444     }
445 
is_attribute(&self) -> bool446     pub fn is_attribute(&self) -> bool {
447         matches!(
448             self.kind,
449             MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, ProcMacroKind::Attr, _)
450         )
451     }
452 
is_attribute_derive(&self) -> bool453     pub fn is_attribute_derive(&self) -> bool {
454         matches!(self.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive())
455     }
456 
is_include(&self) -> bool457     pub fn is_include(&self) -> bool {
458         matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_include())
459     }
460 }
461 
462 impl MacroCallLoc {
to_node(&self, db: &dyn db::ExpandDatabase) -> InFile<SyntaxNode>463     pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> InFile<SyntaxNode> {
464         match self.kind {
465             MacroCallKind::FnLike { ast_id, .. } => {
466                 ast_id.with_value(ast_id.to_node(db).syntax().clone())
467             }
468             MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
469                 // FIXME: handle `cfg_attr`
470                 ast_id.with_value(ast_id.to_node(db)).map(|it| {
471                     it.doc_comments_and_attrs()
472                         .nth(derive_attr_index.ast_index())
473                         .and_then(|it| match it {
474                             Either::Left(attr) => Some(attr.syntax().clone()),
475                             Either::Right(_) => None,
476                         })
477                         .unwrap_or_else(|| it.syntax().clone())
478                 })
479             }
480             MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
481                 if self.def.is_attribute_derive() {
482                     // FIXME: handle `cfg_attr`
483                     ast_id.with_value(ast_id.to_node(db)).map(|it| {
484                         it.doc_comments_and_attrs()
485                             .nth(invoc_attr_index.ast_index())
486                             .and_then(|it| match it {
487                                 Either::Left(attr) => Some(attr.syntax().clone()),
488                                 Either::Right(_) => None,
489                             })
490                             .unwrap_or_else(|| it.syntax().clone())
491                     })
492                 } else {
493                     ast_id.with_value(ast_id.to_node(db).syntax().clone())
494                 }
495             }
496         }
497     }
498 
expand_to(&self) -> ExpandTo499     fn expand_to(&self) -> ExpandTo {
500         match self.kind {
501             MacroCallKind::FnLike { expand_to, .. } => expand_to,
502             MacroCallKind::Derive { .. } => ExpandTo::Items,
503             MacroCallKind::Attr { .. } if self.def.is_attribute_derive() => ExpandTo::Statements,
504             MacroCallKind::Attr { .. } => {
505                 // is this always correct?
506                 ExpandTo::Items
507             }
508         }
509     }
510 }
511 
512 // FIXME: attribute indices do not account for nested `cfg_attr`
513 
514 impl MacroCallKind {
515     /// Returns the file containing the macro invocation.
file_id(&self) -> HirFileId516     fn file_id(&self) -> HirFileId {
517         match *self {
518             MacroCallKind::FnLike { ast_id: InFile { file_id, .. }, .. }
519             | MacroCallKind::Derive { ast_id: InFile { file_id, .. }, .. }
520             | MacroCallKind::Attr { ast_id: InFile { file_id, .. }, .. } => file_id,
521         }
522     }
523 
524     /// Returns the original file range that best describes the location of this macro call.
525     ///
526     /// Unlike `MacroCallKind::original_call_range`, this also spans the item of attributes and derives.
original_call_range_with_body(self, db: &dyn db::ExpandDatabase) -> FileRange527     pub fn original_call_range_with_body(self, db: &dyn db::ExpandDatabase) -> FileRange {
528         let mut kind = self;
529         let file_id = loop {
530             match kind.file_id().repr() {
531                 HirFileIdRepr::MacroFile(file) => {
532                     kind = db.lookup_intern_macro_call(file.macro_call_id).kind;
533                 }
534                 HirFileIdRepr::FileId(file_id) => break file_id,
535             }
536         };
537 
538         let range = match kind {
539             MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
540             MacroCallKind::Derive { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
541             MacroCallKind::Attr { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
542         };
543 
544         FileRange { range, file_id }
545     }
546 
547     /// Returns the original file range that best describes the location of this macro call.
548     ///
549     /// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros
550     /// get the whole `ast::MacroCall`, attribute macros get the attribute's range, and derives
551     /// get only the specific derive that is being referred to.
original_call_range(self, db: &dyn db::ExpandDatabase) -> FileRange552     pub fn original_call_range(self, db: &dyn db::ExpandDatabase) -> FileRange {
553         let mut kind = self;
554         let file_id = loop {
555             match kind.file_id().repr() {
556                 HirFileIdRepr::MacroFile(file) => {
557                     kind = db.lookup_intern_macro_call(file.macro_call_id).kind;
558                 }
559                 HirFileIdRepr::FileId(file_id) => break file_id,
560             }
561         };
562 
563         let range = match kind {
564             MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
565             MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
566                 // FIXME: should be the range of the macro name, not the whole derive
567                 // FIXME: handle `cfg_attr`
568                 ast_id
569                     .to_node(db)
570                     .doc_comments_and_attrs()
571                     .nth(derive_attr_index.ast_index())
572                     .expect("missing derive")
573                     .expect_left("derive is a doc comment?")
574                     .syntax()
575                     .text_range()
576             }
577             // FIXME: handle `cfg_attr`
578             MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => ast_id
579                 .to_node(db)
580                 .doc_comments_and_attrs()
581                 .nth(invoc_attr_index.ast_index())
582                 .expect("missing attribute")
583                 .expect_left("attribute macro is a doc comment?")
584                 .syntax()
585                 .text_range(),
586         };
587 
588         FileRange { range, file_id }
589     }
590 
arg(&self, db: &dyn db::ExpandDatabase) -> Option<SyntaxNode>591     fn arg(&self, db: &dyn db::ExpandDatabase) -> Option<SyntaxNode> {
592         match self {
593             MacroCallKind::FnLike { ast_id, .. } => {
594                 Some(ast_id.to_node(db).token_tree()?.syntax().clone())
595             }
596             MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()),
597             MacroCallKind::Attr { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()),
598         }
599     }
600 }
601 
602 impl MacroCallId {
as_file(self) -> HirFileId603     pub fn as_file(self) -> HirFileId {
604         MacroFile { macro_call_id: self }.into()
605     }
606 
as_macro_file(self) -> MacroFile607     pub fn as_macro_file(self) -> MacroFile {
608         MacroFile { macro_call_id: self }
609     }
610 }
611 
612 /// ExpansionInfo mainly describes how to map text range between src and expanded macro
613 #[derive(Debug, Clone, PartialEq, Eq)]
614 pub struct ExpansionInfo {
615     expanded: InFile<SyntaxNode>,
616     /// The argument TokenTree or item for attributes
617     arg: InFile<SyntaxNode>,
618     /// The `macro_rules!` or attribute input.
619     attr_input_or_mac_def: Option<InFile<ast::TokenTree>>,
620 
621     macro_def: Arc<TokenExpander>,
622     macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>,
623     /// A shift built from `macro_arg`'s subtree, relevant for attributes as the item is the macro arg
624     /// and as such we need to shift tokens if they are part of an attributes input instead of their item.
625     macro_arg_shift: mbe::Shift,
626     exp_map: Arc<mbe::TokenMap>,
627 }
628 
629 impl ExpansionInfo {
expanded(&self) -> InFile<SyntaxNode>630     pub fn expanded(&self) -> InFile<SyntaxNode> {
631         self.expanded.clone()
632     }
633 
call_node(&self) -> Option<InFile<SyntaxNode>>634     pub fn call_node(&self) -> Option<InFile<SyntaxNode>> {
635         Some(self.arg.with_value(self.arg.value.parent()?))
636     }
637 
638     /// Map a token down from macro input into the macro expansion.
639     ///
640     /// The inner workings of this function differ slightly depending on the type of macro we are dealing with:
641     /// - declarative:
642     ///     For declarative macros, we need to accommodate for the macro definition site(which acts as a second unchanging input)
643     ///     , as tokens can mapped in and out of it.
644     ///     To do this we shift all ids in the expansion by the maximum id of the definition site giving us an easy
645     ///     way to map all the tokens.
646     /// - attribute:
647     ///     Attributes have two different inputs, the input tokentree in the attribute node and the item
648     ///     the attribute is annotating. Similarly as for declarative macros we need to do a shift here
649     ///     as well. Currently this is done by shifting the attribute input by the maximum id of the item.
650     /// - function-like and derives:
651     ///     Both of these only have one simple call site input so no special handling is required here.
map_token_down( &self, db: &dyn db::ExpandDatabase, item: Option<ast::Item>, token: InFile<&SyntaxToken>, ) -> Option<impl Iterator<Item = InFile<SyntaxToken>> + '_>652     pub fn map_token_down(
653         &self,
654         db: &dyn db::ExpandDatabase,
655         item: Option<ast::Item>,
656         token: InFile<&SyntaxToken>,
657     ) -> Option<impl Iterator<Item = InFile<SyntaxToken>> + '_> {
658         assert_eq!(token.file_id, self.arg.file_id);
659         let token_id_in_attr_input = if let Some(item) = item {
660             // check if we are mapping down in an attribute input
661             // this is a special case as attributes can have two inputs
662             let call_id = self.expanded.file_id.macro_file()?.macro_call_id;
663             let loc = db.lookup_intern_macro_call(call_id);
664 
665             let token_range = token.value.text_range();
666             match &loc.kind {
667                 MacroCallKind::Attr { attr_args, invoc_attr_index, .. } => {
668                     // FIXME: handle `cfg_attr`
669                     let attr = item
670                         .doc_comments_and_attrs()
671                         .nth(invoc_attr_index.ast_index())
672                         .and_then(Either::left)?;
673                     match attr.token_tree() {
674                         Some(token_tree)
675                             if token_tree.syntax().text_range().contains_range(token_range) =>
676                         {
677                             let attr_input_start =
678                                 token_tree.left_delimiter_token()?.text_range().start();
679                             let relative_range =
680                                 token.value.text_range().checked_sub(attr_input_start)?;
681                             // shift by the item's tree's max id
682                             let token_id = attr_args.1.token_by_range(relative_range)?;
683 
684                             let token_id = if loc.def.is_attribute_derive() {
685                                 // we do not shift for `#[derive]`, as we only need to downmap the derive attribute tokens
686                                 token_id
687                             } else {
688                                 self.macro_arg_shift.shift(token_id)
689                             };
690                             Some(token_id)
691                         }
692                         _ => None,
693                     }
694                 }
695                 _ => None,
696             }
697         } else {
698             None
699         };
700 
701         let token_id = match token_id_in_attr_input {
702             Some(token_id) => token_id,
703             // the token is not inside `an attribute's input so do the lookup in the macro_arg as usual
704             None => {
705                 let relative_range =
706                     token.value.text_range().checked_sub(self.arg.value.text_range().start())?;
707                 let token_id = self.macro_arg.1.token_by_range(relative_range)?;
708                 // conditionally shift the id by a declaratives macro definition
709                 self.macro_def.map_id_down(token_id)
710             }
711         };
712 
713         let tokens = self
714             .exp_map
715             .ranges_by_token(token_id, token.value.kind())
716             .flat_map(move |range| self.expanded.value.covering_element(range).into_token());
717 
718         Some(tokens.map(move |token| self.expanded.with_value(token)))
719     }
720 
721     /// Map a token up out of the expansion it resides in into the arguments of the macro call of the expansion.
map_token_up( &self, db: &dyn db::ExpandDatabase, token: InFile<&SyntaxToken>, ) -> Option<(InFile<SyntaxToken>, Origin)>722     pub fn map_token_up(
723         &self,
724         db: &dyn db::ExpandDatabase,
725         token: InFile<&SyntaxToken>,
726     ) -> Option<(InFile<SyntaxToken>, Origin)> {
727         // Fetch the id through its text range,
728         let token_id = self.exp_map.token_by_range(token.value.text_range())?;
729         // conditionally unshifting the id to accommodate for macro-rules def site
730         let (mut token_id, origin) = self.macro_def.map_id_up(token_id);
731 
732         let call_id = self.expanded.file_id.macro_file()?.macro_call_id;
733         let loc = db.lookup_intern_macro_call(call_id);
734 
735         // Special case: map tokens from `include!` expansions to the included file
736         if loc.def.is_include()
737             && matches!(loc.eager.as_deref(), Some(EagerCallInfo { arg_id: Some(_), .. }))
738         {
739             if let Ok((tt_and_map, file_id)) = db.include_expand(call_id) {
740                 let range = tt_and_map.1.first_range_by_token(token_id, token.value.kind())?;
741                 let source = db.parse(file_id);
742 
743                 let token = source.syntax_node().covering_element(range).into_token()?;
744 
745                 return Some((InFile::new(file_id.into(), token), Origin::Call));
746             }
747         }
748 
749         // Attributes are a bit special for us, they have two inputs, the input tokentree and the annotated item.
750         let (token_map, tt) = match &loc.kind {
751             MacroCallKind::Attr { attr_args, .. } => {
752                 if loc.def.is_attribute_derive() {
753                     (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned())
754                 } else {
755                     // try unshifting the token id, if unshifting fails, the token resides in the non-item attribute input
756                     // note that the `TokenExpander::map_id_up` earlier only unshifts for declarative macros, so we don't double unshift with this
757                     match self.macro_arg_shift.unshift(token_id) {
758                         Some(unshifted) => {
759                             token_id = unshifted;
760                             (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned())
761                         }
762                         None => (&self.macro_arg.1, self.arg.clone()),
763                     }
764                 }
765             }
766             _ => match origin {
767                 mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
768                 mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def) {
769                     (TokenExpander::DeclarativeMacro { def_site_token_map, .. }, Some(tt)) => {
770                         (def_site_token_map, tt.syntax().cloned())
771                     }
772                     _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
773                 },
774             },
775         };
776 
777         let range = token_map.first_range_by_token(token_id, token.value.kind())?;
778         let token =
779             tt.value.covering_element(range + tt.value.text_range().start()).into_token()?;
780         Some((tt.with_value(token), origin))
781     }
782 }
783 
784 /// `AstId` points to an AST node in any file.
785 ///
786 /// It is stable across reparses, and can be used as salsa key/value.
787 pub type AstId<N> = InFile<FileAstId<N>>;
788 
789 impl<N: AstNode> AstId<N> {
to_node(&self, db: &dyn db::ExpandDatabase) -> N790     pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> N {
791         let root = db.parse_or_expand(self.file_id);
792         db.ast_id_map(self.file_id).get(self.value).to_node(&root)
793     }
794 }
795 
796 /// `InFile<T>` stores a value of `T` inside a particular file/syntax tree.
797 ///
798 /// Typical usages are:
799 ///
800 /// * `InFile<SyntaxNode>` -- syntax node in a file
801 /// * `InFile<ast::FnDef>` -- ast node in a file
802 /// * `InFile<TextSize>` -- offset in a file
803 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
804 pub struct InFile<T> {
805     pub file_id: HirFileId,
806     pub value: T,
807 }
808 
809 impl<T> InFile<T> {
new(file_id: HirFileId, value: T) -> InFile<T>810     pub fn new(file_id: HirFileId, value: T) -> InFile<T> {
811         InFile { file_id, value }
812     }
813 
with_value<U>(&self, value: U) -> InFile<U>814     pub fn with_value<U>(&self, value: U) -> InFile<U> {
815         InFile::new(self.file_id, value)
816     }
817 
map<F: FnOnce(T) -> U, U>(self, f: F) -> InFile<U>818     pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> InFile<U> {
819         InFile::new(self.file_id, f(self.value))
820     }
821 
as_ref(&self) -> InFile<&T>822     pub fn as_ref(&self) -> InFile<&T> {
823         self.with_value(&self.value)
824     }
825 
file_syntax(&self, db: &dyn db::ExpandDatabase) -> SyntaxNode826     pub fn file_syntax(&self, db: &dyn db::ExpandDatabase) -> SyntaxNode {
827         db.parse_or_expand(self.file_id)
828     }
829 }
830 
831 impl<T: Clone> InFile<&T> {
cloned(&self) -> InFile<T>832     pub fn cloned(&self) -> InFile<T> {
833         self.with_value(self.value.clone())
834     }
835 }
836 
837 impl<T> InFile<Option<T>> {
transpose(self) -> Option<InFile<T>>838     pub fn transpose(self) -> Option<InFile<T>> {
839         let value = self.value?;
840         Some(InFile::new(self.file_id, value))
841     }
842 }
843 
844 impl<L, R> InFile<Either<L, R>> {
transpose(self) -> Either<InFile<L>, InFile<R>>845     pub fn transpose(self) -> Either<InFile<L>, InFile<R>> {
846         match self.value {
847             Either::Left(l) => Either::Left(InFile::new(self.file_id, l)),
848             Either::Right(r) => Either::Right(InFile::new(self.file_id, r)),
849         }
850     }
851 }
852 
853 impl<'a> InFile<&'a SyntaxNode> {
ancestors_with_macros( self, db: &dyn db::ExpandDatabase, ) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_854     pub fn ancestors_with_macros(
855         self,
856         db: &dyn db::ExpandDatabase,
857     ) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_ {
858         iter::successors(Some(self.cloned()), move |node| match node.value.parent() {
859             Some(parent) => Some(node.with_value(parent)),
860             None => node.file_id.call_node(db),
861         })
862     }
863 
864     /// Skips the attributed item that caused the macro invocation we are climbing up
ancestors_with_macros_skip_attr_item( self, db: &dyn db::ExpandDatabase, ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_865     pub fn ancestors_with_macros_skip_attr_item(
866         self,
867         db: &dyn db::ExpandDatabase,
868     ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
869         let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() {
870             Some(parent) => Some(node.with_value(parent)),
871             None => {
872                 let parent_node = node.file_id.call_node(db)?;
873                 if node.file_id.is_attr_macro(db) {
874                     // macro call was an attributed item, skip it
875                     // FIXME: does this fail if this is a direct expansion of another macro?
876                     parent_node.map(|node| node.parent()).transpose()
877                 } else {
878                     Some(parent_node)
879                 }
880             }
881         };
882         iter::successors(succ(&self.cloned()), succ)
883     }
884 
885     /// Falls back to the macro call range if the node cannot be mapped up fully.
886     ///
887     /// For attributes and derives, this will point back to the attribute only.
888     /// For the entire item use [`InFile::original_file_range_full`].
original_file_range(self, db: &dyn db::ExpandDatabase) -> FileRange889     pub fn original_file_range(self, db: &dyn db::ExpandDatabase) -> FileRange {
890         match self.file_id.repr() {
891             HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
892             HirFileIdRepr::MacroFile(mac_file) => {
893                 if let Some(res) = self.original_file_range_opt(db) {
894                     return res;
895                 }
896                 // Fall back to whole macro call.
897                 let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
898                 loc.kind.original_call_range(db)
899             }
900         }
901     }
902 
903     /// Falls back to the macro call range if the node cannot be mapped up fully.
original_file_range_full(self, db: &dyn db::ExpandDatabase) -> FileRange904     pub fn original_file_range_full(self, db: &dyn db::ExpandDatabase) -> FileRange {
905         match self.file_id.repr() {
906             HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
907             HirFileIdRepr::MacroFile(mac_file) => {
908                 if let Some(res) = self.original_file_range_opt(db) {
909                     return res;
910                 }
911                 // Fall back to whole macro call.
912                 let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
913                 loc.kind.original_call_range_with_body(db)
914             }
915         }
916     }
917 
918     /// Attempts to map the syntax node back up its macro calls.
original_file_range_opt(self, db: &dyn db::ExpandDatabase) -> Option<FileRange>919     pub fn original_file_range_opt(self, db: &dyn db::ExpandDatabase) -> Option<FileRange> {
920         match ascend_node_border_tokens(db, self) {
921             Some(InFile { file_id, value: (first, last) }) => {
922                 let original_file = file_id.original_file(db);
923                 let range = first.text_range().cover(last.text_range());
924                 if file_id != original_file.into() {
925                     tracing::error!("Failed mapping up more for {:?}", range);
926                     return None;
927                 }
928                 Some(FileRange { file_id: original_file, range })
929             }
930             _ if !self.file_id.is_macro() => Some(FileRange {
931                 file_id: self.file_id.original_file(db),
932                 range: self.value.text_range(),
933             }),
934             _ => None,
935         }
936     }
937 
original_syntax_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxNode>>938     pub fn original_syntax_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxNode>> {
939         // This kind of upmapping can only be achieved in attribute expanded files,
940         // as we don't have node inputs otherwise and therefore can't find an `N` node in the input
941         if !self.file_id.is_macro() {
942             return Some(self.map(Clone::clone));
943         } else if !self.file_id.is_attr_macro(db) {
944             return None;
945         }
946 
947         if let Some(InFile { file_id, value: (first, last) }) = ascend_node_border_tokens(db, self)
948         {
949             if file_id.is_macro() {
950                 let range = first.text_range().cover(last.text_range());
951                 tracing::error!("Failed mapping out of macro file for {:?}", range);
952                 return None;
953             }
954             // FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes
955             let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?;
956             let kind = self.value.kind();
957             let value = anc.ancestors().find(|it| it.kind() == kind)?;
958             return Some(InFile::new(file_id, value));
959         }
960         None
961     }
962 }
963 
964 impl InFile<SyntaxToken> {
upmap(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxToken>>965     pub fn upmap(self, db: &dyn db::ExpandDatabase) -> Option<InFile<SyntaxToken>> {
966         let expansion = self.file_id.expansion_info(db)?;
967         expansion.map_token_up(db, self.as_ref()).map(|(it, _)| it)
968     }
969 
970     /// Falls back to the macro call range if the node cannot be mapped up fully.
original_file_range(self, db: &dyn db::ExpandDatabase) -> FileRange971     pub fn original_file_range(self, db: &dyn db::ExpandDatabase) -> FileRange {
972         match self.file_id.repr() {
973             HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
974             HirFileIdRepr::MacroFile(mac_file) => {
975                 if let Some(res) = self.original_file_range_opt(db) {
976                     return res;
977                 }
978                 // Fall back to whole macro call.
979                 let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
980                 loc.kind.original_call_range(db)
981             }
982         }
983     }
984 
985     /// Attempts to map the syntax node back up its macro calls.
original_file_range_opt(self, db: &dyn db::ExpandDatabase) -> Option<FileRange>986     pub fn original_file_range_opt(self, db: &dyn db::ExpandDatabase) -> Option<FileRange> {
987         match self.file_id.repr() {
988             HirFileIdRepr::FileId(file_id) => {
989                 Some(FileRange { file_id, range: self.value.text_range() })
990             }
991             HirFileIdRepr::MacroFile(_) => {
992                 let expansion = self.file_id.expansion_info(db)?;
993                 let InFile { file_id, value } = ascend_call_token(db, &expansion, self)?;
994                 let original_file = file_id.original_file(db);
995                 if file_id != original_file.into() {
996                     return None;
997                 }
998                 Some(FileRange { file_id: original_file, range: value.text_range() })
999             }
1000         }
1001     }
1002 
ancestors_with_macros( self, db: &dyn db::ExpandDatabase, ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_1003     pub fn ancestors_with_macros(
1004         self,
1005         db: &dyn db::ExpandDatabase,
1006     ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
1007         self.value.parent().into_iter().flat_map({
1008             let file_id = self.file_id;
1009             move |parent| InFile::new(file_id, &parent).ancestors_with_macros(db)
1010         })
1011     }
1012 }
1013 
1014 fn ascend_node_border_tokens(
1015     db: &dyn db::ExpandDatabase,
1016     InFile { file_id, value: node }: InFile<&SyntaxNode>,
1017 ) -> Option<InFile<(SyntaxToken, SyntaxToken)>> {
1018     let expansion = file_id.expansion_info(db)?;
1019 
1020     let first_token = |node: &SyntaxNode| skip_trivia_token(node.first_token()?, Direction::Next);
1021     let last_token = |node: &SyntaxNode| skip_trivia_token(node.last_token()?, Direction::Prev);
1022 
1023     // FIXME: Once the token map rewrite is done, this shouldnt need to rely on syntax nodes and tokens anymore
1024     let first = first_token(node)?;
1025     let last = last_token(node)?;
1026     let first = ascend_call_token(db, &expansion, InFile::new(file_id, first))?;
1027     let last = ascend_call_token(db, &expansion, InFile::new(file_id, last))?;
1028     (first.file_id == last.file_id).then(|| InFile::new(first.file_id, (first.value, last.value)))
1029 }
1030 
ascend_call_token( db: &dyn db::ExpandDatabase, expansion: &ExpansionInfo, token: InFile<SyntaxToken>, ) -> Option<InFile<SyntaxToken>>1031 fn ascend_call_token(
1032     db: &dyn db::ExpandDatabase,
1033     expansion: &ExpansionInfo,
1034     token: InFile<SyntaxToken>,
1035 ) -> Option<InFile<SyntaxToken>> {
1036     let mut mapping = expansion.map_token_up(db, token.as_ref())?;
1037     while let (mapped, Origin::Call) = mapping {
1038         match mapped.file_id.expansion_info(db) {
1039             Some(info) => mapping = info.map_token_up(db, mapped.as_ref())?,
1040             None => return Some(mapped),
1041         }
1042     }
1043     None
1044 }
1045 
1046 impl<N: AstNode> InFile<N> {
descendants<T: AstNode>(self) -> impl Iterator<Item = InFile<T>>1047     pub fn descendants<T: AstNode>(self) -> impl Iterator<Item = InFile<T>> {
1048         self.value.syntax().descendants().filter_map(T::cast).map(move |n| self.with_value(n))
1049     }
1050 
1051     // FIXME: this should return `Option<InFileNotHirFile<N>>`
original_ast_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<N>>1052     pub fn original_ast_node(self, db: &dyn db::ExpandDatabase) -> Option<InFile<N>> {
1053         // This kind of upmapping can only be achieved in attribute expanded files,
1054         // as we don't have node inputs otherwise and therefore can't find an `N` node in the input
1055         if !self.file_id.is_macro() {
1056             return Some(self);
1057         } else if !self.file_id.is_attr_macro(db) {
1058             return None;
1059         }
1060 
1061         if let Some(InFile { file_id, value: (first, last) }) =
1062             ascend_node_border_tokens(db, self.syntax())
1063         {
1064             if file_id.is_macro() {
1065                 let range = first.text_range().cover(last.text_range());
1066                 tracing::error!("Failed mapping out of macro file for {:?}", range);
1067                 return None;
1068             }
1069             // FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes
1070             let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?;
1071             let value = anc.ancestors().find_map(N::cast)?;
1072             return Some(InFile::new(file_id, value));
1073         }
1074         None
1075     }
1076 
syntax(&self) -> InFile<&SyntaxNode>1077     pub fn syntax(&self) -> InFile<&SyntaxNode> {
1078         self.with_value(self.value.syntax())
1079     }
1080 }
1081 
1082 /// In Rust, macros expand token trees to token trees. When we want to turn a
1083 /// token tree into an AST node, we need to figure out what kind of AST node we
1084 /// want: something like `foo` can be a type, an expression, or a pattern.
1085 ///
1086 /// Naively, one would think that "what this expands to" is a property of a
1087 /// particular macro: macro `m1` returns an item, while macro `m2` returns an
1088 /// expression, etc. That's not the case -- macros are polymorphic in the
1089 /// result, and can expand to any type of the AST node.
1090 ///
1091 /// What defines the actual AST node is the syntactic context of the macro
1092 /// invocation. As a contrived example, in `let T![*] = T![*];` the first `T`
1093 /// expands to a pattern, while the second one expands to an expression.
1094 ///
1095 /// `ExpandTo` captures this bit of information about a particular macro call
1096 /// site.
1097 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1098 pub enum ExpandTo {
1099     Statements,
1100     Items,
1101     Pattern,
1102     Type,
1103     Expr,
1104 }
1105 
1106 impl ExpandTo {
from_call_site(call: &ast::MacroCall) -> ExpandTo1107     pub fn from_call_site(call: &ast::MacroCall) -> ExpandTo {
1108         use syntax::SyntaxKind::*;
1109 
1110         let syn = call.syntax();
1111 
1112         let parent = match syn.parent() {
1113             Some(it) => it,
1114             None => return ExpandTo::Statements,
1115         };
1116 
1117         // FIXME: macros in statement position are treated as expression statements, they should
1118         // probably be their own statement kind. The *grand*parent indicates what's valid.
1119         if parent.kind() == MACRO_EXPR
1120             && parent
1121                 .parent()
1122                 .map_or(false, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
1123         {
1124             return ExpandTo::Statements;
1125         }
1126 
1127         match parent.kind() {
1128             MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => ExpandTo::Items,
1129             MACRO_STMTS | EXPR_STMT | STMT_LIST => ExpandTo::Statements,
1130             MACRO_PAT => ExpandTo::Pattern,
1131             MACRO_TYPE => ExpandTo::Type,
1132 
1133             ARG_LIST | ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BREAK_EXPR | CALL_EXPR | CAST_EXPR
1134             | CLOSURE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR | INDEX_EXPR | LET_EXPR
1135             | MATCH_ARM | MATCH_EXPR | MATCH_GUARD | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR
1136             | PREFIX_EXPR | RANGE_EXPR | RECORD_EXPR_FIELD | REF_EXPR | RETURN_EXPR | TRY_EXPR
1137             | TUPLE_EXPR | WHILE_EXPR | MACRO_EXPR => ExpandTo::Expr,
1138             _ => {
1139                 // Unknown , Just guess it is `Items`
1140                 ExpandTo::Items
1141             }
1142         }
1143     }
1144 }
1145 
1146 #[derive(Debug)]
1147 pub struct UnresolvedMacro {
1148     pub path: ModPath,
1149 }
1150 
1151 intern::impl_internable!(ModPath, attrs::AttrInput);
1152