Skip to content

Commit f33f47d

Browse files
committed
Add new lint doc_overindented_list_items
Add a new lint `doc_overindented_list_items` to detect and fix list items in docs that are overindented. For example, ```rs /// - first line /// second line fn foo() {} ``` this would be fixed to: ```rs /// - first line /// second line fn foo() {} ``` This lint improves readabiliy and consistency in doc.
1 parent 592fd34 commit f33f47d

11 files changed

+238
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5492,6 +5492,7 @@ Released 2018-09-13
54925492
[`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes
54935493
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
54945494
[`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs
5495+
[`doc_overindented_list_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items
54955496
[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
54965497
[`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
54975498
[`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,11 @@ line. (You can swap `clippy::all` with the specific lint category you are target
159159
You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
160160

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

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

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

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
142142
crate::doc::DOC_LINK_WITH_QUOTES_INFO,
143143
crate::doc::DOC_MARKDOWN_INFO,
144144
crate::doc::DOC_NESTED_REFDEFS_INFO,
145+
crate::doc::DOC_OVERINDENTED_LIST_ITEMS_INFO,
145146
crate::doc::EMPTY_DOCS_INFO,
146147
crate::doc::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
147148
crate::doc::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,

clippy_lints/src/doc/mod.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![allow(clippy::lint_without_lint_pass)]
22

33
mod lazy_continuation;
4+
mod overindented_list_items;
45
mod too_long_first_doc_paragraph;
56

67
use clippy_config::Conf;
@@ -429,6 +430,39 @@ declare_clippy_lint! {
429430
"require every line of a paragraph to be indented and marked"
430431
}
431432

433+
declare_clippy_lint! {
434+
/// ### What it does
435+
///
436+
/// Detects overindented list items in doc comments where the continuation
437+
/// lines are indented more than necessary.
438+
///
439+
/// ### Why is this bad?
440+
///
441+
/// Overindented list items in doc comments can lead to inconsistent and
442+
/// poorly formatted documentation when rendered. Excessive indentation may
443+
/// cause the text to be misinterpreted as a nested list item or code block,
444+
/// affecting readability and the overall structure of the documentation.
445+
///
446+
/// ### Example
447+
///
448+
/// ```no_run
449+
/// /// - This is the first item in a list
450+
/// /// and this line is overindented.
451+
/// # fn foo() {}
452+
/// ```
453+
///
454+
/// Fixes this into:
455+
/// ```no_run
456+
/// /// - This is the first item in a list
457+
/// /// and this line is overindented.
458+
/// # fn foo() {}
459+
/// ```
460+
#[clippy::version = "1.80.0"]
461+
pub DOC_OVERINDENTED_LIST_ITEMS,
462+
style,
463+
"ensure list items are not overindented"
464+
}
465+
432466
declare_clippy_lint! {
433467
/// ### What it does
434468
/// Checks if the first paragraph in the documentation of items listed in the module page is too long.
@@ -618,6 +652,7 @@ impl_lint_pass!(Documentation => [
618652
SUSPICIOUS_DOC_COMMENTS,
619653
EMPTY_DOCS,
620654
DOC_LAZY_CONTINUATION,
655+
DOC_OVERINDENTED_LIST_ITEMS,
621656
EMPTY_LINE_AFTER_OUTER_ATTR,
622657
EMPTY_LINE_AFTER_DOC_COMMENTS,
623658
TOO_LONG_FIRST_DOC_PARAGRAPH,
@@ -1004,11 +1039,19 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
10041039
&& !in_footnote_definition
10051040
&& !matches!(next_event, End(_))
10061041
{
1042+
let span = Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent());
10071043
lazy_continuation::check(
10081044
cx,
10091045
doc,
10101046
range.end..next_range.start,
1011-
Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()),
1047+
span,
1048+
&containers[..],
1049+
);
1050+
overindented_list_items::check(
1051+
cx,
1052+
doc,
1053+
range.end..next_range.start,
1054+
span,
10121055
&containers[..],
10131056
);
10141057
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use clippy_utils::diagnostics::span_lint_and_then;
2+
use itertools::Itertools;
3+
use rustc_errors::Applicability;
4+
use rustc_lint::LateContext;
5+
use rustc_span::Span;
6+
use std::ops::Range;
7+
8+
use super::DOC_OVERINDENTED_LIST_ITEMS;
9+
10+
pub(super) fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, span: Span, containers: &[super::Container]) {
11+
if doc[range.clone()].contains('\t') {
12+
// We don't do tab stops correctly.
13+
return;
14+
}
15+
16+
let is_blockquote = containers.iter().any(|c| matches!(c, super::Container::Blockquote));
17+
if is_blockquote {
18+
// If this doc is a blockquote, we don't go further.
19+
return;
20+
}
21+
22+
let leading_spaces = doc[range].chars().filter(|c| *c == ' ').count();
23+
let list_indentation = containers
24+
.iter()
25+
.map(|c| {
26+
if let super::Container::List(indent) = c {
27+
*indent
28+
} else {
29+
0
30+
}
31+
})
32+
.sum();
33+
34+
if leading_spaces > list_indentation {
35+
span_lint_and_then(
36+
cx,
37+
DOC_OVERINDENTED_LIST_ITEMS,
38+
span,
39+
"doc list item overindented",
40+
|diag| {
41+
diag.span_suggestion_verbose(
42+
span,
43+
"remove unnecessary spaces",
44+
std::iter::repeat(" ").take(list_indentation).join(""),
45+
Applicability::MaybeIncorrect,
46+
);
47+
},
48+
);
49+
}
50+
}

tests/ui/doc/doc_lazy_list.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![warn(clippy::doc_lazy_continuation)]
2+
#![allow(clippy::doc_overindented_list_items)]
23

34
/// 1. nest here
45
/// lazy continuation

tests/ui/doc/doc_lazy_list.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![warn(clippy::doc_lazy_continuation)]
2+
#![allow(clippy::doc_overindented_list_items)]
23

34
/// 1. nest here
45
/// lazy continuation

tests/ui/doc/doc_lazy_list.stderr

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: doc list item without indentation
2-
--> tests/ui/doc/doc_lazy_list.rs:4:5
2+
--> tests/ui/doc/doc_lazy_list.rs:5:5
33
|
44
LL | /// lazy continuation
55
| ^
@@ -13,7 +13,7 @@ LL | /// lazy continuation
1313
| +++
1414

1515
error: doc list item without indentation
16-
--> tests/ui/doc/doc_lazy_list.rs:9:5
16+
--> tests/ui/doc/doc_lazy_list.rs:10:5
1717
|
1818
LL | /// lazy list continuations don't make warnings with this lint
1919
| ^
@@ -25,7 +25,7 @@ LL | /// lazy list continuations don't make warnings with this lint
2525
| +++
2626

2727
error: doc list item without indentation
28-
--> tests/ui/doc/doc_lazy_list.rs:11:5
28+
--> tests/ui/doc/doc_lazy_list.rs:12:5
2929
|
3030
LL | /// because they don't have the
3131
| ^
@@ -37,7 +37,7 @@ LL | /// because they don't have the
3737
| +++
3838

3939
error: doc list item without indentation
40-
--> tests/ui/doc/doc_lazy_list.rs:16:5
40+
--> tests/ui/doc/doc_lazy_list.rs:17:5
4141
|
4242
LL | /// lazy continuation
4343
| ^
@@ -49,7 +49,7 @@ LL | /// lazy continuation
4949
| ++++
5050

5151
error: doc list item without indentation
52-
--> tests/ui/doc/doc_lazy_list.rs:21:5
52+
--> tests/ui/doc/doc_lazy_list.rs:22:5
5353
|
5454
LL | /// lazy list continuations don't make warnings with this lint
5555
| ^
@@ -61,7 +61,7 @@ LL | /// lazy list continuations don't make warnings with this lint
6161
| ++++
6262

6363
error: doc list item without indentation
64-
--> tests/ui/doc/doc_lazy_list.rs:23:5
64+
--> tests/ui/doc/doc_lazy_list.rs:24:5
6565
|
6666
LL | /// because they don't have the
6767
| ^
@@ -73,7 +73,7 @@ LL | /// because they don't have the
7373
| ++++
7474

7575
error: doc list item without indentation
76-
--> tests/ui/doc/doc_lazy_list.rs:28:5
76+
--> tests/ui/doc/doc_lazy_list.rs:29:5
7777
|
7878
LL | /// lazy continuation
7979
| ^
@@ -85,7 +85,7 @@ LL | /// lazy continuation
8585
| ++++
8686

8787
error: doc list item without indentation
88-
--> tests/ui/doc/doc_lazy_list.rs:33:5
88+
--> tests/ui/doc/doc_lazy_list.rs:34:5
8989
|
9090
LL | /// this will warn on the lazy continuation
9191
| ^
@@ -97,7 +97,7 @@ LL | /// this will warn on the lazy continuation
9797
| ++++++
9898

9999
error: doc list item without indentation
100-
--> tests/ui/doc/doc_lazy_list.rs:35:5
100+
--> tests/ui/doc/doc_lazy_list.rs:36:5
101101
|
102102
LL | /// and so should this
103103
| ^^^^
@@ -109,7 +109,7 @@ LL | /// and so should this
109109
| ++
110110

111111
error: doc list item without indentation
112-
--> tests/ui/doc/doc_lazy_list.rs:56:5
112+
--> tests/ui/doc/doc_lazy_list.rs:57:5
113113
|
114114
LL | /// 'protocol_descriptors': [
115115
| ^
@@ -121,7 +121,7 @@ LL | /// 'protocol_descriptors': [
121121
| +
122122

123123
error: doc list item without indentation
124-
--> tests/ui/doc/doc_lazy_list.rs:75:5
124+
--> tests/ui/doc/doc_lazy_list.rs:76:5
125125
|
126126
LL | /// ]
127127
| ^
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#![warn(clippy::doc_overindented_list_items)]
2+
3+
#[rustfmt::skip]
4+
/// - first list item
5+
/// overindented line
6+
//~^ ERROR: doc list item overindented
7+
/// this is overindented line too
8+
//~^ ERROR: doc list item overindented
9+
/// - second list item
10+
fn foo() {}
11+
12+
#[rustfmt::skip]
13+
/// - first list item
14+
/// overindented line
15+
//~^ ERROR: doc list item overindented
16+
/// this is overindented line too
17+
//~^ ERROR: doc list item overindented
18+
/// - second list item
19+
fn bar() {}
20+
21+
#[rustfmt::skip]
22+
/// * first list item
23+
/// overindented line
24+
//~^ ERROR: doc list item overindented
25+
/// this is overindented line too
26+
//~^ ERROR: doc list item overindented
27+
/// * second list item
28+
fn baz() {}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#![warn(clippy::doc_overindented_list_items)]
2+
3+
#[rustfmt::skip]
4+
/// - first list item
5+
/// overindented line
6+
//~^ ERROR: doc list item overindented
7+
/// this is overindented line too
8+
//~^ ERROR: doc list item overindented
9+
/// - second list item
10+
fn foo() {}
11+
12+
#[rustfmt::skip]
13+
/// - first list item
14+
/// overindented line
15+
//~^ ERROR: doc list item overindented
16+
/// this is overindented line too
17+
//~^ ERROR: doc list item overindented
18+
/// - second list item
19+
fn bar() {}
20+
21+
#[rustfmt::skip]
22+
/// * first list item
23+
/// overindented line
24+
//~^ ERROR: doc list item overindented
25+
/// this is overindented line too
26+
//~^ ERROR: doc list item overindented
27+
/// * second list item
28+
fn baz() {}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
error: doc list item overindented
2+
--> tests/ui/doc/doc_overindented_list_items.rs:5:5
3+
|
4+
LL | /// overindented line
5+
| ^^^^^^^
6+
|
7+
= note: `-D clippy::doc-overindented-list-items` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::doc_overindented_list_items)]`
9+
help: remove unnecessary spaces
10+
|
11+
LL | /// overindented line
12+
| ++
13+
14+
error: doc list item overindented
15+
--> tests/ui/doc/doc_overindented_list_items.rs:7:5
16+
|
17+
LL | /// this is overindented line too
18+
| ^^^^^
19+
|
20+
help: remove unnecessary spaces
21+
|
22+
LL | /// this is overindented line too
23+
| ++
24+
25+
error: doc list item overindented
26+
--> tests/ui/doc/doc_overindented_list_items.rs:14:7
27+
|
28+
LL | /// overindented line
29+
| ^^^^^
30+
|
31+
help: remove unnecessary spaces
32+
|
33+
LL | /// overindented line
34+
| ++
35+
36+
error: doc list item overindented
37+
--> tests/ui/doc/doc_overindented_list_items.rs:16:7
38+
|
39+
LL | /// this is overindented line too
40+
| ^^^
41+
|
42+
help: remove unnecessary spaces
43+
|
44+
LL | /// this is overindented line too
45+
| ++
46+
47+
error: doc list item overindented
48+
--> tests/ui/doc/doc_overindented_list_items.rs:23:5
49+
|
50+
LL | /// overindented line
51+
| ^^^^^^^
52+
|
53+
help: remove unnecessary spaces
54+
|
55+
LL | /// overindented line
56+
| ++
57+
58+
error: doc list item overindented
59+
--> tests/ui/doc/doc_overindented_list_items.rs:25:5
60+
|
61+
LL | /// this is overindented line too
62+
| ^^^^^
63+
|
64+
help: remove unnecessary spaces
65+
|
66+
LL | /// this is overindented line too
67+
| ++
68+
69+
error: aborting due to 6 previous errors
70+

0 commit comments

Comments
 (0)