Skip to content

Commit 914e58b

Browse files
committed
New lint [four_forward_slashes]
1 parent 3be3fb7 commit 914e58b

7 files changed

+226
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4806,6 +4806,7 @@ Released 2018-09-13
48064806
[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
48074807
[`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args
48084808
[`format_push_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_push_string
4809+
[`four_forward_slashes`]: https://rust-lang.github.io/rust-clippy/master/index.html#four_forward_slashes
48094810
[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
48104811
[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
48114812
[`from_raw_with_void_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_raw_with_void_ptr

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
184184
crate::formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING_INFO,
185185
crate::formatting::SUSPICIOUS_ELSE_FORMATTING_INFO,
186186
crate::formatting::SUSPICIOUS_UNARY_OP_FORMATTING_INFO,
187+
crate::four_forward_slashes::FOUR_FORWARD_SLASHES_INFO,
187188
crate::from_over_into::FROM_OVER_INTO_INFO,
188189
crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
189190
crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_opt};
2+
use rustc_errors::Applicability;
3+
use rustc_hir::Item;
4+
use rustc_lint::{LateContext, LateLintPass, LintContext};
5+
use rustc_session::{declare_lint_pass, declare_tool_lint};
6+
use rustc_span::{Span, SyntaxContext};
7+
8+
declare_clippy_lint! {
9+
/// ### What it does
10+
/// Checks for outer doc comments written with 4 forward slashes (`////`).
11+
///
12+
/// ### Why is this bad?
13+
/// This is (probably) a typo, and results in it not being a doc comment; just a regular
14+
/// comment.
15+
///
16+
/// ### Example
17+
/// ```rust
18+
/// //// My amazing data structure
19+
/// pub struct Foo {
20+
/// // ...
21+
/// }
22+
/// ```
23+
///
24+
/// Use instead:
25+
/// ```rust
26+
/// /// My amazing data structure
27+
/// pub struct Foo {
28+
/// // ...
29+
/// }
30+
/// ```
31+
#[clippy::version = "1.72.0"]
32+
pub FOUR_FORWARD_SLASHES,
33+
suspicious,
34+
"comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)"
35+
}
36+
declare_lint_pass!(FourForwardSlashes => [FOUR_FORWARD_SLASHES]);
37+
38+
impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes {
39+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
40+
if item.span.from_expansion() {
41+
return;
42+
}
43+
let src = cx.sess().source_map();
44+
let item_and_attrs_span = cx
45+
.tcx
46+
.hir()
47+
.attrs(item.hir_id())
48+
.iter()
49+
.fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span));
50+
let (Some(file), _, _, end_line, _) = src.span_to_location_info(item_and_attrs_span) else {
51+
return;
52+
};
53+
for line in (0..end_line.saturating_sub(1)).rev() {
54+
let Some(contents) = file.get_line(line) else {
55+
continue;
56+
};
57+
if contents.is_empty() {
58+
break;
59+
}
60+
if contents.starts_with("////") {
61+
let bounds = file.line_bounds(line);
62+
let span = Span::new(bounds.start, bounds.end, SyntaxContext::root(), None);
63+
64+
if snippet_opt(cx, span).is_some_and(|s| s.starts_with("////")) {
65+
span_lint_and_sugg(
66+
cx,
67+
FOUR_FORWARD_SLASHES,
68+
span,
69+
"comment with 4 forward slashes (`////`). This looks like a doc comment, but it isn't",
70+
"make this a doc comment by removing one `/`",
71+
// It's a little unfortunate but the span includes the `\n` yet the contents
72+
// do not, so we must add it back. If some codebase uses `\r\n` instead this
73+
// they will need normalization but it should be fine
74+
contents[1..].to_owned() + "\n",
75+
Applicability::MachineApplicable,
76+
);
77+
}
78+
}
79+
}
80+
}
81+
}

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ mod format_args;
137137
mod format_impl;
138138
mod format_push_string;
139139
mod formatting;
140+
mod four_forward_slashes;
140141
mod from_over_into;
141142
mod from_raw_with_void_ptr;
142143
mod from_str_radix_10;
@@ -1081,6 +1082,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10811082
store.register_early_pass(|| Box::new(visibility::Visibility));
10821083
store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
10831084
store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods));
1085+
store.register_late_pass(|_| Box::new(four_forward_slashes::FourForwardSlashes));
10841086
// add lints here, do not remove this comment, it's used in `new_lint`
10851087
}
10861088

tests/ui/four_forward_slashes.fixed

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//// first line borked doc comment. doesn't combust!
2+
//@run-rustfix
3+
//@aux-build:proc_macros.rs:proc-macro
4+
#![allow(unused)]
5+
#![warn(clippy::four_forward_slashes)]
6+
#![no_main]
7+
8+
#[macro_use]
9+
extern crate proc_macros;
10+
11+
/// whoops
12+
fn a() {}
13+
14+
/// whoops
15+
#[allow(dead_code)]
16+
fn b() {}
17+
18+
/// whoops
19+
/// two borked comments!
20+
#[track_caller]
21+
fn c() {}
22+
23+
fn d() {}
24+
25+
#[test]
26+
/// between attributes
27+
#[allow(dead_code)]
28+
fn g() {}
29+
30+
external! {
31+
//// don't lint me bozo
32+
fn e() {}
33+
}
34+
35+
with_span! {
36+
span
37+
//// don't lint me bozo
38+
fn f() {}
39+
}

tests/ui/four_forward_slashes.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//// first line borked doc comment. doesn't combust!
2+
//@run-rustfix
3+
//@aux-build:proc_macros.rs:proc-macro
4+
#![allow(unused)]
5+
#![warn(clippy::four_forward_slashes)]
6+
#![no_main]
7+
8+
#[macro_use]
9+
extern crate proc_macros;
10+
11+
//// whoops
12+
fn a() {}
13+
14+
//// whoops
15+
#[allow(dead_code)]
16+
fn b() {}
17+
18+
//// whoops
19+
//// two borked comments!
20+
#[track_caller]
21+
fn c() {}
22+
23+
fn d() {}
24+
25+
#[test]
26+
//// between attributes
27+
#[allow(dead_code)]
28+
fn g() {}
29+
30+
external! {
31+
//// don't lint me bozo
32+
fn e() {}
33+
}
34+
35+
with_span! {
36+
span
37+
//// don't lint me bozo
38+
fn f() {}
39+
}

tests/ui/four_forward_slashes.stderr

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
error: comment with 4 forward slashes (`////`). This looks like a doc comment, but it isn't
2+
--> $DIR/four_forward_slashes.rs:11:1
3+
|
4+
LL | / //// whoops
5+
LL | | fn a() {}
6+
| |_
7+
|
8+
= note: `-D clippy::four-forward-slashes` implied by `-D warnings`
9+
help: make this a doc comment by removing one `/`
10+
|
11+
LL + /// whoops
12+
|
13+
14+
error: comment with 4 forward slashes (`////`). This looks like a doc comment, but it isn't
15+
--> $DIR/four_forward_slashes.rs:14:1
16+
|
17+
LL | / //// whoops
18+
LL | | #[allow(dead_code)]
19+
| |_
20+
|
21+
help: make this a doc comment by removing one `/`
22+
|
23+
LL + /// whoops
24+
|
25+
26+
error: comment with 4 forward slashes (`////`). This looks like a doc comment, but it isn't
27+
--> $DIR/four_forward_slashes.rs:19:1
28+
|
29+
LL | / //// two borked comments!
30+
LL | | #[track_caller]
31+
| |_
32+
|
33+
help: make this a doc comment by removing one `/`
34+
|
35+
LL + /// two borked comments!
36+
|
37+
38+
error: comment with 4 forward slashes (`////`). This looks like a doc comment, but it isn't
39+
--> $DIR/four_forward_slashes.rs:18:1
40+
|
41+
LL | / //// whoops
42+
LL | | //// two borked comments!
43+
| |_
44+
|
45+
help: make this a doc comment by removing one `/`
46+
|
47+
LL + /// whoops
48+
|
49+
50+
error: comment with 4 forward slashes (`////`). This looks like a doc comment, but it isn't
51+
--> $DIR/four_forward_slashes.rs:26:1
52+
|
53+
LL | / //// between attributes
54+
LL | | #[allow(dead_code)]
55+
| |_
56+
|
57+
help: make this a doc comment by removing one `/`
58+
|
59+
LL + /// between attributes
60+
|
61+
62+
error: aborting due to 5 previous errors
63+

0 commit comments

Comments
 (0)