Skip to content

Commit e3da210

Browse files
committed
fix
1 parent 388e6b7 commit e3da210

File tree

3 files changed

+210
-3
lines changed

3 files changed

+210
-3
lines changed

clippy_lints/src/undocumented_unsafe_blocks.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use clippy_utils::diagnostics::span_lint_and_help;
22
use clippy_utils::is_lint_allowed;
33
use clippy_utils::source::walk_span_to_context;
4+
use rustc_hir as hir;
45
use rustc_hir::{Block, BlockCheckMode, UnsafeSource};
56
use rustc_lexer::{tokenize, TokenKind};
67
use rustc_lint::{LateContext, LateLintPass, LintContext};
78
use rustc_middle::lint::in_external_macro;
89
use rustc_session::{declare_lint_pass, declare_tool_lint};
9-
use rustc_span::{BytePos, Pos, SyntaxContext};
10+
use rustc_span::{BytePos, Pos, Span, SyntaxContext};
1011
use std::rc::Rc;
1112

1213
declare_clippy_lint! {
@@ -86,6 +87,65 @@ impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
8687
);
8788
}
8889
}
90+
91+
fn check_mod(&mut self, cx: &LateContext<'_>, module: &'_ hir::Mod<'_>, mod_span: Span, hir_id: hir::HirId) {
92+
let source_map = cx.sess().source_map();
93+
let mut item_and_spans: Vec<(&hir::Item<'_>, Span)> = Vec::new(); // (start, end, item)
94+
95+
// Collect all items and their spans
96+
for item_id in module.item_ids {
97+
let item = cx.tcx.hir().item(*item_id);
98+
item_and_spans.push((item, item.span));
99+
}
100+
// Sort items by start position
101+
item_and_spans.sort_by_key(|e| e.1.lo());
102+
103+
for (idx, (item, item_span)) in item_and_spans.iter().enumerate() {
104+
if let hir::ItemKind::Impl(imple) = &item.kind
105+
&& imple.unsafety == hir::Unsafety::Unsafe
106+
&& !item_span.from_expansion()
107+
&& !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, hir_id)
108+
{
109+
// Checks if the lines immediately preceding the impl contain a safety comment.
110+
let impl_has_safety_comment = {
111+
let span_before_impl = if idx == 0 {
112+
// mod A { /* comment */ unsafe impl T {} }
113+
// ^--------------------^
114+
mod_span.until(module.inner)
115+
} else {
116+
// unsafe impl S {} /* comment */ unsafe impl T {}
117+
// ^-------------^
118+
item_and_spans[idx - 1].1.between(*item_span)
119+
};
120+
121+
if let Ok(start) = source_map.lookup_line(span_before_impl.lo())
122+
&& let Ok(end) = source_map.lookup_line(span_before_impl.hi())
123+
&& let Some(src) = start.sf.src.as_deref()
124+
{
125+
start.line < end.line && text_has_safety_comment(
126+
src,
127+
&start.sf.lines[start.line + 1 ..= end.line],
128+
start.sf.start_pos.to_usize()
129+
)
130+
} else {
131+
// Problem getting source text. Pretend a comment was found.
132+
true
133+
}
134+
};
135+
136+
if !impl_has_safety_comment {
137+
span_lint_and_help(
138+
cx,
139+
UNDOCUMENTED_UNSAFE_BLOCKS,
140+
*item_span,
141+
"unsafe impl missing a safety comment",
142+
None,
143+
"consider adding a safety comment on the preceding line",
144+
);
145+
}
146+
}
147+
}
148+
}
89149
}
90150

91151
fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, block: &Block<'_>) -> bool {

tests/ui/undocumented_unsafe_blocks.rs

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// aux-build:proc_macro_unsafe.rs
22

33
#![warn(clippy::undocumented_unsafe_blocks)]
4-
#![allow(clippy::let_unit_value)]
4+
#![allow(clippy::let_unit_value, clippy::missing_safety_doc)]
55

66
extern crate proc_macro_unsafe;
77

@@ -334,4 +334,103 @@ pub fn print_binary_tree() {
334334
println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
335335
}
336336

337+
mod unsafe_impl_smoke_test {
338+
unsafe trait A {}
339+
340+
// error: no safety comment
341+
unsafe impl A for () {}
342+
343+
// Safety: ok
344+
unsafe impl A for (i32) {}
345+
346+
mod sub_mod {
347+
// error: also works for the first item
348+
unsafe impl B for (u32) {}
349+
unsafe trait B {}
350+
}
351+
352+
#[rustfmt::skip]
353+
mod sub_mod2 {
354+
//
355+
// SAFETY: ok
356+
//
357+
358+
unsafe impl B for (u32) {}
359+
unsafe trait B {}
360+
}
361+
}
362+
363+
mod unsafe_impl_from_macro {
364+
unsafe trait T {}
365+
366+
macro_rules! unsafe_impl {
367+
($t:ty) => {
368+
unsafe impl T for $t {}
369+
};
370+
}
371+
// ok: from macro expanision
372+
unsafe_impl!(());
373+
// ok: from macro expansion
374+
unsafe_impl!(i32);
375+
}
376+
377+
#[rustfmt::skip]
378+
mod unsafe_impl_valid_comment {
379+
unsafe trait SaFety {}
380+
// SaFety:
381+
unsafe impl SaFety for () {}
382+
383+
unsafe trait MultiLineComment {}
384+
// The following impl is safe
385+
// ...
386+
// Safety: reason
387+
unsafe impl MultiLineComment for () {}
388+
389+
unsafe trait NoAscii {}
390+
// 安全 SAFETY: 以下のコードは安全です
391+
unsafe impl NoAscii for () {}
392+
393+
unsafe trait InlineAndPrecedingComment {}
394+
// SAFETY:
395+
/* comment */ unsafe impl InlineAndPrecedingComment for () {}
396+
397+
unsafe trait BuriedSafety {}
398+
// Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
399+
// incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
400+
// ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
401+
// reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
402+
// occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
403+
// laborum. Safety:
404+
// Tellus elementum sagittis vitae et leo duis ut diam quam. Sit amet nulla facilisi
405+
// morbi tempus iaculis urna. Amet luctus venenatis lectus magna. At quis risus sed vulputate odio
406+
// ut. Luctus venenatis lectus magna fringilla urna. Tortor id aliquet lectus proin nibh nisl
407+
// condimentum id venenatis. Vulputate dignissim suspendisse in est ante in nibh mauris cursus.
408+
unsafe impl BuriedSafety for () {}
409+
410+
unsafe trait MultiLineBlockComment {}
411+
/* This is a description
412+
* Safety: */
413+
unsafe impl MultiLineBlockComment for () {}
414+
}
415+
416+
#[rustfmt::skip]
417+
mod unsafe_impl_invalid_comment {
418+
unsafe trait NoComment {}
419+
420+
unsafe impl NoComment for () {}
421+
422+
unsafe trait InlineComment {}
423+
424+
/* SAFETY: */ unsafe impl InlineComment for () {}
425+
426+
unsafe trait TrailingComment {}
427+
428+
unsafe impl TrailingComment for () {} // SAFETY:
429+
430+
unsafe trait Interference {}
431+
// SAFETY:
432+
const BIG_NUMBER: i32 = 1000000;
433+
unsafe impl Interference for () {}
434+
}
435+
337436
fn main() {}

tests/ui/undocumented_unsafe_blocks.stderr

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,5 +147,53 @@ LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
147147
|
148148
= help: consider adding a safety comment on the preceding line
149149

150-
error: aborting due to 18 previous errors
150+
error: unsafe impl missing a safety comment
151+
--> $DIR/undocumented_unsafe_blocks.rs:341:5
152+
|
153+
LL | unsafe impl A for () {}
154+
| ^^^^^^^^^^^^^^^^^^^^^^^
155+
|
156+
= help: consider adding a safety comment on the preceding line
157+
158+
error: unsafe impl missing a safety comment
159+
--> $DIR/undocumented_unsafe_blocks.rs:348:9
160+
|
161+
LL | unsafe impl B for (u32) {}
162+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
163+
|
164+
= help: consider adding a safety comment on the preceding line
165+
166+
error: unsafe impl missing a safety comment
167+
--> $DIR/undocumented_unsafe_blocks.rs:420:5
168+
|
169+
LL | unsafe impl NoComment for () {}
170+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
171+
|
172+
= help: consider adding a safety comment on the preceding line
173+
174+
error: unsafe impl missing a safety comment
175+
--> $DIR/undocumented_unsafe_blocks.rs:424:19
176+
|
177+
LL | /* SAFETY: */ unsafe impl InlineComment for () {}
178+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
179+
|
180+
= help: consider adding a safety comment on the preceding line
181+
182+
error: unsafe impl missing a safety comment
183+
--> $DIR/undocumented_unsafe_blocks.rs:428:5
184+
|
185+
LL | unsafe impl TrailingComment for () {} // SAFETY:
186+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
187+
|
188+
= help: consider adding a safety comment on the preceding line
189+
190+
error: unsafe impl missing a safety comment
191+
--> $DIR/undocumented_unsafe_blocks.rs:433:5
192+
|
193+
LL | unsafe impl Interference for () {}
194+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
195+
|
196+
= help: consider adding a safety comment on the preceding line
197+
198+
error: aborting due to 24 previous errors
151199

0 commit comments

Comments
 (0)