Skip to content

Commit 8fd021f

Browse files
committed
Auto merge of rust-lang#10986 - Centri3:undocumented_unsafe_blocks, r=Manishearth
Allow safety comment above attributes Closes rust-lang#8679 changelog: Enhancement: [`undocumented_safety_block`]: Added `accept-comment-above-attributes` configuration.
2 parents 1919dff + cc2e49f commit 8fd021f

File tree

9 files changed

+162
-48
lines changed

9 files changed

+162
-48
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5385,4 +5385,5 @@ Released 2018-09-13
53855385
[`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars
53865386
[`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold
53875387
[`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement
5388+
[`accept-comment-above-attributes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-attributes
53885389
<!-- end autogenerated links to configuration documentation -->

Diff for: book/src/lint_configuration.md

+10
Original file line numberDiff line numberDiff line change
@@ -706,3 +706,13 @@ Whether to accept a safety comment to be placed above the statement containing t
706706
* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks)
707707

708708

709+
## `accept-comment-above-attributes`
710+
Whether to accept a safety comment to be placed above the attributes for the `unsafe` block
711+
712+
**Default Value:** `false` (`bool`)
713+
714+
---
715+
**Affected lints:**
716+
* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks)
717+
718+

Diff for: clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -930,9 +930,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
930930
))
931931
});
932932
let accept_comment_above_statement = conf.accept_comment_above_statement;
933+
let accept_comment_above_attributes = conf.accept_comment_above_attributes;
933934
store.register_late_pass(move |_| {
934935
Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(
935936
accept_comment_above_statement,
937+
accept_comment_above_attributes,
936938
))
937939
});
938940
let allow_mixed_uninlined = conf.allow_mixed_uninlined_format_args;

Diff for: clippy_lints/src/undocumented_unsafe_blocks.rs

+71-10
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,14 @@ declare_clippy_lint! {
9595
#[derive(Copy, Clone)]
9696
pub struct UndocumentedUnsafeBlocks {
9797
accept_comment_above_statement: bool,
98+
accept_comment_above_attributes: bool,
9899
}
99100

100101
impl UndocumentedUnsafeBlocks {
101-
pub fn new(accept_comment_above_statement: bool) -> Self {
102+
pub fn new(accept_comment_above_statement: bool, accept_comment_above_attributes: bool) -> Self {
102103
Self {
103104
accept_comment_above_statement,
105+
accept_comment_above_attributes,
104106
}
105107
}
106108
}
@@ -114,7 +116,12 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
114116
&& !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
115117
&& !is_unsafe_from_proc_macro(cx, block.span)
116118
&& !block_has_safety_comment(cx, block.span)
117-
&& !block_parents_have_safety_comment(self.accept_comment_above_statement, cx, block.hir_id)
119+
&& !block_parents_have_safety_comment(
120+
self.accept_comment_above_statement,
121+
self.accept_comment_above_attributes,
122+
cx,
123+
block.hir_id,
124+
)
118125
{
119126
let source_map = cx.tcx.sess.source_map();
120127
let span = if source_map.is_multiline(block.span) {
@@ -328,6 +335,7 @@ fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool {
328335
// has a safety comment
329336
fn block_parents_have_safety_comment(
330337
accept_comment_above_statement: bool,
338+
accept_comment_above_attributes: bool,
331339
cx: &LateContext<'_>,
332340
id: hir::HirId,
333341
) -> bool {
@@ -343,33 +351,77 @@ fn block_parents_have_safety_comment(
343351
}),
344352
) = get_parent_node(cx.tcx, expr.hir_id)
345353
{
354+
let hir_id = match get_parent_node(cx.tcx, expr.hir_id) {
355+
Some(Node::Local(hir::Local { hir_id, .. })) => *hir_id,
356+
Some(Node::Item(hir::Item { owner_id, .. })) => {
357+
cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id)
358+
},
359+
_ => unreachable!(),
360+
};
361+
346362
// if unsafe block is part of a let/const/static statement,
347363
// and accept_comment_above_statement is set to true
348364
// we accept the safety comment in the line the precedes this statement.
349-
accept_comment_above_statement && span_in_body_has_safety_comment(cx, *span)
365+
accept_comment_above_statement
366+
&& span_with_attrs_in_body_has_safety_comment(
367+
cx,
368+
*span,
369+
hir_id,
370+
accept_comment_above_attributes,
371+
)
350372
} else {
351-
!is_branchy(expr) && span_in_body_has_safety_comment(cx, expr.span)
373+
!is_branchy(expr)
374+
&& span_with_attrs_in_body_has_safety_comment(
375+
cx,
376+
expr.span,
377+
expr.hir_id,
378+
accept_comment_above_attributes,
379+
)
352380
}
353381
},
354382
Node::Stmt(hir::Stmt {
355383
kind:
356-
hir::StmtKind::Local(hir::Local { span, .. })
357-
| hir::StmtKind::Expr(hir::Expr { span, .. })
358-
| hir::StmtKind::Semi(hir::Expr { span, .. }),
384+
hir::StmtKind::Local(hir::Local { span, hir_id, .. })
385+
| hir::StmtKind::Expr(hir::Expr { span, hir_id, .. })
386+
| hir::StmtKind::Semi(hir::Expr { span, hir_id, .. }),
359387
..
360388
})
361-
| Node::Local(hir::Local { span, .. })
362-
| Node::Item(hir::Item {
389+
| Node::Local(hir::Local { span, hir_id, .. }) => {
390+
span_with_attrs_in_body_has_safety_comment(cx, *span, *hir_id, accept_comment_above_attributes)
391+
},
392+
Node::Item(hir::Item {
363393
kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
364394
span,
395+
owner_id,
365396
..
366-
}) => span_in_body_has_safety_comment(cx, *span),
397+
}) => span_with_attrs_in_body_has_safety_comment(
398+
cx,
399+
*span,
400+
cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id),
401+
accept_comment_above_attributes,
402+
),
367403
_ => false,
368404
};
369405
}
370406
false
371407
}
372408

409+
/// Extends `span` to also include its attributes, then checks if that span has a safety comment.
410+
fn span_with_attrs_in_body_has_safety_comment(
411+
cx: &LateContext<'_>,
412+
span: Span,
413+
hir_id: HirId,
414+
accept_comment_above_attributes: bool,
415+
) -> bool {
416+
let span = if accept_comment_above_attributes {
417+
include_attrs_in_span(cx, hir_id, span)
418+
} else {
419+
span
420+
};
421+
422+
span_in_body_has_safety_comment(cx, span)
423+
}
424+
373425
/// Checks if an expression is "branchy", e.g. loop, match/if/etc.
374426
fn is_branchy(expr: &hir::Expr<'_>) -> bool {
375427
matches!(
@@ -394,6 +446,15 @@ fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
394446
) || span_in_body_has_safety_comment(cx, span)
395447
}
396448

449+
fn include_attrs_in_span(cx: &LateContext<'_>, hir_id: HirId, span: Span) -> Span {
450+
span.to(cx
451+
.tcx
452+
.hir()
453+
.attrs(hir_id)
454+
.iter()
455+
.fold(span, |acc, attr| acc.to(attr.span)))
456+
}
457+
397458
enum HasSafetyComment {
398459
Yes(BytePos),
399460
No,

Diff for: clippy_lints/src/utils/conf.rs

+4
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,10 @@ define_Conf! {
542542
///
543543
/// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
544544
(accept_comment_above_statement: bool = false),
545+
/// Lint: UNDOCUMENTED_UNSAFE_BLOCKS.
546+
///
547+
/// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block
548+
(accept_comment_above_attributes: bool = false),
545549
}
546550

547551
/// Search for the configuration file.

Diff for: tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
error: error reading Clippy's configuration file: unknown field `foobar`, expected one of
2+
accept-comment-above-attributes
23
accept-comment-above-statement
34
allow-dbg-in-tests
45
allow-expect-in-tests
@@ -66,6 +67,7 @@ LL | foobar = 42
6667
| ^^^^^^
6768

6869
error: error reading Clippy's configuration file: unknown field `barfoo`, expected one of
70+
accept-comment-above-attributes
6971
accept-comment-above-statement
7072
allow-dbg-in-tests
7173
allow-expect-in-tests

Diff for: tests/ui-toml/undocumented_unsafe_blocks/clippy.toml

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
accept-comment-above-statement = true
2+
accept-comment-above-attributes = true

Diff for: tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//@aux-build:proc_macro_unsafe.rs
22

33
#![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)]
4-
#![allow(clippy::let_unit_value, clippy::missing_safety_doc)]
4+
#![allow(deref_nullptr, clippy::let_unit_value, clippy::missing_safety_doc)]
5+
#![feature(lint_reasons)]
56

67
extern crate proc_macro_unsafe;
78

@@ -531,4 +532,36 @@ fn issue_10832() {
531532
unsafe { a_const_function_with_a_very_long_name_to_break_the_line() };
532533
}
533534

535+
fn issue_8679<T: Copy>() {
536+
// SAFETY:
537+
#[allow(unsafe_code)]
538+
unsafe {}
539+
540+
// SAFETY:
541+
#[expect(unsafe_code, reason = "totally safe")]
542+
unsafe {
543+
*std::ptr::null::<T>()
544+
};
545+
546+
// Safety: A safety comment
547+
#[allow(unsafe_code)]
548+
let _some_variable_with_a_very_long_name_to_break_the_line =
549+
unsafe { a_function_with_a_very_long_name_to_break_the_line() };
550+
551+
// Safety: Another safety comment
552+
#[allow(unsafe_code)]
553+
const _SOME_CONST_WITH_A_VERY_LONG_NAME_TO_BREAK_THE_LINE: u32 =
554+
unsafe { a_const_function_with_a_very_long_name_to_break_the_line() };
555+
556+
// Safety: Yet another safety comment
557+
#[allow(unsafe_code)]
558+
static _SOME_STATIC_WITH_A_VERY_LONG_NAME_TO_BREAK_THE_LINE: u32 =
559+
unsafe { a_const_function_with_a_very_long_name_to_break_the_line() };
560+
561+
// SAFETY:
562+
#[allow(unsafe_code)]
563+
// This also works I guess
564+
unsafe {}
565+
}
566+
534567
fn main() {}

0 commit comments

Comments
 (0)