From 29803670304bfad1c46502dfb71af6dd12953b5d Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Mon, 12 Oct 2020 18:28:57 +0200
Subject: [PATCH 01/13] Add new lint for automatic_links improvements

---
 compiler/rustc_lint/src/lib.rs           |  3 +-
 compiler/rustc_lint_defs/src/builtin.rs  | 12 +++
 src/librustdoc/core.rs                   |  2 +
 src/librustdoc/passes/automatic_links.rs | 93 ++++++++++++++++++++++++
 src/librustdoc/passes/mod.rs             |  5 ++
 5 files changed, 114 insertions(+), 1 deletion(-)
 create mode 100644 src/librustdoc/passes/automatic_links.rs

diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 7297a6de42046..0da3ece167e97 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -67,7 +67,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::{
-    BARE_TRAIT_OBJECTS, BROKEN_INTRA_DOC_LINKS, ELIDED_LIFETIMES_IN_PATHS,
+    AUTOMATIC_LINKS, BARE_TRAIT_OBJECTS, BROKEN_INTRA_DOC_LINKS, ELIDED_LIFETIMES_IN_PATHS,
     EXPLICIT_OUTLIVES_REQUIREMENTS, INVALID_CODEBLOCK_ATTRIBUTES, INVALID_HTML_TAGS,
     MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
 };
@@ -313,6 +313,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
 
     add_lint_group!(
         "rustdoc",
+        AUTOMATIC_LINKS,
         BROKEN_INTRA_DOC_LINKS,
         PRIVATE_INTRA_DOC_LINKS,
         INVALID_CODEBLOCK_ATTRIBUTES,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a1b7c13e4c0f0..3fc9c096696ba 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1890,6 +1890,17 @@ declare_lint! {
     "detects invalid HTML tags in doc comments"
 }
 
+declare_lint! {
+    /// The `automatic_links` lint detects when a URL/email address could be
+    /// written using only 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 brackets"
+}
+
 declare_lint! {
     /// The `where_clauses_object_safety` lint detects for [object safety] of
     /// [where clauses].
@@ -2795,6 +2806,7 @@ declare_lint_pass! {
         MISSING_DOC_CODE_EXAMPLES,
         INVALID_HTML_TAGS,
         PRIVATE_DOC_TESTS,
+        AUTOMATIC_LINKS,
         WHERE_CLAUSES_OBJECT_SAFETY,
         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
         MACRO_USE_EXTERN_CRATE,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 45a84c4fb30d3..f834be84d4c59 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -330,11 +330,13 @@ pub fn run_core(
     let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
     let invalid_html_tags = rustc_lint::builtin::INVALID_HTML_TAGS.name;
     let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name;
+    let automatic_links = rustc_lint::builtin::AUTOMATIC_LINKS.name;
     let unknown_lints = rustc_lint::builtin::UNKNOWN_LINTS.name;
 
     // In addition to those specific lints, we also need to allow those given through
     // command line, otherwise they'll get ignored and we don't want that.
     let lints_to_show = vec![
+        automatic_links.to_owned(),
         intra_link_resolution_failure_name.to_owned(),
         missing_docs.to_owned(),
         missing_doc_example.to_owned(),
diff --git a/src/librustdoc/passes/automatic_links.rs b/src/librustdoc/passes/automatic_links.rs
new file mode 100644
index 0000000000000..79542241326da
--- /dev/null
+++ b/src/librustdoc/passes/automatic_links.rs
@@ -0,0 +1,93 @@
+use super::{span_of_attrs, Pass};
+use crate::clean::*;
+use crate::core::DocContext;
+use crate::fold::DocFolder;
+use crate::html::markdown::opts;
+use pulldown_cmark::{Event, Parser, Tag};
+use rustc_feature::UnstableFeatures;
+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 brackets",
+};
+
+struct AutomaticLinksLinter<'a, 'tcx> {
+    cx: &'a DocContext<'tcx>,
+}
+
+impl<'a, 'tcx> AutomaticLinksLinter<'a, 'tcx> {
+    fn new(cx: &'a DocContext<'tcx>) -> Self {
+        AutomaticLinksLinter { cx }
+    }
+}
+
+pub fn check_automatic_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
+    if !UnstableFeatures::from_environment().is_nightly_build() {
+        krate
+    } else {
+        let mut coll = AutomaticLinksLinter::new(cx);
+
+        coll.fold_crate(krate)
+    }
+}
+
+impl<'a, 'tcx> DocFolder for AutomaticLinksLinter<'a, 'tcx> {
+    fn fold_item(&mut self, item: Item) -> Option<Item> {
+        let hir_id = match self.cx.as_local_hir_id(item.def_id) {
+            Some(hir_id) => hir_id,
+            None => {
+                // If non-local, no need to check anything.
+                return self.fold_item_recur(item);
+            }
+        };
+        let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
+        if !dox.is_empty() {
+            let cx = &self.cx;
+
+            let p = Parser::new_ext(&dox, opts()).into_offset_iter();
+
+            let mut title = String::new();
+            let mut in_link = false;
+
+            for (event, range) in p {
+                match event {
+                    Event::Start(Tag::Link(..)) => in_link = true,
+                    Event::End(Tag::Link(_, url, _)) => {
+                        in_link = false;
+                        if url.as_ref() != title {
+                            continue;
+                        }
+                        let sp = match super::source_span_for_markdown_range(
+                            cx,
+                            &dox,
+                            &range,
+                            &item.attrs,
+                        ) {
+                            Some(sp) => sp,
+                            None => span_of_attrs(&item.attrs).unwrap_or(item.source.span()),
+                        };
+                        cx.tcx.struct_span_lint_hir(
+                            lint::builtin::AUTOMATIC_LINKS,
+                            hir_id,
+                            sp,
+                            |lint| {
+                                lint.build("Unneeded long form for URL")
+                                    .help(&format!("Try with `<{}>` instead", url))
+                                    .emit()
+                            },
+                        );
+                        title.clear();
+                    }
+                    Event::Text(s) if in_link => {
+                        title.push_str(&s);
+                    }
+                    _ => {}
+                }
+            }
+        }
+
+        self.fold_item_recur(item)
+    }
+}
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 2591650e3f97f..48dc52c955006 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -11,6 +11,9 @@ use crate::core::DocContext;
 mod stripper;
 pub use stripper::*;
 
+mod automatic_links;
+pub use self::automatic_links::CHECK_AUTOMATIC_LINKS;
+
 mod collapse_docs;
 pub use self::collapse_docs::COLLAPSE_DOCS;
 
@@ -90,6 +93,7 @@ pub const PASSES: &[Pass] = &[
     COLLECT_TRAIT_IMPLS,
     CALCULATE_DOC_COVERAGE,
     CHECK_INVALID_HTML_TAGS,
+    CHECK_AUTOMATIC_LINKS,
 ];
 
 /// The list of passes run by default.
@@ -105,6 +109,7 @@ pub const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
     ConditionalPass::always(CHECK_INVALID_HTML_TAGS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
+    ConditionalPass::always(CHECK_AUTOMATIC_LINKS),
 ];
 
 /// The list of default passes run when `--doc-coverage` is passed to rustdoc.

From a54f04373382b085837f5f835569d238bf6049e1 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Mon, 12 Oct 2020 18:29:38 +0200
Subject: [PATCH 02/13] Add documentation for automatic_links lint

---
 compiler/rustc_lint_defs/src/builtin.rs |  6 ++--
 src/doc/rustdoc/src/lints.md            | 40 +++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 3fc9c096696ba..1294dd9d68583 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1892,13 +1892,13 @@ declare_lint! {
 
 declare_lint! {
     /// The `automatic_links` lint detects when a URL/email address could be
-    /// written using only brackets. This is a `rustdoc` only lint, see the
-    /// documentation in the [rustdoc book].
+    /// 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 brackets"
+    "detects URLs/email adresses 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 cb9099cd50bee..2c10f6c06a93a 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -285,3 +285,43 @@ warning: unclosed HTML tag `h1`
 
 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:
+
+```rust
+#![warn(automatic_links)]
+
+/// [http://a.com](http://a.com)
+/// [http://b.com]
+///
+/// [http://b.com]: http://b.com
+pub fn foo() {}
+```
+
+Which will give:
+
+```text
+error: Unneeded long form for URL
+ --> foo.rs:3:5
+  |
+3 | /// [http://a.com](http://a.com)
+  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+note: the lint level is defined here
+ --> foo.rs:1:9
+  |
+1 | #![deny(automatic_links)]
+  |         ^^^^^^^^^^^^^^^
+  = help: Try with `<http://a.com>` instead
+
+error: Unneeded long form for URL
+ --> foo.rs:5:5
+  |
+5 | /// [http://b.com]
+  |     ^^^^^^^^^^^^^^
+  |
+  = help: Try with `<http://b.com>` instead
+```

From 6bc8965c418e90c135ee90554108bd0bdbe0a8d8 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Mon, 12 Oct 2020 18:29:56 +0200
Subject: [PATCH 03/13] Add tests for automatic_links lint

---
 src/test/rustdoc-ui/automatic-links.rs     | 17 ++++++++++++++++
 src/test/rustdoc-ui/automatic-links.stderr | 23 ++++++++++++++++++++++
 2 files changed, 40 insertions(+)
 create mode 100644 src/test/rustdoc-ui/automatic-links.rs
 create mode 100644 src/test/rustdoc-ui/automatic-links.stderr

diff --git a/src/test/rustdoc-ui/automatic-links.rs b/src/test/rustdoc-ui/automatic-links.rs
new file mode 100644
index 0000000000000..9273b854aee1d
--- /dev/null
+++ b/src/test/rustdoc-ui/automatic-links.rs
@@ -0,0 +1,17 @@
+#![deny(automatic_links)]
+
+/// [http://a.com](http://a.com)
+//~^ ERROR Unneeded long form for URL
+/// [http://b.com]
+//~^ ERROR Unneeded long form for URL
+///
+/// [http://b.com]: http://b.com
+///
+/// [http://c.com][http://c.com]
+pub fn a() {}
+
+/// [a](http://a.com)
+/// [b]
+///
+/// [b]: http://b.com
+pub fn everything_is_fine_here() {}
diff --git a/src/test/rustdoc-ui/automatic-links.stderr b/src/test/rustdoc-ui/automatic-links.stderr
new file mode 100644
index 0000000000000..2922fedb238cb
--- /dev/null
+++ b/src/test/rustdoc-ui/automatic-links.stderr
@@ -0,0 +1,23 @@
+error: Unneeded long form for URL
+  --> $DIR/automatic-links.rs:3:5
+   |
+LL | /// [http://a.com](http://a.com)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/automatic-links.rs:1:9
+   |
+LL | #![deny(automatic_links)]
+   |         ^^^^^^^^^^^^^^^
+   = help: Try with `<http://a.com>` instead
+
+error: Unneeded long form for URL
+  --> $DIR/automatic-links.rs:5:5
+   |
+LL | /// [http://b.com]
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: Try with `<http://b.com>` instead
+
+error: aborting due to 2 previous errors
+

From f467b8d77c7b991ce214e0e5ff9b13c01812c8a7 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Tue, 13 Oct 2020 15:46:34 +0200
Subject: [PATCH 04/13] Extend automatic_links lint to take into account URLs
 without link syntax

---
 Cargo.lock                                 |  1 +
 src/doc/rustdoc/src/lints.md               | 22 +++---
 src/librustdoc/Cargo.toml                  |  1 +
 src/librustdoc/passes/automatic_links.rs   | 89 +++++++++++++++-------
 src/test/rustdoc-ui/automatic-links.rs     |  9 ++-
 src/test/rustdoc-ui/automatic-links.stderr | 17 +++--
 6 files changed, 94 insertions(+), 45 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 3d40ded19dd5a..3a1dae971cc19 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4297,6 +4297,7 @@ dependencies = [
  "itertools 0.9.0",
  "minifier",
  "pulldown-cmark 0.8.0",
+ "regex",
  "rustc-rayon",
  "serde",
  "serde_json",
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index 2c10f6c06a93a..a85aa882af891 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -294,6 +294,7 @@ 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]
 ///
@@ -304,24 +305,27 @@ pub fn foo() {}
 Which will give:
 
 ```text
-error: Unneeded long form for URL
+warning: won't be a link as is
  --> foo.rs:3:5
   |
-3 | /// [http://a.com](http://a.com)
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+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 | #![deny(automatic_links)]
+1 | #![warn(automatic_links)]
   |         ^^^^^^^^^^^^^^^
-  = help: Try with `<http://a.com>` instead
 
-error: Unneeded long form for URL
+warning: unneeded long form for URL
+ --> foo.rs:4:5
+  |
+4 | /// [http://a.com](http://a.com)
+  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://a.com>`
+
+warning: unneeded long form for URL
  --> foo.rs:5:5
   |
 5 | /// [http://b.com]
-  |     ^^^^^^^^^^^^^^
-  |
-  = help: Try with `<http://b.com>` instead
+  |     ^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://b.com>`
 ```
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index a40a44fe27da3..b0f5bac6abd0f 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -16,6 +16,7 @@ serde_json = "1.0"
 smallvec = "1.0"
 tempfile = "3"
 itertools = "0.9"
+regex = "1"
 
 [dev-dependencies]
 expect-test = "1.0"
diff --git a/src/librustdoc/passes/automatic_links.rs b/src/librustdoc/passes/automatic_links.rs
index 79542241326da..11c1a4d0bfba8 100644
--- a/src/librustdoc/passes/automatic_links.rs
+++ b/src/librustdoc/passes/automatic_links.rs
@@ -3,23 +3,55 @@ use crate::clean::*;
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::html::markdown::opts;
-use pulldown_cmark::{Event, Parser, Tag};
+use core::ops::Range;
+use pulldown_cmark::{Event, LinkType, Parser, Tag};
+use regex::Regex;
+use rustc_errors::Applicability;
 use rustc_feature::UnstableFeatures;
 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 brackets",
+    description: "detects URLS/email addresses 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@:%_\+.~#?&//=]*)";
+
 struct AutomaticLinksLinter<'a, 'tcx> {
     cx: &'a DocContext<'tcx>,
+    regex: Regex,
 }
 
 impl<'a, 'tcx> AutomaticLinksLinter<'a, 'tcx> {
     fn new(cx: &'a DocContext<'tcx>) -> Self {
-        AutomaticLinksLinter { cx }
+        AutomaticLinksLinter { cx, regex: Regex::new(URL_REGEX).expect("failed to build regex") }
+    }
+
+    fn find_raw_urls(
+        &self,
+        text: &str,
+        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() },
+                        )
+                    }
+                }
+            }
+        }
     }
 }
 
@@ -44,45 +76,48 @@ impl<'a, 'tcx> DocFolder for AutomaticLinksLinter<'a, 'tcx> {
         };
         let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
         if !dox.is_empty() {
-            let cx = &self.cx;
+            let report_diag = |cx: &DocContext<'_>, msg: &str, url: &str, range: Range<usize>| {
+                let sp = super::source_span_for_markdown_range(cx, &dox, &range, &item.attrs)
+                    .or_else(|| span_of_attrs(&item.attrs))
+                    .unwrap_or(item.source.span());
+                cx.tcx.struct_span_lint_hir(lint::builtin::AUTOMATIC_LINKS, hir_id, sp, |lint| {
+                    lint.build(msg)
+                        .span_suggestion(
+                            sp,
+                            "use an automatic link instead",
+                            format!("<{}>", url),
+                            Applicability::MachineApplicable,
+                        )
+                        .emit()
+                });
+            };
 
             let p = Parser::new_ext(&dox, opts()).into_offset_iter();
 
             let mut title = String::new();
             let mut in_link = false;
+            let mut ignore = false;
 
             for (event, range) in p {
                 match event {
-                    Event::Start(Tag::Link(..)) => in_link = true,
+                    Event::Start(Tag::Link(kind, _, _)) => {
+                        in_link = true;
+                        ignore = matches!(kind, LinkType::Autolink | LinkType::Email);
+                    }
                     Event::End(Tag::Link(_, url, _)) => {
                         in_link = false;
-                        if url.as_ref() != title {
-                            continue;
+                        if url.as_ref() == title && !ignore {
+                            report_diag(self.cx, "unneeded long form for URL", &url, range);
                         }
-                        let sp = match super::source_span_for_markdown_range(
-                            cx,
-                            &dox,
-                            &range,
-                            &item.attrs,
-                        ) {
-                            Some(sp) => sp,
-                            None => span_of_attrs(&item.attrs).unwrap_or(item.source.span()),
-                        };
-                        cx.tcx.struct_span_lint_hir(
-                            lint::builtin::AUTOMATIC_LINKS,
-                            hir_id,
-                            sp,
-                            |lint| {
-                                lint.build("Unneeded long form for URL")
-                                    .help(&format!("Try with `<{}>` instead", url))
-                                    .emit()
-                            },
-                        );
                         title.clear();
+                        ignore = false;
                     }
                     Event::Text(s) if in_link => {
-                        title.push_str(&s);
+                        if !ignore {
+                            title.push_str(&s);
+                        }
                     }
+                    Event::Text(s) => self.find_raw_urls(&s, range, &report_diag),
                     _ => {}
                 }
             }
diff --git a/src/test/rustdoc-ui/automatic-links.rs b/src/test/rustdoc-ui/automatic-links.rs
index 9273b854aee1d..f9dbe67e5b1da 100644
--- a/src/test/rustdoc-ui/automatic-links.rs
+++ b/src/test/rustdoc-ui/automatic-links.rs
@@ -1,15 +1,20 @@
 #![deny(automatic_links)]
 
 /// [http://a.com](http://a.com)
-//~^ ERROR Unneeded long form for URL
+//~^ ERROR unneeded long form for URL
 /// [http://b.com]
-//~^ ERROR Unneeded long form for URL
+//~^ ERROR unneeded long form for URL
 ///
 /// [http://b.com]: http://b.com
 ///
 /// [http://c.com][http://c.com]
 pub fn a() {}
 
+/// https://somewhere.com?hello=12
+//~^ ERROR won't be a link as is
+pub fn c() {}
+
+/// <https://somewhere.com>
 /// [a](http://a.com)
 /// [b]
 ///
diff --git a/src/test/rustdoc-ui/automatic-links.stderr b/src/test/rustdoc-ui/automatic-links.stderr
index 2922fedb238cb..d2c0c51d7a472 100644
--- a/src/test/rustdoc-ui/automatic-links.stderr
+++ b/src/test/rustdoc-ui/automatic-links.stderr
@@ -1,23 +1,26 @@
-error: Unneeded long form for URL
+error: unneeded long form for URL
   --> $DIR/automatic-links.rs:3:5
    |
 LL | /// [http://a.com](http://a.com)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://a.com>`
    |
 note: the lint level is defined here
   --> $DIR/automatic-links.rs:1:9
    |
 LL | #![deny(automatic_links)]
    |         ^^^^^^^^^^^^^^^
-   = help: Try with `<http://a.com>` instead
 
-error: Unneeded long form for URL
+error: unneeded long form for URL
   --> $DIR/automatic-links.rs:5:5
    |
 LL | /// [http://b.com]
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://b.com>`
+
+error: won't be a link as is
+  --> $DIR/automatic-links.rs:13:5
    |
-   = help: Try with `<http://b.com>` instead
+LL | /// https://somewhere.com?hello=12
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 

From 7f839b2ece86b3b5db89673fc402348c71db42f4 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Wed, 14 Oct 2020 15:11:55 +0200
Subject: [PATCH 05/13] Improve automatic_links globally

---
 compiler/rustc_lint_defs/src/builtin.rs    |  10 +--
 src/doc/rustdoc/src/lints.md               |  13 +--
 src/librustdoc/passes/automatic_links.rs   |  37 ++++----
 src/test/rustdoc-ui/automatic-links.rs     |  40 ++++++++-
 src/test/rustdoc-ui/automatic-links.stderr | 100 ++++++++++++++++++++-
 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 1294dd9d68583..b6e6307a40f30 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 a85aa882af891..68ea828bfc1e5 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 11c1a4d0bfba8..816d2fd15eee5 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 f9dbe67e5b1da..27eb4e4a646ce 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 d2c0c51d7a472..00e210aaaa22d 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
 

From 55b4d21e25a63ad36c5e6dcfd9106ae44ba6c75e Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Wed, 14 Oct 2020 17:35:43 +0200
Subject: [PATCH 06/13] Fix automatic_links warnings

---
 compiler/rustc_target/src/spec/crt_objects.rs            | 2 +-
 compiler/rustc_target/src/spec/mod.rs                    | 2 +-
 compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs | 2 +-
 compiler/rustc_target/src/spec/wasm32_wasi.rs            | 2 +-
 library/core/src/intrinsics.rs                           | 2 +-
 library/core/src/lib.rs                                  | 1 +
 library/core/src/num/dec2flt/mod.rs                      | 2 +-
 library/core/src/slice/sort.rs                           | 2 +-
 8 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs
index 8991691a9a30c..76c0bf419e8c4 100644
--- a/compiler/rustc_target/src/spec/crt_objects.rs
+++ b/compiler/rustc_target/src/spec/crt_objects.rs
@@ -3,7 +3,7 @@
 //!
 //! Table of CRT objects for popular toolchains.
 //! The `crtx` ones are generally distributed with libc and the `begin/end` ones with gcc.
-//! See https://dev.gentoo.org/~vapier/crt.txt for some more details.
+//! See <https://dev.gentoo.org/~vapier/crt.txt> for some more details.
 //!
 //! | Pre-link CRT objects | glibc                  | musl                   | bionic           | mingw             | wasi |
 //! |----------------------|------------------------|------------------------|------------------|-------------------|------|
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index ba9e2f7fa0648..d3c5a9433d08e 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -950,7 +950,7 @@ pub struct TargetOptions {
     /// The MergeFunctions pass is generally useful, but some targets may need
     /// to opt out. The default is "aliases".
     ///
-    /// Workaround for: https://github.com/rust-lang/rust/issues/57356
+    /// Workaround for: <https://github.com/rust-lang/rust/issues/57356>
     pub merge_functions: MergeFunctions,
 
     /// Use platform dependent mcount function
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
index 19609b0d496f2..1ef0a81937849 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -8,7 +8,7 @@
 //! (e.g. trying to create a TCP stream or something like that).
 //!
 //! This target is more or less managed by the Rust and WebAssembly Working
-//! Group nowadays at https://github.com/rustwasm.
+//! Group nowadays at <https://github.com/rustwasm>.
 
 use super::wasm32_base;
 use super::{LinkerFlavor, LldFlavor, Target};
diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs
index 26e0722fcf0c2..8c2bb9208291d 100644
--- a/compiler/rustc_target/src/spec/wasm32_wasi.rs
+++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs
@@ -7,7 +7,7 @@
 //! intended to empower WebAssembly binaries with native capabilities such as
 //! filesystem access, network access, etc.
 //!
-//! You can see more about the proposal at https://wasi.dev
+//! You can see more about the proposal at <https://wasi.dev>.
 //!
 //! The Rust target definition here is interesting in a few ways. We want to
 //! serve two use cases here with this target:
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 3e5d7caa2fe5d..3570cab0022e8 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -9,7 +9,7 @@
 //! This includes changes in the stability of the constness.
 //!
 //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation
-//! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to
+//! from <https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs> to
 //! `compiler/rustc_mir/src/interpret/intrinsics.rs` and add a
 //! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic.
 //!
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index b89ec93834fcc..09dbde2c121f6 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -287,6 +287,7 @@ pub mod primitive;
     unused_imports,
     unsafe_op_in_unsafe_fn
 )]
+#[cfg_attr(not(bootstrap), allow(automatic_links))]
 // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
 // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
 #[allow(clashing_extern_declarations)]
diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs
index 6f3a3a867450d..039112e9f3468 100644
--- a/library/core/src/num/dec2flt/mod.rs
+++ b/library/core/src/num/dec2flt/mod.rs
@@ -33,7 +33,7 @@
 //!
 //! Primarily, this module and its children implement the algorithms described in:
 //! "How to Read Floating Point Numbers Accurately" by William D. Clinger,
-//! available online: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.45.4152
+//! available online: <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.45.4152>
 //!
 //! In addition, there are numerous helper functions that are used in the paper but not available
 //! in Rust (or at least in core). Our version is additionally complicated by the need to handle
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index 71d2c2c9b2f4c..2a7693d27efa2 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -1,7 +1,7 @@
 //! Slice sorting
 //!
 //! This module contains a sorting algorithm based on Orson Peters' pattern-defeating quicksort,
-//! published at: https://github.com/orlp/pdqsort
+//! published at: <https://github.com/orlp/pdqsort>
 //!
 //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our
 //! stable sorting implementation.

From 60caf51b0de940705e7679a26343f6dcbe470a54 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sat, 17 Oct 2020 16:38:49 +0200
Subject: [PATCH 07/13] Rename automatic_links to url_improvements

---
 compiler/rustc_lint/src/lib.rs                |  6 +++---
 compiler/rustc_lint_defs/src/builtin.rs       |  8 ++++----
 library/core/src/lib.rs                       |  2 +-
 src/doc/rustdoc/src/lints.md                  |  2 +-
 src/librustdoc/core.rs                        |  4 ++--
 src/librustdoc/passes/mod.rs                  |  8 ++++----
 ...automatic_links.rs => url_improvements.rs} | 20 +++++++++----------
 ...automatic-links.rs => url-improvements.rs} |  4 ++--
 ...c-links.stderr => url-improvements.stderr} |  4 ++--
 9 files changed, 29 insertions(+), 29 deletions(-)
 rename src/librustdoc/passes/{automatic_links.rs => url_improvements.rs} (86%)
 rename src/test/rustdoc-ui/{automatic-links.rs => url-improvements.rs} (96%)
 rename src/test/rustdoc-ui/{automatic-links.stderr => url-improvements.stderr} (98%)

diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 0da3ece167e97..ad353bb28c99d 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -67,9 +67,9 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::{
-    AUTOMATIC_LINKS, BARE_TRAIT_OBJECTS, BROKEN_INTRA_DOC_LINKS, ELIDED_LIFETIMES_IN_PATHS,
+    BARE_TRAIT_OBJECTS, BROKEN_INTRA_DOC_LINKS, ELIDED_LIFETIMES_IN_PATHS,
     EXPLICIT_OUTLIVES_REQUIREMENTS, INVALID_CODEBLOCK_ATTRIBUTES, INVALID_HTML_TAGS,
-    MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
+    MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS, URL_IMPROVEMENTS,
 };
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
@@ -313,7 +313,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
 
     add_lint_group!(
         "rustdoc",
-        AUTOMATIC_LINKS,
+        URL_IMPROVEMENTS,
         BROKEN_INTRA_DOC_LINKS,
         PRIVATE_INTRA_DOC_LINKS,
         INVALID_CODEBLOCK_ATTRIBUTES,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index b6e6307a40f30..c74680c172fe6 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1891,12 +1891,12 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `automatic_links` lint detects when a URL could be written using
+    /// The `url_improvements` 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,
+    /// [rustdoc book]: ../../../rustdoc/lints.html#url_improvements
+    pub URL_IMPROVEMENTS,
     Warn,
     "detects URLs that could be written using only angle brackets"
 }
@@ -2806,7 +2806,7 @@ declare_lint_pass! {
         MISSING_DOC_CODE_EXAMPLES,
         INVALID_HTML_TAGS,
         PRIVATE_DOC_TESTS,
-        AUTOMATIC_LINKS,
+        URL_IMPROVEMENTS,
         WHERE_CLAUSES_OBJECT_SAFETY,
         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
         MACRO_USE_EXTERN_CRATE,
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 09dbde2c121f6..8596d52ceaeb1 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -287,7 +287,7 @@ pub mod primitive;
     unused_imports,
     unsafe_op_in_unsafe_fn
 )]
-#[cfg_attr(not(bootstrap), allow(automatic_links))]
+#[cfg_attr(not(bootstrap), allow(url_improvements))]
 // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
 // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
 #[allow(clashing_extern_declarations)]
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index 68ea828bfc1e5..7db9c93852da8 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -286,7 +286,7 @@ warning: unclosed HTML tag `h1`
 warning: 2 warnings emitted
 ```
 
-## automatic_links
+## url_improvements
 
 This lint is **nightly-only** and **warns by default**. It detects links which
 could use the "automatic" link syntax. For example:
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index f834be84d4c59..85d73a30e4b68 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -330,13 +330,12 @@ pub fn run_core(
     let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
     let invalid_html_tags = rustc_lint::builtin::INVALID_HTML_TAGS.name;
     let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name;
-    let automatic_links = rustc_lint::builtin::AUTOMATIC_LINKS.name;
+    let url_improvements = rustc_lint::builtin::URL_IMPROVEMENTS.name;
     let unknown_lints = rustc_lint::builtin::UNKNOWN_LINTS.name;
 
     // In addition to those specific lints, we also need to allow those given through
     // command line, otherwise they'll get ignored and we don't want that.
     let lints_to_show = vec![
-        automatic_links.to_owned(),
         intra_link_resolution_failure_name.to_owned(),
         missing_docs.to_owned(),
         missing_doc_example.to_owned(),
@@ -346,6 +345,7 @@ pub fn run_core(
         invalid_html_tags.to_owned(),
         renamed_and_removed_lints.to_owned(),
         unknown_lints.to_owned(),
+        url_improvements.to_owned(),
     ];
 
     let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| {
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 48dc52c955006..fa8bd24efa9e2 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -11,8 +11,8 @@ use crate::core::DocContext;
 mod stripper;
 pub use stripper::*;
 
-mod automatic_links;
-pub use self::automatic_links::CHECK_AUTOMATIC_LINKS;
+mod url_improvements;
+pub use self::url_improvements::CHECK_URL_IMPROVEMENTS;
 
 mod collapse_docs;
 pub use self::collapse_docs::COLLAPSE_DOCS;
@@ -93,7 +93,7 @@ pub const PASSES: &[Pass] = &[
     COLLECT_TRAIT_IMPLS,
     CALCULATE_DOC_COVERAGE,
     CHECK_INVALID_HTML_TAGS,
-    CHECK_AUTOMATIC_LINKS,
+    CHECK_URL_IMPROVEMENTS,
 ];
 
 /// The list of passes run by default.
@@ -109,7 +109,7 @@ pub const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
     ConditionalPass::always(CHECK_INVALID_HTML_TAGS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
-    ConditionalPass::always(CHECK_AUTOMATIC_LINKS),
+    ConditionalPass::always(CHECK_URL_IMPROVEMENTS),
 ];
 
 /// The list of default passes run when `--doc-coverage` is passed to rustdoc.
diff --git a/src/librustdoc/passes/automatic_links.rs b/src/librustdoc/passes/url_improvements.rs
similarity index 86%
rename from src/librustdoc/passes/automatic_links.rs
rename to src/librustdoc/passes/url_improvements.rs
index 816d2fd15eee5..d191a89948ae9 100644
--- a/src/librustdoc/passes/automatic_links.rs
+++ b/src/librustdoc/passes/url_improvements.rs
@@ -10,9 +10,9 @@ use rustc_errors::Applicability;
 use rustc_feature::UnstableFeatures;
 use rustc_session::lint;
 
-pub const CHECK_AUTOMATIC_LINKS: Pass = Pass {
-    name: "check-automatic-links",
-    run: check_automatic_links,
+pub const CHECK_URL_IMPROVEMENTS: Pass = Pass {
+    name: "check-url-improvements",
+    run: check_url_improvements,
     description: "detects URLS that could be written using angle brackets",
 };
 
@@ -23,14 +23,14 @@ const URL_REGEX: &str = concat!(
     r"\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)"     // optional query or url fragments
 );
 
-struct AutomaticLinksLinter<'a, 'tcx> {
+struct UrlImprovementsLinter<'a, 'tcx> {
     cx: &'a DocContext<'tcx>,
     regex: Regex,
 }
 
-impl<'a, 'tcx> AutomaticLinksLinter<'a, 'tcx> {
+impl<'a, 'tcx> UrlImprovementsLinter<'a, 'tcx> {
     fn new(cx: &'a DocContext<'tcx>) -> Self {
-        AutomaticLinksLinter { cx, regex: Regex::new(URL_REGEX).expect("failed to build regex") }
+        UrlImprovementsLinter { cx, regex: Regex::new(URL_REGEX).expect("failed to build regex") }
     }
 
     fn find_raw_urls(
@@ -53,17 +53,17 @@ impl<'a, 'tcx> AutomaticLinksLinter<'a, 'tcx> {
     }
 }
 
-pub fn check_automatic_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
+pub fn check_url_improvements(krate: Crate, cx: &DocContext<'_>) -> Crate {
     if !UnstableFeatures::from_environment().is_nightly_build() {
         krate
     } else {
-        let mut coll = AutomaticLinksLinter::new(cx);
+        let mut coll = UrlImprovementsLinter::new(cx);
 
         coll.fold_crate(krate)
     }
 }
 
-impl<'a, 'tcx> DocFolder for AutomaticLinksLinter<'a, 'tcx> {
+impl<'a, 'tcx> DocFolder for UrlImprovementsLinter<'a, 'tcx> {
     fn fold_item(&mut self, item: Item) -> Option<Item> {
         let hir_id = match self.cx.as_local_hir_id(item.def_id) {
             Some(hir_id) => hir_id,
@@ -78,7 +78,7 @@ impl<'a, 'tcx> DocFolder for AutomaticLinksLinter<'a, 'tcx> {
                 let sp = super::source_span_for_markdown_range(cx, &dox, &range, &item.attrs)
                     .or_else(|| span_of_attrs(&item.attrs))
                     .unwrap_or(item.source.span());
-                cx.tcx.struct_span_lint_hir(lint::builtin::AUTOMATIC_LINKS, hir_id, sp, |lint| {
+                cx.tcx.struct_span_lint_hir(lint::builtin::URL_IMPROVEMENTS, hir_id, sp, |lint| {
                     lint.build(msg)
                         .span_suggestion(
                             sp,
diff --git a/src/test/rustdoc-ui/automatic-links.rs b/src/test/rustdoc-ui/url-improvements.rs
similarity index 96%
rename from src/test/rustdoc-ui/automatic-links.rs
rename to src/test/rustdoc-ui/url-improvements.rs
index 27eb4e4a646ce..761ec31feca95 100644
--- a/src/test/rustdoc-ui/automatic-links.rs
+++ b/src/test/rustdoc-ui/url-improvements.rs
@@ -1,4 +1,4 @@
-#![deny(automatic_links)]
+#![deny(url_improvements)]
 
 /// [http://a.com](http://a.com)
 //~^ ERROR unneeded long form for URL
@@ -53,7 +53,7 @@ pub fn c() {}
 /// [b]: http://b.com
 pub fn everything_is_fine_here() {}
 
-#[allow(automatic_links)]
+#[allow(url_improvements)]
 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/url-improvements.stderr
similarity index 98%
rename from src/test/rustdoc-ui/automatic-links.stderr
rename to src/test/rustdoc-ui/url-improvements.stderr
index 00e210aaaa22d..7ef287dfd11ad 100644
--- a/src/test/rustdoc-ui/automatic-links.stderr
+++ b/src/test/rustdoc-ui/url-improvements.stderr
@@ -7,8 +7,8 @@ LL | /// [http://a.com](http://a.com)
 note: the lint level is defined here
   --> $DIR/automatic-links.rs:1:9
    |
-LL | #![deny(automatic_links)]
-   |         ^^^^^^^^^^^^^^^
+LL | #![deny(url_improvements)]
+   |         ^^^^^^^^^^^^^^^^
 
 error: unneeded long form for URL
   --> $DIR/automatic-links.rs:5:5

From fce2be0ea7b90fb9ba1a1704454b36307c9b8c07 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sat, 17 Oct 2020 16:43:13 +0200
Subject: [PATCH 08/13] Update URLs used in the lint example

---
 src/doc/rustdoc/src/lints.md | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index 7db9c93852da8..a89c094bf4c6b 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -292,11 +292,11 @@ This lint is **nightly-only** and **warns by default**. It detects links which
 could use the "automatic" link syntax. For example:
 
 ```rust
-/// http://hello.rs
-/// [http://a.com](http://a.com)
-/// [http://b.com]
+/// http://example.org
+/// [http://example.com](http://example.com)
+/// [http://example.net]
 ///
-/// [http://b.com]: http://b.com
+/// [http://example.com]: http://example.com
 pub fn foo() {}
 ```
 
@@ -304,21 +304,22 @@ Which will give:
 
 ```text
 warning: this URL is not a hyperlink
- --> foo.rs:3:5
+ --> foo.rs:1:5
   |
-3 | /// http://hello.rs
-  |     ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://hello.rs>`
+1 | /// http://example.org
+  |     ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.org>`
   |
+  = note: `#[warn(url_improvements)]` on by default
 
 warning: unneeded long form for URL
- --> foo.rs:4:5
+ --> foo.rs:2:5
   |
-4 | /// [http://a.com](http://a.com)
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://a.com>`
+2 | /// [http://example.com](http://example.com)
+  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.com>`
 
-warning: unneeded long form for URL
- --> foo.rs:5:5
+warning: this URL is not a hyperlink
+ --> foo.rs:3:6
   |
-5 | /// [http://b.com]
-  |     ^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://b.com>`
+3 | /// [http://example.net]
+  |      ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.net>`
 ```

From 1fb404bebe9e7d228859a26b7e40340438d0c427 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sat, 17 Oct 2020 23:58:46 +0200
Subject: [PATCH 09/13] Don't check for URLs inside codeblocks

---
 src/librustdoc/passes/url_improvements.rs   | 50 ++++++++++++---------
 src/test/rustdoc-ui/url-improvements.rs     |  4 ++
 src/test/rustdoc-ui/url-improvements.stderr | 40 ++++++++---------
 3 files changed, 54 insertions(+), 40 deletions(-)

diff --git a/src/librustdoc/passes/url_improvements.rs b/src/librustdoc/passes/url_improvements.rs
index d191a89948ae9..a5d555eb19dca 100644
--- a/src/librustdoc/passes/url_improvements.rs
+++ b/src/librustdoc/passes/url_improvements.rs
@@ -90,33 +90,43 @@ impl<'a, 'tcx> DocFolder for UrlImprovementsLinter<'a, 'tcx> {
                 });
             };
 
-            let p = Parser::new_ext(&dox, opts()).into_offset_iter();
+            let mut p = Parser::new_ext(&dox, opts()).into_offset_iter();
 
-            let mut title = String::new();
-            let mut in_link = false;
-            let mut ignore = false;
-
-            for (event, range) in p {
+            while let Some((event, range)) = p.next() {
                 match event {
                     Event::Start(Tag::Link(kind, _, _)) => {
-                        in_link = true;
-                        ignore = matches!(kind, LinkType::Autolink | LinkType::Email);
-                    }
-                    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);
+                        let ignore = matches!(kind, LinkType::Autolink | LinkType::Email);
+                        let mut title = String::new();
+
+                        while let Some((event, range)) = p.next() {
+                            match event {
+                                Event::End(Tag::Link(_, url, _)) => {
+                                    // 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,
+                                        );
+                                    }
+                                    break;
+                                }
+                                Event::Text(s) if !ignore => title.push_str(&s),
+                                _ => {}
+                            }
                         }
-                        title.clear();
-                        ignore = false;
                     }
-                    Event::Text(s) if in_link => {
-                        if !ignore {
-                            title.push_str(&s);
+                    Event::Text(s) => self.find_raw_urls(&s, range, &report_diag),
+                    Event::Start(Tag::CodeBlock(_)) => {
+                        // We don't want to check the text inside the code blocks.
+                        while let Some((event, _)) = p.next() {
+                            match event {
+                                Event::End(Tag::CodeBlock(_)) => break,
+                                _ => {}
+                            }
                         }
                     }
-                    Event::Text(s) => self.find_raw_urls(&s, range, &report_diag),
                     _ => {}
                 }
             }
diff --git a/src/test/rustdoc-ui/url-improvements.rs b/src/test/rustdoc-ui/url-improvements.rs
index 761ec31feca95..81fd0ba7d512d 100644
--- a/src/test/rustdoc-ui/url-improvements.rs
+++ b/src/test/rustdoc-ui/url-improvements.rs
@@ -51,6 +51,10 @@ pub fn c() {}
 /// [b]
 ///
 /// [b]: http://b.com
+///
+/// ```
+/// This link should not be linted: http://example.com
+/// ```
 pub fn everything_is_fine_here() {}
 
 #[allow(url_improvements)]
diff --git a/src/test/rustdoc-ui/url-improvements.stderr b/src/test/rustdoc-ui/url-improvements.stderr
index 7ef287dfd11ad..e8ed2331dd84c 100644
--- a/src/test/rustdoc-ui/url-improvements.stderr
+++ b/src/test/rustdoc-ui/url-improvements.stderr
@@ -1,119 +1,119 @@
 error: unneeded long form for URL
-  --> $DIR/automatic-links.rs:3:5
+  --> $DIR/url-improvements.rs:3:5
    |
 LL | /// [http://a.com](http://a.com)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://a.com>`
    |
 note: the lint level is defined here
-  --> $DIR/automatic-links.rs:1:9
+  --> $DIR/url-improvements.rs:1:9
    |
 LL | #![deny(url_improvements)]
    |         ^^^^^^^^^^^^^^^^
 
 error: unneeded long form for URL
-  --> $DIR/automatic-links.rs:5:5
+  --> $DIR/url-improvements.rs:5:5
    |
 LL | /// [http://b.com]
    |     ^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://b.com>`
 
 error: this URL is not a hyperlink
-  --> $DIR/automatic-links.rs:13:5
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.rs:27:5
    |
 LL | /// https://somewhere.com?hello=12
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>`
 
 error: this URL is not a hyperlink
-  --> $DIR/automatic-links.rs:29:5
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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
+  --> $DIR/url-improvements.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>`

From 6be97e225099cc59dc63f6fc01af7c525d0334df Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sat, 31 Oct 2020 13:46:28 +0100
Subject: [PATCH 10/13] Improve lint even more

---
 src/librustdoc/passes/url_improvements.rs | 9 +++++----
 src/test/rustdoc-ui/url-improvements.rs   | 2 ++
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/librustdoc/passes/url_improvements.rs b/src/librustdoc/passes/url_improvements.rs
index a5d555eb19dca..f09c44b41c976 100644
--- a/src/librustdoc/passes/url_improvements.rs
+++ b/src/librustdoc/passes/url_improvements.rs
@@ -19,8 +19,8 @@ pub const CHECK_URL_IMPROVEMENTS: Pass = Pass {
 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
+    r"[a-zA-Z]{2,63}",                     // root domain
+    r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)"      // optional query or url fragments
 );
 
 struct UrlImprovementsLinter<'a, 'tcx> {
@@ -101,8 +101,9 @@ impl<'a, 'tcx> DocFolder for UrlImprovementsLinter<'a, 'tcx> {
                         while let Some((event, range)) = p.next() {
                             match event {
                                 Event::End(Tag::Link(_, url, _)) => {
-                                    // NOTE: links cannot be nested, so we don't need to check `kind`
-                                    if url.as_ref() == title && !ignore {
+                                    // NOTE: links cannot be nested, so we don't need to
+                                    // check `kind`
+                                    if url.as_ref() == title && !ignore && self.regex.matches(url) {
                                         report_diag(
                                             self.cx,
                                             "unneeded long form for URL",
diff --git a/src/test/rustdoc-ui/url-improvements.rs b/src/test/rustdoc-ui/url-improvements.rs
index 81fd0ba7d512d..b7b1c26cd6deb 100644
--- a/src/test/rustdoc-ui/url-improvements.rs
+++ b/src/test/rustdoc-ui/url-improvements.rs
@@ -55,6 +55,8 @@ pub fn c() {}
 /// ```
 /// This link should not be linted: http://example.com
 /// ```
+///
+/// [should_not.lint](should_not.lint)
 pub fn everything_is_fine_here() {}
 
 #[allow(url_improvements)]

From 9d114506c68ce717503d0fa1eb335db5c80c195f Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sat, 31 Oct 2020 15:14:44 +0100
Subject: [PATCH 11/13] Rename lint to non_autolinks

---
 compiler/rustc_lint/src/lib.rs                |  4 ++--
 compiler/rustc_lint_defs/src/builtin.rs       |  8 +++----
 library/core/src/lib.rs                       |  2 +-
 src/doc/rustdoc/src/lints.md                  |  4 ++--
 src/librustdoc/core.rs                        |  4 ++--
 src/librustdoc/passes/mod.rs                  |  8 +++----
 .../{url_improvements.rs => non_autolinks.rs} | 23 ++++++++++---------
 src/test/rustdoc-ui/url-improvements.rs       | 10 ++++----
 src/test/rustdoc-ui/url-improvements.stderr   | 12 +++++-----
 9 files changed, 38 insertions(+), 37 deletions(-)
 rename src/librustdoc/passes/{url_improvements.rs => non_autolinks.rs} (88%)

diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index ad353bb28c99d..24bfdad970a1c 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -69,7 +69,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::{
     BARE_TRAIT_OBJECTS, BROKEN_INTRA_DOC_LINKS, ELIDED_LIFETIMES_IN_PATHS,
     EXPLICIT_OUTLIVES_REQUIREMENTS, INVALID_CODEBLOCK_ATTRIBUTES, INVALID_HTML_TAGS,
-    MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS, URL_IMPROVEMENTS,
+    MISSING_DOC_CODE_EXAMPLES, NON_AUTOLINKS, PRIVATE_DOC_TESTS,
 };
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
@@ -313,7 +313,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
 
     add_lint_group!(
         "rustdoc",
-        URL_IMPROVEMENTS,
+        NON_AUTOLINKS,
         BROKEN_INTRA_DOC_LINKS,
         PRIVATE_INTRA_DOC_LINKS,
         INVALID_CODEBLOCK_ATTRIBUTES,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index c74680c172fe6..ff7a145c2668d 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1891,12 +1891,12 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `url_improvements` lint detects when a URL could be written using
+    /// The `non_autolinks` 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#url_improvements
-    pub URL_IMPROVEMENTS,
+    /// [rustdoc book]: ../../../rustdoc/lints.html#non_autolinks
+    pub NON_AUTOLINKS,
     Warn,
     "detects URLs that could be written using only angle brackets"
 }
@@ -2806,7 +2806,7 @@ declare_lint_pass! {
         MISSING_DOC_CODE_EXAMPLES,
         INVALID_HTML_TAGS,
         PRIVATE_DOC_TESTS,
-        URL_IMPROVEMENTS,
+        NON_AUTOLINKS,
         WHERE_CLAUSES_OBJECT_SAFETY,
         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
         MACRO_USE_EXTERN_CRATE,
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 8596d52ceaeb1..069e6e7e71881 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -287,7 +287,7 @@ pub mod primitive;
     unused_imports,
     unsafe_op_in_unsafe_fn
 )]
-#[cfg_attr(not(bootstrap), allow(url_improvements))]
+#[cfg_attr(not(bootstrap), allow(non_autolinks))]
 // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
 // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
 #[allow(clashing_extern_declarations)]
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index a89c094bf4c6b..41292b3d83841 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -286,7 +286,7 @@ warning: unclosed HTML tag `h1`
 warning: 2 warnings emitted
 ```
 
-## url_improvements
+## non_autolinks
 
 This lint is **nightly-only** and **warns by default**. It detects links which
 could use the "automatic" link syntax. For example:
@@ -309,7 +309,7 @@ warning: this URL is not a hyperlink
 1 | /// http://example.org
   |     ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.org>`
   |
-  = note: `#[warn(url_improvements)]` on by default
+  = note: `#[warn(non_autolinks)]` on by default
 
 warning: unneeded long form for URL
  --> foo.rs:2:5
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 85d73a30e4b68..5cb7a32cf0cbc 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -330,7 +330,7 @@ pub fn run_core(
     let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
     let invalid_html_tags = rustc_lint::builtin::INVALID_HTML_TAGS.name;
     let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name;
-    let url_improvements = rustc_lint::builtin::URL_IMPROVEMENTS.name;
+    let non_autolinks = rustc_lint::builtin::NON_AUTOLINKS.name;
     let unknown_lints = rustc_lint::builtin::UNKNOWN_LINTS.name;
 
     // In addition to those specific lints, we also need to allow those given through
@@ -345,7 +345,7 @@ pub fn run_core(
         invalid_html_tags.to_owned(),
         renamed_and_removed_lints.to_owned(),
         unknown_lints.to_owned(),
-        url_improvements.to_owned(),
+        non_autolinks.to_owned(),
     ];
 
     let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| {
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index fa8bd24efa9e2..047a73835c8eb 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -11,8 +11,8 @@ use crate::core::DocContext;
 mod stripper;
 pub use stripper::*;
 
-mod url_improvements;
-pub use self::url_improvements::CHECK_URL_IMPROVEMENTS;
+mod non_autolinks;
+pub use self::non_autolinks::CHECK_NON_AUTOLINKS;
 
 mod collapse_docs;
 pub use self::collapse_docs::COLLAPSE_DOCS;
@@ -93,7 +93,7 @@ pub const PASSES: &[Pass] = &[
     COLLECT_TRAIT_IMPLS,
     CALCULATE_DOC_COVERAGE,
     CHECK_INVALID_HTML_TAGS,
-    CHECK_URL_IMPROVEMENTS,
+    CHECK_NON_AUTOLINKS,
 ];
 
 /// The list of passes run by default.
@@ -109,7 +109,7 @@ pub const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
     ConditionalPass::always(CHECK_INVALID_HTML_TAGS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
-    ConditionalPass::always(CHECK_URL_IMPROVEMENTS),
+    ConditionalPass::always(CHECK_NON_AUTOLINKS),
 ];
 
 /// The list of default passes run when `--doc-coverage` is passed to rustdoc.
diff --git a/src/librustdoc/passes/url_improvements.rs b/src/librustdoc/passes/non_autolinks.rs
similarity index 88%
rename from src/librustdoc/passes/url_improvements.rs
rename to src/librustdoc/passes/non_autolinks.rs
index f09c44b41c976..4a8fc7fc6181e 100644
--- a/src/librustdoc/passes/url_improvements.rs
+++ b/src/librustdoc/passes/non_autolinks.rs
@@ -10,9 +10,9 @@ use rustc_errors::Applicability;
 use rustc_feature::UnstableFeatures;
 use rustc_session::lint;
 
-pub const CHECK_URL_IMPROVEMENTS: Pass = Pass {
-    name: "check-url-improvements",
-    run: check_url_improvements,
+pub const CHECK_NON_AUTOLINKS: Pass = Pass {
+    name: "check-non-autolinks",
+    run: check_non_autolinks,
     description: "detects URLS that could be written using angle brackets",
 };
 
@@ -23,14 +23,14 @@ const URL_REGEX: &str = concat!(
     r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)"      // optional query or url fragments
 );
 
-struct UrlImprovementsLinter<'a, 'tcx> {
+struct NonAutolinksLinter<'a, 'tcx> {
     cx: &'a DocContext<'tcx>,
     regex: Regex,
 }
 
-impl<'a, 'tcx> UrlImprovementsLinter<'a, 'tcx> {
+impl<'a, 'tcx> NonAutolinksLinter<'a, 'tcx> {
     fn new(cx: &'a DocContext<'tcx>) -> Self {
-        UrlImprovementsLinter { cx, regex: Regex::new(URL_REGEX).expect("failed to build regex") }
+        Self { cx, regex: Regex::new(URL_REGEX).expect("failed to build regex") }
     }
 
     fn find_raw_urls(
@@ -53,17 +53,17 @@ impl<'a, 'tcx> UrlImprovementsLinter<'a, 'tcx> {
     }
 }
 
-pub fn check_url_improvements(krate: Crate, cx: &DocContext<'_>) -> Crate {
+pub fn check_non_autolinks(krate: Crate, cx: &DocContext<'_>) -> Crate {
     if !UnstableFeatures::from_environment().is_nightly_build() {
         krate
     } else {
-        let mut coll = UrlImprovementsLinter::new(cx);
+        let mut coll = NonAutolinksLinter::new(cx);
 
         coll.fold_crate(krate)
     }
 }
 
-impl<'a, 'tcx> DocFolder for UrlImprovementsLinter<'a, 'tcx> {
+impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> {
     fn fold_item(&mut self, item: Item) -> Option<Item> {
         let hir_id = match self.cx.as_local_hir_id(item.def_id) {
             Some(hir_id) => hir_id,
@@ -78,7 +78,7 @@ impl<'a, 'tcx> DocFolder for UrlImprovementsLinter<'a, 'tcx> {
                 let sp = super::source_span_for_markdown_range(cx, &dox, &range, &item.attrs)
                     .or_else(|| span_of_attrs(&item.attrs))
                     .unwrap_or(item.source.span());
-                cx.tcx.struct_span_lint_hir(lint::builtin::URL_IMPROVEMENTS, hir_id, sp, |lint| {
+                cx.tcx.struct_span_lint_hir(lint::builtin::NON_AUTOLINKS, hir_id, sp, |lint| {
                     lint.build(msg)
                         .span_suggestion(
                             sp,
@@ -103,7 +103,8 @@ impl<'a, 'tcx> DocFolder for UrlImprovementsLinter<'a, 'tcx> {
                                 Event::End(Tag::Link(_, url, _)) => {
                                     // NOTE: links cannot be nested, so we don't need to
                                     // check `kind`
-                                    if url.as_ref() == title && !ignore && self.regex.matches(url) {
+                                    if url.as_ref() == title && !ignore && self.regex.is_match(&url)
+                                    {
                                         report_diag(
                                             self.cx,
                                             "unneeded long form for URL",
diff --git a/src/test/rustdoc-ui/url-improvements.rs b/src/test/rustdoc-ui/url-improvements.rs
index b7b1c26cd6deb..8531583d38a65 100644
--- a/src/test/rustdoc-ui/url-improvements.rs
+++ b/src/test/rustdoc-ui/url-improvements.rs
@@ -1,11 +1,11 @@
-#![deny(url_improvements)]
+#![deny(non_autolinks)]
 
-/// [http://a.com](http://a.com)
+/// [http://aa.com](http://aa.com)
 //~^ ERROR unneeded long form for URL
-/// [http://b.com]
+/// [http://bb.com]
 //~^ ERROR unneeded long form for URL
 ///
-/// [http://b.com]: http://b.com
+/// [http://bb.com]: http://bb.com
 ///
 /// [http://c.com][http://c.com]
 pub fn a() {}
@@ -59,7 +59,7 @@ pub fn c() {}
 /// [should_not.lint](should_not.lint)
 pub fn everything_is_fine_here() {}
 
-#[allow(url_improvements)]
+#[allow(non_autolinks)]
 pub mod foo {
     /// https://somewhere.com/a?hello=12&bye=11#xyz
     pub fn bar() {}
diff --git a/src/test/rustdoc-ui/url-improvements.stderr b/src/test/rustdoc-ui/url-improvements.stderr
index e8ed2331dd84c..70ad4b06a515d 100644
--- a/src/test/rustdoc-ui/url-improvements.stderr
+++ b/src/test/rustdoc-ui/url-improvements.stderr
@@ -1,20 +1,20 @@
 error: unneeded long form for URL
   --> $DIR/url-improvements.rs:3:5
    |
-LL | /// [http://a.com](http://a.com)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://a.com>`
+LL | /// [http://aa.com](http://aa.com)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://aa.com>`
    |
 note: the lint level is defined here
   --> $DIR/url-improvements.rs:1:9
    |
-LL | #![deny(url_improvements)]
-   |         ^^^^^^^^^^^^^^^^
+LL | #![deny(non_autolinks)]
+   |         ^^^^^^^^^^^^^
 
 error: unneeded long form for URL
   --> $DIR/url-improvements.rs:5:5
    |
-LL | /// [http://b.com]
-   |     ^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://b.com>`
+LL | /// [http://bb.com]
+   |     ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://bb.com>`
 
 error: this URL is not a hyperlink
   --> $DIR/url-improvements.rs:13:5

From 16ed8501ef35f0008fefd7f51746a10a7e7505ac Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Thu, 5 Nov 2020 10:23:39 +0100
Subject: [PATCH 12/13] Fix more URLs

---
 compiler/rustc_lint_defs/src/lib.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 25a7bfcabb728..af9926400ca44 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -99,13 +99,13 @@ pub struct Lint {
     /// The name is written with underscores, e.g., "unused_imports".
     /// On the command line, underscores become dashes.
     ///
-    /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming
+    /// See <https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming>
     /// for naming guidelines.
     pub name: &'static str,
 
     /// Default level for the lint.
     ///
-    /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels
+    /// See <https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels>
     /// for guidelines on choosing a default level.
     pub default_level: Level,
 
@@ -330,8 +330,8 @@ impl LintBuffer {
 
 /// Declares a static item of type `&'static Lint`.
 ///
-/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html for documentation
-/// and guidelines on writing lints.
+/// See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for
+/// documentation and guidelines on writing lints.
 ///
 /// The macro call should start with a doc comment explaining the lint
 /// which will be embedded in the rustc user documentation book. It should

From 99200f760bf588435ca53477bb1eaff34770db0b Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Thu, 5 Nov 2020 14:33:23 +0100
Subject: [PATCH 13/13] Fix even more URLs

---
 compiler/rustc_codegen_cranelift/src/discriminant.rs      | 2 +-
 compiler/rustc_middle/src/mir/coverage.rs                 | 6 +++---
 compiler/rustc_middle/src/mir/mono.rs                     | 2 +-
 compiler/rustc_middle/src/ty/context.rs                   | 2 +-
 compiler/rustc_mir/src/borrow_check/region_infer/mod.rs   | 2 +-
 compiler/rustc_mir/src/transform/dest_prop.rs             | 2 +-
 compiler/rustc_mir_build/src/thir/pattern/_match.rs       | 4 ++--
 compiler/rustc_parse/src/lexer/mod.rs                     | 2 +-
 compiler/rustc_privacy/src/lib.rs                         | 2 +-
 .../rustc_trait_selection/src/traits/object_safety.rs     | 2 +-
 library/core/src/future/mod.rs                            | 2 +-
 library/panic_unwind/src/dwarf/eh.rs                      | 8 ++++----
 library/panic_unwind/src/gcc.rs                           | 6 +++---
 src/bootstrap/toolstate.rs                                | 4 ++--
 src/build_helper/lib.rs                                   | 2 +-
 src/librustdoc/core.rs                                    | 2 +-
 16 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs
index 6c9fb8e051b3c..1e8e86add1a59 100644
--- a/compiler/rustc_codegen_cranelift/src/discriminant.rs
+++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs
@@ -1,6 +1,6 @@
 //! Handling of enum discriminants
 //!
-//! Adapted from https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs
+//! Adapted from <https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs>
 
 use rustc_target::abi::{Int, TagEncoding, Variants};
 
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 0421eabc2dc05..22c36b928781b 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -17,9 +17,9 @@ rustc_index::newtype_index! {
 impl ExpressionOperandId {
     /// An expression operand for a "zero counter", as described in the following references:
     ///
-    /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter
-    /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#tag
-    /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter-expressions
+    /// * <https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter>
+    /// * <https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#tag>
+    /// * <https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
     ///
     /// This operand can be used to count two or more separate code regions with a single counter,
     /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 79e2c5aac2385..1e70f7605045e 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -228,7 +228,7 @@ pub struct CodegenUnit<'tcx> {
 
 /// Specifies the linkage type for a `MonoItem`.
 ///
-/// See https://llvm.org/docs/LangRef.html#linkage-types for more details about these variants.
+/// See <https://llvm.org/docs/LangRef.html#linkage-types> for more details about these variants.
 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum Linkage {
     External,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 216451f268f4e..1c6937e685c65 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -368,7 +368,7 @@ pub struct TypeckResults<'tcx> {
     /// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
     ///
     /// See:
-    /// https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions
+    /// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
     pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
 
     /// Borrows
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index 47726632727d0..ac8ab71a1dc96 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -1364,7 +1364,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// terms that the "longer free region" `'a` outlived the "shorter free region" `'b`.
     ///
     /// More details can be found in this blog post by Niko:
-    /// http://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/
+    /// <http://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/>
     ///
     /// In the canonical example
     ///
diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs
index 410f462ed469f..46de5dba6e0ed 100644
--- a/compiler/rustc_mir/src/transform/dest_prop.rs
+++ b/compiler/rustc_mir/src/transform/dest_prop.rs
@@ -8,7 +8,7 @@
 //! inside a single block to shuffle a value around unnecessarily.
 //!
 //! LLVM by itself is not good enough at eliminating these redundant copies (eg. see
-//! https://github.com/rust-lang/rust/issues/32966), so this leaves some performance on the table
+//! <https://github.com/rust-lang/rust/issues/32966>), so this leaves some performance on the table
 //! that we can regain by implementing an optimization for removing these assign statements in rustc
 //! itself. When this optimization runs fast enough, it can also speed up the constant evaluation
 //! and code generation phases of rustc due to the reduced number of statements and locals.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
index 9e096f9ad6847..bc85d45d86773 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
@@ -8,7 +8,7 @@
 //! (b) each pattern is necessary (usefulness)
 //!
 //! The algorithm implemented here is a modified version of the one described in:
-//! http://moscova.inria.fr/~maranget/papers/warn/index.html
+//! <http://moscova.inria.fr/~maranget/papers/warn/index.html>
 //! However, to save future implementors from reading the original paper, we
 //! summarise the algorithm here to hopefully save time and be a little clearer
 //! (without being so rigorous).
@@ -2040,7 +2040,7 @@ impl<'tcx> MissingConstructors<'tcx> {
     }
 }
 
-/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html.
+/// Algorithm from <http://moscova.inria.fr/~maranget/papers/warn/index.html>.
 /// The algorithm from the paper has been modified to correctly handle empty
 /// types. The changes are:
 ///   (0) We don't exit early if the pattern matrix has zero rows. We just
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 32b124970cf7c..0dfacd78908ba 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -511,7 +511,7 @@ impl<'a> StringReader<'a> {
     }
 
     /// Note: It was decided to not add a test case, because it would be to big.
-    /// https://github.com/rust-lang/rust/pull/50296#issuecomment-392135180
+    /// <https://github.com/rust-lang/rust/pull/50296#issuecomment-392135180>
     fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! {
         self.fatal_span_(
             start,
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 4c0941120a6fc..75d75433f1bf1 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -38,7 +38,7 @@ use std::{cmp, fmt, mem};
 /// Implemented to visit all `DefId`s in a type.
 /// Visiting `DefId`s is useful because visibilities and reachabilities are attached to them.
 /// The idea is to visit "all components of a type", as documented in
-/// https://github.com/rust-lang/rfcs/blob/master/text/2145-type-privacy.md#how-to-determine-visibility-of-a-type.
+/// <https://github.com/rust-lang/rfcs/blob/master/text/2145-type-privacy.md#how-to-determine-visibility-of-a-type>.
 /// The default type visitor (`TypeVisitor`) does most of the job, but it has some shortcomings.
 /// First, it doesn't have overridable `fn visit_trait_ref`, so we have to catch trait `DefId`s
 /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 50efbbbe0fd76..32e0991733bd9 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -621,7 +621,7 @@ fn object_ty_for_trait<'tcx>(
 ///
 /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
 /// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch
-/// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561).
+/// is stabilized, see tracking issue <https://github.com/rust-lang/rust/issues/43561>).
 /// Instead, we fudge a little by introducing a new type parameter `U` such that
 /// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
 /// Written as a chalk-style query:
diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs
index fa5655ca35f41..cdde094147012 100644
--- a/library/core/src/future/mod.rs
+++ b/library/core/src/future/mod.rs
@@ -32,7 +32,7 @@ pub use poll_fn::{poll_fn, PollFn};
 /// This type is needed because:
 ///
 /// a) Generators cannot implement `for<'a, 'b> Generator<&'a mut Context<'b>>`, so we need to pass
-///    a raw pointer (see https://github.com/rust-lang/rust/issues/68923).
+///    a raw pointer (see <https://github.com/rust-lang/rust/issues/68923>).
 /// b) Raw pointers and `NonNull` aren't `Send` or `Sync`, so that would make every single future
 ///    non-Send/Sync as well, and we don't want that.
 ///
diff --git a/library/panic_unwind/src/dwarf/eh.rs b/library/panic_unwind/src/dwarf/eh.rs
index 8ce4dcd2acd9c..6dbf7c11b4c4e 100644
--- a/library/panic_unwind/src/dwarf/eh.rs
+++ b/library/panic_unwind/src/dwarf/eh.rs
@@ -1,9 +1,9 @@
 //! Parsing of GCC-style Language-Specific Data Area (LSDA)
 //! For details see:
-//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
-//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
-//!   http://www.airs.com/blog/archives/460
-//!   http://www.airs.com/blog/archives/464
+//!  * <http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html>
+//!  * <http://mentorembedded.github.io/cxx-abi/exceptions.pdf>
+//!  * <http://www.airs.com/blog/archives/460>
+//!  * <http://www.airs.com/blog/archives/464>
 //!
 //! A reference implementation may be found in the GCC source tree
 //! (`<root>/libgcc/unwind-c.c` as of this writing).
diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs
index 6b88bab8277ee..14f49bbf48337 100644
--- a/library/panic_unwind/src/gcc.rs
+++ b/library/panic_unwind/src/gcc.rs
@@ -4,9 +4,9 @@
 //! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
 //! documents linked from it.
 //! These are also good reads:
-//!     https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
-//!     http://monoinfinito.wordpress.com/series/exception-handling-in-c/
-//!     http://www.airs.com/blog/index.php?s=exception+frames
+//!  * <https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html>
+//!  * <http://monoinfinito.wordpress.com/series/exception-handling-in-c/>
+//!  * <http://www.airs.com/blog/index.php?s=exception+frames>
 //!
 //! ## A brief summary
 //!
diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs
index 8740393288c48..205524ad84fb7 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/toolstate.rs
@@ -152,7 +152,7 @@ impl Step for ToolStateCheck {
     /// error if there are any.
     ///
     /// This also handles publishing the results to the `history` directory of
-    /// the toolstate repo https://github.com/rust-lang-nursery/rust-toolstate
+    /// the toolstate repo <https://github.com/rust-lang-nursery/rust-toolstate>
     /// if the env var `TOOLSTATE_PUBLISH` is set. Note that there is a
     /// *separate* step of updating the `latest.json` file and creating GitHub
     /// issues and comments in `src/ci/publish_toolstate.sh`, which is only
@@ -162,7 +162,7 @@ impl Step for ToolStateCheck {
     /// The rules for failure are:
     /// * If the PR modifies a tool, the status must be test-pass.
     ///   NOTE: There is intent to change this, see
-    ///   https://github.com/rust-lang/rust/issues/65000.
+    ///   <https://github.com/rust-lang/rust/issues/65000>.
     /// * All "stable" tools must be test-pass on the stable or beta branches.
     /// * During beta promotion week, a PR is not allowed to "regress" a
     ///   stable tool. That is, the status is not allowed to get worse
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index e30da8d56e10f..80f804174ed08 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -32,7 +32,7 @@ macro_rules! t {
 
 /// Reads an environment variable and adds it to dependencies.
 /// Supposed to be used for all variables except those set for build scripts by cargo
-/// https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
+/// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts>
 pub fn tracked_env_var_os<K: AsRef<OsStr> + Display>(key: K) -> Option<OsString> {
     println!("cargo:rerun-if-env-changed={}", key);
     env::var_os(key)
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 5cb7a32cf0cbc..5eca54199d6c8 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -665,7 +665,7 @@ fn run_global_ctxt(
     (krate, ctxt.renderinfo.into_inner(), ctxt.render_options)
 }
 
-/// Due to https://github.com/rust-lang/rust/pull/73566,
+/// Due to <https://github.com/rust-lang/rust/pull/73566>,
 /// the name resolution pass may find errors that are never emitted.
 /// If typeck is called after this happens, then we'll get an ICE:
 /// 'Res::Error found but not reported'. To avoid this, emit the errors now.