@@ -49,6 +49,9 @@ pub struct DocFragment {
4949    pub  doc :  Symbol , 
5050    pub  kind :  DocFragmentKind , 
5151    pub  indent :  usize , 
52+     /// Because we tamper with the spans context, this information cannot be correctly retrieved 
53+      /// later on. So instead, we compute it and store it here. 
54+      pub  from_expansion :  bool , 
5255} 
5356
5457#[ derive( Clone ,  Copy ,  Debug ) ]  
@@ -208,17 +211,18 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>(
208211    for  ( attr,  item_id)  in  attrs { 
209212        if  let  Some ( ( doc_str,  comment_kind) )  = attr. doc_str_and_comment_kind ( )  { 
210213            let  doc = beautify_doc_string ( doc_str,  comment_kind) ; 
211-             let  ( span,  kind)  = if  attr. is_doc_comment ( )  { 
212-                 ( attr. span ( ) ,  DocFragmentKind :: SugaredDoc ) 
214+             let  ( span,  kind,  from_expansion)  = if  attr. is_doc_comment ( )  { 
215+                 let  span = attr. span ( ) ; 
216+                 ( span,  DocFragmentKind :: SugaredDoc ,  span. from_expansion ( ) ) 
213217            }  else  { 
214-                 ( 
215-                      attr. value_span ( ) 
216-                          . map ( |i| i . with_ctxt ( attr . span ( ) . ctxt ( ) ) ) 
217-                          . unwrap_or ( attr . span ( ) ) , 
218-                      DocFragmentKind :: RawDoc , 
219-                 ) 
218+                 let  attr_span = attr . span ( ) ; 
219+                 let   ( span ,  from_expansion )  =  match   attr. value_span ( )   { 
220+                     Some ( sp )  =>  ( sp . with_ctxt ( attr_span . ctxt ( ) ) ,  sp . from_expansion ( ) ) , 
221+                     None  =>  ( attr_span ,  attr_span . from_expansion ( ) ) , 
222+                 } ; 
223+                 ( span ,   DocFragmentKind :: RawDoc ,  from_expansion ) 
220224            } ; 
221-             let  fragment = DocFragment  {  span,  doc,  kind,  item_id,  indent :  0  } ; 
225+             let  fragment = DocFragment  {  span,  doc,  kind,  item_id,  indent :  0 ,  from_expansion  } ; 
222226            doc_fragments. push ( fragment) ; 
223227        }  else  if  !doc_only { 
224228            other_attrs. push ( attr. clone ( ) ) ; 
@@ -505,17 +509,26 @@ fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
505509    display_text. map ( String :: into_boxed_str) 
506510} 
507511
508- /// Returns a span encompassing all the document fragments. 
509- pub  fn  span_of_fragments ( fragments :  & [ DocFragment ] )  -> Option < Span >  { 
510-     if  fragments. is_empty ( )  { 
511-         return  None ; 
512-     } 
513-     let  start = fragments[ 0 ] . span ; 
514-     if  start == DUMMY_SP  { 
512+ /// Returns a tuple containing a span encompassing all the document fragments and a boolean that is 
513+ /// `true` if any of the fragments are from a macro expansion. 
514+ pub  fn  span_of_fragments_with_expansion ( fragments :  & [ DocFragment ] )  -> Option < ( Span ,  bool ) >  { 
515+     let  ( first_fragment,  last_fragment)  = match  fragments { 
516+         [ ]  => return  None , 
517+         [ first,  ..,  last]  => ( first,  last) , 
518+         [ first]  => ( first,  first) , 
519+     } ; 
520+     if  first_fragment. span  == DUMMY_SP  { 
515521        return  None ; 
516522    } 
517-     let  end = fragments. last ( ) . expect ( "no doc strings provided" ) . span ; 
518-     Some ( start. to ( end) ) 
523+     Some ( ( 
524+         first_fragment. span . to ( last_fragment. span ) , 
525+         fragments. iter ( ) . any ( |frag| frag. from_expansion ) , 
526+     ) ) 
527+ } 
528+ 
529+ /// Returns a span encompassing all the document fragments. 
530+ pub  fn  span_of_fragments ( fragments :  & [ DocFragment ] )  -> Option < Span >  { 
531+     span_of_fragments_with_expansion ( fragments) . map ( |( sp,  _) | sp) 
519532} 
520533
521534/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code. 
@@ -529,18 +542,22 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
529542/// This method will return `Some` only if one of the following is true: 
530543/// 
531544/// - The doc is made entirely from sugared doc comments, which cannot contain escapes 
532- /// - The doc is entirely from a single doc fragment with a string literal exactly equal to `markdown`. 
545+ /// - The doc is entirely from a single doc fragment with a string literal exactly equal to 
546+ ///   `markdown`. 
533547/// - The doc comes from `include_str!` 
534- /// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a single doc fragment. 
548+ /// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a 
549+ ///   single doc fragment. 
550+ /// 
551+ /// This function is defined in the compiler so it can be used by both `rustdoc` and `clippy`. 
535552/// 
536- /// This function is defined in the compiler so it can be used by  
537- /// both `rustdoc` and `clippy` . 
553+ /// It returns a tuple containing a span encompassing all the document fragments and a boolean that  
554+ /// is `true` if any of the *matched* fragments are from a macro expansion . 
538555pub  fn  source_span_for_markdown_range ( 
539556    tcx :  TyCtxt < ' _ > , 
540557    markdown :  & str , 
541558    md_range :  & Range < usize > , 
542559    fragments :  & [ DocFragment ] , 
543- )  -> Option < Span >  { 
560+ )  -> Option < ( Span ,   bool ) >  { 
544561    let  map = tcx. sess . source_map ( ) ; 
545562    source_span_for_markdown_range_inner ( map,  markdown,  md_range,  fragments) 
546563} 
@@ -551,7 +568,7 @@ pub fn source_span_for_markdown_range_inner(
551568    markdown :  & str , 
552569    md_range :  & Range < usize > , 
553570    fragments :  & [ DocFragment ] , 
554- )  -> Option < Span >  { 
571+ )  -> Option < ( Span ,   bool ) >  { 
555572    use  rustc_span:: BytePos ; 
556573
557574    if  let  & [ fragment]  = & fragments
@@ -562,11 +579,14 @@ pub fn source_span_for_markdown_range_inner(
562579        && let  Ok ( md_range_hi)  = u32:: try_from ( md_range. end ) 
563580    { 
564581        // Single fragment with string that contains same bytes as doc. 
565-         return  Some ( Span :: new ( 
566-             fragment. span . lo ( )  + rustc_span:: BytePos ( md_range_lo) , 
567-             fragment. span . lo ( )  + rustc_span:: BytePos ( md_range_hi) , 
568-             fragment. span . ctxt ( ) , 
569-             fragment. span . parent ( ) , 
582+         return  Some ( ( 
583+             Span :: new ( 
584+                 fragment. span . lo ( )  + rustc_span:: BytePos ( md_range_lo) , 
585+                 fragment. span . lo ( )  + rustc_span:: BytePos ( md_range_hi) , 
586+                 fragment. span . ctxt ( ) , 
587+                 fragment. span . parent ( ) , 
588+             ) , 
589+             fragment. from_expansion , 
570590        ) ) ; 
571591    } 
572592
@@ -598,19 +618,21 @@ pub fn source_span_for_markdown_range_inner(
598618                { 
599619                    match_data = Some ( ( i,  match_start) ) ; 
600620                }  else  { 
601-                     // Heirustic  produced ambiguity, return nothing. 
621+                     // Heuristic  produced ambiguity, return nothing. 
602622                    return  None ; 
603623                } 
604624            } 
605625        } 
606626        if  let  Some ( ( i,  match_start) )  = match_data { 
607-             let  sp = fragments[ i] . span ; 
627+             let  fragment = & fragments[ i] ; 
628+             let  sp = fragment. span ; 
608629            // we need to calculate the span start, 
609630            // then use that in our calulations for the span end 
610631            let  lo = sp. lo ( )  + BytePos ( match_start as  u32 ) ; 
611-             return  Some ( 
632+             return  Some ( ( 
612633                sp. with_lo ( lo) . with_hi ( lo + BytePos ( ( md_range. end  - md_range. start )  as  u32 ) ) , 
613-             ) ; 
634+                 fragment. from_expansion , 
635+             ) ) ; 
614636        } 
615637        return  None ; 
616638    } 
@@ -664,8 +686,13 @@ pub fn source_span_for_markdown_range_inner(
664686        } 
665687    } 
666688
667-     Some ( span_of_fragments ( fragments) ?. from_inner ( InnerSpan :: new ( 
689+     let  ( span,  _)  = span_of_fragments_with_expansion ( fragments) ?; 
690+     let  src_span = span. from_inner ( InnerSpan :: new ( 
668691        md_range. start  + start_bytes, 
669692        md_range. end  + start_bytes + end_bytes, 
670-     ) ) ) 
693+     ) ) ; 
694+     Some ( ( 
695+         src_span, 
696+         fragments. iter ( ) . any ( |frag| frag. span . overlaps ( src_span)  && frag. from_expansion ) , 
697+     ) ) 
671698} 
0 commit comments