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;
add_lint_group!(
"rustdoc",
- URL_IMPROVEMENTS,
+ NON_AUTOLINKS,
BROKEN_INTRA_DOC_LINKS,
PRIVATE_INTRA_DOC_LINKS,
INVALID_CODEBLOCK_ATTRIBUTES,
}
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"
}
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,
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)]
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:
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
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
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| {
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;
COLLECT_TRAIT_IMPLS,
CALCULATE_DOC_COVERAGE,
CHECK_INVALID_HTML_TAGS,
- CHECK_URL_IMPROVEMENTS,
+ CHECK_NON_AUTOLINKS,
];
/// The list of passes run by default.
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.
--- /dev/null
+use super::{span_of_attrs, Pass};
+use crate::clean::*;
+use crate::core::DocContext;
+use crate::fold::DocFolder;
+use crate::html::markdown::opts;
+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_NON_AUTOLINKS: Pass = Pass {
+ name: "check-non-autolinks",
+ run: check_non_autolinks,
+ description: "detects URLS that could be written using angle brackets",
+};
+
+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,63}", // root domain
+ r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)" // optional query or url fragments
+);
+
+struct NonAutolinksLinter<'a, 'tcx> {
+ cx: &'a DocContext<'tcx>,
+ regex: Regex,
+}
+
+impl<'a, 'tcx> NonAutolinksLinter<'a, 'tcx> {
+ fn new(cx: &'a DocContext<'tcx>) -> Self {
+ Self { 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 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 },
+ );
+ }
+ }
+}
+
+pub fn check_non_autolinks(krate: Crate, cx: &DocContext<'_>) -> Crate {
+ if !UnstableFeatures::from_environment().is_nightly_build() {
+ krate
+ } else {
+ let mut coll = NonAutolinksLinter::new(cx);
+
+ coll.fold_crate(krate)
+ }
+}
+
+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,
+ 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 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::NON_AUTOLINKS, hir_id, sp, |lint| {
+ lint.build(msg)
+ .span_suggestion(
+ sp,
+ "use an automatic link instead",
+ format!("<{}>", url),
+ Applicability::MachineApplicable,
+ )
+ .emit()
+ });
+ };
+
+ let mut p = Parser::new_ext(&dox, opts()).into_offset_iter();
+
+ while let Some((event, range)) = p.next() {
+ match event {
+ Event::Start(Tag::Link(kind, _, _)) => {
+ 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 && self.regex.is_match(&url)
+ {
+ report_diag(
+ self.cx,
+ "unneeded long form for URL",
+ &url,
+ range,
+ );
+ }
+ break;
+ }
+ Event::Text(s) 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,
+ _ => {}
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+
+ self.fold_item_recur(item)
+ }
+}
+++ /dev/null
-use super::{span_of_attrs, Pass};
-use crate::clean::*;
-use crate::core::DocContext;
-use crate::fold::DocFolder;
-use crate::html::markdown::opts;
-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_URL_IMPROVEMENTS: Pass = Pass {
- name: "check-url-improvements",
- run: check_url_improvements,
- description: "detects URLS that could be written using angle brackets",
-};
-
-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,63}", // root domain
- r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)" // optional query or url fragments
-);
-
-struct UrlImprovementsLinter<'a, 'tcx> {
- cx: &'a DocContext<'tcx>,
- regex: Regex,
-}
-
-impl<'a, 'tcx> UrlImprovementsLinter<'a, 'tcx> {
- fn new(cx: &'a DocContext<'tcx>) -> Self {
- UrlImprovementsLinter { 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 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 },
- );
- }
- }
-}
-
-pub fn check_url_improvements(krate: Crate, cx: &DocContext<'_>) -> Crate {
- if !UnstableFeatures::from_environment().is_nightly_build() {
- krate
- } else {
- let mut coll = UrlImprovementsLinter::new(cx);
-
- coll.fold_crate(krate)
- }
-}
-
-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,
- 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 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::URL_IMPROVEMENTS, hir_id, sp, |lint| {
- lint.build(msg)
- .span_suggestion(
- sp,
- "use an automatic link instead",
- format!("<{}>", url),
- Applicability::MachineApplicable,
- )
- .emit()
- });
- };
-
- let mut p = Parser::new_ext(&dox, opts()).into_offset_iter();
-
- while let Some((event, range)) = p.next() {
- match event {
- Event::Start(Tag::Link(kind, _, _)) => {
- 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 && self.regex.matches(url) {
- report_diag(
- self.cx,
- "unneeded long form for URL",
- &url,
- range,
- );
- }
- break;
- }
- Event::Text(s) 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,
- _ => {}
- }
- }
- }
- _ => {}
- }
- }
- }
-
- self.fold_item_recur(item)
- }
-}
-#![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() {}
/// [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() {}
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