@@ -154,8 +154,9 @@ pub enum MacroDefKind {
154
154
struct EagerCallInfo {
155
155
/// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro!
156
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.
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.
159
160
arg_id : Option < MacroCallId > ,
160
161
error : Option < ExpandError > ,
161
162
}
@@ -270,53 +271,7 @@ impl HirFileId {
270
271
/// Return expansion information if it is a macro-expansion file
271
272
pub fn expansion_info ( self , db : & dyn db:: ExpandDatabase ) -> Option < ExpansionInfo > {
272
273
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)
320
275
}
321
276
322
277
pub fn as_builtin_derive_attr_node (
@@ -603,13 +558,18 @@ impl MacroCallKind {
603
558
FileRange { range, file_id }
604
559
}
605
560
606
- fn arg ( & self , db : & dyn db:: ExpandDatabase ) -> Option < SyntaxNode > {
561
+ fn arg ( & self , db : & dyn db:: ExpandDatabase ) -> Option < InFile < SyntaxNode > > {
607
562
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 ( ) )
610
572
}
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 ( ) ) ,
613
573
}
614
574
}
615
575
}
@@ -627,7 +587,7 @@ impl MacroCallId {
627
587
/// ExpansionInfo mainly describes how to map text range between src and expanded macro
628
588
#[ derive( Debug , Clone , PartialEq , Eq ) ]
629
589
pub struct ExpansionInfo {
630
- expanded : InFile < SyntaxNode > ,
590
+ expanded : InMacroFile < SyntaxNode > ,
631
591
/// The argument TokenTree or item for attributes
632
592
arg : InFile < SyntaxNode > ,
633
593
/// The `macro_rules!` or attribute input.
@@ -643,7 +603,7 @@ pub struct ExpansionInfo {
643
603
644
604
impl ExpansionInfo {
645
605
pub fn expanded ( & self ) -> InFile < SyntaxNode > {
646
- self . expanded . clone ( )
606
+ self . expanded . clone ( ) . into ( )
647
607
}
648
608
649
609
pub fn call_node ( & self ) -> Option < InFile < SyntaxNode > > {
@@ -674,7 +634,7 @@ impl ExpansionInfo {
674
634
let token_id_in_attr_input = if let Some ( item) = item {
675
635
// check if we are mapping down in an attribute input
676
636
// 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 ;
678
638
let loc = db. lookup_intern_macro_call ( call_id) ;
679
639
680
640
let token_range = token. value . text_range ( ) ;
@@ -720,7 +680,7 @@ impl ExpansionInfo {
720
680
let relative_range =
721
681
token. value . text_range ( ) . checked_sub ( self . arg . value . text_range ( ) . start ( ) ) ?;
722
682
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
724
684
self . macro_def . map_id_down ( token_id)
725
685
}
726
686
} ;
@@ -730,7 +690,7 @@ impl ExpansionInfo {
730
690
. ranges_by_token ( token_id, token. value . kind ( ) )
731
691
. flat_map ( move |range| self . expanded . value . covering_element ( range) . into_token ( ) ) ;
732
692
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) ) )
734
694
}
735
695
736
696
/// 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 {
739
699
db : & dyn db:: ExpandDatabase ,
740
700
token : InFile < & SyntaxToken > ,
741
701
) -> Option < ( InFile < SyntaxToken > , Origin ) > {
702
+ assert_eq ! ( token. file_id, self . expanded. file_id. into( ) ) ;
742
703
// Fetch the id through its text range,
743
704
let token_id = self . exp_map . token_by_range ( token. value . text_range ( ) ) ?;
744
705
// conditionally unshifting the id to accommodate for macro-rules def site
745
706
let ( mut token_id, origin) = self . macro_def . map_id_up ( token_id) ;
746
707
747
- let call_id = self . expanded . file_id . macro_file ( ) ? . macro_call_id ;
708
+ let call_id = self . expanded . file_id . macro_call_id ;
748
709
let loc = db. lookup_intern_macro_call ( call_id) ;
749
710
750
711
// Special case: map tokens from `include!` expansions to the included file
@@ -794,6 +755,63 @@ impl ExpansionInfo {
794
755
tt. value . covering_element ( range + tt. value . text_range ( ) . start ( ) ) . into_token ( ) ?;
795
756
Some ( ( tt. with_value ( token) , origin) )
796
757
}
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
+ }
797
815
}
798
816
799
817
/// `AstId` points to an AST node in any file.
@@ -805,6 +823,9 @@ impl<N: AstIdNode> AstId<N> {
805
823
pub fn to_node ( & self , db : & dyn db:: ExpandDatabase ) -> N {
806
824
self . to_ptr ( db) . to_node ( & db. parse_or_expand ( self . file_id ) )
807
825
}
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
+ }
808
829
pub fn to_ptr ( & self , db : & dyn db:: ExpandDatabase ) -> AstPtr < N > {
809
830
db. ast_id_map ( self . file_id ) . get ( self . value )
810
831
}
@@ -820,6 +841,7 @@ impl ErasedAstId {
820
841
db. ast_id_map ( self . file_id ) . get_raw ( self . value )
821
842
}
822
843
}
844
+
823
845
/// `InFile<T>` stores a value of `T` inside a particular file/syntax tree.
824
846
///
825
847
/// Typical usages are:
@@ -1038,6 +1060,18 @@ impl InFile<SyntaxToken> {
1038
1060
}
1039
1061
}
1040
1062
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
+
1041
1075
fn ascend_node_border_tokens (
1042
1076
db : & dyn db:: ExpandDatabase ,
1043
1077
InFile { file_id, value : node } : InFile < & SyntaxNode > ,
0 commit comments