Skip to content

Commit 65e24a5

Browse files
committed
Fix resolution caching
1 parent da582a7 commit 65e24a5

File tree

6 files changed

+217
-53
lines changed

6 files changed

+217
-53
lines changed

compiler/rustc_resolve/src/rustdoc.rs

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -392,16 +392,57 @@ pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<Box<s
392392
let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
393393
let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap();
394394

395-
Parser::new_with_broken_link_callback(
395+
parse_links(&doc)
396+
}
397+
398+
/// Similiar version of `markdown_links` from rustdoc.
399+
/// This will collect destination links and display text if exists.
400+
fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
401+
let mut broken_link_callback = |link: BrokenLink<'md>| Some((link.reference, "".into()));
402+
let mut event_iter = Parser::new_with_broken_link_callback(
396403
&doc,
397404
main_body_opts(),
398-
Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))),
405+
Some(&mut broken_link_callback),
399406
)
400-
.filter_map(|event| match event {
401-
Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
402-
Some(preprocess_link(&dest))
407+
.into_iter();
408+
let mut links = Vec::new();
409+
410+
while let Some(event) = event_iter.next() {
411+
match event {
412+
Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
413+
if let Some(display_text) = collect_link_data(&mut event_iter) {
414+
links.push(display_text);
415+
}
416+
417+
links.push(preprocess_link(&dest));
418+
}
419+
_ => {}
420+
}
421+
}
422+
423+
links
424+
}
425+
426+
/// Collects additional data of link.
427+
fn collect_link_data<'input, 'callback>(
428+
event_iter: &mut Parser<'input, 'callback>,
429+
) -> Option<Box<str>> {
430+
let mut display_text = None;
431+
432+
while let Some(event) = event_iter.next() {
433+
match event {
434+
Event::Text(code) => {
435+
display_text = Some(code.to_string().into_boxed_str());
436+
}
437+
Event::Code(code) => {
438+
display_text = Some(code.to_string().into_boxed_str());
439+
}
440+
Event::End(_) => {
441+
break;
442+
}
443+
_ => {}
403444
}
404-
_ => None,
405-
})
406-
.collect()
445+
}
446+
447+
display_text
407448
}

src/doc/rustdoc/src/lints.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -420,17 +420,29 @@ as computed automatic links.
420420
This usually means the explicit links is removeable. For example:
421421

422422
```rust
423-
#![warn(rustdoc::redundant_explicit_links)]
423+
#![warn(rustdoc::redundant_explicit_links)] // note: unnecessary - warns by default.
424424

425-
pub fn dummy_target() {} // note: unnecessary - warns by default.
426-
427-
/// [`dummy_target`](dummy_target)
428-
/// [dummy_target](dummy_target)
429-
pub fn c() {}
425+
/// add takes 2 [`usize`](usize) and performs addition
426+
/// on them, then returns result.
427+
pub fn add(left: usize, right: usize) -> usize {
428+
left + right
429+
}
430430
```
431431

432432
Which will give:
433433

434434
```text
435-
435+
error: redundant explicit rustdoc link
436+
--> src/lib.rs:3:27
437+
|
438+
3 | /// add takes 2 [`usize`](usize) and performs addition
439+
| ^^^^^
440+
|
441+
= note: Explicit link does not affect the original link
442+
note: the lint level is defined here
443+
--> src/lib.rs:1:9
444+
|
445+
1 | #![deny(rustdoc::redundant_explicit_links)]
446+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
447+
= help: Remove explicit link instead
436448
```

src/librustdoc/html/markdown.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,7 @@ pub(crate) fn markdown_links<'md, R>(
14211421
links
14221422
}
14231423

1424+
/// Collects additional data of link.
14241425
fn collect_link_data<'input, 'callback>(
14251426
event_iter: &mut OffsetIter<'input, 'callback>,
14261427
) -> Option<CowStr<'input>> {

src/librustdoc/passes/collect_intra_doc_links.rs

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -994,15 +994,7 @@ impl LinkCollector<'_, '_> {
994994
_ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(),
995995
};
996996
for md_link in preprocessed_markdown_links(&doc) {
997-
let PreprocessedMarkdownLink(_pp_link, ori_link) = &md_link;
998-
let diag_info = DiagnosticInfo {
999-
item,
1000-
dox: &doc,
1001-
ori_link: &ori_link.link,
1002-
link_range: ori_link.range.clone(),
1003-
};
1004-
1005-
let link = self.resolve_link(item, item_id, module_id, &md_link, &diag_info);
997+
let link = self.resolve_link(&doc, item, item_id, module_id, &md_link);
1006998
if let Some(link) = link {
1007999
self.cx.cache.intra_doc_links.entry(item.item_id).or_default().insert(link);
10081000
}
@@ -1015,14 +1007,20 @@ impl LinkCollector<'_, '_> {
10151007
/// FIXME(jynelson): this is way too many arguments
10161008
fn resolve_link(
10171009
&mut self,
1010+
dox: &String,
10181011
item: &Item,
10191012
item_id: DefId,
10201013
module_id: DefId,
10211014
PreprocessedMarkdownLink(pp_link, ori_link): &PreprocessedMarkdownLink,
1022-
diag_info: &DiagnosticInfo<'_>,
10231015
) -> Option<ItemLink> {
10241016
trace!("considering link '{}'", ori_link.link);
10251017

1018+
let diag_info = DiagnosticInfo {
1019+
item,
1020+
dox,
1021+
ori_link: &ori_link.link,
1022+
link_range: ori_link.range.clone(),
1023+
};
10261024
let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } =
10271025
pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?;
10281026
let disambiguator = *disambiguator;
@@ -1045,11 +1043,14 @@ impl LinkCollector<'_, '_> {
10451043
self.check_redundant_explicit_link(
10461044
&res,
10471045
path_str,
1048-
item_id,
1049-
module_id,
1050-
disambiguator,
1046+
ResolutionInfo {
1047+
item_id,
1048+
module_id,
1049+
dis: disambiguator,
1050+
path_str: ori_link.display_text.clone().into_boxed_str(),
1051+
extra_fragment: extra_fragment.clone(),
1052+
},
10511053
&ori_link,
1052-
extra_fragment,
10531054
&diag_info,
10541055
);
10551056

@@ -1384,15 +1385,13 @@ impl LinkCollector<'_, '_> {
13841385
}
13851386
}
13861387

1388+
/// Check if resolution of inline link's display text and explicit link are same.
13871389
fn check_redundant_explicit_link(
13881390
&mut self,
1389-
ex_res: &Res,
1390-
ex: &Box<str>,
1391-
item_id: DefId,
1392-
module_id: DefId,
1393-
dis: Option<Disambiguator>,
1391+
explicit_res: &Res,
1392+
explicit_link: &Box<str>,
1393+
display_res_info: ResolutionInfo,
13941394
ori_link: &MarkdownLink,
1395-
extra_fragment: &Option<String>,
13961395
diag_info: &DiagnosticInfo<'_>,
13971396
) {
13981397
// Check if explicit resolution's path is same as resolution of original link's display text path, e.g.
@@ -1409,21 +1408,15 @@ impl LinkCollector<'_, '_> {
14091408
return;
14101409
}
14111410

1412-
let di_text = &ori_link.display_text;
1413-
let di_len = di_text.len();
1414-
let ex_len = ex.len();
1415-
1416-
let intra_doc_links = std::mem::take(&mut self.cx.cache.intra_doc_links);
1411+
let display_text = &ori_link.display_text;
1412+
let display_len = display_text.len();
1413+
let explicit_len = explicit_link.len();
14171414

1418-
if ex_len >= di_len && &ex[(ex_len - di_len)..] == di_text {
1419-
let Some((di_res, _)) = self.resolve_with_disambiguator_cached(
1420-
ResolutionInfo {
1421-
item_id,
1422-
module_id,
1423-
dis,
1424-
path_str: di_text.clone().into_boxed_str(),
1425-
extra_fragment: extra_fragment.clone(),
1426-
},
1415+
if explicit_len >= display_len
1416+
&& &explicit_link[(explicit_len - display_len)..] == display_text
1417+
{
1418+
let Some((display_res, _)) = self.resolve_with_disambiguator_cached(
1419+
display_res_info,
14271420
diag_info.clone(), // this struct should really be Copy, but Range is not :(
14281421
// For reference-style links we want to report only one error so unsuccessful
14291422
// resolutions are cached, for other links we want to report an error every
@@ -1433,7 +1426,7 @@ impl LinkCollector<'_, '_> {
14331426
return;
14341427
};
14351428

1436-
if &di_res == ex_res {
1429+
if &display_res == explicit_res {
14371430
use crate::lint::REDUNDANT_EXPLICIT_LINKS;
14381431

14391432
report_diagnostic(
@@ -1444,9 +1437,14 @@ impl LinkCollector<'_, '_> {
14441437
|diag, sp, _link_range| {
14451438
if let Some(sp) = sp {
14461439
diag.note("Explicit link does not affect the original link")
1447-
.span_suggestion(sp, "Remove explicit link instead", format!("[{}]", ori_link.link), Applicability::MachineApplicable);
1440+
.span_suggestion_hidden(
1441+
sp,
1442+
"Remove explicit link instead",
1443+
format!(""),
1444+
Applicability::MachineApplicable,
1445+
);
14481446
}
1449-
}
1447+
},
14501448
);
14511449
}
14521450
}

tests/rustdoc-ui/lints/redundant_explicit_links.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,20 @@
22

33
pub fn dummy_target() {}
44

5+
/// [dummy_target](dummy_target)
6+
/// [`dummy_target`](dummy_target)
7+
/// [Vec](Vec)
8+
/// [`Vec`](Vec)
9+
/// [Vec](std::vec::Vec)
510
/// [`Vec`](std::vec::Vec)
6-
pub fn c() {}
11+
/// [std::vec::Vec](std::vec::Vec)
12+
/// [`std::vec::Vec`](std::vec::Vec)
13+
/// [usize](usize)
14+
/// [`usize`](usize)
15+
/// [std::primitive::usize](usize)
16+
/// [`std::primitive::usize`](usize)
17+
pub fn should_warn() {}
18+
19+
/// [`Vec<T>`](Vec)
20+
/// [`Vec<T>`](std::vec::Vec)
21+
pub fn should_not_warn() {}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
error: redundant explicit rustdoc link
2+
--> $DIR/redundant_explicit_links.rs:5:20
3+
|
4+
LL | /// [dummy_target](dummy_target)
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: Explicit link does not affect the original link
8+
note: the lint level is defined here
9+
--> $DIR/redundant_explicit_links.rs:1:9
10+
|
11+
LL | #![deny(rustdoc::redundant_explicit_links)]
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13+
= help: Remove explicit link instead
14+
15+
error: redundant explicit rustdoc link
16+
--> $DIR/redundant_explicit_links.rs:6:22
17+
|
18+
LL | /// [`dummy_target`](dummy_target)
19+
| ^^^^^^^^^^^^
20+
|
21+
= note: Explicit link does not affect the original link
22+
= help: Remove explicit link instead
23+
24+
error: redundant explicit rustdoc link
25+
--> $DIR/redundant_explicit_links.rs:7:11
26+
|
27+
LL | /// [Vec](Vec)
28+
| ^^^
29+
|
30+
= note: Explicit link does not affect the original link
31+
= help: Remove explicit link instead
32+
33+
error: redundant explicit rustdoc link
34+
--> $DIR/redundant_explicit_links.rs:8:13
35+
|
36+
LL | /// [`Vec`](Vec)
37+
| ^^^
38+
|
39+
= note: Explicit link does not affect the original link
40+
= help: Remove explicit link instead
41+
42+
error: redundant explicit rustdoc link
43+
--> $DIR/redundant_explicit_links.rs:9:11
44+
|
45+
LL | /// [Vec](std::vec::Vec)
46+
| ^^^^^^^^^^^^^
47+
|
48+
= note: Explicit link does not affect the original link
49+
= help: Remove explicit link instead
50+
51+
error: redundant explicit rustdoc link
52+
--> $DIR/redundant_explicit_links.rs:10:13
53+
|
54+
LL | /// [`Vec`](std::vec::Vec)
55+
| ^^^^^^^^^^^^^
56+
|
57+
= note: Explicit link does not affect the original link
58+
= help: Remove explicit link instead
59+
60+
error: redundant explicit rustdoc link
61+
--> $DIR/redundant_explicit_links.rs:11:21
62+
|
63+
LL | /// [std::vec::Vec](std::vec::Vec)
64+
| ^^^^^^^^^^^^^
65+
|
66+
= note: Explicit link does not affect the original link
67+
= help: Remove explicit link instead
68+
69+
error: redundant explicit rustdoc link
70+
--> $DIR/redundant_explicit_links.rs:12:23
71+
|
72+
LL | /// [`std::vec::Vec`](std::vec::Vec)
73+
| ^^^^^^^^^^^^^
74+
|
75+
= note: Explicit link does not affect the original link
76+
= help: Remove explicit link instead
77+
78+
error: redundant explicit rustdoc link
79+
--> $DIR/redundant_explicit_links.rs:13:13
80+
|
81+
LL | /// [usize](usize)
82+
| ^^^^^
83+
|
84+
= note: Explicit link does not affect the original link
85+
= help: Remove explicit link instead
86+
87+
error: redundant explicit rustdoc link
88+
--> $DIR/redundant_explicit_links.rs:14:15
89+
|
90+
LL | /// [`usize`](usize)
91+
| ^^^^^
92+
|
93+
= note: Explicit link does not affect the original link
94+
= help: Remove explicit link instead
95+
96+
error: aborting due to 10 previous errors
97+

0 commit comments

Comments
 (0)