diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index b39f9f878921a..c44514ed3cb83 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1162,6 +1162,7 @@ crate fn plain_text_summary(md: &str) -> String {
s
}
+#[derive(Debug)]
crate struct MarkdownLink {
pub kind: LinkType,
pub link: String,
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 499931f7e9631..55978ca551b05 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -950,6 +950,7 @@ impl LinkCollector<'_, '_> {
}
let link = ori_link.link.replace("`", "");
+ let no_backticks_range = range_between_backticks(&ori_link);
let parts = link.split('#').collect::>();
let (link, extra_fragment) = if parts.len() > 2 {
// A valid link can't have multiple #'s
@@ -973,10 +974,15 @@ impl LinkCollector<'_, '_> {
};
// Parse and strip the disambiguator from the link, if present.
- let (mut path_str, disambiguator) = if let Ok((d, path)) = Disambiguator::from_str(&link) {
- (path.trim(), Some(d))
- } else {
- (link.trim(), None)
+ let (mut path_str, disambiguator) = match Disambiguator::from_str(&link) {
+ Ok(Some((d, path))) => (path.trim(), Some(d)),
+ Ok(None) => (link.trim(), None),
+ Err((err_msg, relative_range)) => {
+ let disambiguator_range = (no_backticks_range.start + relative_range.start)
+ ..(no_backticks_range.start + relative_range.end);
+ disambiguator_error(self.cx, &item, dox, disambiguator_range, &err_msg);
+ return None;
+ }
};
if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !*&;".contains(ch))) {
@@ -1488,6 +1494,27 @@ impl LinkCollector<'_, '_> {
}
}
+/// Get the section of a link between the backticks,
+/// or the whole link if there aren't any backticks.
+///
+/// For example:
+///
+/// ```text
+/// [`Foo`]
+/// ^^^
+/// ```
+fn range_between_backticks(ori_link: &MarkdownLink) -> Range {
+ let after_first_backtick_group = ori_link.link.bytes().position(|b| b != b'`').unwrap_or(0);
+ let before_second_backtick_group = ori_link
+ .link
+ .bytes()
+ .skip(after_first_backtick_group)
+ .position(|b| b == b'`')
+ .unwrap_or(ori_link.link.len());
+ (ori_link.range.start + after_first_backtick_group)
+ ..(ori_link.range.start + before_second_backtick_group)
+}
+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
/// Disambiguators for a link.
enum Disambiguator {
@@ -1514,27 +1541,14 @@ impl Disambiguator {
}
}
- /// Given a link, parse and return `(disambiguator, path_str)`
- fn from_str(link: &str) -> Result<(Self, &str), ()> {
+ /// Given a link, parse and return `(disambiguator, path_str)`.
+ ///
+ /// This returns `Ok(Some(...))` if a disambiguator was found,
+ /// `Ok(None)` if no disambiguator was found, or `Err(...)`
+ /// if there was a problem with the disambiguator.
+ fn from_str(link: &str) -> Result