1 use clippy_utils
::diagnostics
::span_lint_and_then
;
2 use rustc_errors
::Applicability
;
4 use rustc_lint
::{LateContext, LateLintPass, LintContext}
;
5 use rustc_session
::declare_lint_pass
;
10 /// Checks for outer doc comments written with 4 forward slashes (`////`).
12 /// ### Why is this bad?
13 /// This is (probably) a typo, and results in it not being a doc comment; just a regular
18 /// //// My amazing data structure
26 /// /// My amazing data structure
31 #[clippy::version = "1.73.0"]
32 pub FOUR_FORWARD_SLASHES
,
34 "comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)"
36 declare_lint_pass
!(FourForwardSlashes
=> [FOUR_FORWARD_SLASHES
]);
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() {
43 let sm
= cx
.sess().source_map();
49 .fold(item
.span
.shrink_to_lo(), |span
, attr
| span
.to(attr
.span
));
50 let (Some(file
), _
, _
, end_line
, _
) = sm
.span_to_location_info(span
) else {
53 let mut bad_comments
= vec
![];
54 for line
in (0..end_line
.saturating_sub(1)).rev() {
55 let Some(contents
) = file
.get_line(line
).map(|c
| c
.trim().to_owned()) else {
58 // Keep searching until we find the next item
59 if !contents
.is_empty() && !contents
.starts_with("//") && !contents
.starts_with("#[") {
63 if contents
.starts_with("////") && !matches
!(contents
.chars().nth(4), Some('
/'
| '
!'
)) {
64 let bounds
= file
.line_bounds(line
);
65 let line_span
= Span
::with_root_ctxt(bounds
.start
, bounds
.end
);
66 span
= line_span
.to(span
);
67 bad_comments
.push((line_span
, contents
));
71 if !bad_comments
.is_empty() {
76 "this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't",
78 let msg
= if bad_comments
.len() == 1 {
79 "make this a doc comment by removing one `/`"
81 "turn these into doc comments by removing one `/`"
84 diag
.multipart_suggestion(
88 // It's a little unfortunate but the span includes the `\n` yet the contents
89 // do not, so we must add it back. If some codebase uses `\r\n` instead they
90 // will need normalization but it should be fine
91 .map(|(span
, c
)| (span
, c
.replacen("////", "///", 1) + "\n"))
93 Applicability
::MachineApplicable
,