Still resolving rustdoc resolution panicking
This commit is contained in:
parent
46df95817d
commit
5ce6cc7df3
10 changed files with 90 additions and 80 deletions
|
@ -410,8 +410,10 @@ fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
|
|||
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);
|
||||
if matches!(link_type, LinkType::Inline | LinkType::ReferenceUnknown | LinkType::Reference) {
|
||||
if let Some(display_text) = collect_link_data(&mut event_iter) {
|
||||
links.push(display_text);
|
||||
}
|
||||
}
|
||||
|
||||
links.push(preprocess_link(&dest));
|
||||
|
|
|
@ -1038,6 +1038,7 @@ impl LinkCollector<'_, '_> {
|
|||
// resolutions are cached, for other links we want to report an error every
|
||||
// time so they are not cached.
|
||||
matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut),
|
||||
false,
|
||||
)?;
|
||||
|
||||
self.resolve_display_text(
|
||||
|
@ -1232,6 +1233,9 @@ impl LinkCollector<'_, '_> {
|
|||
// If errors are cached then they are only reported on first occurrence
|
||||
// which we want in some cases but not in others.
|
||||
cache_errors: bool,
|
||||
// If this call is intended to be recoverable, then pass true to silence.
|
||||
// This is only recoverable when path is failed to resolved.
|
||||
recoverable: bool,
|
||||
) -> Option<(Res, Option<UrlFragment>)> {
|
||||
if let Some(res) = self.visited_links.get(&key) {
|
||||
if res.is_some() || cache_errors {
|
||||
|
@ -1239,7 +1243,7 @@ impl LinkCollector<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
let mut candidates = self.resolve_with_disambiguator(&key, diag.clone());
|
||||
let mut candidates = self.resolve_with_disambiguator(&key, diag.clone(), recoverable);
|
||||
|
||||
// FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
|
||||
// However I'm not sure how to check that across crates.
|
||||
|
@ -1290,6 +1294,9 @@ impl LinkCollector<'_, '_> {
|
|||
&mut self,
|
||||
key: &ResolutionInfo,
|
||||
diag: DiagnosticInfo<'_>,
|
||||
// If this call is intended to be recoverable, then pass true to silence.
|
||||
// This is only recoverable when path is failed to resolved.
|
||||
recoverable: bool,
|
||||
) -> Vec<(Res, Option<DefId>)> {
|
||||
let disambiguator = key.dis;
|
||||
let path_str = &key.path_str;
|
||||
|
@ -1319,7 +1326,9 @@ impl LinkCollector<'_, '_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
resolution_failure(self, diag, path_str, disambiguator, smallvec![err]);
|
||||
if !recoverable {
|
||||
resolution_failure(self, diag, path_str, disambiguator, smallvec![err]);
|
||||
}
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
|
@ -1356,13 +1365,15 @@ impl LinkCollector<'_, '_> {
|
|||
.fold(0, |acc, res| if let Ok(res) = res { acc + res.len() } else { acc });
|
||||
|
||||
if len == 0 {
|
||||
resolution_failure(
|
||||
self,
|
||||
diag,
|
||||
path_str,
|
||||
disambiguator,
|
||||
candidates.into_iter().filter_map(|res| res.err()).collect(),
|
||||
);
|
||||
if !recoverable {
|
||||
resolution_failure(
|
||||
self,
|
||||
diag,
|
||||
path_str,
|
||||
disambiguator,
|
||||
candidates.into_iter().filter_map(|res| res.err()).collect(),
|
||||
);
|
||||
}
|
||||
return vec![];
|
||||
} else if len == 1 {
|
||||
candidates.into_iter().filter_map(|res| res.ok()).flatten().collect::<Vec<_>>()
|
||||
|
@ -1396,43 +1407,8 @@ impl LinkCollector<'_, '_> {
|
|||
ori_link: &MarkdownLink,
|
||||
diag_info: &DiagnosticInfo<'_>,
|
||||
) {
|
||||
// Check if explicit resolution's path is same as resolution of original link's display text path, e.g.
|
||||
//
|
||||
// LinkType::Inline:
|
||||
//
|
||||
// [target](target)
|
||||
// [`target`](target)
|
||||
// [target](path::to::target)
|
||||
// [`target`](path::to::target)
|
||||
// [path::to::target](target)
|
||||
// [`path::to::target`](target)
|
||||
// [path::to::target](path::to::target)
|
||||
// [`path::to::target`](path::to::target)
|
||||
//
|
||||
// LinkType::ReferenceUnknown
|
||||
//
|
||||
// [target][target]
|
||||
// [`target`][target]
|
||||
// [target][path::to::target]
|
||||
// [`target`][path::to::target]
|
||||
// [path::to::target][target]
|
||||
// [`path::to::target`][target]
|
||||
// [path::to::target][path::to::target]
|
||||
// [`path::to::target`][path::to::target]
|
||||
//
|
||||
// LinkType::Reference
|
||||
//
|
||||
// [target][target]
|
||||
// [`target`][target]
|
||||
// [target][path::to::target]
|
||||
// [`target`][path::to::target]
|
||||
// [path::to::target][target]
|
||||
// [`path::to::target`][target]
|
||||
// [path::to::target][path::to::target]
|
||||
// [`path::to::target`][path::to::target]
|
||||
//
|
||||
// [target]: target // or [target]: path::to::target
|
||||
// [path::to::target]: path::to::target // or [path::to::target]: target
|
||||
// Check if explicit resolution's path is same as resolution of original link's display text path, see
|
||||
// tests/rustdoc-ui/lint/redundant_explicit_links.rs for more cases.
|
||||
//
|
||||
// To avoid disambiguator from panicking, we check if display text path is possible to be disambiguated
|
||||
// into explicit path.
|
||||
|
@ -1471,6 +1447,7 @@ impl LinkCollector<'_, '_> {
|
|||
display_res_info,
|
||||
diag_info.clone(), // this struct should really be Copy, but Range is not :(
|
||||
false,
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,13 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
|
|||
return;
|
||||
}
|
||||
|
||||
if item.link_names(&cx.cache).is_empty() {
|
||||
// If there's no link names in this item,
|
||||
// then we skip resolution querying to
|
||||
// avoid from panicking.
|
||||
return;
|
||||
}
|
||||
|
||||
check_redundant_explicit_link(cx, item, hir_id, &doc);
|
||||
}
|
||||
|
||||
|
@ -57,33 +64,52 @@ fn check_redundant_explicit_link<'md>(
|
|||
|
||||
while let Some((event, link_range)) = offset_iter.next() {
|
||||
match event {
|
||||
Event::Start(Tag::Link(link_type, dest, _)) => match link_type {
|
||||
LinkType::Inline | LinkType::ReferenceUnknown => {
|
||||
check_inline_or_reference_unknown_redundancy(
|
||||
cx,
|
||||
item,
|
||||
hir_id,
|
||||
doc,
|
||||
resolutions,
|
||||
link_range,
|
||||
dest.to_string(),
|
||||
collect_link_data(&mut offset_iter),
|
||||
if link_type == LinkType::Inline { (b'(', b')') } else { (b'[', b']') },
|
||||
);
|
||||
Event::Start(Tag::Link(link_type, dest, _)) => {
|
||||
let link_data = collect_link_data(&mut offset_iter);
|
||||
|
||||
let explicit_link = dest.to_string();
|
||||
let display_link = link_data.resolvable_link.clone()?;
|
||||
let explicit_len = explicit_link.len();
|
||||
let display_len = display_link.len();
|
||||
|
||||
if explicit_len == display_len && explicit_link != display_link {
|
||||
// Skips if they possibly have no relativity.
|
||||
continue;
|
||||
}
|
||||
LinkType::Reference => {
|
||||
check_reference_redundancy(
|
||||
cx,
|
||||
item,
|
||||
hir_id,
|
||||
doc,
|
||||
resolutions,
|
||||
link_range,
|
||||
&dest,
|
||||
collect_link_data(&mut offset_iter),
|
||||
);
|
||||
|
||||
if (explicit_len >= display_len
|
||||
&& &explicit_link[(explicit_len - display_len)..] == display_link)
|
||||
|| (display_len >= explicit_len
|
||||
&& &display_link[(display_len - explicit_len)..] == explicit_link) {
|
||||
match link_type {
|
||||
LinkType::Inline | LinkType::ReferenceUnknown => {
|
||||
check_inline_or_reference_unknown_redundancy(
|
||||
cx,
|
||||
item,
|
||||
hir_id,
|
||||
doc,
|
||||
resolutions,
|
||||
link_range,
|
||||
dest.to_string(),
|
||||
link_data,
|
||||
if link_type == LinkType::Inline { (b'(', b')') } else { (b'[', b']') },
|
||||
);
|
||||
}
|
||||
LinkType::Reference => {
|
||||
check_reference_redundancy(
|
||||
cx,
|
||||
item,
|
||||
hir_id,
|
||||
doc,
|
||||
resolutions,
|
||||
link_range,
|
||||
&dest,
|
||||
link_data,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#![deny(rustdoc::unescaped_backticks)]
|
||||
#![allow(rustdoc::broken_intra_doc_links)]
|
||||
#![allow(rustdoc::invalid_html_tags)]
|
||||
#![allow(rustdoc::redundant_explicit_links)]
|
||||
|
||||
///
|
||||
pub fn empty() {}
|
||||
|
|
|
@ -26,5 +26,5 @@ pub fn foo_fn() {}
|
|||
// @has 'foo/fn.bar_fn.html' '//meta[@name="description"]/@content' \
|
||||
// 'Description with intra-doc link to foo_fn and [nonexistent_item] and foo_fn.'
|
||||
#[allow(rustdoc::broken_intra_doc_links)]
|
||||
/// Description with intra-doc link to [foo_fn] and [nonexistent_item] and [foo_fn](self::foo_fn).
|
||||
/// Description with intra-doc link to [foo_fn] and [nonexistent_item] and [foo_fn].
|
||||
pub fn bar_fn() {}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(rustdoc::redundant_explicit_links)]
|
||||
|
||||
// @has basic/index.html
|
||||
// @has - '//a/@href' 'struct.ThisType.html'
|
||||
// @has - '//a/@title' 'struct basic::ThisType'
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// ignore-tidy-linelength
|
||||
|
||||
#![crate_name = "foo"]
|
||||
#![allow(rustdoc::redundant_explicit_links)]
|
||||
|
||||
//! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`].
|
||||
//! Here's a link to [`Iterator<Box<T>>::Item`].
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
#![allow(rustdoc::redundant_explicit_links)]
|
||||
|
||||
pub struct S;
|
||||
pub mod char {}
|
||||
|
|
Loading…
Add table
Reference in a new issue