Still resolving rustdoc resolution panicking

This commit is contained in:
Kyle Lin 2023-07-01 00:55:37 +08:00
parent 46df95817d
commit 5ce6cc7df3
10 changed files with 90 additions and 80 deletions

View File

@ -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));

View File

@ -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,
);
}
}

View File

@ -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,
);
}
_ => {}
}
}
_ => {}
},
_ => {}
}

View File

@ -42,7 +42,7 @@ pub fn dummy_target() {}
//~^ ERROR redundant explicit link target
/// [`std::primitive::usize`]
//~^ ERROR redundant explicit link target
///
///
/// [dummy_target] TEXT
//~^ ERROR redundant explicit link target
/// [`dummy_target`] TEXT
@ -91,7 +91,7 @@ pub fn should_not_warn_inline() {}
//~^ ERROR redundant explicit link target
/// [`std::primitive::usize`]
//~^ ERROR redundant explicit link target
///
///
/// [dummy_target] TEXT
//~^ ERROR redundant explicit link target
/// [`dummy_target`] TEXT
@ -140,7 +140,7 @@ pub fn should_not_warn_reference_unknown() {}
//~^ ERROR redundant explicit link target
/// [`std::primitive::usize`]
//~^ ERROR redundant explicit link target
///
///
/// [dummy_target] TEXT
//~^ ERROR redundant explicit link target
/// [`dummy_target`] TEXT

View File

@ -42,7 +42,7 @@ pub fn dummy_target() {}
//~^ ERROR redundant explicit link target
/// [`std::primitive::usize`](std::primitive::usize)
//~^ ERROR redundant explicit link target
///
///
/// [dummy_target](dummy_target) TEXT
//~^ ERROR redundant explicit link target
/// [`dummy_target`](dummy_target) TEXT
@ -91,7 +91,7 @@ pub fn should_not_warn_inline() {}
//~^ ERROR redundant explicit link target
/// [`std::primitive::usize`][std::primitive::usize]
//~^ ERROR redundant explicit link target
///
///
/// [dummy_target][dummy_target] TEXT
//~^ ERROR redundant explicit link target
/// [`dummy_target`][dummy_target] TEXT
@ -140,7 +140,7 @@ pub fn should_not_warn_reference_unknown() {}
//~^ ERROR redundant explicit link target
/// [`std::primitive::usize`][std::primitive::usize]
//~^ ERROR redundant explicit link target
///
///
/// [dummy_target][dummy_target] TEXT
//~^ ERROR redundant explicit link target
/// [`dummy_target`][dummy_target] TEXT

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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'

View File

@ -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`].

View File

@ -1,4 +1,5 @@
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(rustdoc::redundant_explicit_links)]
pub struct S;
pub mod char {}