@@ -49,6 +49,9 @@ pub struct DocFragment {
4949 pub doc: Symbol,
5050 pub kind: DocFragmentKind,
5151 pub indent: usize,
52+ /// Because we temper 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());
@@ -506,16 +510,21 @@ fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
506510}
507511
508512/// 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 {
513+ pub fn span_of_fragments_with_expansion(fragments: &[DocFragment]) -> Option<(Span, bool)> {
514+ let Some(first_fragment) = fragments.first() else { return None };
515+ if first_fragment.span == DUMMY_SP {
515516 return None;
516517 }
517- let end = fragments.last().expect("no doc strings provided").span;
518- Some(start.to(end))
518+ let last_fragment = fragments.last().expect("no doc strings provided");
519+ Some((
520+ first_fragment.span.to(last_fragment.span),
521+ first_fragment.from_expansion || last_fragment.from_expansion,
522+ ))
523+ }
524+
525+ /// Returns a span encompassing all the document fragments.
526+ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
527+ span_of_fragments_with_expansion(fragments).map(|(sp, _)| sp)
519528}
520529
521530/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
@@ -540,7 +549,7 @@ pub fn source_span_for_markdown_range(
540549 markdown: &str,
541550 md_range: &Range<usize>,
542551 fragments: &[DocFragment],
543- ) -> Option<Span> {
552+ ) -> Option<( Span, bool) > {
544553 let map = tcx.sess.source_map();
545554 source_span_for_markdown_range_inner(map, markdown, md_range, fragments)
546555}
@@ -551,7 +560,7 @@ pub fn source_span_for_markdown_range_inner(
551560 markdown: &str,
552561 md_range: &Range<usize>,
553562 fragments: &[DocFragment],
554- ) -> Option<Span> {
563+ ) -> Option<( Span, bool) > {
555564 use rustc_span::BytePos;
556565
557566 if let &[fragment] = &fragments
@@ -562,11 +571,14 @@ pub fn source_span_for_markdown_range_inner(
562571 && let Ok(md_range_hi) = u32::try_from(md_range.end)
563572 {
564573 // 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(),
574+ return Some((
575+ Span::new(
576+ fragment.span.lo() + rustc_span::BytePos(md_range_lo),
577+ fragment.span.lo() + rustc_span::BytePos(md_range_hi),
578+ fragment.span.ctxt(),
579+ fragment.span.parent(),
580+ ),
581+ fragment.from_expansion,
570582 ));
571583 }
572584
@@ -598,19 +610,21 @@ pub fn source_span_for_markdown_range_inner(
598610 {
599611 match_data = Some((i, match_start));
600612 } else {
601- // Heirustic produced ambiguity, return nothing.
613+ // Heuristic produced ambiguity, return nothing.
602614 return None;
603615 }
604616 }
605617 }
606618 if let Some((i, match_start)) = match_data {
607- let sp = fragments[i].span;
619+ let fragment = &fragments[i];
620+ let sp = fragment.span;
608621 // we need to calculate the span start,
609622 // then use that in our calulations for the span end
610623 let lo = sp.lo() + BytePos(match_start as u32);
611- return Some(
624+ return Some((
612625 sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)),
613- );
626+ fragment.from_expansion,
627+ ));
614628 }
615629 return None;
616630 }
@@ -664,8 +678,12 @@ pub fn source_span_for_markdown_range_inner(
664678 }
665679 }
666680
667- Some(span_of_fragments(fragments)?.from_inner(InnerSpan::new(
668- md_range.start + start_bytes,
669- md_range.end + start_bytes + end_bytes,
670- )))
681+ let (span, from_expansion) = span_of_fragments_with_expansion(fragments)?;
682+ Some((
683+ span.from_inner(InnerSpan::new(
684+ md_range.start + start_bytes,
685+ md_range.end + start_bytes + end_bytes,
686+ )),
687+ from_expansion,
688+ ))
671689}
0 commit comments