Skip to content

Commit 2f80536

Browse files
committed
Auto merge of #13002 - notriddle:notriddle/blank-line, r=Manishearth
doc_lazy_continuation: blank comment line for gap This change addresses cases where doc comments are separated by blank lines, comments, or non-doc-comment attributes, like this: ```rust /// - first line // not part of doc comment /// second line ``` Before this commit, Clippy gave a pedantically-correct warning about how you needed to indent the second line. This is unlikely to be what the user intends, and has been described as a "false positive." Since Clippy is warning you about a highly unintuitive behavior [that Rustdoc actually has](https://notriddle.com/rustdoc-html-demo-11/lazy-continuation-bad/test_dingus_2024/constant.D.html), we definitely want it to output *something*, but the suggestion to indent was poor. Fixes #12917 ``` changelog: [`doc_lazy_continuation`]: suggest blank line for likely-unintended lazy continuations ```
2 parents 68a799a + 6de8782 commit 2f80536

11 files changed

+246
-68
lines changed

clippy_lints/src/doc/lazy_continuation.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub(super) fn check(
2222
range: Range<usize>,
2323
mut span: Span,
2424
containers: &[super::Container],
25+
line_break_span: Span,
2526
) {
2627
if doc[range.clone()].contains('\t') {
2728
// We don't do tab stops correctly.
@@ -46,11 +47,35 @@ pub(super) fn check(
4647
.sum();
4748
if ccount < blockquote_level || lcount < list_indentation {
4849
let msg = if ccount < blockquote_level {
49-
"doc quote missing `>` marker"
50+
"doc quote line without `>` marker"
5051
} else {
51-
"doc list item missing indentation"
52+
"doc list item without indentation"
5253
};
5354
span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| {
55+
let snippet = clippy_utils::source::snippet(cx, line_break_span, "");
56+
if snippet.chars().filter(|&c| c == '\n').count() > 1
57+
&& let Some(doc_comment_start) = snippet.rfind('\n')
58+
&& let doc_comment = snippet[doc_comment_start..].trim()
59+
&& (doc_comment == "///" || doc_comment == "//!")
60+
{
61+
// suggest filling in a blank line
62+
diag.span_suggestion_with_style(
63+
line_break_span.shrink_to_lo(),
64+
"if this should be its own paragraph, add a blank doc comment line",
65+
format!("\n{doc_comment}"),
66+
Applicability::MaybeIncorrect,
67+
SuggestionStyle::ShowAlways,
68+
);
69+
if ccount > 0 || blockquote_level > 0 {
70+
diag.help("if this not intended to be a quote at all, escape it with `\\>`");
71+
} else {
72+
let indent = list_indentation - lcount;
73+
diag.help(format!(
74+
"if this is intended to be part of the list, indent {indent} spaces"
75+
));
76+
}
77+
return;
78+
}
5479
if ccount == 0 && blockquote_level == 0 {
5580
// simpler suggestion style for indentation
5681
let indent = list_indentation - lcount;

clippy_lints/src/doc/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
762762
range.end..next_range.start,
763763
Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()),
764764
&containers[..],
765+
span,
765766
);
766767
}
767768
},
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// https://github.com/rust-lang/rust-clippy/issues/12917
2+
#![warn(clippy::doc_lazy_continuation)]
3+
4+
/// This is a constant.
5+
///
6+
/// The meaning of which should not be explained.
7+
pub const A: i32 = 42;
8+
9+
/// This is another constant, no longer used.
10+
///
11+
/// This block of documentation has a long
12+
/// explanation and derivation to explain
13+
/// why it is what it is, and how it's used.
14+
///
15+
/// It is left here for historical reasons, and
16+
/// for reference.
17+
///
18+
/// Reasons it's great:
19+
/// - First reason
20+
/// - Second reason
21+
///
22+
//pub const B: i32 = 1337;
23+
24+
/// This is yet another constant.
25+
///
26+
/// This has a similar fate as `B`.
27+
///
28+
/// Reasons it's useful:
29+
/// 1. First reason
30+
/// 2. Second reason
31+
///
32+
//pub const C: i32 = 8008;
33+
34+
/// This is still in use.
35+
pub const D: i32 = 20;
36+
37+
/// > blockquote code path
38+
///
39+
40+
/// bottom text
41+
pub const E: i32 = 20;
42+
43+
/// > blockquote code path
44+
///
45+
#[repr(C)]
46+
/// bottom text
47+
pub struct Foo(i32);

tests/ui/doc/doc_lazy_blank_line.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// https://github.com/rust-lang/rust-clippy/issues/12917
2+
#![warn(clippy::doc_lazy_continuation)]
3+
4+
/// This is a constant.
5+
///
6+
/// The meaning of which should not be explained.
7+
pub const A: i32 = 42;
8+
9+
/// This is another constant, no longer used.
10+
///
11+
/// This block of documentation has a long
12+
/// explanation and derivation to explain
13+
/// why it is what it is, and how it's used.
14+
///
15+
/// It is left here for historical reasons, and
16+
/// for reference.
17+
///
18+
/// Reasons it's great:
19+
/// - First reason
20+
/// - Second reason
21+
//pub const B: i32 = 1337;
22+
23+
/// This is yet another constant.
24+
///
25+
/// This has a similar fate as `B`.
26+
///
27+
/// Reasons it's useful:
28+
/// 1. First reason
29+
/// 2. Second reason
30+
//pub const C: i32 = 8008;
31+
32+
/// This is still in use.
33+
pub const D: i32 = 20;
34+
35+
/// > blockquote code path
36+
37+
/// bottom text
38+
pub const E: i32 = 20;
39+
40+
/// > blockquote code path
41+
#[repr(C)]
42+
/// bottom text
43+
pub struct Foo(i32);
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
error: doc list item without indentation
2+
--> tests/ui/doc/doc_lazy_blank_line.rs:23:5
3+
|
4+
LL | /// This is yet another constant.
5+
| ^
6+
|
7+
= help: if this is intended to be part of the list, indent 3 spaces
8+
= note: `-D clippy::doc-lazy-continuation` implied by `-D warnings`
9+
= help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]`
10+
help: if this should be its own paragraph, add a blank doc comment line
11+
|
12+
LL ~ /// - Second reason
13+
LL + ///
14+
|
15+
16+
error: doc list item without indentation
17+
--> tests/ui/doc/doc_lazy_blank_line.rs:32:5
18+
|
19+
LL | /// This is still in use.
20+
| ^
21+
|
22+
= help: if this is intended to be part of the list, indent 4 spaces
23+
help: if this should be its own paragraph, add a blank doc comment line
24+
|
25+
LL ~ /// 2. Second reason
26+
LL + ///
27+
|
28+
29+
error: doc quote line without `>` marker
30+
--> tests/ui/doc/doc_lazy_blank_line.rs:37:5
31+
|
32+
LL | /// bottom text
33+
| ^
34+
|
35+
= help: if this not intended to be a quote at all, escape it with `\>`
36+
help: if this should be its own paragraph, add a blank doc comment line
37+
|
38+
LL ~ /// > blockquote code path
39+
LL + ///
40+
|
41+
42+
error: doc quote line without `>` marker
43+
--> tests/ui/doc/doc_lazy_blank_line.rs:42:5
44+
|
45+
LL | /// bottom text
46+
| ^
47+
|
48+
= help: if this not intended to be a quote at all, escape it with `\>`
49+
help: if this should be its own paragraph, add a blank doc comment line
50+
|
51+
LL ~ /// > blockquote code path
52+
LL + ///
53+
|
54+
55+
error: aborting due to 4 previous errors
56+

tests/ui/doc/doc_lazy_blockquote.fixed

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
/// > blockquote with
44
/// > lazy continuation
5-
//~^ ERROR: doc quote missing `>` marker
5+
//~^ ERROR: doc quote line without `>` marker
66
fn first() {}
77

88
/// > blockquote with no
@@ -18,30 +18,30 @@ fn two_nowarn() {}
1818
/// >
1919
/// > > nest here
2020
/// > > lazy continuation
21-
//~^ ERROR: doc quote missing `>` marker
21+
//~^ ERROR: doc quote line without `>` marker
2222
fn two() {}
2323

2424
/// > nest here
2525
/// >
2626
/// > > nest here
2727
/// > > lazy continuation
28-
//~^ ERROR: doc quote missing `>` marker
28+
//~^ ERROR: doc quote line without `>` marker
2929
fn three() {}
3030

3131
/// > * > nest here
3232
/// > > lazy continuation
33-
//~^ ERROR: doc quote missing `>` marker
33+
//~^ ERROR: doc quote line without `>` marker
3434
fn four() {}
3535

3636
/// > * > nest here
3737
/// > > lazy continuation
38-
//~^ ERROR: doc quote missing `>` marker
38+
//~^ ERROR: doc quote line without `>` marker
3939
fn four_point_1() {}
4040

4141
/// * > nest here lazy continuation
4242
fn five() {}
4343

4444
/// 1. > nest here
4545
/// > lazy continuation (this results in strange indentation, but still works)
46-
//~^ ERROR: doc quote missing `>` marker
46+
//~^ ERROR: doc quote line without `>` marker
4747
fn six() {}

tests/ui/doc/doc_lazy_blockquote.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
/// > blockquote with
44
/// lazy continuation
5-
//~^ ERROR: doc quote missing `>` marker
5+
//~^ ERROR: doc quote line without `>` marker
66
fn first() {}
77

88
/// > blockquote with no
@@ -18,30 +18,30 @@ fn two_nowarn() {}
1818
/// >
1919
/// > > nest here
2020
/// > lazy continuation
21-
//~^ ERROR: doc quote missing `>` marker
21+
//~^ ERROR: doc quote line without `>` marker
2222
fn two() {}
2323

2424
/// > nest here
2525
/// >
2626
/// > > nest here
2727
/// lazy continuation
28-
//~^ ERROR: doc quote missing `>` marker
28+
//~^ ERROR: doc quote line without `>` marker
2929
fn three() {}
3030

3131
/// > * > nest here
3232
/// lazy continuation
33-
//~^ ERROR: doc quote missing `>` marker
33+
//~^ ERROR: doc quote line without `>` marker
3434
fn four() {}
3535

3636
/// > * > nest here
3737
/// lazy continuation
38-
//~^ ERROR: doc quote missing `>` marker
38+
//~^ ERROR: doc quote line without `>` marker
3939
fn four_point_1() {}
4040

4141
/// * > nest here lazy continuation
4242
fn five() {}
4343

4444
/// 1. > nest here
4545
/// lazy continuation (this results in strange indentation, but still works)
46-
//~^ ERROR: doc quote missing `>` marker
46+
//~^ ERROR: doc quote line without `>` marker
4747
fn six() {}

tests/ui/doc/doc_lazy_blockquote.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: doc quote missing `>` marker
1+
error: doc quote line without `>` marker
22
--> tests/ui/doc/doc_lazy_blockquote.rs:4:5
33
|
44
LL | /// lazy continuation
@@ -12,7 +12,7 @@ help: add markers to start of line
1212
LL | /// > lazy continuation
1313
| +
1414

15-
error: doc quote missing `>` marker
15+
error: doc quote line without `>` marker
1616
--> tests/ui/doc/doc_lazy_blockquote.rs:20:5
1717
|
1818
LL | /// > lazy continuation
@@ -24,7 +24,7 @@ help: add markers to start of line
2424
LL | /// > > lazy continuation
2525
| +
2626

27-
error: doc quote missing `>` marker
27+
error: doc quote line without `>` marker
2828
--> tests/ui/doc/doc_lazy_blockquote.rs:27:5
2929
|
3030
LL | /// lazy continuation
@@ -36,7 +36,7 @@ help: add markers to start of line
3636
LL | /// > > lazy continuation
3737
| +++
3838

39-
error: doc quote missing `>` marker
39+
error: doc quote line without `>` marker
4040
--> tests/ui/doc/doc_lazy_blockquote.rs:32:5
4141
|
4242
LL | /// lazy continuation
@@ -48,7 +48,7 @@ help: add markers to start of line
4848
LL | /// > > lazy continuation
4949
| +++++++
5050

51-
error: doc quote missing `>` marker
51+
error: doc quote line without `>` marker
5252
--> tests/ui/doc/doc_lazy_blockquote.rs:37:5
5353
|
5454
LL | /// lazy continuation
@@ -60,7 +60,7 @@ help: add markers to start of line
6060
LL | /// > > lazy continuation
6161
| +++++
6262

63-
error: doc quote missing `>` marker
63+
error: doc quote line without `>` marker
6464
--> tests/ui/doc/doc_lazy_blockquote.rs:45:5
6565
|
6666
LL | /// lazy continuation (this results in strange indentation, but still works)

0 commit comments

Comments
 (0)