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