@@ -154,8 +154,9 @@ pub enum MacroDefKind {
154154struct EagerCallInfo {
155155 /// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro!
156156 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.
157+ /// Call id of the eager macro's input file (this is the macro file for its fully expanded input).
158+ /// If this is none, `arg` contains the pre-expanded input, otherwise arg contains the
159+ /// post-expanded input.
159160 arg_id : Option < MacroCallId > ,
160161 error : Option < ExpandError > ,
161162}
@@ -270,53 +271,7 @@ impl HirFileId {
270271 /// Return expansion information if it is a macro-expansion file
271272 pub fn expansion_info ( self , db : & dyn db:: ExpandDatabase ) -> Option < ExpansionInfo > {
272273 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 ) ;
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- } )
274+ ExpansionInfo :: new ( db, macro_file)
320275 }
321276
322277 pub fn as_builtin_derive_attr_node (
@@ -603,13 +558,18 @@ impl MacroCallKind {
603558 FileRange { range, file_id }
604559 }
605560
606- fn arg ( & self , db : & dyn db:: ExpandDatabase ) -> Option < SyntaxNode > {
561+ fn arg ( & self , db : & dyn db:: ExpandDatabase ) -> Option < InFile < SyntaxNode > > {
607562 match self {
608- MacroCallKind :: FnLike { ast_id, .. } => {
609- Some ( ast_id. to_node ( db) . token_tree ( ) ?. syntax ( ) . clone ( ) )
563+ MacroCallKind :: FnLike { ast_id, .. } => ast_id
564+ . to_in_file_node ( db)
565+ . map ( |it| Some ( it. token_tree ( ) ?. syntax ( ) . clone ( ) ) )
566+ . transpose ( ) ,
567+ MacroCallKind :: Derive { ast_id, .. } => {
568+ Some ( ast_id. to_in_file_node ( db) . syntax ( ) . cloned ( ) )
569+ }
570+ MacroCallKind :: Attr { ast_id, .. } => {
571+ Some ( ast_id. to_in_file_node ( db) . syntax ( ) . cloned ( ) )
610572 }
611- MacroCallKind :: Derive { ast_id, .. } => Some ( ast_id. to_node ( db) . syntax ( ) . clone ( ) ) ,
612- MacroCallKind :: Attr { ast_id, .. } => Some ( ast_id. to_node ( db) . syntax ( ) . clone ( ) ) ,
613573 }
614574 }
615575}
@@ -627,7 +587,7 @@ impl MacroCallId {
627587/// ExpansionInfo mainly describes how to map text range between src and expanded macro
628588#[ derive( Debug , Clone , PartialEq , Eq ) ]
629589pub struct ExpansionInfo {
630- expanded : InFile < SyntaxNode > ,
590+ expanded : InMacroFile < SyntaxNode > ,
631591 /// The argument TokenTree or item for attributes
632592 arg : InFile < SyntaxNode > ,
633593 /// The `macro_rules!` or attribute input.
@@ -643,7 +603,7 @@ pub struct ExpansionInfo {
643603
644604impl ExpansionInfo {
645605 pub fn expanded ( & self ) -> InFile < SyntaxNode > {
646- self . expanded . clone ( )
606+ self . expanded . clone ( ) . into ( )
647607 }
648608
649609 pub fn call_node ( & self ) -> Option < InFile < SyntaxNode > > {
@@ -674,7 +634,7 @@ impl ExpansionInfo {
674634 let token_id_in_attr_input = if let Some ( item) = item {
675635 // check if we are mapping down in an attribute input
676636 // this is a special case as attributes can have two inputs
677- let call_id = self . expanded . file_id . macro_file ( ) ? . macro_call_id ;
637+ let call_id = self . expanded . file_id . macro_call_id ;
678638 let loc = db. lookup_intern_macro_call ( call_id) ;
679639
680640 let token_range = token. value . text_range ( ) ;
@@ -720,7 +680,7 @@ impl ExpansionInfo {
720680 let relative_range =
721681 token. value . text_range ( ) . checked_sub ( self . arg . value . text_range ( ) . start ( ) ) ?;
722682 let token_id = self . macro_arg . 1 . token_by_range ( relative_range) ?;
723- // conditionally shift the id by a declaratives macro definition
683+ // conditionally shift the id by a declarative macro definition
724684 self . macro_def . map_id_down ( token_id)
725685 }
726686 } ;
@@ -730,7 +690,7 @@ impl ExpansionInfo {
730690 . ranges_by_token ( token_id, token. value . kind ( ) )
731691 . flat_map ( move |range| self . expanded . value . covering_element ( range) . into_token ( ) ) ;
732692
733- Some ( tokens. map ( move |token| self . expanded . with_value ( token) ) )
693+ Some ( tokens. map ( move |token| InFile :: new ( self . expanded . file_id . into ( ) , token) ) )
734694 }
735695
736696 /// Map a token up out of the expansion it resides in into the arguments of the macro call of the expansion.
@@ -739,12 +699,13 @@ impl ExpansionInfo {
739699 db : & dyn db:: ExpandDatabase ,
740700 token : InFile < & SyntaxToken > ,
741701 ) -> Option < ( InFile < SyntaxToken > , Origin ) > {
702+ assert_eq ! ( token. file_id, self . expanded. file_id. into( ) ) ;
742703 // Fetch the id through its text range,
743704 let token_id = self . exp_map . token_by_range ( token. value . text_range ( ) ) ?;
744705 // conditionally unshifting the id to accommodate for macro-rules def site
745706 let ( mut token_id, origin) = self . macro_def . map_id_up ( token_id) ;
746707
747- let call_id = self . expanded . file_id . macro_file ( ) ? . macro_call_id ;
708+ let call_id = self . expanded . file_id . macro_call_id ;
748709 let loc = db. lookup_intern_macro_call ( call_id) ;
749710
750711 // Special case: map tokens from `include!` expansions to the included file
@@ -794,6 +755,63 @@ impl ExpansionInfo {
794755 tt. value . covering_element ( range + tt. value . text_range ( ) . start ( ) ) . into_token ( ) ?;
795756 Some ( ( tt. with_value ( token) , origin) )
796757 }
758+
759+ fn new ( db : & dyn db:: ExpandDatabase , macro_file : MacroFile ) -> Option < ExpansionInfo > {
760+ let loc: MacroCallLoc = db. lookup_intern_macro_call ( macro_file. macro_call_id ) ;
761+
762+ let arg_tt = loc. kind . arg ( db) ?;
763+
764+ let macro_def = db. macro_def ( loc. def ) ;
765+ let ( parse, exp_map) = db. parse_macro_expansion ( macro_file) . value ;
766+ let expanded = InMacroFile { file_id : macro_file, value : parse. syntax_node ( ) } ;
767+
768+ let macro_arg = db
769+ . macro_arg ( match loc. eager . as_deref ( ) {
770+ Some ( & EagerCallInfo { arg_id : Some ( _) , .. } ) => return None ,
771+ _ => macro_file. macro_call_id ,
772+ } )
773+ . unwrap_or_else ( || {
774+ Arc :: new ( (
775+ tt:: Subtree { delimiter : tt:: Delimiter :: UNSPECIFIED , token_trees : Vec :: new ( ) } ,
776+ Default :: default ( ) ,
777+ Default :: default ( ) ,
778+ ) )
779+ } ) ;
780+
781+ let def = loc. def . ast_id ( ) . left ( ) . and_then ( |id| {
782+ let def_tt = match id. to_node ( db) {
783+ ast:: Macro :: MacroRules ( mac) => mac. token_tree ( ) ?,
784+ ast:: Macro :: MacroDef ( _) if matches ! ( macro_def, TokenExpander :: BuiltInAttr ( _) ) => {
785+ return None
786+ }
787+ ast:: Macro :: MacroDef ( mac) => mac. body ( ) ?,
788+ } ;
789+ Some ( InFile :: new ( id. file_id , def_tt) )
790+ } ) ;
791+ let attr_input_or_mac_def = def. or_else ( || match loc. kind {
792+ MacroCallKind :: Attr { ast_id, invoc_attr_index, .. } => {
793+ // FIXME: handle `cfg_attr`
794+ let tt = ast_id
795+ . to_node ( db)
796+ . doc_comments_and_attrs ( )
797+ . nth ( invoc_attr_index. ast_index ( ) )
798+ . and_then ( Either :: left) ?
799+ . token_tree ( ) ?;
800+ Some ( InFile :: new ( ast_id. file_id , tt) )
801+ }
802+ _ => None ,
803+ } ) ;
804+
805+ Some ( ExpansionInfo {
806+ expanded,
807+ arg : arg_tt,
808+ attr_input_or_mac_def,
809+ macro_arg_shift : mbe:: Shift :: new ( & macro_arg. 0 ) ,
810+ macro_arg,
811+ macro_def,
812+ exp_map,
813+ } )
814+ }
797815}
798816
799817/// `AstId` points to an AST node in any file.
@@ -805,6 +823,9 @@ impl<N: AstIdNode> AstId<N> {
805823 pub fn to_node ( & self , db : & dyn db:: ExpandDatabase ) -> N {
806824 self . to_ptr ( db) . to_node ( & db. parse_or_expand ( self . file_id ) )
807825 }
826+ pub fn to_in_file_node ( & self , db : & dyn db:: ExpandDatabase ) -> InFile < N > {
827+ InFile :: new ( self . file_id , self . to_ptr ( db) . to_node ( & db. parse_or_expand ( self . file_id ) ) )
828+ }
808829 pub fn to_ptr ( & self , db : & dyn db:: ExpandDatabase ) -> AstPtr < N > {
809830 db. ast_id_map ( self . file_id ) . get ( self . value )
810831 }
@@ -820,6 +841,7 @@ impl ErasedAstId {
820841 db. ast_id_map ( self . file_id ) . get_raw ( self . value )
821842 }
822843}
844+
823845/// `InFile<T>` stores a value of `T` inside a particular file/syntax tree.
824846///
825847/// Typical usages are:
@@ -1038,6 +1060,18 @@ impl InFile<SyntaxToken> {
10381060 }
10391061}
10401062
1063+ #[ derive( Debug , PartialEq , Eq , Clone , Copy , Hash ) ]
1064+ pub struct InMacroFile < T > {
1065+ pub file_id : MacroFile ,
1066+ pub value : T ,
1067+ }
1068+
1069+ impl < T > From < InMacroFile < T > > for InFile < T > {
1070+ fn from ( macro_file : InMacroFile < T > ) -> Self {
1071+ InFile { file_id : macro_file. file_id . into ( ) , value : macro_file. value }
1072+ }
1073+ }
1074+
10411075fn ascend_node_border_tokens (
10421076 db : & dyn db:: ExpandDatabase ,
10431077 InFile { file_id, value : node } : InFile < & SyntaxNode > ,
0 commit comments