From f94f64f5e84e5b55c39be795e4e2a8515bbca517 Mon Sep 17 00:00:00 2001 From: Jacher Date: Sat, 1 Jun 2024 15:44:27 +0000 Subject: [PATCH] new lint: `doc_comment_double_space_linebreak` fix typo change replacement character in example, remove extraneous space from suggested change add additional testcases; check doc comment not from expansion do not lint on macros, add more testcases fix wording, remove commented out code, add additonal testcase uibless fix doc comments, use optional snippets Remove unneeded additional space --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + .../doc/doc_comment_double_space_linebreak.rs | 41 ++++++++ clippy_lints/src/doc/mod.rs | 49 ++++++++++ .../doc_comment_double_space_linebreak.fixed | 94 +++++++++++++++++++ .../doc/doc_comment_double_space_linebreak.rs | 94 +++++++++++++++++++ .../doc_comment_double_space_linebreak.stderr | 76 +++++++++++++++ 7 files changed, 356 insertions(+) create mode 100644 clippy_lints/src/doc/doc_comment_double_space_linebreak.rs create mode 100644 tests/ui/doc/doc_comment_double_space_linebreak.fixed create mode 100644 tests/ui/doc/doc_comment_double_space_linebreak.rs create mode 100644 tests/ui/doc/doc_comment_double_space_linebreak.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 51441ab9fc0d..91608fb8d1e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5571,6 +5571,7 @@ Released 2018-09-13 [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression [`doc_include_without_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_include_without_cfg +[`doc_comment_double_space_linebreak`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_comment_double_space_linebreak [`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation [`doc_link_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_code [`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 0834618499c7..586ee22d9ef7 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -138,6 +138,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO, crate::disallowed_types::DISALLOWED_TYPES_INFO, crate::doc::DOC_INCLUDE_WITHOUT_CFG_INFO, + crate::doc::DOC_COMMENT_DOUBLE_SPACE_LINEBREAK_INFO, crate::doc::DOC_LAZY_CONTINUATION_INFO, crate::doc::DOC_LINK_CODE_INFO, crate::doc::DOC_LINK_WITH_QUOTES_INFO, diff --git a/clippy_lints/src/doc/doc_comment_double_space_linebreak.rs b/clippy_lints/src/doc/doc_comment_double_space_linebreak.rs new file mode 100644 index 000000000000..4c2475ad8d85 --- /dev/null +++ b/clippy_lints/src/doc/doc_comment_double_space_linebreak.rs @@ -0,0 +1,41 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; +use rustc_errors::Applicability; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::DOC_COMMENT_DOUBLE_SPACE_LINEBREAK; + +pub fn check(cx: &LateContext<'_>, collected_breaks: &[Span]) { + let replacements: Vec<_> = collect_doc_replacements(cx, collected_breaks); + + if let Some((&(lo_span, _), &(hi_span, _))) = replacements.first().zip(replacements.last()) { + span_lint_and_then( + cx, + DOC_COMMENT_DOUBLE_SPACE_LINEBREAK, + lo_span.to(hi_span), + "doc comment uses two spaces for a hard line break", + |diag| { + diag.multipart_suggestion( + "replace this double space with a backslash", + replacements, + Applicability::MachineApplicable, + ); + }, + ); + } +} + +fn collect_doc_replacements(cx: &LateContext<'_>, spans: &[Span]) -> Vec<(Span, String)> { + spans + .iter() + .map(|span| { + // we already made sure the snippet exists when collecting spans + let s = snippet_opt(cx, *span).expect("snippet was already validated to exist"); + let after_newline = s.trim_start_matches(' '); + + let new_comment = format!("\\{after_newline}"); + (*span, new_comment) + }) + .collect() +} diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index c742d6abb5c2..d36ef10f4b94 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -7,6 +7,7 @@ use clippy_config::Conf; use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then}; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; +use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::Visitable; use clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args}; @@ -33,6 +34,7 @@ use rustc_span::{Span, sym}; use std::ops::Range; use url::Url; +mod doc_comment_double_space_linebreak; mod include_in_doc_without_cfg; mod link_with_quotes; mod markdown; @@ -567,6 +569,38 @@ declare_clippy_lint! { "link reference defined in list item or quote" } +declare_clippy_lint! { + /// Detects doc comment linebreaks that use double spaces to separate lines, instead of back-slash (`\`). + /// + /// ### Why is this bad? + /// Double spaces, when used as doc comment linebreaks, can be difficult to see, and may + /// accidentally be removed during automatic formatting or manual refactoring. The use of a back-slash (`\`) + /// is clearer in this regard. + /// + /// ### Example + /// The two replacement dots in this example represent a double space. + /// ```no_run + /// /// This command takes two numbers as inputs andΒ·Β· + /// /// adds them together, and then returns the result. + /// fn add(l: i32, r: i32) -> i32 { + /// l + r + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// /// This command takes two numbers as inputs and\ + /// /// adds them together, and then returns the result. + /// fn add(l: i32, r: i32) -> i32 { + /// l + r + /// } + /// ``` + #[clippy::version = "1.80.0"] + pub DOC_COMMENT_DOUBLE_SPACE_LINEBREAK, + pedantic, + "double-space used for doc comment linebreak instead of `\\`" +} + pub struct Documentation { valid_idents: FxHashSet, check_private_items: bool, @@ -598,6 +632,7 @@ impl_lint_pass!(Documentation => [ DOC_OVERINDENTED_LIST_ITEMS, TOO_LONG_FIRST_DOC_PARAGRAPH, DOC_INCLUDE_WITHOUT_CFG, + DOC_COMMENT_DOUBLE_SPACE_LINEBREAK ]); impl EarlyLintPass for Documentation { @@ -737,6 +772,8 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ return None; } + suspicious_doc_comments::check(cx, attrs); + let (fragments, _) = attrs_to_doc_fragments( attrs.iter().filter_map(|attr| { if attr.doc_str_and_comment_kind().is_none() || attr.span().in_external_macro(cx.sess().source_map()) { @@ -894,6 +931,7 @@ fn check_doc<'a, Events: Iterator, Range = Vec::new(); let mut is_first_paragraph = true; let mut containers = Vec::new(); @@ -1069,6 +1107,14 @@ fn check_doc<'a, Events: Iterator, Range { paragraph_range.end = range.end; @@ -1119,6 +1165,9 @@ fn check_doc<'a, Events: Iterator, Range {} } } + + doc_comment_double_space_linebreak::check(cx, &collected_breaks); + headers } diff --git a/tests/ui/doc/doc_comment_double_space_linebreak.fixed b/tests/ui/doc/doc_comment_double_space_linebreak.fixed new file mode 100644 index 000000000000..efcd56809b7e --- /dev/null +++ b/tests/ui/doc/doc_comment_double_space_linebreak.fixed @@ -0,0 +1,94 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] + +#![warn(clippy::doc_comment_double_space_linebreak)] +#![allow(unused, clippy::empty_docs)] + +//! Should warn on double space linebreaks\ +//! in file/module doc comment + +/// Should not warn on single-line doc comments +fn single_line() {} + +/// Should not warn on single-line doc comments +/// split across multiple lines +fn single_line_split() {} + +// Should not warn on normal comments + +// note: cargo fmt can remove double spaces from normal and block comments +// Should not warn on normal comments +// with double spaces at the end of a line + +#[doc = "This is a doc attribute, which should not be linted"] +fn normal_comment() { + /* + Should not warn on block comments + */ + + /* + Should not warn on block comments + with double space at the end of a line + */ +} + +/// Should warn when doc comment uses double space\ +/// as a line-break, even when there are multiple\ +/// in a row +fn double_space_doc_comment() {} + +/// Should not warn when back-slash is used \ +/// as a line-break +fn back_slash_doc_comment() {} + +/// 🌹 are πŸŸ₯\ +/// 🌷 are 🟦\ +/// πŸ“Ž is 😎\ +/// and so are 🫡\ +/// (hopefully no formatting weirdness linting this) +fn multi_byte_chars_tada() {} + +macro_rules! macro_that_makes_function { + () => { + /// Shouldn't lint on this! + /// (hopefully) + fn my_macro_created_function() {} + } +} + +macro_that_makes_function!(); + +// dont lint when its alone on a line +/// +fn alone() {} + +/// | First column | Second column | +/// | ------------ | ------------- | +/// | Not a line | break when | +/// | after a line | in a table | +fn table() {} + +/// ```text +/// It's also not a hard line break if +/// there's two spaces at the end of a +/// line in a block code. +/// ``` +fn codeblock() {} + +/// It's also not a hard line break `if +/// there's` two spaces in the middle of inline code. +fn inline() {} + +/// It's also not a hard line break [when]( +/// https://example.com) in a URL. +fn url() {} + +/// here we mix\ +/// double spaces\ +/// and also\ +/// adding backslash\ +/// to some of them\ +/// to see how that looks +fn mixed() {} + +fn main() {} diff --git a/tests/ui/doc/doc_comment_double_space_linebreak.rs b/tests/ui/doc/doc_comment_double_space_linebreak.rs new file mode 100644 index 000000000000..c64eedc24289 --- /dev/null +++ b/tests/ui/doc/doc_comment_double_space_linebreak.rs @@ -0,0 +1,94 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] + +#![warn(clippy::doc_comment_double_space_linebreak)] +#![allow(unused, clippy::empty_docs)] + +//! Should warn on double space linebreaks +//! in file/module doc comment + +/// Should not warn on single-line doc comments +fn single_line() {} + +/// Should not warn on single-line doc comments +/// split across multiple lines +fn single_line_split() {} + +// Should not warn on normal comments + +// note: cargo fmt can remove double spaces from normal and block comments +// Should not warn on normal comments +// with double spaces at the end of a line + +#[doc = "This is a doc attribute, which should not be linted"] +fn normal_comment() { + /* + Should not warn on block comments + */ + + /* + Should not warn on block comments + with double space at the end of a line + */ +} + +/// Should warn when doc comment uses double space +/// as a line-break, even when there are multiple +/// in a row +fn double_space_doc_comment() {} + +/// Should not warn when back-slash is used \ +/// as a line-break +fn back_slash_doc_comment() {} + +/// 🌹 are πŸŸ₯ +/// 🌷 are 🟦 +/// πŸ“Ž is 😎 +/// and so are 🫡 +/// (hopefully no formatting weirdness linting this) +fn multi_byte_chars_tada() {} + +macro_rules! macro_that_makes_function { + () => { + /// Shouldn't lint on this! + /// (hopefully) + fn my_macro_created_function() {} + } +} + +macro_that_makes_function!(); + +// dont lint when its alone on a line +/// +fn alone() {} + +/// | First column | Second column | +/// | ------------ | ------------- | +/// | Not a line | break when | +/// | after a line | in a table | +fn table() {} + +/// ```text +/// It's also not a hard line break if +/// there's two spaces at the end of a +/// line in a block code. +/// ``` +fn codeblock() {} + +/// It's also not a hard line break `if +/// there's` two spaces in the middle of inline code. +fn inline() {} + +/// It's also not a hard line break [when]( +/// https://example.com) in a URL. +fn url() {} + +/// here we mix +/// double spaces\ +/// and also +/// adding backslash\ +/// to some of them +/// to see how that looks +fn mixed() {} + +fn main() {} diff --git a/tests/ui/doc/doc_comment_double_space_linebreak.stderr b/tests/ui/doc/doc_comment_double_space_linebreak.stderr new file mode 100644 index 000000000000..4c77f8e15034 --- /dev/null +++ b/tests/ui/doc/doc_comment_double_space_linebreak.stderr @@ -0,0 +1,76 @@ +error: doc comment uses two spaces for a hard line break + --> tests/ui/doc/doc_comment_double_space_linebreak.rs:7:43 + | +LL | //! Should warn on double space linebreaks + | ___________________________________________^ +LL | | //! in file/module doc comment + | |____^ + | + = note: `-D clippy::doc-comment-double-space-linebreak` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_comment_double_space_linebreak)]` +help: replace this double space with a backslash + | +LL ~ //! Should warn on double space linebreaks\ +LL ~ //! in file/module doc comment + | + +error: doc comment uses two spaces for a hard line break + --> tests/ui/doc/doc_comment_double_space_linebreak.rs:35:51 + | +LL | /// Should warn when doc comment uses double space + | ___________________________________________________^ +LL | | /// as a line-break, even when there are multiple +LL | | /// in a row + | |____^ + | +help: replace this double space with a backslash + | +LL ~ /// Should warn when doc comment uses double space\ +LL ~ /// as a line-break, even when there are multiple\ +LL ~ /// in a row + | + +error: doc comment uses two spaces for a hard line break + --> tests/ui/doc/doc_comment_double_space_linebreak.rs:44:12 + | +LL | /// 🌹 are πŸŸ₯ + | ______________^ +LL | | /// 🌷 are 🟦 +LL | | /// πŸ“Ž is 😎 +LL | | /// and so are 🫡 +LL | | /// (hopefully no formatting weirdness linting this) + | |____^ + | +help: replace this double space with a backslash + | +LL ~ /// 🌹 are πŸŸ₯\ +LL ~ /// 🌷 are 🟦\ +LL ~ /// πŸ“Ž is 😎\ +LL ~ /// and so are 🫡\ +LL ~ /// (hopefully no formatting weirdness linting this) + | + +error: doc comment uses two spaces for a hard line break + --> tests/ui/doc/doc_comment_double_space_linebreak.rs:86:16 + | +LL | /// here we mix + | ________________^ +LL | | /// double spaces\ +LL | | /// and also +LL | | /// adding backslash\ +LL | | /// to some of them +LL | | /// to see how that looks + | |____^ + | +help: replace this double space with a backslash + | +LL ~ /// here we mix\ +LL ~ /// double spaces\ +LL ~ /// and also\ +LL ~ /// adding backslash\ +LL ~ /// to some of them\ +LL ~ /// to see how that looks + | + +error: aborting due to 4 previous errors +