@@ -20,11 +20,12 @@ use hir_def::{
20
20
} ;
21
21
use hir_expand:: {
22
22
attrs:: collect_attrs, db:: ExpandDatabase , files:: InRealFile , name:: AsName , ExpansionInfo ,
23
- InMacroFile , MacroCallId , MacroFileId , MacroFileIdExt ,
23
+ HirFileIdExt , InMacroFile , MacroCallId , MacroFileId , MacroFileIdExt ,
24
24
} ;
25
25
use itertools:: Itertools ;
26
26
use rustc_hash:: { FxHashMap , FxHashSet } ;
27
27
use smallvec:: { smallvec, SmallVec } ;
28
+ use span:: Span ;
28
29
use stdx:: TupleExt ;
29
30
use syntax:: {
30
31
algo:: skip_trivia_token,
@@ -607,29 +608,111 @@ impl<'db> SemanticsImpl<'db> {
607
608
res
608
609
}
609
610
610
- fn descend_into_macros_impl (
611
+ // return:
612
+ // SourceAnalyzer(file_id that original call include!)
613
+ // macro file id
614
+ // token in include! macro mapped from token in params
615
+ // span for the mapped token
616
+ fn is_from_include_file (
611
617
& self ,
612
618
token : SyntaxToken ,
619
+ ) -> Option < ( SourceAnalyzer , HirFileId , SyntaxToken , Span ) > {
620
+ let parent = token. parent ( ) ?;
621
+ let file_id = self . find_file ( & parent) . file_id . file_id ( ) ?;
622
+
623
+ // iterate related crates and find all include! invocations that include_file_id matches
624
+ for ( invoc, _) in self
625
+ . db
626
+ . relevant_crates ( file_id)
627
+ . iter ( )
628
+ . flat_map ( |krate| self . db . include_macro_invoc ( * krate) )
629
+ . filter ( |( _, include_file_id) | * include_file_id == file_id)
630
+ {
631
+ // find file_id which original calls include!
632
+ let Some ( callnode) = invoc. as_file ( ) . original_call_node ( self . db . upcast ( ) ) else {
633
+ continue ;
634
+ } ;
635
+
636
+ // call .parse to avoid panic in .find_file
637
+ let _ = self . parse ( callnode. file_id ) ;
638
+ let Some ( sa) = self . analyze_no_infer ( & callnode. value ) else { continue } ;
639
+
640
+ let expinfo = invoc. as_macro_file ( ) . expansion_info ( self . db . upcast ( ) ) ;
641
+ {
642
+ let InMacroFile { file_id, value } = expinfo. expanded ( ) ;
643
+ self . cache ( value, file_id. into ( ) ) ;
644
+ }
645
+
646
+ // map token to the corresponding span in include! macro file
647
+ let Some ( ( _, span) ) =
648
+ expinfo. exp_map . iter ( ) . find ( |( _, x) | x. range == token. text_range ( ) )
649
+ else {
650
+ continue ;
651
+ } ;
652
+
653
+ // get mapped token in the include! macro file
654
+ let Some ( InMacroFile { file_id : _, value : mapped_tokens } ) =
655
+ expinfo. map_range_down ( span)
656
+ else {
657
+ continue ;
658
+ } ;
659
+
660
+ // if we find one, then return
661
+ if let Some ( t) = mapped_tokens. into_iter ( ) . next ( ) {
662
+ return Some ( ( sa, invoc. as_file ( ) , t, span) ) ;
663
+ } ;
664
+ }
665
+
666
+ None
667
+ }
668
+
669
+ fn descend_into_macros_impl (
670
+ & self ,
671
+ mut token : SyntaxToken ,
613
672
f : & mut dyn FnMut ( InFile < SyntaxToken > ) -> ControlFlow < ( ) > ,
614
673
) {
615
674
let _p = profile:: span ( "descend_into_macros" ) ;
675
+
676
+ let mut include_macro_file_id_and_span = None ;
677
+
616
678
let sa = match token. parent ( ) . and_then ( |parent| self . analyze_no_infer ( & parent) ) {
617
679
Some ( it) => it,
618
- None => return ,
680
+ None => {
681
+ // if we cannot find a source analyzer for this token, then we try to find out whether this file is included from other file
682
+ let Some ( ( it, macro_file_id, mapped_token, s) ) = self . is_from_include_file ( token)
683
+ else {
684
+ return ;
685
+ } ;
686
+
687
+ include_macro_file_id_and_span = Some ( ( macro_file_id, s) ) ;
688
+ token = mapped_token;
689
+ it
690
+ }
619
691
} ;
620
692
621
- let span = match sa. file_id . file_id ( ) {
622
- Some ( file_id) => self . db . real_span_map ( file_id) . span_for_range ( token. text_range ( ) ) ,
623
- None => {
624
- stdx:: never!( ) ;
625
- return ;
693
+ let span = if let Some ( ( _, s) ) = include_macro_file_id_and_span {
694
+ s
695
+ } else {
696
+ match sa. file_id . file_id ( ) {
697
+ Some ( file_id) => self . db . real_span_map ( file_id) . span_for_range ( token. text_range ( ) ) ,
698
+ None => {
699
+ stdx:: never!( ) ;
700
+ return ;
701
+ }
626
702
}
627
703
} ;
628
704
629
705
let mut cache = self . expansion_info_cache . borrow_mut ( ) ;
630
706
let mut mcache = self . macro_call_cache . borrow_mut ( ) ;
631
707
let def_map = sa. resolver . def_map ( ) ;
632
708
709
+ let mut stack: Vec < ( _ , SmallVec < [ _ ; 2 ] > ) > =
710
+ if let Some ( ( macro_file_id, _) ) = include_macro_file_id_and_span {
711
+ vec ! [ ( macro_file_id, smallvec![ token] ) ]
712
+ } else {
713
+ vec ! [ ( sa. file_id, smallvec![ token] ) ]
714
+ } ;
715
+
633
716
let mut process_expansion_for_token = |stack : & mut Vec < _ > , macro_file| {
634
717
let expansion_info = cache
635
718
. entry ( macro_file)
@@ -651,8 +734,6 @@ impl<'db> SemanticsImpl<'db> {
651
734
res
652
735
} ;
653
736
654
- let mut stack: Vec < ( _ , SmallVec < [ _ ; 2 ] > ) > = vec ! [ ( sa. file_id, smallvec![ token] ) ] ;
655
-
656
737
while let Some ( ( file_id, mut tokens) ) = stack. pop ( ) {
657
738
while let Some ( token) = tokens. pop ( ) {
658
739
let was_not_remapped = ( || {
0 commit comments