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() {
|
while let Some(event) = event_iter.next() {
|
||||||
match event {
|
match event {
|
||||||
Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
|
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) {
|
if matches!(link_type, LinkType::Inline | LinkType::ReferenceUnknown | LinkType::Reference) {
|
||||||
links.push(display_text);
|
if let Some(display_text) = collect_link_data(&mut event_iter) {
|
||||||
|
links.push(display_text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
links.push(preprocess_link(&dest));
|
links.push(preprocess_link(&dest));
|
||||||
|
|
|
@ -1038,6 +1038,7 @@ impl LinkCollector<'_, '_> {
|
||||||
// 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
|
||||||
// time so they are not cached.
|
// time so they are not cached.
|
||||||
matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut),
|
matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut),
|
||||||
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.resolve_display_text(
|
self.resolve_display_text(
|
||||||
|
@ -1232,6 +1233,9 @@ impl LinkCollector<'_, '_> {
|
||||||
// If errors are cached then they are only reported on first occurrence
|
// If errors are cached then they are only reported on first occurrence
|
||||||
// which we want in some cases but not in others.
|
// which we want in some cases but not in others.
|
||||||
cache_errors: bool,
|
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>)> {
|
) -> Option<(Res, Option<UrlFragment>)> {
|
||||||
if let Some(res) = self.visited_links.get(&key) {
|
if let Some(res) = self.visited_links.get(&key) {
|
||||||
if res.is_some() || cache_errors {
|
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.
|
// 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.
|
// However I'm not sure how to check that across crates.
|
||||||
|
@ -1290,6 +1294,9 @@ impl LinkCollector<'_, '_> {
|
||||||
&mut self,
|
&mut self,
|
||||||
key: &ResolutionInfo,
|
key: &ResolutionInfo,
|
||||||
diag: DiagnosticInfo<'_>,
|
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>)> {
|
) -> Vec<(Res, Option<DefId>)> {
|
||||||
let disambiguator = key.dis;
|
let disambiguator = key.dis;
|
||||||
let path_str = &key.path_str;
|
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![];
|
return vec![];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1356,13 +1365,15 @@ impl LinkCollector<'_, '_> {
|
||||||
.fold(0, |acc, res| if let Ok(res) = res { acc + res.len() } else { acc });
|
.fold(0, |acc, res| if let Ok(res) = res { acc + res.len() } else { acc });
|
||||||
|
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
resolution_failure(
|
if !recoverable {
|
||||||
self,
|
resolution_failure(
|
||||||
diag,
|
self,
|
||||||
path_str,
|
diag,
|
||||||
disambiguator,
|
path_str,
|
||||||
candidates.into_iter().filter_map(|res| res.err()).collect(),
|
disambiguator,
|
||||||
);
|
candidates.into_iter().filter_map(|res| res.err()).collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
return vec![];
|
return vec![];
|
||||||
} else if len == 1 {
|
} else if len == 1 {
|
||||||
candidates.into_iter().filter_map(|res| res.ok()).flatten().collect::<Vec<_>>()
|
candidates.into_iter().filter_map(|res| res.ok()).flatten().collect::<Vec<_>>()
|
||||||
|
@ -1396,43 +1407,8 @@ impl LinkCollector<'_, '_> {
|
||||||
ori_link: &MarkdownLink,
|
ori_link: &MarkdownLink,
|
||||||
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, see
|
||||||
//
|
// tests/rustdoc-ui/lint/redundant_explicit_links.rs for more cases.
|
||||||
// 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
|
|
||||||
//
|
//
|
||||||
// To avoid disambiguator from panicking, we check if display text path is possible to be disambiguated
|
// To avoid disambiguator from panicking, we check if display text path is possible to be disambiguated
|
||||||
// into explicit path.
|
// into explicit path.
|
||||||
|
@ -1471,6 +1447,7 @@ impl LinkCollector<'_, '_> {
|
||||||
display_res_info,
|
display_res_info,
|
||||||
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 :(
|
||||||
false,
|
false,
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,13 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
|
||||||
return;
|
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);
|
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() {
|
while let Some((event, link_range)) = offset_iter.next() {
|
||||||
match event {
|
match event {
|
||||||
Event::Start(Tag::Link(link_type, dest, _)) => match link_type {
|
Event::Start(Tag::Link(link_type, dest, _)) => {
|
||||||
LinkType::Inline | LinkType::ReferenceUnknown => {
|
let link_data = collect_link_data(&mut offset_iter);
|
||||||
check_inline_or_reference_unknown_redundancy(
|
|
||||||
cx,
|
let explicit_link = dest.to_string();
|
||||||
item,
|
let display_link = link_data.resolvable_link.clone()?;
|
||||||
hir_id,
|
let explicit_len = explicit_link.len();
|
||||||
doc,
|
let display_len = display_link.len();
|
||||||
resolutions,
|
|
||||||
link_range,
|
if explicit_len == display_len && explicit_link != display_link {
|
||||||
dest.to_string(),
|
// Skips if they possibly have no relativity.
|
||||||
collect_link_data(&mut offset_iter),
|
continue;
|
||||||
if link_type == LinkType::Inline { (b'(', b')') } else { (b'[', b']') },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
LinkType::Reference => {
|
|
||||||
check_reference_redundancy(
|
if (explicit_len >= display_len
|
||||||
cx,
|
&& &explicit_link[(explicit_len - display_len)..] == display_link)
|
||||||
item,
|
|| (display_len >= explicit_len
|
||||||
hir_id,
|
&& &display_link[(display_len - explicit_len)..] == explicit_link) {
|
||||||
doc,
|
match link_type {
|
||||||
resolutions,
|
LinkType::Inline | LinkType::ReferenceUnknown => {
|
||||||
link_range,
|
check_inline_or_reference_unknown_redundancy(
|
||||||
&dest,
|
cx,
|
||||||
collect_link_data(&mut offset_iter),
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub fn dummy_target() {}
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`std::primitive::usize`]
|
/// [`std::primitive::usize`]
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
///
|
///
|
||||||
/// [dummy_target] TEXT
|
/// [dummy_target] TEXT
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`dummy_target`] TEXT
|
/// [`dummy_target`] TEXT
|
||||||
|
@ -91,7 +91,7 @@ pub fn should_not_warn_inline() {}
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`std::primitive::usize`]
|
/// [`std::primitive::usize`]
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
///
|
///
|
||||||
/// [dummy_target] TEXT
|
/// [dummy_target] TEXT
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`dummy_target`] TEXT
|
/// [`dummy_target`] TEXT
|
||||||
|
@ -140,7 +140,7 @@ pub fn should_not_warn_reference_unknown() {}
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`std::primitive::usize`]
|
/// [`std::primitive::usize`]
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
///
|
///
|
||||||
/// [dummy_target] TEXT
|
/// [dummy_target] TEXT
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`dummy_target`] TEXT
|
/// [`dummy_target`] TEXT
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub fn dummy_target() {}
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`std::primitive::usize`](std::primitive::usize)
|
/// [`std::primitive::usize`](std::primitive::usize)
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
///
|
///
|
||||||
/// [dummy_target](dummy_target) TEXT
|
/// [dummy_target](dummy_target) TEXT
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`dummy_target`](dummy_target) TEXT
|
/// [`dummy_target`](dummy_target) TEXT
|
||||||
|
@ -91,7 +91,7 @@ pub fn should_not_warn_inline() {}
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`std::primitive::usize`][std::primitive::usize]
|
/// [`std::primitive::usize`][std::primitive::usize]
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
///
|
///
|
||||||
/// [dummy_target][dummy_target] TEXT
|
/// [dummy_target][dummy_target] TEXT
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`dummy_target`][dummy_target] TEXT
|
/// [`dummy_target`][dummy_target] TEXT
|
||||||
|
@ -140,7 +140,7 @@ pub fn should_not_warn_reference_unknown() {}
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`std::primitive::usize`][std::primitive::usize]
|
/// [`std::primitive::usize`][std::primitive::usize]
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
///
|
///
|
||||||
/// [dummy_target][dummy_target] TEXT
|
/// [dummy_target][dummy_target] TEXT
|
||||||
//~^ ERROR redundant explicit link target
|
//~^ ERROR redundant explicit link target
|
||||||
/// [`dummy_target`][dummy_target] TEXT
|
/// [`dummy_target`][dummy_target] TEXT
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![deny(rustdoc::unescaped_backticks)]
|
#![deny(rustdoc::unescaped_backticks)]
|
||||||
#![allow(rustdoc::broken_intra_doc_links)]
|
#![allow(rustdoc::broken_intra_doc_links)]
|
||||||
#![allow(rustdoc::invalid_html_tags)]
|
#![allow(rustdoc::invalid_html_tags)]
|
||||||
|
#![allow(rustdoc::redundant_explicit_links)]
|
||||||
|
|
||||||
///
|
///
|
||||||
pub fn empty() {}
|
pub fn empty() {}
|
||||||
|
|
|
@ -26,5 +26,5 @@ pub fn foo_fn() {}
|
||||||
// @has 'foo/fn.bar_fn.html' '//meta[@name="description"]/@content' \
|
// @has 'foo/fn.bar_fn.html' '//meta[@name="description"]/@content' \
|
||||||
// 'Description with intra-doc link to foo_fn and [nonexistent_item] and foo_fn.'
|
// 'Description with intra-doc link to foo_fn and [nonexistent_item] and foo_fn.'
|
||||||
#[allow(rustdoc::broken_intra_doc_links)]
|
#[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() {}
|
pub fn bar_fn() {}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(rustdoc::redundant_explicit_links)]
|
||||||
|
|
||||||
// @has basic/index.html
|
// @has basic/index.html
|
||||||
// @has - '//a/@href' 'struct.ThisType.html'
|
// @has - '//a/@href' 'struct.ThisType.html'
|
||||||
// @has - '//a/@title' 'struct basic::ThisType'
|
// @has - '//a/@title' 'struct basic::ThisType'
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// ignore-tidy-linelength
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
#![crate_name = "foo"]
|
#![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 [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`].
|
||||||
//! Here's a link to [`Iterator<Box<T>>::Item`].
|
//! Here's a link to [`Iterator<Box<T>>::Item`].
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#![deny(rustdoc::broken_intra_doc_links)]
|
#![deny(rustdoc::broken_intra_doc_links)]
|
||||||
|
#![allow(rustdoc::redundant_explicit_links)]
|
||||||
|
|
||||||
pub struct S;
|
pub struct S;
|
||||||
pub mod char {}
|
pub mod char {}
|
||||||
|
|
Loading…
Add table
Reference in a new issue