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