From 29803670304bfad1c46502dfb71af6dd12953b5d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez 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 { + 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 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 `` instead + +error: Unneeded long form for URL + --> foo.rs:5:5 + | +5 | /// [http://b.com] + | ^^^^^^^^^^^^^^ + | + = help: Try with `` instead +``` From 6bc8965c418e90c135ee90554108bd0bdbe0a8d8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez 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 `` instead + +error: Unneeded long form for URL + --> $DIR/automatic-links.rs:5:5 + | +LL | /// [http://b.com] + | ^^^^^^^^^^^^^^ + | + = help: Try with `` instead + +error: aborting due to 2 previous errors + From f467b8d77c7b991ce214e0e5ff9b13c01812c8a7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez 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: `` | note: the lint level is defined here --> foo.rs:1:9 | -1 | #![deny(automatic_links)] +1 | #![warn(automatic_links)] | ^^^^^^^^^^^^^^^ - = help: Try with `` 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: `` + +warning: unneeded long form for URL --> foo.rs:5:5 | 5 | /// [http://b.com] - | ^^^^^^^^^^^^^^ - | - = help: Try with `` instead + | ^^^^^^^^^^^^^^ help: use an automatic link instead: `` ``` 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, + 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() }, + ) + } + } + } + } } } @@ -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| { + 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() {} + +/// /// [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: `` | note: the lint level is defined here --> $DIR/automatic-links.rs:1:9 | LL | #![deny(automatic_links)] | ^^^^^^^^^^^^^^^ - = help: Try with `` 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: `` + +error: won't be a link as is + --> $DIR/automatic-links.rs:13:5 | - = help: Try with `` instead +LL | /// https://somewhere.com?hello=12 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` -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 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: `` | -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, 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 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() {} /// @@ -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: `` -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 From 55b4d21e25a63ad36c5e6dcfd9106ae44ba6c75e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez 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 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: 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 . 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 . //! //! 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 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: //! //! 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: //! //! 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 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 { 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 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: `` +1 | /// http://example.org + | ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` | + = 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: `` +2 | /// [http://example.com](http://example.com) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` -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: `` +3 | /// [http://example.net] + | ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` ``` From 1fb404bebe9e7d228859a26b7e40340438d0c427 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez 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: `` | 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` 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: `` From 6be97e225099cc59dc63f6fc01af7c525d0334df Mon Sep 17 00:00:00 2001 From: Guillaume Gomez 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 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: `` | - = 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 { 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: `` +LL | /// [http://aa.com](http://aa.com) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` | 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: `` +LL | /// [http://bb.com] + | ^^^^^^^^^^^^^^^ help: use an automatic link instead: `` 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 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 /// 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 /// 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 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 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 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 + /// * + /// * + /// * /// /// 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 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, &Option]`. Empty vectors are not stored. /// /// See: - /// https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions + /// pat_adjustments: ItemLocalMap>>, /// 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/ + /// /// /// 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 +//! ), 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 +//! //! 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 . /// 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 + /// 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. +/// . /// 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 ). /// Instead, we fudge a little by introducing a new type parameter `U` such that /// `Self: Unsize` 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 ). /// 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 +//! * +//! * +//! * +//! * //! //! A reference implementation may be found in the GCC source tree //! (`/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 +//! * +//! * +//! * //! //! ## 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 /// 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. + /// . /// * 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 +/// pub fn tracked_env_var_os + Display>(key: K) -> Option { 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 , /// 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.