Skip to content

Commit fbbda9e

Browse files
Do not emit redundant_explicit_links rustdoc lint if the doc comment comes from expansion
1 parent a124fb3 commit fbbda9e

File tree

7 files changed

+100
-54
lines changed

7 files changed

+100
-54
lines changed

compiler/rustc_resolve/src/rustdoc.rs

Lines changed: 50 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -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());
@@ -501,16 +505,21 @@ fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
501505
}
502506

503507
/// Returns a span encompassing all the document fragments.
504-
pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
505-
if fragments.is_empty() {
506-
return None;
507-
}
508-
let start = fragments[0].span;
509-
if start == DUMMY_SP {
508+
pub fn span_of_fragments_with_expansion(fragments: &[DocFragment]) -> Option<(Span, bool)> {
509+
let Some(first_fragment) = fragments.first() else { return None };
510+
if first_fragment.span == DUMMY_SP {
510511
return None;
511512
}
512-
let end = fragments.last().expect("no doc strings provided").span;
513-
Some(start.to(end))
513+
let last_fragment = fragments.last().expect("no doc strings provided");
514+
Some((
515+
first_fragment.span.to(last_fragment.span),
516+
first_fragment.from_expansion || last_fragment.from_expansion,
517+
))
518+
}
519+
520+
/// Returns a span encompassing all the document fragments.
521+
pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
522+
span_of_fragments_with_expansion(fragments).map(|(sp, _)| sp)
514523
}
515524

516525
/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
@@ -535,7 +544,7 @@ pub fn source_span_for_markdown_range(
535544
markdown: &str,
536545
md_range: &Range<usize>,
537546
fragments: &[DocFragment],
538-
) -> Option<Span> {
547+
) -> Option<(Span, bool)> {
539548
let map = tcx.sess.source_map();
540549
source_span_for_markdown_range_inner(map, markdown, md_range, fragments)
541550
}
@@ -546,7 +555,7 @@ pub fn source_span_for_markdown_range_inner(
546555
markdown: &str,
547556
md_range: &Range<usize>,
548557
fragments: &[DocFragment],
549-
) -> Option<Span> {
558+
) -> Option<(Span, bool)> {
550559
use rustc_span::BytePos;
551560

552561
if let &[fragment] = &fragments
@@ -557,11 +566,14 @@ pub fn source_span_for_markdown_range_inner(
557566
&& let Ok(md_range_hi) = u32::try_from(md_range.end)
558567
{
559568
// Single fragment with string that contains same bytes as doc.
560-
return Some(Span::new(
561-
fragment.span.lo() + rustc_span::BytePos(md_range_lo),
562-
fragment.span.lo() + rustc_span::BytePos(md_range_hi),
563-
fragment.span.ctxt(),
564-
fragment.span.parent(),
569+
return Some((
570+
Span::new(
571+
fragment.span.lo() + rustc_span::BytePos(md_range_lo),
572+
fragment.span.lo() + rustc_span::BytePos(md_range_hi),
573+
fragment.span.ctxt(),
574+
fragment.span.parent(),
575+
),
576+
fragment.from_expansion,
565577
));
566578
}
567579

@@ -593,19 +605,21 @@ pub fn source_span_for_markdown_range_inner(
593605
{
594606
match_data = Some((i, match_start));
595607
} else {
596-
// Heirustic produced ambiguity, return nothing.
608+
// Heuristic produced ambiguity, return nothing.
597609
return None;
598610
}
599611
}
600612
}
601613
if let Some((i, match_start)) = match_data {
602-
let sp = fragments[i].span;
614+
let fragment = &fragments[i];
615+
let sp = fragment.span;
603616
// we need to calculate the span start,
604617
// then use that in our calulations for the span end
605618
let lo = sp.lo() + BytePos(match_start as u32);
606-
return Some(
619+
return Some((
607620
sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)),
608-
);
621+
fragment.from_expansion,
622+
));
609623
}
610624
return None;
611625
}
@@ -659,8 +673,12 @@ pub fn source_span_for_markdown_range_inner(
659673
}
660674
}
661675

662-
Some(span_of_fragments(fragments)?.from_inner(InnerSpan::new(
663-
md_range.start + start_bytes,
664-
md_range.end + start_bytes + end_bytes,
665-
)))
676+
let (span, from_expansion) = span_of_fragments_with_expansion(fragments)?;
677+
Some((
678+
span.from_inner(InnerSpan::new(
679+
md_range.start + start_bytes,
680+
md_range.end + start_bytes + end_bytes,
681+
)),
682+
from_expansion,
683+
))
666684
}

src/librustdoc/passes/collect_intra_doc_links.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,13 +1387,15 @@ impl LinkCollector<'_, '_> {
13871387
ori_link: &MarkdownLinkRange,
13881388
item: &Item,
13891389
) {
1390-
let span = source_span_for_markdown_range(
1390+
let span = match source_span_for_markdown_range(
13911391
self.cx.tcx,
13921392
dox,
13931393
ori_link.inner_range(),
13941394
&item.attrs.doc_strings,
1395-
)
1396-
.unwrap_or_else(|| item.attr_span(self.cx.tcx));
1395+
) {
1396+
Some((sp, _)) => sp,
1397+
None => item.attr_span(self.cx.tcx),
1398+
};
13971399
rustc_session::parse::feature_err(
13981400
self.cx.tcx.sess,
13991401
sym::intra_doc_pointers,
@@ -1836,7 +1838,7 @@ fn report_diagnostic(
18361838
let mut md_range = md_range.clone();
18371839
let sp =
18381840
source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs.doc_strings)
1839-
.map(|mut sp| {
1841+
.map(|(mut sp, _)| {
18401842
while dox.as_bytes().get(md_range.start) == Some(&b' ')
18411843
|| dox.as_bytes().get(md_range.start) == Some(&b'`')
18421844
{
@@ -1854,7 +1856,8 @@ fn report_diagnostic(
18541856
(sp, MarkdownLinkRange::Destination(md_range))
18551857
}
18561858
MarkdownLinkRange::WholeLink(md_range) => (
1857-
source_span_for_markdown_range(tcx, dox, md_range, &item.attrs.doc_strings),
1859+
source_span_for_markdown_range(tcx, dox, md_range, &item.attrs.doc_strings)
1860+
.map(|(sp, _)| sp),
18581861
link_range.clone(),
18591862
),
18601863
};

src/librustdoc/passes/lint/bare_urls.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ use crate::html::markdown::main_body_opts;
1818

1919
pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) {
2020
let report_diag = |cx: &DocContext<'_>, msg: &'static str, range: Range<usize>| {
21-
let maybe_sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings);
21+
let maybe_sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings)
22+
.map(|(sp, _)| sp);
2223
let sp = maybe_sp.unwrap_or_else(|| item.attr_span(cx.tcx));
2324
cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| {
2425
lint.primary_message(msg)

src/librustdoc/passes/lint/check_code_block_syntax.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ fn check_rust_syntax(
9090
&code_block.range,
9191
&item.attrs.doc_strings,
9292
) {
93-
Some(sp) => (sp, true),
93+
Some((sp, _)) => (sp, true),
9494
None => (item.attr_span(cx.tcx), false),
9595
};
9696

src/librustdoc/passes/lint/html_tags.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
1616
let tcx = cx.tcx;
1717
let report_diag = |msg: String, range: &Range<usize>, is_open_tag: bool| {
1818
let sp = match source_span_for_markdown_range(tcx, dox, range, &item.attrs.doc_strings) {
19-
Some(sp) => sp,
19+
Some((sp, _)) => sp,
2020
None => item.attr_span(tcx),
2121
};
2222
tcx.node_span_lint(crate::lint::INVALID_HTML_TAGS, hir_id, sp, |lint| {
@@ -55,7 +55,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
5555
&(generics_start..generics_end),
5656
&item.attrs.doc_strings,
5757
) {
58-
Some(sp) => sp,
58+
Some((sp, _)) => sp,
5959
None => item.attr_span(tcx),
6060
};
6161
// Sometimes, we only extract part of a path. For example, consider this:

src/librustdoc/passes/lint/redundant_explicit_links.rs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,26 @@ fn check_inline_or_reference_unknown_redundancy(
161161

162162
if dest_res == display_res {
163163
let link_span =
164-
source_span_for_markdown_range(cx.tcx, doc, &link_range, &item.attrs.doc_strings)
165-
.unwrap_or(item.attr_span(cx.tcx));
166-
let explicit_span = source_span_for_markdown_range(
164+
match source_span_for_markdown_range(cx.tcx, doc, &link_range, &item.attrs.doc_strings)
165+
{
166+
Some((sp, from_expansion)) => {
167+
if from_expansion {
168+
return None;
169+
}
170+
sp
171+
}
172+
None => item.attr_span(cx.tcx),
173+
};
174+
let (explicit_span, from_expansion) = source_span_for_markdown_range(
167175
cx.tcx,
168176
doc,
169177
&offset_explicit_range(doc, link_range, open, close),
170178
&item.attrs.doc_strings,
171179
)?;
172-
let display_span = source_span_for_markdown_range(
180+
if from_expansion {
181+
return None;
182+
}
183+
let (display_span, _) = source_span_for_markdown_range(
173184
cx.tcx,
174185
doc,
175186
resolvable_link_range,
@@ -206,21 +217,32 @@ fn check_reference_redundancy(
206217

207218
if dest_res == display_res {
208219
let link_span =
209-
source_span_for_markdown_range(cx.tcx, doc, &link_range, &item.attrs.doc_strings)
210-
.unwrap_or(item.attr_span(cx.tcx));
211-
let explicit_span = source_span_for_markdown_range(
220+
match source_span_for_markdown_range(cx.tcx, doc, &link_range, &item.attrs.doc_strings)
221+
{
222+
Some((sp, from_expansion)) => {
223+
if from_expansion {
224+
return None;
225+
}
226+
sp
227+
}
228+
None => item.attr_span(cx.tcx),
229+
};
230+
let (explicit_span, from_expansion) = source_span_for_markdown_range(
212231
cx.tcx,
213232
doc,
214233
&offset_explicit_range(doc, link_range.clone(), b'[', b']'),
215234
&item.attrs.doc_strings,
216235
)?;
217-
let display_span = source_span_for_markdown_range(
236+
if from_expansion {
237+
return None;
238+
}
239+
let (display_span, _) = source_span_for_markdown_range(
218240
cx.tcx,
219241
doc,
220242
resolvable_link_range,
221243
&item.attrs.doc_strings,
222244
)?;
223-
let def_span = source_span_for_markdown_range(
245+
let (def_span, _) = source_span_for_markdown_range(
224246
cx.tcx,
225247
doc,
226248
&offset_reference_def_range(doc, dest, link_range),

src/librustdoc/passes/lint/unescaped_backticks.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
4242

4343
// If we can't get a span of the backtick, because it is in a `#[doc = ""]` attribute,
4444
// use the span of the entire attribute as a fallback.
45-
let span = source_span_for_markdown_range(
45+
let span = match source_span_for_markdown_range(
4646
tcx,
4747
dox,
4848
&(backtick_index..backtick_index + 1),
4949
&item.attrs.doc_strings,
50-
)
51-
.unwrap_or_else(|| item.attr_span(tcx));
50+
) {
51+
Some((sp, _)) => sp,
52+
None => item.attr_span(tcx),
53+
};
5254

5355
tcx.node_span_lint(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, |lint| {
5456
lint.primary_message("unescaped backtick");
@@ -419,7 +421,7 @@ fn suggest_insertion(
419421
/// Maximum bytes of context to show around the insertion.
420422
const CONTEXT_MAX_LEN: usize = 80;
421423

422-
if let Some(span) = source_span_for_markdown_range(
424+
if let Some((span, _)) = source_span_for_markdown_range(
423425
cx.tcx,
424426
dox,
425427
&(insert_index..insert_index),

0 commit comments

Comments
 (0)