From 8ae65860e2db8a11d3fdc7e33bc8e6c4e0cb527c Mon Sep 17 00:00:00 2001
From: binarycat <binarycat@envs.net>
Date: Thu, 7 Nov 2024 15:33:45 -0600
Subject: [PATCH] get rid of some false negatives in
 rustdoc::broken_intra_doc_links

rustdoc will not try to do intra-doc linking if the "path"
of a link looks too much like a "real url".

however, only inline links ([text](url)) can actually contain
a url, other types of links (reference links, shortcut links)
contain a *reference* which is later resolved to an actual url.

the "path" in this case cannot be a url, and therefore it should
not be skipped due to looking like a url.

fixes https://github.com/rust-lang/rust/issues/54191
---
 .../passes/collect_intra_doc_links.rs         | 13 +++++--
 tests/rustdoc-ui/bad-intra-doc.rs             | 13 +++++++
 tests/rustdoc-ui/bad-intra-doc.stderr         | 39 +++++++++++++++++++
 3 files changed, 61 insertions(+), 4 deletions(-)
 create mode 100644 tests/rustdoc-ui/bad-intra-doc.rs
 create mode 100644 tests/rustdoc-ui/bad-intra-doc.stderr

diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 140fda7091885..0989b94e900fd 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -930,13 +930,18 @@ fn preprocess_link(
     ori_link: &MarkdownLink,
     dox: &str,
 ) -> Option<Result<PreprocessingInfo, PreprocessingError>> {
+    // certain link kinds cannot have their path be urls,
+    // so they should not be ignored, no matter how much they look like urls.
+    // e.g. [https://example.com/] is not a link to example.com.
+    let can_be_url = ori_link.kind == LinkType::Inline || ori_link.kind == LinkType::Autolink;
+
     // [] is mostly likely not supposed to be a link
     if ori_link.link.is_empty() {
         return None;
     }
 
     // Bail early for real links.
-    if ori_link.link.contains('/') {
+    if can_be_url && ori_link.link.contains('/') {
         return None;
     }
 
@@ -961,7 +966,7 @@ fn preprocess_link(
         Ok(None) => (None, link, link),
         Err((err_msg, relative_range)) => {
             // Only report error if we would not have ignored this link. See issue #83859.
-            if !should_ignore_link_with_disambiguators(link) {
+            if can_be_url && !should_ignore_link_with_disambiguators(link) {
                 let disambiguator_range = match range_between_backticks(&ori_link.range, dox) {
                     MarkdownLinkRange::Destination(no_backticks_range) => {
                         MarkdownLinkRange::Destination(
@@ -978,7 +983,7 @@ fn preprocess_link(
         }
     };
 
-    if should_ignore_link(path_str) {
+    if can_be_url && should_ignore_link(path_str) {
         return None;
     }
 
@@ -995,7 +1000,7 @@ fn preprocess_link(
     assert!(!path_str.contains(['<', '>'].as_slice()));
 
     // The link is not an intra-doc link if it still contains spaces after stripping generics.
-    if path_str.contains(' ') {
+    if can_be_url && path_str.contains(' ') {
         return None;
     }
 
diff --git a/tests/rustdoc-ui/bad-intra-doc.rs b/tests/rustdoc-ui/bad-intra-doc.rs
new file mode 100644
index 0000000000000..4801744606770
--- /dev/null
+++ b/tests/rustdoc-ui/bad-intra-doc.rs
@@ -0,0 +1,13 @@
+#![no_std]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// regression test for https://github.com/rust-lang/rust/issues/54191
+
+/// this is not a link to [`example.com`]
+///
+/// this link [`has spaces in it`].
+///
+/// attempted link to method: [`Foo.bar()`]
+///
+/// classic broken intra-doc link: [`Bar`]
+pub struct Foo;
diff --git a/tests/rustdoc-ui/bad-intra-doc.stderr b/tests/rustdoc-ui/bad-intra-doc.stderr
new file mode 100644
index 0000000000000..a9c6fb3af9338
--- /dev/null
+++ b/tests/rustdoc-ui/bad-intra-doc.stderr
@@ -0,0 +1,39 @@
+error: unresolved link to `example.com`
+  --> $DIR/bad-intra-doc.rs:6:29
+   |
+LL | /// this is not a link to [`example.com`]
+   |                             ^^^^^^^^^^^ no item named `example.com` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+note: the lint level is defined here
+  --> $DIR/bad-intra-doc.rs:2:9
+   |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unresolved link to `has spaces in it`
+  --> $DIR/bad-intra-doc.rs:8:17
+   |
+LL | /// this link [`has spaces in it`].
+   |                 ^^^^^^^^^^^^^^^^ no item named `has spaces in it` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Foo.bar`
+  --> $DIR/bad-intra-doc.rs:10:33
+   |
+LL | /// attempted link to method: [`Foo.bar()`]
+   |                                 ^^^^^^^^^ no item named `Foo.bar` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Bar`
+  --> $DIR/bad-intra-doc.rs:12:38
+   |
+LL | /// classic broken intra-doc link: [`Bar`]
+   |                                      ^^^ no item named `Bar` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: aborting due to 4 previous errors
+