about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2020-10-14 15:11:55 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2020-11-05 10:22:08 +0100
commit7f839b2ece86b3b5db89673fc402348c71db42f4 (patch)
tree393aafabaccc58958994077c874a23f901aa1d94
parentf467b8d77c7b991ce214e0e5ff9b13c01812c8a7 (diff)
downloadrust-7f839b2ece86b3b5db89673fc402348c71db42f4.tar.gz
rust-7f839b2ece86b3b5db89673fc402348c71db42f4.zip
Improve automatic_links globally
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs10
-rw-r--r--src/doc/rustdoc/src/lints.md13
-rw-r--r--src/librustdoc/passes/automatic_links.rs37
-rw-r--r--src/test/rustdoc-ui/automatic-links.rs40
-rw-r--r--src/test/rustdoc-ui/automatic-links.stderr100
5 files changed, 163 insertions, 37 deletions
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 1294dd9d685..b6e6307a40f 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1891,14 +1891,14 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `automatic_links` lint detects when a URL/email address could be
-    /// written using only angle brackets. This is a `rustdoc` only lint, see
-    /// the documentation in the [rustdoc book].
+    /// The `automatic_links` lint detects when a URL could be written using
+    /// only angle brackets. This is a `rustdoc` only lint, see the
+    /// documentation in the [rustdoc book].
     ///
     /// [rustdoc book]: ../../../rustdoc/lints.html#automatic_links
     pub AUTOMATIC_LINKS,
-    Allow,
-    "detects URLs/email adresses that could be written using only angle brackets"
+    Warn,
+    "detects URLs that could be written using only angle brackets"
 }
 
 declare_lint! {
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index a85aa882af8..68ea828bfc1 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -288,12 +288,10 @@ warning: 2 warnings emitted
 
 ## automatic_links
 
-This link is **allowed by default** and is **nightly-only**. It detects links
-which could use the "automatic" link syntax. For example:
+This lint is **nightly-only** and **warns by default**. It detects links which
+could use the "automatic" link syntax. For example:
 
 ```rust
-#![warn(automatic_links)]
-
 /// http://hello.rs
 /// [http://a.com](http://a.com)
 /// [http://b.com]
@@ -305,17 +303,12 @@ pub fn foo() {}
 Which will give:
 
 ```text
-warning: won't be a link as is
+warning: this URL is not a hyperlink
  --> foo.rs:3:5
   |
 3 | /// http://hello.rs
   |     ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://hello.rs>`
   |
-note: the lint level is defined here
- --> foo.rs:1:9
-  |
-1 | #![warn(automatic_links)]
-  |         ^^^^^^^^^^^^^^^
 
 warning: unneeded long form for URL
  --> foo.rs:4:5
diff --git a/src/librustdoc/passes/automatic_links.rs b/src/librustdoc/passes/automatic_links.rs
index 11c1a4d0bfb..816d2fd15ee 100644
--- a/src/librustdoc/passes/automatic_links.rs
+++ b/src/librustdoc/passes/automatic_links.rs
@@ -13,11 +13,15 @@ use rustc_session::lint;
 pub const CHECK_AUTOMATIC_LINKS: Pass = Pass {
     name: "check-automatic-links",
     run: check_automatic_links,
-    description: "detects URLS/email addresses that could be written using angle brackets",
+    description: "detects URLS that could be written using angle brackets",
 };
 
-const URL_REGEX: &str =
-    r"https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)";
+const URL_REGEX: &str = concat!(
+    r"https?://",                          // url scheme
+    r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains
+    r"[a-zA-Z]{2,4}",                      // root domain
+    r"\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)"     // optional query or url fragments
+);
 
 struct AutomaticLinksLinter<'a, 'tcx> {
     cx: &'a DocContext<'tcx>,
@@ -35,22 +39,16 @@ impl<'a, 'tcx> AutomaticLinksLinter<'a, 'tcx> {
         range: Range<usize>,
         f: &impl Fn(&DocContext<'_>, &str, &str, Range<usize>),
     ) {
-        for (pos, c) in text.char_indices() {
-            // For now, we only check "full" URLs.
-            if c == 'h' {
-                let text = &text[pos..];
-                if text.starts_with("http://") || text.starts_with("https://") {
-                    if let Some(m) = self.regex.find(text) {
-                        let url = &text[..m.end()];
-                        f(
-                            self.cx,
-                            "won't be a link as is",
-                            url,
-                            Range { start: range.start + pos, end: range.start + pos + m.end() },
-                        )
-                    }
-                }
-            }
+        // For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
+        for match_ in self.regex.find_iter(&text) {
+            let url = match_.as_str();
+            let url_range = match_.range();
+            f(
+                self.cx,
+                "this URL is not a hyperlink",
+                url,
+                Range { start: range.start + url_range.start, end: range.start + url_range.end },
+            );
         }
     }
 }
@@ -106,6 +104,7 @@ impl<'a, 'tcx> DocFolder for AutomaticLinksLinter<'a, 'tcx> {
                     }
                     Event::End(Tag::Link(_, url, _)) => {
                         in_link = false;
+                        // NOTE: links cannot be nested, so we don't need to check `kind`
                         if url.as_ref() == title && !ignore {
                             report_diag(self.cx, "unneeded long form for URL", &url, range);
                         }
diff --git a/src/test/rustdoc-ui/automatic-links.rs b/src/test/rustdoc-ui/automatic-links.rs
index f9dbe67e5b1..27eb4e4a646 100644
--- a/src/test/rustdoc-ui/automatic-links.rs
+++ b/src/test/rustdoc-ui/automatic-links.rs
@@ -10,8 +10,40 @@
 /// [http://c.com][http://c.com]
 pub fn a() {}
 
+/// https://somewhere.com
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a
+//~^ ERROR this URL is not a hyperlink
+/// https://www.somewhere.com
+//~^ ERROR this URL is not a hyperlink
+/// https://www.somewhere.com/a
+//~^ ERROR this URL is not a hyperlink
+/// https://subdomain.example.com
+//~^ ERROR not a hyperlink
+/// https://somewhere.com?
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?
+//~^ ERROR this URL is not a hyperlink
 /// https://somewhere.com?hello=12
-//~^ ERROR won't be a link as is
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?hello=12
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com?hello=12#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com/a?hello=12#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com/a#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12&bye=11
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?hello=12&bye=11
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12&bye=11#xyz
+//~^ ERROR this URL is not a hyperlink
+/// hey! https://somewhere.com/a?hello=12&bye=11#xyz
+//~^ ERROR this URL is not a hyperlink
 pub fn c() {}
 
 /// <https://somewhere.com>
@@ -20,3 +52,9 @@ pub fn c() {}
 ///
 /// [b]: http://b.com
 pub fn everything_is_fine_here() {}
+
+#[allow(automatic_links)]
+pub mod foo {
+    /// https://somewhere.com/a?hello=12&bye=11#xyz
+    pub fn bar() {}
+}
diff --git a/src/test/rustdoc-ui/automatic-links.stderr b/src/test/rustdoc-ui/automatic-links.stderr
index d2c0c51d7a4..00e210aaaa2 100644
--- a/src/test/rustdoc-ui/automatic-links.stderr
+++ b/src/test/rustdoc-ui/automatic-links.stderr
@@ -16,11 +16,107 @@ error: unneeded long form for URL
 LL | /// [http://b.com]
    |     ^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://b.com>`
 
-error: won't be a link as is
+error: this URL is not a hyperlink
   --> $DIR/automatic-links.rs:13:5
    |
+LL | /// https://somewhere.com
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:15:5
+   |
+LL | /// https://somewhere.com/a
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:17:5
+   |
+LL | /// https://www.somewhere.com
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:19:5
+   |
+LL | /// https://www.somewhere.com/a
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com/a>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:21:5
+   |
+LL | /// https://subdomain.example.com
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://subdomain.example.com>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:23:5
+   |
+LL | /// https://somewhere.com?
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:25:5
+   |
+LL | /// https://somewhere.com/a?
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:27:5
+   |
 LL | /// https://somewhere.com?hello=12
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>`
 
-error: aborting due to 3 previous errors
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:29:5
+   |
+LL | /// https://somewhere.com/a?hello=12
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:31:5
+   |
+LL | /// https://example.com?hello=12#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com?hello=12#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:33:5
+   |
+LL | /// https://example.com/a?hello=12#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a?hello=12#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:35:5
+   |
+LL | /// https://example.com#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:37:5
+   |
+LL | /// https://example.com/a#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:39:5
+   |
+LL | /// https://somewhere.com?hello=12&bye=11
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:41:5
+   |
+LL | /// https://somewhere.com/a?hello=12&bye=11
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:43:5
+   |
+LL | /// https://somewhere.com?hello=12&bye=11#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/automatic-links.rs:45:10
+   |
+LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11#xyz>`
+
+error: aborting due to 19 previous errors