Auto merge of #136400 - lolbinarycat:rustdoc-link-lint-135851, r= · rust-lang/rust@75eefd1 (original) (raw)
`@@ -514,20 +514,25 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option {
`
514
514
`/// This method does not always work, because markdown bytes don't necessarily match source bytes,
`
515
515
`` /// like if escapes are used in the string. In this case, it returns None
.
``
516
516
`///
`
517
``
`` -
/// This method will return Some
only if:
``
``
517
`` +
/// markdown
is typically the entire documentation for an item,
``
``
518
`+
/// after combining fragments.
`
``
519
`+
///
`
``
520
`` +
/// This method will return Some
only if one of the following is true:
``
518
521
`///
`
519
522
`/// - The doc is made entirely from sugared doc comments, which cannot contain escapes
`
520
523
`/// - The doc is entirely from a single doc fragment, with a string literal, exactly equal
`
521
524
`` /// - The doc comes from include_str!
``
``
525
`` +
/// - The doc includes exactly one substring matching markdown[md_range]
which is contained in a single doc fragment.
``
522
526
`pub fn source_span_for_markdown_range(
`
523
527
`tcx: TyCtxt<'_>,
`
524
528
`markdown: &str,
`
525
529
`md_range: &Range,
`
526
530
`fragments: &[DocFragment],
`
527
531
`) -> Option {
`
``
532
`+
let span_to_snippet = |span| tcx.sess.source_map().span_to_snippet(span);
`
528
533
`if let &[fragment] = &fragments
`
529
534
` && fragment.kind == DocFragmentKind::RawDoc
`
530
``
`-
&& let Ok(snippet) = tcx.sess.source_map().span_to_snippet(fragment.span)
`
``
535
`+
&& let Ok(snippet) = span_to_snippet(fragment.span)
`
531
536
` && snippet.trim_end() == markdown.trim_end()
`
532
537
` && let Ok(md_range_lo) = u32::try_from(md_range.start)
`
533
538
` && let Ok(md_range_hi) = u32::try_from(md_range.end)
`
`@@ -544,6 +549,38 @@ pub fn source_span_for_markdown_range(
`
544
549
`let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
`
545
550
``
546
551
`if !is_all_sugared_doc {
`
``
552
`+
// this case ignores the markdown outside of the range so that it can
`
``
553
`+
// work in cases where the markdown is made from several different
`
``
554
`+
// doc fragments, but the target range does not span across multiple
`
``
555
`+
// fragments.
`
``
556
`+
let mut match_data = None;
`
``
557
`+
let pat = &markdown[md_range.clone()];
`
``
558
`+
// this heirustic doesn't make sense with a zero-sized range.
`
``
559
`+
if pat.len() == 0 {
`
``
560
`+
return None;
`
``
561
`+
}
`
``
562
`+
for (i, fragment) in fragments.iter().enumerate() {
`
``
563
`+
if let Ok(snippet) = span_to_snippet(fragment.span)
`
``
564
`+
&& let Some(match_start) = snippet.find(pat)
`
``
565
`+
{
`
``
566
`+
// if there is either a match in a previous fragment,
`
``
567
`+
// or multiple matches in this fragment,
`
``
568
`+
// there is ambiguity.
`
``
569
`+
if match_data.is_none() && !snippet[match_start + 1..].contains(pat) {
`
``
570
`+
match_data = Some((i, match_start));
`
``
571
`+
} else {
`
``
572
`+
// heirustic produced ambiguity, return nothing.
`
``
573
`+
return None;
`
``
574
`+
}
`
``
575
`+
}
`
``
576
`+
}
`
``
577
`+
if let Some((i, match_start)) = match_data {
`
``
578
`+
use rustc_span::BytePos;
`
``
579
`+
let mut sp = fragments[i].span;
`
``
580
`+
sp = sp.with_lo(sp.lo() + BytePos(match_start as u32));
`
``
581
`+
sp = sp.with_hi(sp.lo() + BytePos((md_range.end - md_range.start) as u32));
`
``
582
`+
return Some(sp);
`
``
583
`+
}
`
547
584
`return None;
`
548
585
`}
`
549
586
``