@@ -20,11 +20,12 @@ use hir_def::{
2020} ;
2121use hir_expand:: {
2222 attrs:: collect_attrs, db:: ExpandDatabase , files:: InRealFile , name:: AsName , ExpansionInfo ,
23- InMacroFile , MacroCallId , MacroFileId , MacroFileIdExt ,
23+ HirFileIdExt , InMacroFile , MacroCallId , MacroFileId , MacroFileIdExt ,
2424} ;
2525use itertools:: Itertools ;
2626use rustc_hash:: { FxHashMap , FxHashSet } ;
2727use smallvec:: { smallvec, SmallVec } ;
28+ use span:: Span ;
2829use stdx:: TupleExt ;
2930use syntax:: {
3031 algo:: skip_trivia_token,
@@ -607,29 +608,111 @@ impl<'db> SemanticsImpl<'db> {
607608 res
608609 }
609610
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 (
611617 & self ,
612618 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 ,
613672 f : & mut dyn FnMut ( InFile < SyntaxToken > ) -> ControlFlow < ( ) > ,
614673 ) {
615674 let _p = profile:: span ( "descend_into_macros" ) ;
675+
676+ let mut include_macro_file_id_and_span = None ;
677+
616678 let sa = match token. parent ( ) . and_then ( |parent| self . analyze_no_infer ( & parent) ) {
617679 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+ }
619691 } ;
620692
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+ }
626702 }
627703 } ;
628704
629705 let mut cache = self . expansion_info_cache . borrow_mut ( ) ;
630706 let mut mcache = self . macro_call_cache . borrow_mut ( ) ;
631707 let def_map = sa. resolver . def_map ( ) ;
632708
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+
633716 let mut process_expansion_for_token = |stack : & mut Vec < _ > , macro_file| {
634717 let expansion_info = cache
635718 . entry ( macro_file)
@@ -651,8 +734,6 @@ impl<'db> SemanticsImpl<'db> {
651734 res
652735 } ;
653736
654- let mut stack: Vec < ( _ , SmallVec < [ _ ; 2 ] > ) > = vec ! [ ( sa. file_id, smallvec![ token] ) ] ;
655-
656737 while let Some ( ( file_id, mut tokens) ) = stack. pop ( ) {
657738 while let Some ( token) = tokens. pop ( ) {
658739 let was_not_remapped = ( || {
0 commit comments