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

``