@@ -377,7 +377,7 @@ impl HygieneData {
377377 self . local_expn_data [ expn_id] . as_ref ( ) . expect ( "no expansion data for an expansion ID" )
378378 }
379379
380- fn expn_data ( & self , expn_id : ExpnId ) -> & ExpnData {
380+ pub fn expn_data ( & self , expn_id : ExpnId ) -> & ExpnData {
381381 if let Some ( expn_id) = expn_id. as_local ( ) {
382382 self . local_expn_data [ expn_id] . as_ref ( ) . expect ( "no expansion data for an expansion ID" )
383383 } else {
@@ -412,7 +412,7 @@ impl HygieneData {
412412 self . syntax_context_data [ ctxt. 0 as usize ] . opaque_and_semitransparent
413413 }
414414
415- fn outer_expn ( & self , ctxt : SyntaxContext ) -> ExpnId {
415+ pub fn outer_expn ( & self , ctxt : SyntaxContext ) -> ExpnId {
416416 self . syntax_context_data [ ctxt. 0 as usize ] . outer_expn
417417 }
418418
@@ -443,15 +443,65 @@ impl HygieneData {
443443 }
444444
445445 fn walk_chain ( & self , mut span : Span , to : SyntaxContext ) -> Span {
446+ let orig_span = span;
446447 debug ! ( "walk_chain({:?}, {:?})" , span, to) ;
447448 debug ! ( "walk_chain: span ctxt = {:?}" , span. ctxt( ) ) ;
448- while span. from_expansion ( ) && span. ctxt ( ) != to {
449+ while span. ctxt ( ) != to && span. from_expansion ( ) {
449450 let outer_expn = self . outer_expn ( span. ctxt ( ) ) ;
450451 debug ! ( "walk_chain({:?}): outer_expn={:?}" , span, outer_expn) ;
451452 let expn_data = self . expn_data ( outer_expn) ;
452453 debug ! ( "walk_chain({:?}): expn_data={:?}" , span, expn_data) ;
453454 span = expn_data. call_site ;
454455 }
456+ debug ! ( "walk_chain: for span {:?} >>> return span = {:?}" , orig_span, span) ;
457+ span
458+ }
459+
460+ /// Returns `true` if the debuginfo for `span` should be collapsed to the outermost expansion
461+ /// site. Only applies when `Span` is the result of macro expansion.
462+ ///
463+ /// - If the `collapse_debuginfo` feature is enabled then debuginfo is not collapsed by default
464+ /// and only when a macro definition is annotated with `#[collapse_debuginfo]`.
465+ /// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default.
466+ ///
467+ /// When `-Zdebug-macros` is provided then debuginfo will never be collapsed.
468+ fn should_collapse_debuginfo < F : Fn ( DefId ) -> bool > (
469+ & self ,
470+ span : Span ,
471+ collapse_enabled : bool ,
472+ attr_enabled : bool ,
473+ in_std_macro : & F ,
474+ ) -> bool {
475+ collapse_enabled
476+ && if attr_enabled {
477+ span. in_macro_expansion_with_collapse_debuginfo ( & self , in_std_macro)
478+ } else {
479+ span. from_expansion ( )
480+ }
481+ }
482+
483+ fn walk_chain_collapsed < F : Fn ( DefId ) -> bool > (
484+ & self ,
485+ mut span : Span ,
486+ to : SyntaxContext ,
487+ collapse_enabled : bool ,
488+ attr_enabled : bool ,
489+ in_std_macro : F ,
490+ ) -> Span {
491+ let orig_span = span;
492+
493+ debug ! ( "walk_chain_collapsed({:?}, {:?})" , span, to) ;
494+ debug ! ( "walk_chain_collapsed: span ctxt = {:?}" , span. ctxt( ) ) ;
495+ while span. ctxt ( ) != to
496+ && self . should_collapse_debuginfo ( span, collapse_enabled, attr_enabled, & in_std_macro)
497+ {
498+ let outer_expn = self . outer_expn ( span. ctxt ( ) ) ;
499+ debug ! ( "walk_chain_collapsed({:?}): outer_expn={:?}" , span, outer_expn) ;
500+ let expn_data = self . expn_data ( outer_expn) ;
501+ debug ! ( "walk_chain_collapsed({:?}): expn_data={:?}" , span, expn_data) ;
502+ span = expn_data. call_site ;
503+ }
504+ debug ! ( "walk_chain_collapsed: for span {:?} >>> return span = {:?}" , orig_span, span) ;
455505 span
456506 }
457507
@@ -571,6 +621,22 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
571621 HygieneData :: with ( |data| data. walk_chain ( span, to) )
572622}
573623
624+ pub fn walk_chain_collapsed < F : Fn ( DefId ) -> bool > (
625+ span : Span ,
626+ to : SyntaxContext ,
627+ collapse_enabled : bool ,
628+ attr_enabled : bool ,
629+ in_std_macro : F ,
630+ ) -> Span {
631+ HygieneData :: with ( |hdata| {
632+ if hdata. should_collapse_debuginfo ( span, collapse_enabled, attr_enabled, & in_std_macro) {
633+ hdata. walk_chain_collapsed ( span, to, collapse_enabled, attr_enabled, in_std_macro)
634+ } else {
635+ span
636+ }
637+ } )
638+ }
639+
574640pub fn update_dollar_crate_names ( mut get_name : impl FnMut ( SyntaxContext ) -> Symbol ) {
575641 // The new contexts that need updating are at the end of the list and have `$crate` as a name.
576642 let ( len, to_update) = HygieneData :: with ( |data| {
0 commit comments