Rollup merge of #112014 - notriddle:notriddle/intra-doc-weird-syntax, r=GuillaumeGomez,fmease
rustdoc: get unnormalized link destination for suggestions Fixes #110111 This bug, and the workaround in this PR, is closely linked to [raphlinus/pulldown-cmark#441], getting offsets of link components. In particular, pulldown-cmark doesn't provide the offsets of the contents of a link. To work around this, rustdoc parser parts of a link definition itself. [raphlinus/pulldown-cmark#441]: https://github.com/raphlinus/pulldown-cmark/issues/441
This commit is contained in:
commit
30896536f3
@ -1237,7 +1237,27 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
|
|||||||
pub(crate) struct MarkdownLink {
|
pub(crate) struct MarkdownLink {
|
||||||
pub kind: LinkType,
|
pub kind: LinkType,
|
||||||
pub link: String,
|
pub link: String,
|
||||||
pub range: Range<usize>,
|
pub range: MarkdownLinkRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub(crate) enum MarkdownLinkRange {
|
||||||
|
/// Normally, markdown link warnings point only at the destination.
|
||||||
|
Destination(Range<usize>),
|
||||||
|
/// In some cases, it's not possible to point at the destination.
|
||||||
|
/// Usually, this happens because backslashes `\\` are used.
|
||||||
|
/// When that happens, point at the whole link, and don't provide structured suggestions.
|
||||||
|
WholeLink(Range<usize>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MarkdownLinkRange {
|
||||||
|
/// Extracts the inner range.
|
||||||
|
pub fn inner_range(&self) -> &Range<usize> {
|
||||||
|
match self {
|
||||||
|
MarkdownLinkRange::Destination(range) => range,
|
||||||
|
MarkdownLinkRange::WholeLink(range) => range,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn markdown_links<R>(
|
pub(crate) fn markdown_links<R>(
|
||||||
@ -1257,9 +1277,9 @@ pub(crate) fn markdown_links<R>(
|
|||||||
if md_start <= s_start && s_end <= md_end {
|
if md_start <= s_start && s_end <= md_end {
|
||||||
let start = s_start.offset_from(md_start) as usize;
|
let start = s_start.offset_from(md_start) as usize;
|
||||||
let end = s_end.offset_from(md_start) as usize;
|
let end = s_end.offset_from(md_start) as usize;
|
||||||
start..end
|
MarkdownLinkRange::Destination(start..end)
|
||||||
} else {
|
} else {
|
||||||
fallback
|
MarkdownLinkRange::WholeLink(fallback)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1267,6 +1287,7 @@ pub(crate) fn markdown_links<R>(
|
|||||||
// For diagnostics, we want to underline the link's definition but `span` will point at
|
// For diagnostics, we want to underline the link's definition but `span` will point at
|
||||||
// where the link is used. This is a problem for reference-style links, where the definition
|
// where the link is used. This is a problem for reference-style links, where the definition
|
||||||
// is separate from the usage.
|
// is separate from the usage.
|
||||||
|
|
||||||
match link {
|
match link {
|
||||||
// `Borrowed` variant means the string (the link's destination) may come directly from
|
// `Borrowed` variant means the string (the link's destination) may come directly from
|
||||||
// the markdown text and we can locate the original link destination.
|
// the markdown text and we can locate the original link destination.
|
||||||
@ -1275,10 +1296,82 @@ pub(crate) fn markdown_links<R>(
|
|||||||
CowStr::Borrowed(s) => locate(s, span),
|
CowStr::Borrowed(s) => locate(s, span),
|
||||||
|
|
||||||
// For anything else, we can only use the provided range.
|
// For anything else, we can only use the provided range.
|
||||||
CowStr::Boxed(_) | CowStr::Inlined(_) => span,
|
CowStr::Boxed(_) | CowStr::Inlined(_) => MarkdownLinkRange::WholeLink(span),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let span_for_offset_backward = |span: Range<usize>, open: u8, close: u8| {
|
||||||
|
let mut open_brace = !0;
|
||||||
|
let mut close_brace = !0;
|
||||||
|
for (i, b) in md.as_bytes()[span.clone()].iter().copied().enumerate().rev() {
|
||||||
|
let i = i + span.start;
|
||||||
|
if b == close {
|
||||||
|
close_brace = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if close_brace < span.start || close_brace >= span.end {
|
||||||
|
return MarkdownLinkRange::WholeLink(span);
|
||||||
|
}
|
||||||
|
let mut nesting = 1;
|
||||||
|
for (i, b) in md.as_bytes()[span.start..close_brace].iter().copied().enumerate().rev() {
|
||||||
|
let i = i + span.start;
|
||||||
|
if b == close {
|
||||||
|
nesting += 1;
|
||||||
|
}
|
||||||
|
if b == open {
|
||||||
|
nesting -= 1;
|
||||||
|
}
|
||||||
|
if nesting == 0 {
|
||||||
|
open_brace = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(open_brace != close_brace);
|
||||||
|
if open_brace < span.start || open_brace >= span.end {
|
||||||
|
return MarkdownLinkRange::WholeLink(span);
|
||||||
|
}
|
||||||
|
// do not actually include braces in the span
|
||||||
|
let range = (open_brace + 1)..close_brace;
|
||||||
|
MarkdownLinkRange::Destination(range.clone())
|
||||||
|
};
|
||||||
|
|
||||||
|
let span_for_offset_forward = |span: Range<usize>, open: u8, close: u8| {
|
||||||
|
let mut open_brace = !0;
|
||||||
|
let mut close_brace = !0;
|
||||||
|
for (i, b) in md.as_bytes()[span.clone()].iter().copied().enumerate() {
|
||||||
|
let i = i + span.start;
|
||||||
|
if b == open {
|
||||||
|
open_brace = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if open_brace < span.start || open_brace >= span.end {
|
||||||
|
return MarkdownLinkRange::WholeLink(span);
|
||||||
|
}
|
||||||
|
let mut nesting = 0;
|
||||||
|
for (i, b) in md.as_bytes()[open_brace..span.end].iter().copied().enumerate() {
|
||||||
|
let i = i + open_brace;
|
||||||
|
if b == close {
|
||||||
|
nesting -= 1;
|
||||||
|
}
|
||||||
|
if b == open {
|
||||||
|
nesting += 1;
|
||||||
|
}
|
||||||
|
if nesting == 0 {
|
||||||
|
close_brace = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(open_brace != close_brace);
|
||||||
|
if open_brace < span.start || open_brace >= span.end {
|
||||||
|
return MarkdownLinkRange::WholeLink(span);
|
||||||
|
}
|
||||||
|
// do not actually include braces in the span
|
||||||
|
let range = (open_brace + 1)..close_brace;
|
||||||
|
MarkdownLinkRange::Destination(range.clone())
|
||||||
|
};
|
||||||
|
|
||||||
Parser::new_with_broken_link_callback(
|
Parser::new_with_broken_link_callback(
|
||||||
md,
|
md,
|
||||||
main_body_opts(),
|
main_body_opts(),
|
||||||
@ -1287,11 +1380,20 @@ pub(crate) fn markdown_links<R>(
|
|||||||
.into_offset_iter()
|
.into_offset_iter()
|
||||||
.filter_map(|(event, span)| match event {
|
.filter_map(|(event, span)| 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) => {
|
||||||
preprocess_link(MarkdownLink {
|
let range = match link_type {
|
||||||
kind: link_type,
|
// Link is pulled from the link itself.
|
||||||
range: span_for_link(&dest, span),
|
LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => {
|
||||||
link: dest.into_string(),
|
span_for_offset_backward(span, b'[', b']')
|
||||||
})
|
}
|
||||||
|
LinkType::CollapsedUnknown => span_for_offset_forward(span, b'[', b']'),
|
||||||
|
LinkType::Inline => span_for_offset_backward(span, b'(', b')'),
|
||||||
|
// Link is pulled from elsewhere in the document.
|
||||||
|
LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => {
|
||||||
|
span_for_link(&dest, span)
|
||||||
|
}
|
||||||
|
LinkType::Autolink | LinkType::Email => unreachable!(),
|
||||||
|
};
|
||||||
|
preprocess_link(MarkdownLink { kind: link_type, range, link: dest.into_string() })
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
use crate::clean::{self, utils::find_nearest_parent_module};
|
use crate::clean::{self, utils::find_nearest_parent_module};
|
||||||
use crate::clean::{Crate, Item, ItemLink, PrimitiveType};
|
use crate::clean::{Crate, Item, ItemLink, PrimitiveType};
|
||||||
use crate::core::DocContext;
|
use crate::core::DocContext;
|
||||||
use crate::html::markdown::{markdown_links, MarkdownLink};
|
use crate::html::markdown::{markdown_links, MarkdownLink, MarkdownLinkRange};
|
||||||
use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
|
use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
|
||||||
use crate::passes::Pass;
|
use crate::passes::Pass;
|
||||||
use crate::visit::DocVisitor;
|
use crate::visit::DocVisitor;
|
||||||
@ -248,7 +248,7 @@ struct DiagnosticInfo<'a> {
|
|||||||
item: &'a Item,
|
item: &'a Item,
|
||||||
dox: &'a str,
|
dox: &'a str,
|
||||||
ori_link: &'a str,
|
ori_link: &'a str,
|
||||||
link_range: Range<usize>,
|
link_range: MarkdownLinkRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LinkCollector<'a, 'tcx> {
|
struct LinkCollector<'a, 'tcx> {
|
||||||
@ -833,7 +833,7 @@ fn visit_item(&mut self, item: &Item) {
|
|||||||
enum PreprocessingError {
|
enum PreprocessingError {
|
||||||
/// User error: `[std#x#y]` is not valid
|
/// User error: `[std#x#y]` is not valid
|
||||||
MultipleAnchors,
|
MultipleAnchors,
|
||||||
Disambiguator(Range<usize>, String),
|
Disambiguator(MarkdownLinkRange, String),
|
||||||
MalformedGenerics(MalformedGenerics, String),
|
MalformedGenerics(MalformedGenerics, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -873,6 +873,7 @@ pub(crate) struct PreprocessedMarkdownLink(
|
|||||||
/// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored.
|
/// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored.
|
||||||
fn preprocess_link(
|
fn preprocess_link(
|
||||||
ori_link: &MarkdownLink,
|
ori_link: &MarkdownLink,
|
||||||
|
dox: &str,
|
||||||
) -> Option<Result<PreprocessingInfo, PreprocessingError>> {
|
) -> Option<Result<PreprocessingInfo, PreprocessingError>> {
|
||||||
// [] is mostly likely not supposed to be a link
|
// [] is mostly likely not supposed to be a link
|
||||||
if ori_link.link.is_empty() {
|
if ori_link.link.is_empty() {
|
||||||
@ -906,9 +907,15 @@ fn preprocess_link(
|
|||||||
Err((err_msg, relative_range)) => {
|
Err((err_msg, relative_range)) => {
|
||||||
// Only report error if we would not have ignored this link. See issue #83859.
|
// Only report error if we would not have ignored this link. See issue #83859.
|
||||||
if !should_ignore_link_with_disambiguators(link) {
|
if !should_ignore_link_with_disambiguators(link) {
|
||||||
let no_backticks_range = range_between_backticks(ori_link);
|
let disambiguator_range = match range_between_backticks(&ori_link.range, dox) {
|
||||||
let disambiguator_range = (no_backticks_range.start + relative_range.start)
|
MarkdownLinkRange::Destination(no_backticks_range) => {
|
||||||
..(no_backticks_range.start + relative_range.end);
|
MarkdownLinkRange::Destination(
|
||||||
|
(no_backticks_range.start + relative_range.start)
|
||||||
|
..(no_backticks_range.start + relative_range.end),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
mdlr @ MarkdownLinkRange::WholeLink(_) => mdlr,
|
||||||
|
};
|
||||||
return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg)));
|
return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg)));
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
@ -947,7 +954,7 @@ fn preprocess_link(
|
|||||||
|
|
||||||
fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> {
|
fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> {
|
||||||
markdown_links(s, |link| {
|
markdown_links(s, |link| {
|
||||||
preprocess_link(&link).map(|pp_link| PreprocessedMarkdownLink(pp_link, link))
|
preprocess_link(&link, s).map(|pp_link| PreprocessedMarkdownLink(pp_link, link))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1060,22 +1067,12 @@ fn resolve_link(
|
|||||||
// valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677
|
// valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677
|
||||||
// for discussion on the matter.
|
// for discussion on the matter.
|
||||||
let kind = self.cx.tcx.def_kind(id);
|
let kind = self.cx.tcx.def_kind(id);
|
||||||
self.verify_disambiguator(
|
self.verify_disambiguator(path_str, kind, id, disambiguator, item, &diag_info)?;
|
||||||
path_str,
|
|
||||||
ori_link,
|
|
||||||
kind,
|
|
||||||
id,
|
|
||||||
disambiguator,
|
|
||||||
item,
|
|
||||||
&diag_info,
|
|
||||||
)?;
|
|
||||||
} else {
|
} else {
|
||||||
match disambiguator {
|
match disambiguator {
|
||||||
Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {}
|
Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {}
|
||||||
Some(other) => {
|
Some(other) => {
|
||||||
self.report_disambiguator_mismatch(
|
self.report_disambiguator_mismatch(path_str, other, res, &diag_info);
|
||||||
path_str, ori_link, other, res, &diag_info,
|
|
||||||
);
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1096,7 +1093,6 @@ fn resolve_link(
|
|||||||
};
|
};
|
||||||
self.verify_disambiguator(
|
self.verify_disambiguator(
|
||||||
path_str,
|
path_str,
|
||||||
ori_link,
|
|
||||||
kind_for_dis,
|
kind_for_dis,
|
||||||
id_for_dis,
|
id_for_dis,
|
||||||
disambiguator,
|
disambiguator,
|
||||||
@ -1118,7 +1114,6 @@ fn resolve_link(
|
|||||||
fn verify_disambiguator(
|
fn verify_disambiguator(
|
||||||
&self,
|
&self,
|
||||||
path_str: &str,
|
path_str: &str,
|
||||||
ori_link: &MarkdownLink,
|
|
||||||
kind: DefKind,
|
kind: DefKind,
|
||||||
id: DefId,
|
id: DefId,
|
||||||
disambiguator: Option<Disambiguator>,
|
disambiguator: Option<Disambiguator>,
|
||||||
@ -1142,7 +1137,7 @@ fn verify_disambiguator(
|
|||||||
=> {}
|
=> {}
|
||||||
(actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
|
(actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
|
||||||
(_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
|
(_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
|
||||||
self.report_disambiguator_mismatch(path_str,ori_link,specified, Res::Def(kind, id),diag_info);
|
self.report_disambiguator_mismatch(path_str, specified, Res::Def(kind, id), diag_info);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1164,14 +1159,13 @@ fn verify_disambiguator(
|
|||||||
fn report_disambiguator_mismatch(
|
fn report_disambiguator_mismatch(
|
||||||
&self,
|
&self,
|
||||||
path_str: &str,
|
path_str: &str,
|
||||||
ori_link: &MarkdownLink,
|
|
||||||
specified: Disambiguator,
|
specified: Disambiguator,
|
||||||
resolved: Res,
|
resolved: Res,
|
||||||
diag_info: &DiagnosticInfo<'_>,
|
diag_info: &DiagnosticInfo<'_>,
|
||||||
) {
|
) {
|
||||||
// The resolved item did not match the disambiguator; give a better error than 'not found'
|
// The resolved item did not match the disambiguator; give a better error than 'not found'
|
||||||
let msg = format!("incompatible link kind for `{}`", path_str);
|
let msg = format!("incompatible link kind for `{}`", path_str);
|
||||||
let callback = |diag: &mut Diagnostic, sp: Option<rustc_span::Span>| {
|
let callback = |diag: &mut Diagnostic, sp: Option<rustc_span::Span>, link_range| {
|
||||||
let note = format!(
|
let note = format!(
|
||||||
"this link resolved to {} {}, which is not {} {}",
|
"this link resolved to {} {}, which is not {} {}",
|
||||||
resolved.article(),
|
resolved.article(),
|
||||||
@ -1184,13 +1178,23 @@ fn report_disambiguator_mismatch(
|
|||||||
} else {
|
} else {
|
||||||
diag.note(note);
|
diag.note(note);
|
||||||
}
|
}
|
||||||
suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp);
|
suggest_disambiguator(resolved, diag, path_str, link_range, sp, diag_info);
|
||||||
};
|
};
|
||||||
report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, callback);
|
report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &Range<usize>, item: &Item) {
|
fn report_rawptr_assoc_feature_gate(
|
||||||
let span = super::source_span_for_markdown_range(self.cx.tcx, dox, ori_link, &item.attrs)
|
&self,
|
||||||
|
dox: &str,
|
||||||
|
ori_link: &MarkdownLinkRange,
|
||||||
|
item: &Item,
|
||||||
|
) {
|
||||||
|
let span = super::source_span_for_markdown_range(
|
||||||
|
self.cx.tcx,
|
||||||
|
dox,
|
||||||
|
ori_link.inner_range(),
|
||||||
|
&item.attrs,
|
||||||
|
)
|
||||||
.unwrap_or_else(|| item.attr_span(self.cx.tcx));
|
.unwrap_or_else(|| item.attr_span(self.cx.tcx));
|
||||||
rustc_session::parse::feature_err(
|
rustc_session::parse::feature_err(
|
||||||
&self.cx.tcx.sess.parse_sess,
|
&self.cx.tcx.sess.parse_sess,
|
||||||
@ -1371,16 +1375,23 @@ fn resolve_with_disambiguator(
|
|||||||
/// [`Foo`]
|
/// [`Foo`]
|
||||||
/// ^^^
|
/// ^^^
|
||||||
/// ```
|
/// ```
|
||||||
fn range_between_backticks(ori_link: &MarkdownLink) -> Range<usize> {
|
///
|
||||||
let after_first_backtick_group = ori_link.link.bytes().position(|b| b != b'`').unwrap_or(0);
|
/// This function does nothing if `ori_link.range` is a `MarkdownLinkRange::WholeLink`.
|
||||||
let before_second_backtick_group = ori_link
|
fn range_between_backticks(ori_link_range: &MarkdownLinkRange, dox: &str) -> MarkdownLinkRange {
|
||||||
.link
|
let range = match ori_link_range {
|
||||||
|
mdlr @ MarkdownLinkRange::WholeLink(_) => return mdlr.clone(),
|
||||||
|
MarkdownLinkRange::Destination(inner) => inner.clone(),
|
||||||
|
};
|
||||||
|
let ori_link_text = &dox[range.clone()];
|
||||||
|
let after_first_backtick_group = ori_link_text.bytes().position(|b| b != b'`').unwrap_or(0);
|
||||||
|
let before_second_backtick_group = ori_link_text
|
||||||
.bytes()
|
.bytes()
|
||||||
.skip(after_first_backtick_group)
|
.skip(after_first_backtick_group)
|
||||||
.position(|b| b == b'`')
|
.position(|b| b == b'`')
|
||||||
.unwrap_or(ori_link.link.len());
|
.unwrap_or(ori_link_text.len());
|
||||||
(ori_link.range.start + after_first_backtick_group)
|
MarkdownLinkRange::Destination(
|
||||||
..(ori_link.range.start + before_second_backtick_group)
|
(range.start + after_first_backtick_group)..(range.start + before_second_backtick_group),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if we should ignore `link` due to it being unlikely
|
/// Returns true if we should ignore `link` due to it being unlikely
|
||||||
@ -1530,14 +1541,23 @@ fn as_help_span(
|
|||||||
sp: rustc_span::Span,
|
sp: rustc_span::Span,
|
||||||
) -> Vec<(rustc_span::Span, String)> {
|
) -> Vec<(rustc_span::Span, String)> {
|
||||||
let inner_sp = match ori_link.find('(') {
|
let inner_sp = match ori_link.find('(') {
|
||||||
|
Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => {
|
||||||
|
sp.with_hi(sp.lo() + BytePos((index - 1) as _))
|
||||||
|
}
|
||||||
Some(index) => sp.with_hi(sp.lo() + BytePos(index as _)),
|
Some(index) => sp.with_hi(sp.lo() + BytePos(index as _)),
|
||||||
None => sp,
|
None => sp,
|
||||||
};
|
};
|
||||||
let inner_sp = match ori_link.find('!') {
|
let inner_sp = match ori_link.find('!') {
|
||||||
|
Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => {
|
||||||
|
sp.with_hi(sp.lo() + BytePos((index - 1) as _))
|
||||||
|
}
|
||||||
Some(index) => inner_sp.with_hi(inner_sp.lo() + BytePos(index as _)),
|
Some(index) => inner_sp.with_hi(inner_sp.lo() + BytePos(index as _)),
|
||||||
None => inner_sp,
|
None => inner_sp,
|
||||||
};
|
};
|
||||||
let inner_sp = match ori_link.find('@') {
|
let inner_sp = match ori_link.find('@') {
|
||||||
|
Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => {
|
||||||
|
sp.with_hi(sp.lo() + BytePos((index - 1) as _))
|
||||||
|
}
|
||||||
Some(index) => inner_sp.with_lo(inner_sp.lo() + BytePos(index as u32 + 1)),
|
Some(index) => inner_sp.with_lo(inner_sp.lo() + BytePos(index as u32 + 1)),
|
||||||
None => inner_sp,
|
None => inner_sp,
|
||||||
};
|
};
|
||||||
@ -1584,7 +1604,7 @@ fn report_diagnostic(
|
|||||||
lint: &'static Lint,
|
lint: &'static Lint,
|
||||||
msg: impl Into<DiagnosticMessage> + Display,
|
msg: impl Into<DiagnosticMessage> + Display,
|
||||||
DiagnosticInfo { item, ori_link: _, dox, link_range }: &DiagnosticInfo<'_>,
|
DiagnosticInfo { item, ori_link: _, dox, link_range }: &DiagnosticInfo<'_>,
|
||||||
decorate: impl FnOnce(&mut Diagnostic, Option<rustc_span::Span>),
|
decorate: impl FnOnce(&mut Diagnostic, Option<rustc_span::Span>, MarkdownLinkRange),
|
||||||
) {
|
) {
|
||||||
let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id)
|
let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id)
|
||||||
else {
|
else {
|
||||||
@ -1596,16 +1616,32 @@ fn report_diagnostic(
|
|||||||
let sp = item.attr_span(tcx);
|
let sp = item.attr_span(tcx);
|
||||||
|
|
||||||
tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |lint| {
|
tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |lint| {
|
||||||
let span =
|
let (span, link_range) = match link_range {
|
||||||
super::source_span_for_markdown_range(tcx, dox, link_range, &item.attrs).map(|sp| {
|
MarkdownLinkRange::Destination(md_range) => {
|
||||||
if dox.as_bytes().get(link_range.start) == Some(&b'`')
|
let mut md_range = md_range.clone();
|
||||||
&& dox.as_bytes().get(link_range.end - 1) == Some(&b'`')
|
let sp = super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs)
|
||||||
|
.map(|mut sp| {
|
||||||
|
while dox.as_bytes().get(md_range.start) == Some(&b' ')
|
||||||
|
|| dox.as_bytes().get(md_range.start) == Some(&b'`')
|
||||||
{
|
{
|
||||||
sp.with_lo(sp.lo() + BytePos(1)).with_hi(sp.hi() - BytePos(1))
|
md_range.start += 1;
|
||||||
} else {
|
sp = sp.with_lo(sp.lo() + BytePos(1));
|
||||||
sp
|
|
||||||
}
|
}
|
||||||
|
while dox.as_bytes().get(md_range.end - 1) == Some(&b' ')
|
||||||
|
|| dox.as_bytes().get(md_range.end - 1) == Some(&b'`')
|
||||||
|
{
|
||||||
|
md_range.end -= 1;
|
||||||
|
sp = sp.with_hi(sp.hi() - BytePos(1));
|
||||||
|
}
|
||||||
|
sp
|
||||||
});
|
});
|
||||||
|
(sp, MarkdownLinkRange::Destination(md_range))
|
||||||
|
}
|
||||||
|
MarkdownLinkRange::WholeLink(md_range) => (
|
||||||
|
super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs),
|
||||||
|
link_range.clone(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(sp) = span {
|
if let Some(sp) = span {
|
||||||
lint.set_span(sp);
|
lint.set_span(sp);
|
||||||
@ -1614,21 +1650,22 @@ fn report_diagnostic(
|
|||||||
// ^ ~~~~
|
// ^ ~~~~
|
||||||
// | link_range
|
// | link_range
|
||||||
// last_new_line_offset
|
// last_new_line_offset
|
||||||
let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
|
let md_range = link_range.inner_range().clone();
|
||||||
|
let last_new_line_offset = dox[..md_range.start].rfind('\n').map_or(0, |n| n + 1);
|
||||||
let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
|
let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
|
||||||
|
|
||||||
// Print the line containing the `link_range` and manually mark it with '^'s.
|
// Print the line containing the `md_range` and manually mark it with '^'s.
|
||||||
lint.note(format!(
|
lint.note(format!(
|
||||||
"the link appears in this line:\n\n{line}\n\
|
"the link appears in this line:\n\n{line}\n\
|
||||||
{indicator: <before$}{indicator:^<found$}",
|
{indicator: <before$}{indicator:^<found$}",
|
||||||
line = line,
|
line = line,
|
||||||
indicator = "",
|
indicator = "",
|
||||||
before = link_range.start - last_new_line_offset,
|
before = md_range.start - last_new_line_offset,
|
||||||
found = link_range.len(),
|
found = md_range.len(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
decorate(lint, span);
|
decorate(lint, span, link_range);
|
||||||
|
|
||||||
lint
|
lint
|
||||||
});
|
});
|
||||||
@ -1652,7 +1689,7 @@ fn resolution_failure(
|
|||||||
BROKEN_INTRA_DOC_LINKS,
|
BROKEN_INTRA_DOC_LINKS,
|
||||||
format!("unresolved link to `{}`", path_str),
|
format!("unresolved link to `{}`", path_str),
|
||||||
&diag_info,
|
&diag_info,
|
||||||
|diag, sp| {
|
|diag, sp, link_range| {
|
||||||
let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx),);
|
let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx),);
|
||||||
let assoc_item_not_allowed = |res: Res| {
|
let assoc_item_not_allowed = |res: Res| {
|
||||||
let name = res.name(tcx);
|
let name = res.name(tcx);
|
||||||
@ -1845,7 +1882,14 @@ fn split(path: &str) -> Option<(&str, &str)> {
|
|||||||
let note = match failure {
|
let note = match failure {
|
||||||
ResolutionFailure::NotResolved { .. } => unreachable!("handled above"),
|
ResolutionFailure::NotResolved { .. } => unreachable!("handled above"),
|
||||||
ResolutionFailure::WrongNamespace { res, expected_ns } => {
|
ResolutionFailure::WrongNamespace { res, expected_ns } => {
|
||||||
suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
|
suggest_disambiguator(
|
||||||
|
res,
|
||||||
|
diag,
|
||||||
|
path_str,
|
||||||
|
link_range.clone(),
|
||||||
|
sp,
|
||||||
|
&diag_info,
|
||||||
|
);
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"this link resolves to {}, which is not in the {} namespace",
|
"this link resolves to {}, which is not in the {} namespace",
|
||||||
@ -1882,7 +1926,7 @@ fn anchor_failure(
|
|||||||
msg: String,
|
msg: String,
|
||||||
anchor_idx: usize,
|
anchor_idx: usize,
|
||||||
) {
|
) {
|
||||||
report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, sp| {
|
report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, sp, _link_range| {
|
||||||
if let Some(mut sp) = sp {
|
if let Some(mut sp) = sp {
|
||||||
if let Some((fragment_offset, _)) =
|
if let Some((fragment_offset, _)) =
|
||||||
diag_info.ori_link.char_indices().filter(|(_, x)| *x == '#').nth(anchor_idx)
|
diag_info.ori_link.char_indices().filter(|(_, x)| *x == '#').nth(anchor_idx)
|
||||||
@ -1898,11 +1942,11 @@ fn anchor_failure(
|
|||||||
fn disambiguator_error(
|
fn disambiguator_error(
|
||||||
cx: &DocContext<'_>,
|
cx: &DocContext<'_>,
|
||||||
mut diag_info: DiagnosticInfo<'_>,
|
mut diag_info: DiagnosticInfo<'_>,
|
||||||
disambiguator_range: Range<usize>,
|
disambiguator_range: MarkdownLinkRange,
|
||||||
msg: impl Into<DiagnosticMessage> + Display,
|
msg: impl Into<DiagnosticMessage> + Display,
|
||||||
) {
|
) {
|
||||||
diag_info.link_range = disambiguator_range;
|
diag_info.link_range = disambiguator_range;
|
||||||
report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| {
|
report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp, _link_range| {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"see {}/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators",
|
"see {}/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators",
|
||||||
crate::DOC_RUST_LANG_ORG_CHANNEL
|
crate::DOC_RUST_LANG_ORG_CHANNEL
|
||||||
@ -1922,7 +1966,7 @@ fn report_malformed_generics(
|
|||||||
BROKEN_INTRA_DOC_LINKS,
|
BROKEN_INTRA_DOC_LINKS,
|
||||||
format!("unresolved link to `{}`", path_str),
|
format!("unresolved link to `{}`", path_str),
|
||||||
&diag_info,
|
&diag_info,
|
||||||
|diag, sp| {
|
|diag, sp, _link_range| {
|
||||||
let note = match err {
|
let note = match err {
|
||||||
MalformedGenerics::UnbalancedAngleBrackets => "unbalanced angle brackets",
|
MalformedGenerics::UnbalancedAngleBrackets => "unbalanced angle brackets",
|
||||||
MalformedGenerics::MissingType => "missing type for generic parameters",
|
MalformedGenerics::MissingType => "missing type for generic parameters",
|
||||||
@ -1995,7 +2039,7 @@ fn ambiguity_error(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| {
|
report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, |diag, sp, link_range| {
|
||||||
if let Some(sp) = sp {
|
if let Some(sp) = sp {
|
||||||
diag.span_label(sp, "ambiguous link");
|
diag.span_label(sp, "ambiguous link");
|
||||||
} else {
|
} else {
|
||||||
@ -2003,7 +2047,7 @@ fn ambiguity_error(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for res in kinds {
|
for res in kinds {
|
||||||
suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
|
suggest_disambiguator(res, diag, path_str, link_range.clone(), sp, diag_info);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
true
|
true
|
||||||
@ -2015,13 +2059,19 @@ fn suggest_disambiguator(
|
|||||||
res: Res,
|
res: Res,
|
||||||
diag: &mut Diagnostic,
|
diag: &mut Diagnostic,
|
||||||
path_str: &str,
|
path_str: &str,
|
||||||
ori_link: &str,
|
link_range: MarkdownLinkRange,
|
||||||
sp: Option<rustc_span::Span>,
|
sp: Option<rustc_span::Span>,
|
||||||
|
diag_info: &DiagnosticInfo<'_>,
|
||||||
) {
|
) {
|
||||||
let suggestion = res.disambiguator_suggestion();
|
let suggestion = res.disambiguator_suggestion();
|
||||||
let help = format!("to link to the {}, {}", res.descr(), suggestion.descr());
|
let help = format!("to link to the {}, {}", res.descr(), suggestion.descr());
|
||||||
|
|
||||||
if let Some(sp) = sp {
|
let ori_link = match link_range {
|
||||||
|
MarkdownLinkRange::Destination(range) => Some(&diag_info.dox[range]),
|
||||||
|
MarkdownLinkRange::WholeLink(_) => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let (Some(sp), Some(ori_link)) = (sp, ori_link) {
|
||||||
let mut spans = suggestion.as_help_span(path_str, ori_link, sp);
|
let mut spans = suggestion.as_help_span(path_str, ori_link, sp);
|
||||||
if spans.len() > 1 {
|
if spans.len() > 1 {
|
||||||
diag.multipart_suggestion(help, spans, Applicability::MaybeIncorrect);
|
diag.multipart_suggestion(help, spans, Applicability::MaybeIncorrect);
|
||||||
@ -2047,7 +2097,7 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str:
|
|||||||
let msg =
|
let msg =
|
||||||
format!("public documentation for `{}` links to private item `{}`", item_name, path_str);
|
format!("public documentation for `{}` links to private item `{}`", item_name, path_str);
|
||||||
|
|
||||||
report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| {
|
report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp, _link_range| {
|
||||||
if let Some(sp) = sp {
|
if let Some(sp) = sp {
|
||||||
diag.span_label(sp, "this item is private");
|
diag.span_label(sp, "this item is private");
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ LL | //! [`Clone ()`].
|
|||||||
help: to link to the trait, prefix with `trait@`
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
|
||||||
LL - //! [`Clone ()`].
|
LL - //! [`Clone ()`].
|
||||||
LL + //! [`trait@Clone (`].
|
LL + //! [`trait@Clone `].
|
||||||
|
|
|
|
||||||
|
|
||||||
error: incompatible link kind for `Clone`
|
error: incompatible link kind for `Clone`
|
||||||
@ -47,8 +47,9 @@ LL | //! [`Clone !`].
|
|||||||
|
|
|
|
||||||
help: to link to the derive macro, prefix with `derive@`
|
help: to link to the derive macro, prefix with `derive@`
|
||||||
|
|
|
|
||||||
LL | //! [`derive@Clone !`].
|
LL - //! [`Clone !`].
|
||||||
| +++++++
|
LL + //! [`derive@Clone `].
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
140
tests/rustdoc-ui/intra-doc/weird-syntax.rs
Normal file
140
tests/rustdoc-ui/intra-doc/weird-syntax.rs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
// Many examples are from
|
||||||
|
// https://github.com/rust-lang/rust/issues/110111#issuecomment-1517800781
|
||||||
|
#![deny(rustdoc::broken_intra_doc_links)]
|
||||||
|
|
||||||
|
//! This test case is closely linked to [raphlinus/pulldown-cmark#441], getting offsets of
|
||||||
|
//! link components. In particular, pulldown-cmark doesn't provide the offsets of the contents
|
||||||
|
//! of a link.
|
||||||
|
//!
|
||||||
|
//! To work around this, rustdoc parses parts of a link definition itself. This is basically a
|
||||||
|
//! test suite for that link syntax parser.
|
||||||
|
//!
|
||||||
|
//! [raphlinus/pulldown-cmark#441]: https://github.com/raphlinus/pulldown-cmark/issues/441
|
||||||
|
|
||||||
|
use std::clone::Clone;
|
||||||
|
|
||||||
|
// Basic version //
|
||||||
|
|
||||||
|
/// [`struct@Clone`] //~ERROR link
|
||||||
|
pub struct LinkToCloneWithBackquotes;
|
||||||
|
|
||||||
|
/// [```struct@Clone```] //~ERROR link
|
||||||
|
pub struct LinkToCloneWithMultipleBackquotes;
|
||||||
|
|
||||||
|
/// [ ` struct@Clone ` ] //~ERROR link
|
||||||
|
pub struct LinkToCloneWithSpacesAndBackquotes;
|
||||||
|
|
||||||
|
/// [ `Clone ()` ] //~ERROR link
|
||||||
|
pub struct LinkToCloneWithSpacesBackquotesAndParens;
|
||||||
|
|
||||||
|
/// [`Clone ()` ] //~ERROR link
|
||||||
|
pub struct LinkToCloneWithSpacesEndBackquotesAndParens;
|
||||||
|
|
||||||
|
/// [ `Clone ()`] //~ERROR link
|
||||||
|
pub struct LinkToCloneWithSpacesStartBackquotesAndParens;
|
||||||
|
|
||||||
|
/// [```Clone ()```] //~ERROR link
|
||||||
|
pub struct LinkToCloneWithMultipleBackquotesAndParens;
|
||||||
|
|
||||||
|
/// [```Clone \(\)```] // not URL-shaped enough
|
||||||
|
pub struct LinkToCloneWithMultipleBackquotesAndEscapedParens;
|
||||||
|
|
||||||
|
/// [ ``` Clone () ``` ] //~ERROR link
|
||||||
|
pub struct LinkToCloneWithSpacesMultipleBackquotesAndParens;
|
||||||
|
|
||||||
|
/// [ x \] ] // not URL-shaped enough
|
||||||
|
pub struct LinkWithEscapedCloseBrace;
|
||||||
|
|
||||||
|
/// [ x \[ ] // not URL-shaped enough
|
||||||
|
pub struct LinkWithEscapedOpenBrace;
|
||||||
|
|
||||||
|
/// [ x \( ] // not URL-shaped enough
|
||||||
|
pub struct LinkWithEscapedCloseParen;
|
||||||
|
|
||||||
|
/// [ x \) ] // not URL-shaped enough
|
||||||
|
pub struct LinkWithEscapedOpenParen;
|
||||||
|
|
||||||
|
/// [ Clone \(\) ] // not URL-shaped enough
|
||||||
|
pub struct LinkWithEscapedParens;
|
||||||
|
|
||||||
|
// [][] version //
|
||||||
|
|
||||||
|
/// [x][ struct@Clone] //~ERROR link
|
||||||
|
pub struct XLinkToCloneWithStartSpace;
|
||||||
|
|
||||||
|
/// [x][struct@Clone ] //~ERROR link
|
||||||
|
pub struct XLinkToCloneWithEndSpace;
|
||||||
|
|
||||||
|
/// [x][Clone\(\)] not URL-shaped enough
|
||||||
|
pub struct XLinkToCloneWithEscapedParens;
|
||||||
|
|
||||||
|
/// [x][`Clone`] not URL-shaped enough
|
||||||
|
pub struct XLinkToCloneWithBackquotes;
|
||||||
|
|
||||||
|
/// [x][Clone()] //~ERROR link
|
||||||
|
pub struct XLinkToCloneWithUnescapedParens;
|
||||||
|
|
||||||
|
/// [x][Clone ()] //~ERROR link
|
||||||
|
pub struct XLinkToCloneWithUnescapedParensAndDoubleSpace;
|
||||||
|
|
||||||
|
/// [x][Clone [] //~ERROR unresolved link to `x`
|
||||||
|
pub struct XLinkToCloneWithUnmatchedOpenParenAndDoubleSpace;
|
||||||
|
|
||||||
|
/// [x][Clone \[] // not URL-shaped enough
|
||||||
|
pub struct XLinkToCloneWithUnmatchedEscapedOpenParenAndDoubleSpace;
|
||||||
|
|
||||||
|
/// [x][Clone \]] // not URL-shaped enough
|
||||||
|
pub struct XLinkToCloneWithUnmatchedEscapedCloseParenAndDoubleSpace;
|
||||||
|
|
||||||
|
// []() version //
|
||||||
|
|
||||||
|
/// [w]( struct@Clone) //~ERROR link
|
||||||
|
pub struct WLinkToCloneWithStartSpace;
|
||||||
|
|
||||||
|
/// [w](struct@Clone ) //~ERROR link
|
||||||
|
pub struct WLinkToCloneWithEndSpace;
|
||||||
|
|
||||||
|
/// [w](Clone\(\)) //~ERROR link
|
||||||
|
pub struct WLinkToCloneWithEscapedParens;
|
||||||
|
|
||||||
|
/// [w](`Clone`) not URL-shaped enough
|
||||||
|
pub struct WLinkToCloneWithBackquotes;
|
||||||
|
|
||||||
|
/// [w](Clone()) //~ERROR link
|
||||||
|
pub struct WLinkToCloneWithUnescapedParens;
|
||||||
|
|
||||||
|
/// [w](Clone ()) not URL-shaped enough
|
||||||
|
pub struct WLinkToCloneWithUnescapedParensAndDoubleSpace;
|
||||||
|
|
||||||
|
/// [w](Clone () //~ERROR unresolved link to `w`
|
||||||
|
pub struct WLinkToCloneWithUnmatchedOpenParenAndDoubleSpace;
|
||||||
|
|
||||||
|
/// [w](Clone \() //~ERROR unresolved link to `w`
|
||||||
|
pub struct WLinkToCloneWithUnmatchedEscapedOpenParenAndDoubleSpace;
|
||||||
|
|
||||||
|
/// [w](Clone \)) //~ERROR unresolved link to `w`
|
||||||
|
pub struct WLinkToCloneWithUnmatchedEscapedCloseParenAndDoubleSpace;
|
||||||
|
|
||||||
|
// References
|
||||||
|
|
||||||
|
/// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected //~ERROR link
|
||||||
|
/// in Markdown for not being URL-shaped enough.
|
||||||
|
///
|
||||||
|
/// [cln]: Clone() //~ERROR link
|
||||||
|
pub struct LinkToCloneWithParensInReference;
|
||||||
|
|
||||||
|
/// The [cln][] link here is going to be unresolved, because `struct@Clone` gets //~ERROR link
|
||||||
|
/// rejected in Markdown for not being URL-shaped enough.
|
||||||
|
///
|
||||||
|
/// [cln]: struct@Clone //~ERROR link
|
||||||
|
pub struct LinkToCloneWithWrongPrefix;
|
||||||
|
|
||||||
|
/// The [cln][] link here will produce a plain text suggestion //~ERROR link
|
||||||
|
///
|
||||||
|
/// [cln]: Clone\(\)
|
||||||
|
pub struct LinkToCloneWithEscapedParensInReference;
|
||||||
|
|
||||||
|
/// The [cln][] link here will produce a plain text suggestion //~ERROR link
|
||||||
|
///
|
||||||
|
/// [cln]: struct\@Clone
|
||||||
|
pub struct LinkToCloneWithEscapedAtsInReference;
|
272
tests/rustdoc-ui/intra-doc/weird-syntax.stderr
Normal file
272
tests/rustdoc-ui/intra-doc/weird-syntax.stderr
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
error: incompatible link kind for `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:18:7
|
||||||
|
|
|
||||||
|
LL | /// [`struct@Clone`]
|
||||||
|
| ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/weird-syntax.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL | /// [`trait@Clone`]
|
||||||
|
| ~~~~~~
|
||||||
|
|
||||||
|
error: incompatible link kind for `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:21:9
|
||||||
|
|
|
||||||
|
LL | /// [```struct@Clone```]
|
||||||
|
| ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL | /// [```trait@Clone```]
|
||||||
|
| ~~~~~~
|
||||||
|
|
||||||
|
error: incompatible link kind for `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:24:11
|
||||||
|
|
|
||||||
|
LL | /// [ ` struct@Clone ` ]
|
||||||
|
| ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL | /// [ ` trait@Clone ` ]
|
||||||
|
| ~~~~~~
|
||||||
|
|
||||||
|
error: unresolved link to `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:27:9
|
||||||
|
|
|
||||||
|
LL | /// [ `Clone ()` ]
|
||||||
|
| ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL - /// [ `Clone ()` ]
|
||||||
|
LL + /// [ `trait@Clone ` ]
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unresolved link to `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:30:7
|
||||||
|
|
|
||||||
|
LL | /// [`Clone ()` ]
|
||||||
|
| ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL - /// [`Clone ()` ]
|
||||||
|
LL + /// [`trait@Clone ` ]
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unresolved link to `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:33:9
|
||||||
|
|
|
||||||
|
LL | /// [ `Clone ()`]
|
||||||
|
| ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL - /// [ `Clone ()`]
|
||||||
|
LL + /// [ `trait@Clone `]
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unresolved link to `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:36:9
|
||||||
|
|
|
||||||
|
LL | /// [```Clone ()```]
|
||||||
|
| ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL - /// [```Clone ()```]
|
||||||
|
LL + /// [```trait@Clone ```]
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unresolved link to `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:42:13
|
||||||
|
|
|
||||||
|
LL | /// [ ``` Clone () ``` ]
|
||||||
|
| ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL - /// [ ``` Clone () ``` ]
|
||||||
|
LL + /// [ ``` trait@Clone ``` ]
|
||||||
|
|
|
||||||
|
|
||||||
|
error: incompatible link kind for `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:62:10
|
||||||
|
|
|
||||||
|
LL | /// [x][ struct@Clone]
|
||||||
|
| ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL | /// [x][ trait@Clone]
|
||||||
|
| ~~~~~~
|
||||||
|
|
||||||
|
error: incompatible link kind for `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:65:9
|
||||||
|
|
|
||||||
|
LL | /// [x][struct@Clone ]
|
||||||
|
| ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL | /// [x][trait@Clone ]
|
||||||
|
| ~~~~~~
|
||||||
|
|
||||||
|
error: unresolved link to `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:74:9
|
||||||
|
|
|
||||||
|
LL | /// [x][Clone()]
|
||||||
|
| ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL - /// [x][Clone()]
|
||||||
|
LL + /// [x][trait@Clone]
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unresolved link to `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:77:9
|
||||||
|
|
|
||||||
|
LL | /// [x][Clone ()]
|
||||||
|
| ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL - /// [x][Clone ()]
|
||||||
|
LL + /// [x][trait@Clone ]
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unresolved link to `x`
|
||||||
|
--> $DIR/weird-syntax.rs:80:6
|
||||||
|
|
|
||||||
|
LL | /// [x][Clone []
|
||||||
|
| ^ no item named `x` in scope
|
||||||
|
|
|
||||||
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
error: incompatible link kind for `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:91:10
|
||||||
|
|
|
||||||
|
LL | /// [w]( struct@Clone)
|
||||||
|
| ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL | /// [w]( trait@Clone)
|
||||||
|
| ~~~~~~
|
||||||
|
|
||||||
|
error: incompatible link kind for `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:94:9
|
||||||
|
|
|
||||||
|
LL | /// [w](struct@Clone )
|
||||||
|
| ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL | /// [w](trait@Clone )
|
||||||
|
| ~~~~~~
|
||||||
|
|
||||||
|
error: unresolved link to `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:97:9
|
||||||
|
|
|
||||||
|
LL | /// [w](Clone\(\))
|
||||||
|
| ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL - /// [w](Clone\(\))
|
||||||
|
LL + /// [w](trait@Clone)
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unresolved link to `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:103:9
|
||||||
|
|
|
||||||
|
LL | /// [w](Clone())
|
||||||
|
| ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
|
||||||
|
|
|
||||||
|
help: to link to the trait, prefix with `trait@`
|
||||||
|
|
|
||||||
|
LL - /// [w](Clone())
|
||||||
|
LL + /// [w](trait@Clone)
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unresolved link to `w`
|
||||||
|
--> $DIR/weird-syntax.rs:109:6
|
||||||
|
|
|
||||||
|
LL | /// [w](Clone ()
|
||||||
|
| ^ no item named `w` in scope
|
||||||
|
|
|
||||||
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
error: unresolved link to `w`
|
||||||
|
--> $DIR/weird-syntax.rs:112:6
|
||||||
|
|
|
||||||
|
LL | /// [w](Clone \()
|
||||||
|
| ^ no item named `w` in scope
|
||||||
|
|
|
||||||
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
error: unresolved link to `w`
|
||||||
|
--> $DIR/weird-syntax.rs:115:6
|
||||||
|
|
|
||||||
|
LL | /// [w](Clone \))
|
||||||
|
| ^ no item named `w` in scope
|
||||||
|
|
|
||||||
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
error: unresolved link to `cln`
|
||||||
|
--> $DIR/weird-syntax.rs:120:10
|
||||||
|
|
|
||||||
|
LL | /// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected
|
||||||
|
| ^^^ no item named `cln` in scope
|
||||||
|
|
|
||||||
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
error: unresolved link to `cln`
|
||||||
|
--> $DIR/weird-syntax.rs:123:6
|
||||||
|
|
|
||||||
|
LL | /// [cln]: Clone()
|
||||||
|
| ^^^ no item named `cln` in scope
|
||||||
|
|
|
||||||
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
error: unresolved link to `cln`
|
||||||
|
--> $DIR/weird-syntax.rs:126:10
|
||||||
|
|
|
||||||
|
LL | /// The [cln][] link here is going to be unresolved, because `struct@Clone` gets
|
||||||
|
| ^^^ no item named `cln` in scope
|
||||||
|
|
|
||||||
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
error: unresolved link to `cln`
|
||||||
|
--> $DIR/weird-syntax.rs:129:6
|
||||||
|
|
|
||||||
|
LL | /// [cln]: struct@Clone
|
||||||
|
| ^^^ no item named `cln` in scope
|
||||||
|
|
|
||||||
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
error: unresolved link to `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:132:9
|
||||||
|
|
|
||||||
|
LL | /// The [cln][] link here will produce a plain text suggestion
|
||||||
|
| ^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
|
||||||
|
|
|
||||||
|
= help: to link to the trait, prefix with `trait@`: trait@Clone
|
||||||
|
|
||||||
|
error: incompatible link kind for `Clone`
|
||||||
|
--> $DIR/weird-syntax.rs:137:9
|
||||||
|
|
|
||||||
|
LL | /// The [cln][] link here will produce a plain text suggestion
|
||||||
|
| ^^^^^ this link resolved to a trait, which is not a struct
|
||||||
|
|
|
||||||
|
= help: to link to the trait, prefix with `trait@`: trait@Clone
|
||||||
|
|
||||||
|
error: aborting due to 26 previous errors
|
||||||
|
|
Loading…
Reference in New Issue
Block a user