about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbenediktwerner <1benediktwerner@gmail.com>2023-02-25 17:52:25 +0100
committerBenedikt Werner <1benediktwerner@gmail.com>2023-05-30 21:22:30 +0200
commit9968f3ce55d83baf916d55920b721d737581efc7 (patch)
treea0f51c9b122caccefaeac77d5b3bf4f822937266
parent26c98689f2060ec834dbe8b8e80b24b31ffd48f2 (diff)
downloadrust-9968f3ce55d83baf916d55920b721d737581efc7.tar.gz
rust-9968f3ce55d83baf916d55920b721d737581efc7.zip
rustdoc: Fix LinkReplacer link matching
-rw-r--r--src/librustdoc/html/markdown.rs15
-rw-r--r--tests/rustdoc/intra-doc/issue-108459.rs37
-rw-r--r--tests/rustdoc/intra-doc/prim-precedence.rs2
3 files changed, 48 insertions, 6 deletions
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 9ef0b501c08..2f7ffce017b 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -382,7 +382,6 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
             Some(Event::Code(text)) => {
                 trace!("saw code {}", text);
                 if let Some(link) = self.shortcut_link {
-                    trace!("original text was {}", link.original_text);
                     // NOTE: this only replaces if the code block is the *entire* text.
                     // If only part of the link has code highlighting, the disambiguator will not be removed.
                     // e.g. [fn@`f`]
@@ -391,8 +390,11 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
                     // So we could never be sure we weren't replacing too much:
                     // [fn@my_`f`unc] is treated the same as [my_func()] in that pass.
                     //
-                    // NOTE: &[1..len() - 1] is to strip the backticks
-                    if **text == link.original_text[1..link.original_text.len() - 1] {
+                    // NOTE: .get(1..len() - 1) is to strip the backticks
+                    if let Some(link) = self.links.iter().find(|l| {
+                        l.href == link.href
+                            && Some(&**text) == l.original_text.get(1..l.original_text.len() - 1)
+                    }) {
                         debug!("replacing {} with {}", text, link.new_text);
                         *text = CowStr::Borrowed(&link.new_text);
                     }
@@ -403,9 +405,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
             Some(Event::Text(text)) => {
                 trace!("saw text {}", text);
                 if let Some(link) = self.shortcut_link {
-                    trace!("original text was {}", link.original_text);
                     // NOTE: same limitations as `Event::Code`
-                    if **text == *link.original_text {
+                    if let Some(link) = self
+                        .links
+                        .iter()
+                        .find(|l| l.href == link.href && **text == *l.original_text)
+                    {
                         debug!("replacing {} with {}", text, link.new_text);
                         *text = CowStr::Borrowed(&link.new_text);
                     }
diff --git a/tests/rustdoc/intra-doc/issue-108459.rs b/tests/rustdoc/intra-doc/issue-108459.rs
new file mode 100644
index 00000000000..eb1c7a05e54
--- /dev/null
+++ b/tests/rustdoc/intra-doc/issue-108459.rs
@@ -0,0 +1,37 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub struct S;
+pub mod char {}
+
+// Ensure this doesn't ICE due to trying to slice off non-existent backticks from "S"
+
+/// See [S] and [`S`]
+pub struct MyStruct1;
+
+// Ensure that link texts are replaced correctly even if there are multiple links with
+// the same target but different text
+
+/// See also [crate::char] and [mod@char] and [prim@char]
+// @has issue_108459/struct.MyStruct2.html '//*[@href="char/index.html"]' 'crate::char'
+// @has - '//*[@href="char/index.html"]' 'char'
+// @has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char'
+pub struct MyStruct2;
+
+/// See also [mod@char] and [prim@char] and [crate::char]
+// @has issue_108459/struct.MyStruct3.html '//*[@href="char/index.html"]' 'crate::char'
+// @has - '//*[@href="char/index.html"]' 'char'
+// @has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char'
+pub struct MyStruct3;
+
+// Ensure that links are correct even if there are multiple links with the same text but
+// different targets
+
+/// See also [char][mod@char] and [char][prim@char]
+// @has issue_108459/struct.MyStruct4.html '//*[@href="char/index.html"]' 'char'
+// @has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char'
+pub struct MyStruct4;
+
+/// See also [char][prim@char] and [char][crate::char]
+// @has issue_108459/struct.MyStruct5.html '//*[@href="char/index.html"]' 'char'
+// @has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char'
+pub struct MyStruct5;
diff --git a/tests/rustdoc/intra-doc/prim-precedence.rs b/tests/rustdoc/intra-doc/prim-precedence.rs
index 25625b95277..c5a64e42a01 100644
--- a/tests/rustdoc/intra-doc/prim-precedence.rs
+++ b/tests/rustdoc/intra-doc/prim-precedence.rs
@@ -12,5 +12,5 @@ pub struct MyString;
 
 /// See also [crate::char] and [mod@char]
 // @has prim_precedence/struct.MyString2.html '//*[@href="char/index.html"]' 'crate::char'
-// @has - '//*[@href="char/index.html"]' 'mod@char'
+// @has - '//*[@href="char/index.html"]' 'char'
 pub struct MyString2;