Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lint for overindented list items in docs #13711

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,11 @@ line. (You can swap `clippy::all` with the specific lint category you are target
You can add options to your code to `allow`/`warn`/`deny` Clippy lints:

* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`).
Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html).
Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html).

* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`,
`#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive
lints prone to false positives.
`#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive
lints prone to false positives.

* only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.)

Expand Down
78 changes: 49 additions & 29 deletions clippy_lints/src/doc/lazy_continuation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,41 +28,15 @@ pub(super) fn check(
return;
}

// Handle blockquotes.
let ccount = doc[range.clone()].chars().filter(|c| *c == '>').count();
let blockquote_level = containers
.iter()
.filter(|c| matches!(c, super::Container::Blockquote))
.count();
let lcount = doc[range.clone()].chars().filter(|c| *c == ' ').count();
let list_indentation = containers
.iter()
.map(|c| {
if let super::Container::List(indent) = c {
*indent
} else {
0
}
})
.sum();
if ccount < blockquote_level || lcount < list_indentation {
let msg = if ccount < blockquote_level {
"doc quote line without `>` marker"
} else {
"doc list item without indentation"
};
if ccount < blockquote_level {
let msg = "doc quote line without `>` marker";
span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| {
if ccount == 0 && blockquote_level == 0 {
// simpler suggestion style for indentation
let indent = list_indentation - lcount;
diag.span_suggestion_verbose(
span.shrink_to_hi(),
"indent this line",
std::iter::repeat(" ").take(indent).join(""),
Applicability::MaybeIncorrect,
);
diag.help("if this is supposed to be its own paragraph, add a blank line");
return;
}
let mut doc_start_range = &doc[range];
let mut suggested = String::new();
for c in containers {
Expand All @@ -89,5 +63,51 @@ pub(super) fn check(
);
diag.help("if this not intended to be a quote at all, escape it with `\\>`");
});
return;
}

if ccount != 0 || blockquote_level != 0 {
// If this doc is a blockquote, we don't go further.
return;
}

// Handle list items
let lcount = doc[range.clone()].chars().filter(|c| *c == ' ').count();
let list_indentation = containers
.iter()
.map(|c| {
if let super::Container::List(indent) = c {
*indent
} else {
0
}
})
.sum();
if lcount != list_indentation {
let msg = if lcount < list_indentation {
"doc list item without indentation"
} else {
"doc list item overindented"
};
span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| {
if lcount < list_indentation {
// simpler suggestion style for indentation
let indent = list_indentation - lcount;
diag.span_suggestion_verbose(
span.shrink_to_hi(),
"indent this line",
std::iter::repeat(" ").take(indent).join(""),
Applicability::MaybeIncorrect,
);
} else {
diag.span_suggestion_verbose(
span,
"indent this line",
std::iter::repeat(" ").take(list_indentation).join(""),
Applicability::MaybeIncorrect,
);
}
diag.help("if this is supposed to be its own paragraph, add a blank line");
});
}
}
40 changes: 23 additions & 17 deletions tests/ui/doc/doc_lazy_list.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,32 @@ fn seven() {}
///
/// # Arguments
/// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors
/// to set up. Example:
/// to set up. Example:
/// 'protocol_descriptors': [
//~^ ERROR: doc list item without indentation
/// {
/// 'protocol': 25, # u64 Representation of ProtocolIdentifier::AVDTP
/// 'params': [
/// {
/// 'data': 0x0103 # to indicate 1.3
/// },
/// {
/// 'data': 0x0105 # to indicate 1.5
/// }
/// {
/// 'protocol': 25, # u64 Representation of ProtocolIdentifier::AVDTP
/// 'params': [
/// {
/// 'data': 0x0103 # to indicate 1.3
/// },
/// {
/// 'data': 0x0105 # to indicate 1.5
/// }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to add error annotations here for consistency, like has already been done with it having no indentation.

/// ]
/// },
/// {
/// 'protocol': 1, # u64 Representation of ProtocolIdentifier::SDP
/// 'params': [{
/// 'data': 0x0019
/// }]
/// }
/// },
/// {
/// 'protocol': 1, # u64 Representation of ProtocolIdentifier::SDP
/// 'params': [{
/// 'data': 0x0019
/// }]
/// }
/// ]
//~^ ERROR: doc list item without indentation
fn eight() {}

#[rustfmt::skip]
/// - first line
/// second line
//~^ ERROR: doc list item overindented
fn nine() {}
6 changes: 6 additions & 0 deletions tests/ui/doc/doc_lazy_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,9 @@ fn seven() {}
/// ]
//~^ ERROR: doc list item without indentation
fn eight() {}

#[rustfmt::skip]
/// - first line
/// second line
//~^ ERROR: doc list item overindented
fn nine() {}
Loading