Skip to content

Commit 084a9ee

Browse files
committed
fix: unnecessary_safety_comment does not lint for the first line
1 parent 0397819 commit 084a9ee

File tree

4 files changed

+72
-8
lines changed

4 files changed

+72
-8
lines changed

clippy_lints/src/undocumented_unsafe_blocks.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,8 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
505505
},
506506
Node::Stmt(stmt) => {
507507
if let Node::Block(block) = cx.tcx.parent_hir_node(stmt.hir_id) {
508-
walk_span_to_context(block.span, SyntaxContext::root()).map(Span::lo)
508+
walk_span_to_context(block.span, SyntaxContext::root())
509+
.map(|sp| CommentStartBeforeItem::Offset(sp.lo()))
509510
} else {
510511
// Problem getting the parent node. Pretend a comment was found.
511512
return HasSafetyComment::Maybe;
@@ -518,18 +519,21 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
518519
};
519520

520521
let source_map = cx.sess().source_map();
522+
// If the comment is in the first line of the file, there is no preceding line
521523
if let Some(comment_start) = comment_start
522524
&& let Ok(unsafe_line) = source_map.lookup_line(item.span.lo())
523-
&& let Ok(comment_start_line) = source_map.lookup_line(comment_start)
524-
&& Arc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
525+
&& let Ok(comment_start_line) = source_map.lookup_line(comment_start.into())
526+
&& let include_first_line_of_file = matches!(comment_start, CommentStartBeforeItem::Start)
527+
&& (include_first_line_of_file || Arc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf))
525528
&& let Some(src) = unsafe_line.sf.src.as_deref()
526529
{
527530
return if comment_start_line.line >= unsafe_line.line {
528531
HasSafetyComment::No
529532
} else {
530533
match text_has_safety_comment(
531534
src,
532-
&unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line],
535+
&unsafe_line.sf.lines()
536+
[(comment_start_line.line + usize::from(!include_first_line_of_file))..=unsafe_line.line],
533537
unsafe_line.sf.start_pos,
534538
) {
535539
Some(b) => HasSafetyComment::Yes(b),
@@ -592,28 +596,47 @@ fn stmt_has_safety_comment(
592596
HasSafetyComment::Maybe
593597
}
594598

599+
#[derive(Clone, Copy, Debug)]
600+
enum CommentStartBeforeItem {
601+
Offset(BytePos),
602+
Start,
603+
}
604+
605+
impl From<CommentStartBeforeItem> for BytePos {
606+
fn from(value: CommentStartBeforeItem) -> Self {
607+
match value {
608+
CommentStartBeforeItem::Offset(loc) => loc,
609+
CommentStartBeforeItem::Start => BytePos(0),
610+
}
611+
}
612+
}
613+
595614
fn comment_start_before_item_in_mod(
596615
cx: &LateContext<'_>,
597616
parent_mod: &hir::Mod<'_>,
598617
parent_mod_span: Span,
599618
item: &hir::Item<'_>,
600-
) -> Option<BytePos> {
619+
) -> Option<CommentStartBeforeItem> {
601620
parent_mod.item_ids.iter().enumerate().find_map(|(idx, item_id)| {
602621
if *item_id == item.item_id() {
603622
if idx == 0 {
604623
// mod A { /* comment */ unsafe impl T {} ... }
605624
// ^------------------------------------------^ returns the start of this span
606625
// ^---------------------^ finally checks comments in this range
607626
if let Some(sp) = walk_span_to_context(parent_mod_span, SyntaxContext::root()) {
608-
return Some(sp.lo());
627+
return Some(CommentStartBeforeItem::Offset(sp.lo()));
609628
}
610629
} else {
611630
// some_item /* comment */ unsafe impl T {}
612631
// ^-------^ returns the end of this span
613632
// ^---------------^ finally checks comments in this range
614633
let prev_item = cx.tcx.hir_item(parent_mod.item_ids[idx - 1]);
615634
if let Some(sp) = walk_span_to_context(prev_item.span, SyntaxContext::root()) {
616-
return Some(sp.hi());
635+
return Some(if sp.is_dummy() {
636+
CommentStartBeforeItem::Start
637+
} else {
638+
CommentStartBeforeItem::Offset(sp.hi())
639+
});
617640
}
618641
}
619642
}
@@ -668,7 +691,7 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
668691
}) => {
669692
return maybe_mod_item
670693
.and_then(|item| comment_start_before_item_in_mod(cx, mod_, *span, &item))
671-
.map(|comment_start| mod_.spans.inner_span.with_lo(comment_start))
694+
.map(|comment_start| mod_.spans.inner_span.with_lo(comment_start.into()))
672695
.or(Some(*span));
673696
},
674697
node if let Some((span, _)) = span_and_hid_of_item_alike_node(&node)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: module has unnecessary safety comment
2+
--> src/main.rs:2:1
3+
|
4+
2 | mod x {}
5+
| ^^^^^^^^
6+
|
7+
help: consider removing the safety comment
8+
--> src/main.rs:1:1
9+
|
10+
1 | // SAFETY: ...
11+
| ^^^^^^^^^^^^^^
12+
= note: requested on the command line with `-D clippy::unnecessary-safety-comment`
13+
14+
error: module has unnecessary safety comment
15+
--> src/main.rs:5:1
16+
|
17+
5 | mod y {}
18+
| ^^^^^^^^
19+
|
20+
help: consider removing the safety comment
21+
--> src/main.rs:4:1
22+
|
23+
4 | // SAFETY: ...
24+
| ^^^^^^^^^^^^^^
25+
26+
error: could not compile `undocumented_unsafe_blocks` (bin "undocumented_unsafe_blocks") due to 2 previous errors
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "undocumented_unsafe_blocks"
3+
edition = "2024"
4+
publish = false
5+
version = "0.1.0"
6+
7+
[lints.clippy]
8+
unnecessary_safety_comment = "deny"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// SAFETY: ...
2+
mod x {}
3+
4+
// SAFETY: ...
5+
mod y {}
6+
7+
fn main() {}

0 commit comments

Comments
 (0)