Skip to content

Commit 6032ce1

Browse files
Do not emit redundant_explicit_links rustdoc lint if the doc comment comes from expansion
1 parent b5eb989 commit 6032ce1

File tree

7 files changed

+99
-53
lines changed

7 files changed

+99
-53
lines changed

compiler/rustc_resolve/src/rustdoc.rs

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ pub struct DocFragment {
4545
pub doc: Symbol,
4646
pub kind: DocFragmentKind,
4747
pub indent: usize,
48+
/// Because we temper with the spans context, this information cannot be correctly retrieved
49+
/// later on. So instead, we compute it and store it here.
50+
pub from_expansion: bool,
4851
}
4952

5053
#[derive(Clone, Copy, Debug)]
@@ -204,17 +207,18 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>(
204207
for (attr, item_id) in attrs {
205208
if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
206209
let doc = beautify_doc_string(doc_str, comment_kind);
207-
let (span, kind) = if attr.is_doc_comment() {
208-
(attr.span(), DocFragmentKind::SugaredDoc)
210+
let (span, kind, from_expansion) = if attr.is_doc_comment() {
211+
let span = attr.span();
212+
(span, DocFragmentKind::SugaredDoc, span.from_expansion())
209213
} else {
210-
(
211-
attr.value_span()
212-
.map(|i| i.with_ctxt(attr.span().ctxt()))
213-
.unwrap_or(attr.span()),
214-
DocFragmentKind::RawDoc,
215-
)
214+
let attr_span = attr.span();
215+
let (span, from_expansion) = match attr.value_span() {
216+
Some(sp) => (sp.with_ctxt(attr_span.ctxt()), sp.from_expansion()),
217+
None => (attr_span, attr_span.from_expansion()),
218+
};
219+
(span, DocFragmentKind::RawDoc, from_expansion)
216220
};
217-
let fragment = DocFragment { span, doc, kind, item_id, indent: 0 };
221+
let fragment = DocFragment { span, doc, kind, item_id, indent: 0, from_expansion };
218222
doc_fragments.push(fragment);
219223
} else if !doc_only {
220224
other_attrs.push(attr.clone());
@@ -497,16 +501,21 @@ fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
497501
}
498502

499503
/// Returns a span encompassing all the document fragments.
500-
pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
501-
if fragments.is_empty() {
502-
return None;
503-
}
504-
let start = fragments[0].span;
505-
if start == DUMMY_SP {
504+
pub fn span_of_fragments_with_expansion(fragments: &[DocFragment]) -> Option<(Span, bool)> {
505+
let Some(first_fragment) = fragments.first() else { return None };
506+
if first_fragment.span == DUMMY_SP {
506507
return None;
507508
}
508-
let end = fragments.last().expect("no doc strings provided").span;
509-
Some(start.to(end))
509+
let last_fragment = fragments.last().expect("no doc strings provided");
510+
Some((
511+
first_fragment.span.to(last_fragment.span),
512+
first_fragment.from_expansion || last_fragment.from_expansion,
513+
))
514+
}
515+
516+
/// Returns a span encompassing all the document fragments.
517+
pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
518+
span_of_fragments_with_expansion(fragments).map(|(sp, _)| sp)
510519
}
511520

512521
/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
@@ -531,7 +540,7 @@ pub fn source_span_for_markdown_range(
531540
markdown: &str,
532541
md_range: &Range<usize>,
533542
fragments: &[DocFragment],
534-
) -> Option<Span> {
543+
) -> Option<(Span, bool)> {
535544
use rustc_span::BytePos;
536545

537546
let map = tcx.sess.source_map();
@@ -543,11 +552,14 @@ pub fn source_span_for_markdown_range(
543552
&& let Ok(md_range_hi) = u32::try_from(md_range.end)
544553
{
545554
// Single fragment with string that contains same bytes as doc.
546-
return Some(Span::new(
547-
fragment.span.lo() + rustc_span::BytePos(md_range_lo),
548-
fragment.span.lo() + rustc_span::BytePos(md_range_hi),
549-
fragment.span.ctxt(),
550-
fragment.span.parent(),
555+
return Some((
556+
Span::new(
557+
fragment.span.lo() + rustc_span::BytePos(md_range_lo),
558+
fragment.span.lo() + rustc_span::BytePos(md_range_hi),
559+
fragment.span.ctxt(),
560+
fragment.span.parent(),
561+
),
562+
fragment.from_expansion,
551563
));
552564
}
553565

@@ -573,19 +585,21 @@ pub fn source_span_for_markdown_range(
573585
if match_data.is_none() && !snippet[match_start + 1..].contains(pat) {
574586
match_data = Some((i, match_start));
575587
} else {
576-
// Heirustic produced ambiguity, return nothing.
588+
// Heuristic produced ambiguity, return nothing.
577589
return None;
578590
}
579591
}
580592
}
581593
if let Some((i, match_start)) = match_data {
582-
let sp = fragments[i].span;
594+
let fragment = &fragments[i];
595+
let sp = fragment.span;
583596
// we need to calculate the span start,
584597
// then use that in our calulations for the span end
585598
let lo = sp.lo() + BytePos(match_start as u32);
586-
return Some(
599+
return Some((
587600
sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)),
588-
);
601+
fragment.from_expansion,
602+
));
589603
}
590604
return None;
591605
}
@@ -639,8 +653,12 @@ pub fn source_span_for_markdown_range(
639653
}
640654
}
641655

642-
Some(span_of_fragments(fragments)?.from_inner(InnerSpan::new(
643-
md_range.start + start_bytes,
644-
md_range.end + start_bytes + end_bytes,
645-
)))
656+
let (span, from_expansion) = span_of_fragments_with_expansion(fragments)?;
657+
Some((
658+
span.from_inner(InnerSpan::new(
659+
md_range.start + start_bytes,
660+
md_range.end + start_bytes + end_bytes,
661+
)),
662+
from_expansion,
663+
))
646664
}

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)