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
This commit is contained in:
Jacher 2024-06-01 15:44:27 +00:00 committed by xFrednet
parent 1419ac2982
commit f94f64f5e8
No known key found for this signature in database
GPG key ID: E126C23F63C8907A
7 changed files with 356 additions and 0 deletions

View file

@ -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

View file

@ -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,

View file

@ -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()
}

View file

@ -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<String>,
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<String>, 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<Item = (pulldown_cmark::Event<'a>, Range<usize
let mut paragraph_range = 0..0;
let mut code_level = 0;
let mut blockquote_level = 0;
let mut collected_breaks: Vec<Span> = Vec::new();
let mut is_first_paragraph = true;
let mut containers = Vec::new();
@ -1069,6 +1107,14 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
&containers[..],
);
}
if let Some(span) = fragments.span(cx, range.clone())
&& !span.from_expansion()
&& let Some(snippet) = snippet_opt(cx, span)
&& !snippet.trim().starts_with('\\')
&& event == HardBreak {
collected_breaks.push(span);
}
},
Text(text) => {
paragraph_range.end = range.end;
@ -1119,6 +1165,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
FootnoteReference(_) => {}
}
}
doc_comment_double_space_linebreak::check(cx, &collected_breaks);
headers
}

View file

@ -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() {}

View file

@ -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() {}

View file

@ -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