Skip to content

Commit 0df651d

Browse files
doc_comments_missing_terminal_punctuation: treat some trailers as unfixable
1 parent 5ca9ca1 commit 0df651d

6 files changed

+116
-78
lines changed

clippy_lints/src/doc/doc_comments_missing_terminal_punctuation.rs

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,45 @@ const MSG: &str = "doc comments should end with a terminal punctuation mark";
1010
const PUNCTUATION_SUGGESTION: char = '.';
1111

1212
pub fn check(cx: &LateContext<'_>, doc: &str, fragments: Fragments<'_>) {
13-
// This ignores `#[doc]` attributes, which we do not handle.
14-
if let Some(offset) = is_missing_punctuation(doc)
15-
&& let Some(span) = fragments.span(cx, offset..offset)
16-
{
17-
clippy_utils::diagnostics::span_lint_and_sugg(
18-
cx,
19-
DOC_COMMENTS_MISSING_TERMINAL_PUNCTUATION,
20-
span,
21-
MSG,
22-
"end the doc comment with some punctuation",
23-
PUNCTUATION_SUGGESTION.to_string(),
24-
Applicability::MaybeIncorrect,
25-
);
13+
match is_missing_punctuation(doc) {
14+
IsMissingPunctuation::Fixable(offset) => {
15+
// This ignores `#[doc]` attributes, which we do not handle.
16+
if let Some(span) = fragments.span(cx, offset..offset) {
17+
clippy_utils::diagnostics::span_lint_and_sugg(
18+
cx,
19+
DOC_COMMENTS_MISSING_TERMINAL_PUNCTUATION,
20+
span,
21+
MSG,
22+
"end the doc comment with some punctuation",
23+
PUNCTUATION_SUGGESTION.to_string(),
24+
Applicability::MaybeIncorrect,
25+
);
26+
}
27+
},
28+
IsMissingPunctuation::Unfixable(offset) => {
29+
// This ignores `#[doc]` attributes, which we do not handle.
30+
if let Some(span) = fragments.span(cx, offset..offset) {
31+
clippy_utils::diagnostics::span_lint_and_help(
32+
cx,
33+
DOC_COMMENTS_MISSING_TERMINAL_PUNCTUATION,
34+
span,
35+
MSG,
36+
None,
37+
"end the doc comment with some punctuation",
38+
);
39+
}
40+
},
41+
IsMissingPunctuation::No => {},
2642
}
2743
}
2844

2945
#[must_use]
3046
/// If punctuation is missing, returns the offset where new punctuation should be inserted.
31-
fn is_missing_punctuation(doc_string: &str) -> Option<usize> {
47+
fn is_missing_punctuation(doc_string: &str) -> IsMissingPunctuation {
3248
const TERMINAL_PUNCTUATION_MARKS: &[char] = &['.', '?', '!', '…'];
3349

3450
let mut no_report_depth = 0;
35-
let mut text_offset = None;
51+
let mut missing_punctuation = IsMissingPunctuation::No;
3652
for (event, offset) in
3753
Parser::new_ext(doc_string, main_body_opts() - Options::ENABLE_SMART_PUNCTUATION).into_offset_iter()
3854
{
@@ -54,35 +70,48 @@ fn is_missing_punctuation(doc_string: &str) -> Option<usize> {
5470
TagEnd::CodeBlock | TagEnd::Heading(_) | TagEnd::HtmlBlock | TagEnd::List(_) | TagEnd::Table,
5571
) => {
5672
no_report_depth -= 1;
57-
text_offset = None;
73+
missing_punctuation = IsMissingPunctuation::No;
5874
},
5975
Event::InlineHtml(_) | Event::Start(Tag::Image { .. }) | Event::End(TagEnd::Image) => {
60-
text_offset = None;
76+
missing_punctuation = IsMissingPunctuation::No;
6177
},
6278
Event::Code(..) | Event::Start(Tag::Link { .. }) | Event::End(TagEnd::Link)
6379
if no_report_depth == 0 && !offset.is_empty() =>
6480
{
65-
text_offset = Some(offset.end);
81+
if doc_string[..offset.end]
82+
.trim_end()
83+
.ends_with(TERMINAL_PUNCTUATION_MARKS)
84+
{
85+
missing_punctuation = IsMissingPunctuation::No;
86+
} else {
87+
missing_punctuation = IsMissingPunctuation::Fixable(offset.end);
88+
}
6689
},
6790
Event::Text(..) if no_report_depth == 0 && !offset.is_empty() => {
68-
// American-style quotes require punctuation to be placed inside closing quotation marks.
69-
if doc_string[..offset.end].trim_end().ends_with('"') {
70-
text_offset = Some(offset.end - 1);
91+
let trimmed = doc_string[..offset.end].trim_end();
92+
if trimmed.ends_with(TERMINAL_PUNCTUATION_MARKS) {
93+
missing_punctuation = IsMissingPunctuation::No;
94+
} else if let Some(t) = trimmed.strip_suffix(|c| c == ')' || c == '"') {
95+
if t.ends_with(TERMINAL_PUNCTUATION_MARKS) {
96+
// Avoid false positives.
97+
missing_punctuation = IsMissingPunctuation::No;
98+
} else {
99+
missing_punctuation = IsMissingPunctuation::Unfixable(offset.end);
100+
}
71101
} else {
72-
text_offset = Some(offset.end);
102+
missing_punctuation = IsMissingPunctuation::Fixable(offset.end);
73103
}
74104
},
75105
_ => {},
76106
}
77107
}
78108

79-
let text_offset = text_offset?;
80-
if doc_string[..text_offset]
81-
.trim_end()
82-
.ends_with(TERMINAL_PUNCTUATION_MARKS)
83-
{
84-
None
85-
} else {
86-
Some(text_offset)
87-
}
109+
missing_punctuation
110+
}
111+
112+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
113+
enum IsMissingPunctuation {
114+
Fixable(usize),
115+
Unfixable(usize),
116+
No,
88117
}

tests/ui/doc/doc_comments_missing_terminal_punctuation.fixed

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,10 @@ mod module {
8080
}
8181

8282
enum Trailers {
83-
/// Sometimes the doc comment ends with parentheses (like this).
84-
//~^ doc_comments_missing_terminal_punctuation
85-
EndsWithParens,
86-
/// (Sometimes the last sentence is in parentheses, but there is no special treatment of this.).
87-
//~^ doc_comments_missing_terminal_punctuation
88-
ParensFailing,
83+
/// Sometimes the last sentence ends with parentheses (and that's ok).
84+
ParensPassing,
85+
/// (Sometimes the last sentence is in parentheses.)
86+
SentenceInParensPassing,
8987
/// **Sometimes the last sentence is in bold, and that's ok.**
9088
DoubleStarPassing,
9189
/// **But sometimes it is missing a period.**
@@ -97,10 +95,9 @@ enum Trailers {
9795
//~^ doc_comments_missing_terminal_punctuation
9896
UnderscoreFailing,
9997
/// This comment ends with "a quote."
100-
QuotePassing,
101-
/// This comment ends with "a quote."
102-
//~^ doc_comments_missing_terminal_punctuation
103-
QuoteFailing,
98+
AmericanStyleQuotePassing,
99+
/// This comment ends with "a quote".
100+
BritishStyleQuotePassing,
104101
}
105102

106103
/// Doc comments can end with an [inline link](#anchor).

tests/ui/doc/doc_comments_missing_terminal_punctuation.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,10 @@ mod module {
8080
}
8181

8282
enum Trailers {
83-
/// Sometimes the doc comment ends with parentheses (like this)
84-
//~^ doc_comments_missing_terminal_punctuation
85-
EndsWithParens,
86-
/// (Sometimes the last sentence is in parentheses, but there is no special treatment of this.)
87-
//~^ doc_comments_missing_terminal_punctuation
88-
ParensFailing,
83+
/// Sometimes the last sentence ends with parentheses (and that's ok).
84+
ParensPassing,
85+
/// (Sometimes the last sentence is in parentheses.)
86+
SentenceInParensPassing,
8987
/// **Sometimes the last sentence is in bold, and that's ok.**
9088
DoubleStarPassing,
9189
/// **But sometimes it is missing a period**
@@ -97,10 +95,9 @@ enum Trailers {
9795
//~^ doc_comments_missing_terminal_punctuation
9896
UnderscoreFailing,
9997
/// This comment ends with "a quote."
100-
QuotePassing,
101-
/// This comment ends with "a quote"
102-
//~^ doc_comments_missing_terminal_punctuation
103-
QuoteFailing,
98+
AmericanStyleQuotePassing,
99+
/// This comment ends with "a quote".
100+
BritishStyleQuotePassing,
104101
}
105102

106103
/// Doc comments can end with an [inline link](#anchor)

tests/ui/doc/doc_comments_missing_terminal_punctuation.stderr

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -44,70 +44,52 @@ LL | //! inner attributes too
4444
| ^ help: end the doc comment with some punctuation: `.`
4545

4646
error: doc comments should end with a terminal punctuation mark
47-
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:83:68
48-
|
49-
LL | /// Sometimes the doc comment ends with parentheses (like this)
50-
| ^ help: end the doc comment with some punctuation: `.`
51-
52-
error: doc comments should end with a terminal punctuation mark
53-
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:86:100
54-
|
55-
LL | /// (Sometimes the last sentence is in parentheses, but there is no special treatment of this.)
56-
| ^ help: end the doc comment with some punctuation: `.`
57-
58-
error: doc comments should end with a terminal punctuation mark
59-
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:91:47
47+
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:89:47
6048
|
6149
LL | /// **But sometimes it is missing a period**
6250
| ^ help: end the doc comment with some punctuation: `.`
6351

6452
error: doc comments should end with a terminal punctuation mark
65-
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:96:46
53+
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:94:46
6654
|
6755
LL | /// _But sometimes it is missing a period_
6856
| ^ help: end the doc comment with some punctuation: `.`
6957

7058
error: doc comments should end with a terminal punctuation mark
71-
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:101:40
72-
|
73-
LL | /// This comment ends with "a quote"
74-
| ^ help: end the doc comment with some punctuation: `.`
75-
76-
error: doc comments should end with a terminal punctuation mark
77-
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:106:56
59+
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:103:56
7860
|
7961
LL | /// Doc comments can end with an [inline link](#anchor)
8062
| ^ help: end the doc comment with some punctuation: `.`
8163

8264
error: doc comments should end with a terminal punctuation mark
83-
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:110:65
65+
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:107:65
8466
|
8567
LL | /// Some doc comments contain [link reference definitions][spec]
8668
| ^ help: end the doc comment with some punctuation: `.`
8769

8870
error: doc comments should end with a terminal punctuation mark
89-
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:135:57
71+
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:132:57
9072
|
9173
LL | /// Doc comments with trailing blank lines are supported
9274
| ^ help: end the doc comment with some punctuation: `.`
9375

9476
error: doc comments should end with a terminal punctuation mark
95-
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:143:30
77+
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:140:30
9678
|
9779
LL | /// Only the last sentence is
9880
| ^ help: end the doc comment with some punctuation: `.`
9981

10082
error: doc comments should end with a terminal punctuation mark
101-
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:150:33
83+
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:147:33
10284
|
10385
LL | /// This ends with a code `span`
10486
| ^ help: end the doc comment with some punctuation: `.`
10587

10688
error: doc comments should end with a terminal punctuation mark
107-
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:159:27
89+
--> tests/ui/doc/doc_comments_missing_terminal_punctuation.rs:156:27
10890
|
10991
LL | * Block doc comments work
11092
| ^ help: end the doc comment with some punctuation: `.`
11193

112-
error: aborting due to 18 previous errors
94+
error: aborting due to 15 previous errors
11395

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(custom_inner_attributes)]
2+
#![rustfmt::skip]
3+
#![warn(clippy::doc_comments_missing_terminal_punctuation)]
4+
//@no-rustfix
5+
6+
enum UnfixableTrailers {
7+
/// Sometimes the doc comment ends with parentheses (like this)
8+
//~^ doc_comments_missing_terminal_punctuation
9+
EndsWithParens,
10+
/// This comment ends with "a quote"
11+
//~^ doc_comments_missing_terminal_punctuation
12+
QuoteFailing,
13+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: doc comments should end with a terminal punctuation mark
2+
--> tests/ui/doc/doc_comments_missing_terminal_punctuation_unfixable.rs:7:68
3+
|
4+
LL | /// Sometimes the doc comment ends with parentheses (like this)
5+
| ^
6+
|
7+
= help: end the doc comment with some punctuation
8+
= note: `-D clippy::doc-comments-missing-terminal-punctuation` implied by `-D warnings`
9+
= help: to override `-D warnings` add `#[allow(clippy::doc_comments_missing_terminal_punctuation)]`
10+
11+
error: doc comments should end with a terminal punctuation mark
12+
--> tests/ui/doc/doc_comments_missing_terminal_punctuation_unfixable.rs:10:41
13+
|
14+
LL | /// This comment ends with "a quote"
15+
| ^
16+
|
17+
= help: end the doc comment with some punctuation
18+
19+
error: aborting due to 2 previous errors
20+

0 commit comments

Comments
 (0)