Skip to content

Commit bb78d76

Browse files
committed
Auto merge of #10886 - lochetti:fix_10832, r=Centri3,xFrednet
Adding configuration to allow safety comment above stmt containing unsafe block Adding a new configuration, `accept-comment-above-statement`, to allow a safety comment to be placed before the statement that has the `unsafe` block. It affects the `undocumented_unsafe_blocks` lint. The default value for this configuration will be `false`. So the user has to opt-in for the change. This PR fixes #10832 --- changelog: Enhancement [`undocumented_unsafe_blocks`]: Added `accept-comment-above-statement` configuration. [#10886](#10886)
2 parents 965f4a8 + d610201 commit bb78d76

File tree

12 files changed

+984
-8
lines changed

12 files changed

+984
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5383,4 +5383,5 @@ Released 2018-09-13
53835383
[`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception
53845384
[`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars
53855385
[`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold
5386+
[`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement
53865387
<!-- end autogenerated links to configuration documentation -->

book/src/lint_configuration.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,3 +695,13 @@ Minimum chars an ident can have, anything below or equal to this will be linted.
695695
* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars)
696696

697697

698+
## `accept-comment-above-statement`
699+
Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
700+
701+
**Default Value:** `false` (`bool`)
702+
703+
---
704+
**Affected lints:**
705+
* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks)
706+
707+

clippy_lints/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
929929
enable_raw_pointer_heuristic_for_send,
930930
))
931931
});
932-
store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
932+
let accept_comment_above_statement = conf.accept_comment_above_statement;
933+
store.register_late_pass(move |_| {
934+
Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(
935+
accept_comment_above_statement,
936+
))
937+
});
933938
let allow_mixed_uninlined = conf.allow_mixed_uninlined_format_args;
934939
store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined)));
935940
store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));

clippy_lints/src/undocumented_unsafe_blocks.rs

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
1111
use rustc_lexer::{tokenize, TokenKind};
1212
use rustc_lint::{LateContext, LateLintPass, LintContext};
1313
use rustc_middle::lint::in_external_macro;
14-
use rustc_session::{declare_lint_pass, declare_tool_lint};
14+
use rustc_session::{declare_tool_lint, impl_lint_pass};
1515
use rustc_span::{BytePos, Pos, Span, SyntaxContext};
1616

1717
declare_clippy_lint! {
@@ -92,7 +92,20 @@ declare_clippy_lint! {
9292
"annotating safe code with a safety comment"
9393
}
9494

95-
declare_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECESSARY_SAFETY_COMMENT]);
95+
#[derive(Copy, Clone)]
96+
pub struct UndocumentedUnsafeBlocks {
97+
accept_comment_above_statement: bool,
98+
}
99+
100+
impl UndocumentedUnsafeBlocks {
101+
pub fn new(accept_comment_above_statement: bool) -> Self {
102+
Self {
103+
accept_comment_above_statement,
104+
}
105+
}
106+
}
107+
108+
impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECESSARY_SAFETY_COMMENT]);
96109

97110
impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
98111
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
@@ -101,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
101114
&& !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
102115
&& !is_unsafe_from_proc_macro(cx, block.span)
103116
&& !block_has_safety_comment(cx, block.span)
104-
&& !block_parents_have_safety_comment(cx, block.hir_id)
117+
&& !block_parents_have_safety_comment(self.accept_comment_above_statement, cx, block.hir_id)
105118
{
106119
let source_map = cx.tcx.sess.source_map();
107120
let span = if source_map.is_multiline(block.span) {
@@ -313,10 +326,31 @@ fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool {
313326

314327
// Checks if any parent {expression, statement, block, local, const, static}
315328
// has a safety comment
316-
fn block_parents_have_safety_comment(cx: &LateContext<'_>, id: hir::HirId) -> bool {
329+
fn block_parents_have_safety_comment(
330+
accept_comment_above_statement: bool,
331+
cx: &LateContext<'_>,
332+
id: hir::HirId,
333+
) -> bool {
317334
if let Some(node) = get_parent_node(cx.tcx, id) {
318335
return match node {
319-
Node::Expr(expr) => !is_branchy(expr) && span_in_body_has_safety_comment(cx, expr.span),
336+
Node::Expr(expr) => {
337+
if let Some(
338+
Node::Local(hir::Local { span, .. })
339+
| Node::Item(hir::Item {
340+
kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
341+
span,
342+
..
343+
}),
344+
) = get_parent_node(cx.tcx, expr.hir_id)
345+
{
346+
// if unsafe block is part of a let/const/static statement,
347+
// and accept_comment_above_statement is set to true
348+
// 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)
350+
} else {
351+
!is_branchy(expr) && span_in_body_has_safety_comment(cx, expr.span)
352+
}
353+
},
320354
Node::Stmt(hir::Stmt {
321355
kind:
322356
hir::StmtKind::Local(hir::Local { span, .. })
@@ -546,7 +580,14 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
546580
for (_, node) in map.parent_iter(body.hir_id) {
547581
match node {
548582
Node::Expr(e) => span = e.span,
549-
Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::Local(_) => (),
583+
Node::Block(_)
584+
| Node::Arm(_)
585+
| Node::Stmt(_)
586+
| Node::Local(_)
587+
| Node::Item(hir::Item {
588+
kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
589+
..
590+
}) => (),
550591
_ => break,
551592
}
552593
}

clippy_lints/src/utils/conf.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,10 @@ define_Conf! {
538538
///
539539
/// Minimum chars an ident can have, anything below or equal to this will be linted.
540540
(min_ident_chars_threshold: u64 = 1),
541+
/// Lint: UNDOCUMENTED_UNSAFE_BLOCKS.
542+
///
543+
/// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
544+
(accept_comment_above_statement: bool = false),
541545
}
542546

543547
/// Search for the configuration file.

tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr

Lines changed: 2 additions & 0 deletions
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-statement
23
allow-dbg-in-tests
34
allow-expect-in-tests
45
allow-mixed-uninlined-format-args
@@ -65,6 +66,7 @@ LL | foobar = 42
6566
| ^^^^^^
6667

6768
error: error reading Clippy's configuration file: unknown field `barfoo`, expected one of
69+
accept-comment-above-statement
6870
allow-dbg-in-tests
6971
allow-expect-in-tests
7072
allow-mixed-uninlined-format-args
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//@compile-flags: --emit=link
2+
//@no-prefer-dynamic
3+
4+
#![crate_type = "proc-macro"]
5+
6+
extern crate proc_macro;
7+
8+
use proc_macro::{Delimiter, Group, Ident, TokenStream, TokenTree};
9+
10+
#[proc_macro]
11+
pub fn unsafe_block(input: TokenStream) -> TokenStream {
12+
let span = input.into_iter().next().unwrap().span();
13+
TokenStream::from_iter([TokenTree::Ident(Ident::new("unsafe", span)), {
14+
let mut group = Group::new(Delimiter::Brace, TokenStream::new());
15+
group.set_span(span);
16+
TokenTree::Group(group)
17+
}])
18+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
accept-comment-above-statement = true

0 commit comments

Comments
 (0)