Fix resolution caching
This commit is contained in:
parent
da582a71d2
commit
65e24a57bb
6 changed files with 217 additions and 53 deletions
|
@ -392,16 +392,57 @@ pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<Box<s
|
||||||
let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
|
let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
|
||||||
let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap();
|
let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap();
|
||||||
|
|
||||||
Parser::new_with_broken_link_callback(
|
parse_links(&doc)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Similiar version of `markdown_links` from rustdoc.
|
||||||
|
/// This will collect destination links and display text if exists.
|
||||||
|
fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
|
||||||
|
let mut broken_link_callback = |link: BrokenLink<'md>| Some((link.reference, "".into()));
|
||||||
|
let mut event_iter = Parser::new_with_broken_link_callback(
|
||||||
&doc,
|
&doc,
|
||||||
main_body_opts(),
|
main_body_opts(),
|
||||||
Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))),
|
Some(&mut broken_link_callback),
|
||||||
)
|
)
|
||||||
.filter_map(|event| match event {
|
.into_iter();
|
||||||
Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
|
let mut links = Vec::new();
|
||||||
Some(preprocess_link(&dest))
|
|
||||||
|
while let Some(event) = event_iter.next() {
|
||||||
|
match event {
|
||||||
|
Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
|
||||||
|
if let Some(display_text) = collect_link_data(&mut event_iter) {
|
||||||
|
links.push(display_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
links.push(preprocess_link(&dest));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
_ => None,
|
}
|
||||||
})
|
|
||||||
.collect()
|
links
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects additional data of link.
|
||||||
|
fn collect_link_data<'input, 'callback>(
|
||||||
|
event_iter: &mut Parser<'input, 'callback>,
|
||||||
|
) -> Option<Box<str>> {
|
||||||
|
let mut display_text = None;
|
||||||
|
|
||||||
|
while let Some(event) = event_iter.next() {
|
||||||
|
match event {
|
||||||
|
Event::Text(code) => {
|
||||||
|
display_text = Some(code.to_string().into_boxed_str());
|
||||||
|
}
|
||||||
|
Event::Code(code) => {
|
||||||
|
display_text = Some(code.to_string().into_boxed_str());
|
||||||
|
}
|
||||||
|
Event::End(_) => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display_text
|
||||||
}
|
}
|
||||||
|
|
|
@ -420,17 +420,29 @@ as computed automatic links.
|
||||||
This usually means the explicit links is removeable. For example:
|
This usually means the explicit links is removeable. For example:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#![warn(rustdoc::redundant_explicit_links)]
|
#![warn(rustdoc::redundant_explicit_links)] // note: unnecessary - warns by default.
|
||||||
|
|
||||||
pub fn dummy_target() {} // note: unnecessary - warns by default.
|
/// add takes 2 [`usize`](usize) and performs addition
|
||||||
|
/// on them, then returns result.
|
||||||
/// [`dummy_target`](dummy_target)
|
pub fn add(left: usize, right: usize) -> usize {
|
||||||
/// [dummy_target](dummy_target)
|
left + right
|
||||||
pub fn c() {}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Which will give:
|
Which will give:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
error: redundant explicit rustdoc link
|
||||||
|
--> src/lib.rs:3:27
|
||||||
|
|
|
||||||
|
3 | /// add takes 2 [`usize`](usize) and performs addition
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: Explicit link does not affect the original link
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> src/lib.rs:1:9
|
||||||
|
|
|
||||||
|
1 | #![deny(rustdoc::redundant_explicit_links)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= help: Remove explicit link instead
|
||||||
```
|
```
|
||||||
|
|
|
@ -1421,6 +1421,7 @@ pub(crate) fn markdown_links<'md, R>(
|
||||||
links
|
links
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collects additional data of link.
|
||||||
fn collect_link_data<'input, 'callback>(
|
fn collect_link_data<'input, 'callback>(
|
||||||
event_iter: &mut OffsetIter<'input, 'callback>,
|
event_iter: &mut OffsetIter<'input, 'callback>,
|
||||||
) -> Option<CowStr<'input>> {
|
) -> Option<CowStr<'input>> {
|
||||||
|
|
|
@ -994,15 +994,7 @@ impl LinkCollector<'_, '_> {
|
||||||
_ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(),
|
_ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(),
|
||||||
};
|
};
|
||||||
for md_link in preprocessed_markdown_links(&doc) {
|
for md_link in preprocessed_markdown_links(&doc) {
|
||||||
let PreprocessedMarkdownLink(_pp_link, ori_link) = &md_link;
|
let link = self.resolve_link(&doc, item, item_id, module_id, &md_link);
|
||||||
let diag_info = DiagnosticInfo {
|
|
||||||
item,
|
|
||||||
dox: &doc,
|
|
||||||
ori_link: &ori_link.link,
|
|
||||||
link_range: ori_link.range.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let link = self.resolve_link(item, item_id, module_id, &md_link, &diag_info);
|
|
||||||
if let Some(link) = link {
|
if let Some(link) = link {
|
||||||
self.cx.cache.intra_doc_links.entry(item.item_id).or_default().insert(link);
|
self.cx.cache.intra_doc_links.entry(item.item_id).or_default().insert(link);
|
||||||
}
|
}
|
||||||
|
@ -1015,14 +1007,20 @@ impl LinkCollector<'_, '_> {
|
||||||
/// FIXME(jynelson): this is way too many arguments
|
/// FIXME(jynelson): this is way too many arguments
|
||||||
fn resolve_link(
|
fn resolve_link(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
dox: &String,
|
||||||
item: &Item,
|
item: &Item,
|
||||||
item_id: DefId,
|
item_id: DefId,
|
||||||
module_id: DefId,
|
module_id: DefId,
|
||||||
PreprocessedMarkdownLink(pp_link, ori_link): &PreprocessedMarkdownLink,
|
PreprocessedMarkdownLink(pp_link, ori_link): &PreprocessedMarkdownLink,
|
||||||
diag_info: &DiagnosticInfo<'_>,
|
|
||||||
) -> Option<ItemLink> {
|
) -> Option<ItemLink> {
|
||||||
trace!("considering link '{}'", ori_link.link);
|
trace!("considering link '{}'", ori_link.link);
|
||||||
|
|
||||||
|
let diag_info = DiagnosticInfo {
|
||||||
|
item,
|
||||||
|
dox,
|
||||||
|
ori_link: &ori_link.link,
|
||||||
|
link_range: ori_link.range.clone(),
|
||||||
|
};
|
||||||
let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } =
|
let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } =
|
||||||
pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?;
|
pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?;
|
||||||
let disambiguator = *disambiguator;
|
let disambiguator = *disambiguator;
|
||||||
|
@ -1045,11 +1043,14 @@ impl LinkCollector<'_, '_> {
|
||||||
self.check_redundant_explicit_link(
|
self.check_redundant_explicit_link(
|
||||||
&res,
|
&res,
|
||||||
path_str,
|
path_str,
|
||||||
item_id,
|
ResolutionInfo {
|
||||||
module_id,
|
item_id,
|
||||||
disambiguator,
|
module_id,
|
||||||
|
dis: disambiguator,
|
||||||
|
path_str: ori_link.display_text.clone().into_boxed_str(),
|
||||||
|
extra_fragment: extra_fragment.clone(),
|
||||||
|
},
|
||||||
&ori_link,
|
&ori_link,
|
||||||
extra_fragment,
|
|
||||||
&diag_info,
|
&diag_info,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1384,15 +1385,13 @@ impl LinkCollector<'_, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if resolution of inline link's display text and explicit link are same.
|
||||||
fn check_redundant_explicit_link(
|
fn check_redundant_explicit_link(
|
||||||
&mut self,
|
&mut self,
|
||||||
ex_res: &Res,
|
explicit_res: &Res,
|
||||||
ex: &Box<str>,
|
explicit_link: &Box<str>,
|
||||||
item_id: DefId,
|
display_res_info: ResolutionInfo,
|
||||||
module_id: DefId,
|
|
||||||
dis: Option<Disambiguator>,
|
|
||||||
ori_link: &MarkdownLink,
|
ori_link: &MarkdownLink,
|
||||||
extra_fragment: &Option<String>,
|
|
||||||
diag_info: &DiagnosticInfo<'_>,
|
diag_info: &DiagnosticInfo<'_>,
|
||||||
) {
|
) {
|
||||||
// Check if explicit resolution's path is same as resolution of original link's display text path, e.g.
|
// 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<'_, '_> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let di_text = &ori_link.display_text;
|
let display_text = &ori_link.display_text;
|
||||||
let di_len = di_text.len();
|
let display_len = display_text.len();
|
||||||
let ex_len = ex.len();
|
let explicit_len = explicit_link.len();
|
||||||
|
|
||||||
let intra_doc_links = std::mem::take(&mut self.cx.cache.intra_doc_links);
|
if explicit_len >= display_len
|
||||||
|
&& &explicit_link[(explicit_len - display_len)..] == display_text
|
||||||
if ex_len >= di_len && &ex[(ex_len - di_len)..] == di_text {
|
{
|
||||||
let Some((di_res, _)) = self.resolve_with_disambiguator_cached(
|
let Some((display_res, _)) = self.resolve_with_disambiguator_cached(
|
||||||
ResolutionInfo {
|
display_res_info,
|
||||||
item_id,
|
|
||||||
module_id,
|
|
||||||
dis,
|
|
||||||
path_str: di_text.clone().into_boxed_str(),
|
|
||||||
extra_fragment: extra_fragment.clone(),
|
|
||||||
},
|
|
||||||
diag_info.clone(), // this struct should really be Copy, but Range is not :(
|
diag_info.clone(), // this struct should really be Copy, but Range is not :(
|
||||||
// For reference-style links we want to report only one error so unsuccessful
|
// For reference-style links we want to report only one error so unsuccessful
|
||||||
// resolutions are cached, for other links we want to report an error every
|
// resolutions are cached, for other links we want to report an error every
|
||||||
|
@ -1433,7 +1426,7 @@ impl LinkCollector<'_, '_> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if &di_res == ex_res {
|
if &display_res == explicit_res {
|
||||||
use crate::lint::REDUNDANT_EXPLICIT_LINKS;
|
use crate::lint::REDUNDANT_EXPLICIT_LINKS;
|
||||||
|
|
||||||
report_diagnostic(
|
report_diagnostic(
|
||||||
|
@ -1444,9 +1437,14 @@ impl LinkCollector<'_, '_> {
|
||||||
|diag, sp, _link_range| {
|
|diag, sp, _link_range| {
|
||||||
if let Some(sp) = sp {
|
if let Some(sp) = sp {
|
||||||
diag.note("Explicit link does not affect the original link")
|
diag.note("Explicit link does not affect the original link")
|
||||||
.span_suggestion(sp, "Remove explicit link instead", format!("[{}]", ori_link.link), Applicability::MachineApplicable);
|
.span_suggestion_hidden(
|
||||||
|
sp,
|
||||||
|
"Remove explicit link instead",
|
||||||
|
format!(""),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,20 @@
|
||||||
|
|
||||||
pub fn dummy_target() {}
|
pub fn dummy_target() {}
|
||||||
|
|
||||||
|
/// [dummy_target](dummy_target)
|
||||||
|
/// [`dummy_target`](dummy_target)
|
||||||
|
/// [Vec](Vec)
|
||||||
|
/// [`Vec`](Vec)
|
||||||
|
/// [Vec](std::vec::Vec)
|
||||||
/// [`Vec`](std::vec::Vec)
|
/// [`Vec`](std::vec::Vec)
|
||||||
pub fn c() {}
|
/// [std::vec::Vec](std::vec::Vec)
|
||||||
|
/// [`std::vec::Vec`](std::vec::Vec)
|
||||||
|
/// [usize](usize)
|
||||||
|
/// [`usize`](usize)
|
||||||
|
/// [std::primitive::usize](usize)
|
||||||
|
/// [`std::primitive::usize`](usize)
|
||||||
|
pub fn should_warn() {}
|
||||||
|
|
||||||
|
/// [`Vec<T>`](Vec)
|
||||||
|
/// [`Vec<T>`](std::vec::Vec)
|
||||||
|
pub fn should_not_warn() {}
|
||||||
|
|
97
tests/rustdoc-ui/lints/redundant_explicit_links.stderr
Normal file
97
tests/rustdoc-ui/lints/redundant_explicit_links.stderr
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
error: redundant explicit rustdoc link
|
||||||
|
--> $DIR/redundant_explicit_links.rs:5:20
|
||||||
|
|
|
||||||
|
LL | /// [dummy_target](dummy_target)
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: Explicit link does not affect the original link
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/redundant_explicit_links.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(rustdoc::redundant_explicit_links)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= help: Remove explicit link instead
|
||||||
|
|
||||||
|
error: redundant explicit rustdoc link
|
||||||
|
--> $DIR/redundant_explicit_links.rs:6:22
|
||||||
|
|
|
||||||
|
LL | /// [`dummy_target`](dummy_target)
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: Explicit link does not affect the original link
|
||||||
|
= help: Remove explicit link instead
|
||||||
|
|
||||||
|
error: redundant explicit rustdoc link
|
||||||
|
--> $DIR/redundant_explicit_links.rs:7:11
|
||||||
|
|
|
||||||
|
LL | /// [Vec](Vec)
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= note: Explicit link does not affect the original link
|
||||||
|
= help: Remove explicit link instead
|
||||||
|
|
||||||
|
error: redundant explicit rustdoc link
|
||||||
|
--> $DIR/redundant_explicit_links.rs:8:13
|
||||||
|
|
|
||||||
|
LL | /// [`Vec`](Vec)
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= note: Explicit link does not affect the original link
|
||||||
|
= help: Remove explicit link instead
|
||||||
|
|
||||||
|
error: redundant explicit rustdoc link
|
||||||
|
--> $DIR/redundant_explicit_links.rs:9:11
|
||||||
|
|
|
||||||
|
LL | /// [Vec](std::vec::Vec)
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: Explicit link does not affect the original link
|
||||||
|
= help: Remove explicit link instead
|
||||||
|
|
||||||
|
error: redundant explicit rustdoc link
|
||||||
|
--> $DIR/redundant_explicit_links.rs:10:13
|
||||||
|
|
|
||||||
|
LL | /// [`Vec`](std::vec::Vec)
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: Explicit link does not affect the original link
|
||||||
|
= help: Remove explicit link instead
|
||||||
|
|
||||||
|
error: redundant explicit rustdoc link
|
||||||
|
--> $DIR/redundant_explicit_links.rs:11:21
|
||||||
|
|
|
||||||
|
LL | /// [std::vec::Vec](std::vec::Vec)
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: Explicit link does not affect the original link
|
||||||
|
= help: Remove explicit link instead
|
||||||
|
|
||||||
|
error: redundant explicit rustdoc link
|
||||||
|
--> $DIR/redundant_explicit_links.rs:12:23
|
||||||
|
|
|
||||||
|
LL | /// [`std::vec::Vec`](std::vec::Vec)
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: Explicit link does not affect the original link
|
||||||
|
= help: Remove explicit link instead
|
||||||
|
|
||||||
|
error: redundant explicit rustdoc link
|
||||||
|
--> $DIR/redundant_explicit_links.rs:13:13
|
||||||
|
|
|
||||||
|
LL | /// [usize](usize)
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: Explicit link does not affect the original link
|
||||||
|
= help: Remove explicit link instead
|
||||||
|
|
||||||
|
error: redundant explicit rustdoc link
|
||||||
|
--> $DIR/redundant_explicit_links.rs:14:15
|
||||||
|
|
|
||||||
|
LL | /// [`usize`](usize)
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: Explicit link does not affect the original link
|
||||||
|
= help: Remove explicit link instead
|
||||||
|
|
||||||
|
error: aborting due to 10 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue