Skip to content

Commit

Permalink
Auto merge of #10886 - lochetti:fix_10832, r=Centri3,xFrednet
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
bors committed Jun 17, 2023
2 parents 965f4a8 + d610201 commit bb78d76
Show file tree
Hide file tree
Showing 12 changed files with 984 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5383,4 +5383,5 @@ Released 2018-09-13
[`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception
[`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars
[`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold
[`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement
<!-- end autogenerated links to configuration documentation -->
10 changes: 10 additions & 0 deletions book/src/lint_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -695,3 +695,13 @@ Minimum chars an ident can have, anything below or equal to this will be linted.
* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars)


## `accept-comment-above-statement`
Whether to accept a safety comment to be placed above the statement containing the `unsafe` block

**Default Value:** `false` (`bool`)

---
**Affected lints:**
* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks)


7 changes: 6 additions & 1 deletion clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
enable_raw_pointer_heuristic_for_send,
))
});
store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
let accept_comment_above_statement = conf.accept_comment_above_statement;
store.register_late_pass(move |_| {
Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(
accept_comment_above_statement,
))
});
let allow_mixed_uninlined = conf.allow_mixed_uninlined_format_args;
store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined)));
store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
Expand Down
53 changes: 47 additions & 6 deletions clippy_lints/src/undocumented_unsafe_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{BytePos, Pos, Span, SyntaxContext};

declare_clippy_lint! {
Expand Down Expand Up @@ -92,7 +92,20 @@ declare_clippy_lint! {
"annotating safe code with a safety comment"
}

declare_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECESSARY_SAFETY_COMMENT]);
#[derive(Copy, Clone)]
pub struct UndocumentedUnsafeBlocks {
accept_comment_above_statement: bool,
}

impl UndocumentedUnsafeBlocks {
pub fn new(accept_comment_above_statement: bool) -> Self {
Self {
accept_comment_above_statement,
}
}
}

impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECESSARY_SAFETY_COMMENT]);

impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
Expand All @@ -101,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
&& !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
&& !is_unsafe_from_proc_macro(cx, block.span)
&& !block_has_safety_comment(cx, block.span)
&& !block_parents_have_safety_comment(cx, block.hir_id)
&& !block_parents_have_safety_comment(self.accept_comment_above_statement, cx, block.hir_id)
{
let source_map = cx.tcx.sess.source_map();
let span = if source_map.is_multiline(block.span) {
Expand Down Expand Up @@ -313,10 +326,31 @@ fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool {

// Checks if any parent {expression, statement, block, local, const, static}
// has a safety comment
fn block_parents_have_safety_comment(cx: &LateContext<'_>, id: hir::HirId) -> bool {
fn block_parents_have_safety_comment(
accept_comment_above_statement: bool,
cx: &LateContext<'_>,
id: hir::HirId,
) -> bool {
if let Some(node) = get_parent_node(cx.tcx, id) {
return match node {
Node::Expr(expr) => !is_branchy(expr) && span_in_body_has_safety_comment(cx, expr.span),
Node::Expr(expr) => {
if let Some(
Node::Local(hir::Local { span, .. })
| Node::Item(hir::Item {
kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
span,
..
}),
) = get_parent_node(cx.tcx, expr.hir_id)
{
// if unsafe block is part of a let/const/static statement,
// and accept_comment_above_statement is set to true
// we accept the safety comment in the line the precedes this statement.
accept_comment_above_statement && span_in_body_has_safety_comment(cx, *span)
} else {
!is_branchy(expr) && span_in_body_has_safety_comment(cx, expr.span)
}
},
Node::Stmt(hir::Stmt {
kind:
hir::StmtKind::Local(hir::Local { span, .. })
Expand Down Expand Up @@ -546,7 +580,14 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
for (_, node) in map.parent_iter(body.hir_id) {
match node {
Node::Expr(e) => span = e.span,
Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::Local(_) => (),
Node::Block(_)
| Node::Arm(_)
| Node::Stmt(_)
| Node::Local(_)
| Node::Item(hir::Item {
kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
..
}) => (),
_ => break,
}
}
Expand Down
4 changes: 4 additions & 0 deletions clippy_lints/src/utils/conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,10 @@ define_Conf! {
///
/// Minimum chars an ident can have, anything below or equal to this will be linted.
(min_ident_chars_threshold: u64 = 1),
/// Lint: UNDOCUMENTED_UNSAFE_BLOCKS.
///
/// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
(accept_comment_above_statement: bool = false),
}

/// Search for the configuration file.
Expand Down
2 changes: 2 additions & 0 deletions tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
error: error reading Clippy's configuration file: unknown field `foobar`, expected one of
accept-comment-above-statement
allow-dbg-in-tests
allow-expect-in-tests
allow-mixed-uninlined-format-args
Expand Down Expand Up @@ -65,6 +66,7 @@ LL | foobar = 42
| ^^^^^^

error: error reading Clippy's configuration file: unknown field `barfoo`, expected one of
accept-comment-above-statement
allow-dbg-in-tests
allow-expect-in-tests
allow-mixed-uninlined-format-args
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//@compile-flags: --emit=link
//@no-prefer-dynamic

#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::{Delimiter, Group, Ident, TokenStream, TokenTree};

#[proc_macro]
pub fn unsafe_block(input: TokenStream) -> TokenStream {
let span = input.into_iter().next().unwrap().span();
TokenStream::from_iter([TokenTree::Ident(Ident::new("unsafe", span)), {
let mut group = Group::new(Delimiter::Brace, TokenStream::new());
group.set_span(span);
TokenTree::Group(group)
}])
}
1 change: 1 addition & 0 deletions tests/ui-toml/undocumented_unsafe_blocks/clippy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
accept-comment-above-statement = true
Loading

0 comments on commit bb78d76

Please sign in to comment.