about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--book/src/lint_configuration.md18
-rw-r--r--clippy_lints/src/lib.rs9
-rw-r--r--clippy_lints/src/semicolon_block.rs125
-rw-r--r--clippy_lints/src/utils/conf.rs8
-rw-r--r--tests/ui-toml/semicolon_block/both.fixed86
-rw-r--r--tests/ui-toml/semicolon_block/both.rs86
-rw-r--r--tests/ui-toml/semicolon_block/both.stderr55
-rw-r--r--tests/ui-toml/semicolon_block/clippy.toml2
-rw-r--r--tests/ui-toml/semicolon_block/semicolon_inside_block.fixed85
-rw-r--r--tests/ui-toml/semicolon_block/semicolon_inside_block.rs85
-rw-r--r--tests/ui-toml/semicolon_block/semicolon_inside_block.stderr18
-rw-r--r--tests/ui-toml/semicolon_block/semicolon_outside_block.fixed85
-rw-r--r--tests/ui-toml/semicolon_block/semicolon_outside_block.rs85
-rw-r--r--tests/ui-toml/semicolon_block/semicolon_outside_block.stderr39
-rw-r--r--tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
15 files changed, 744 insertions, 44 deletions
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md
index a702226e861..5646c9b1520 100644
--- a/book/src/lint_configuration.md
+++ b/book/src/lint_configuration.md
@@ -13,6 +13,8 @@ Please use that command to update the file and do not edit it by hand.
 | [msrv](#msrv) | `None` |
 | [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` |
 | [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` |
+| [semicolon-inside-block-ignore-singleline](#semicolon-inside-block-ignore-singleline) | `false` |
+| [semicolon-outside-block-ignore-multiline](#semicolon-outside-block-ignore-multiline) | `false` |
 | [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` |
 | [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` |
 | [type-complexity-threshold](#type-complexity-threshold) | `250` |
@@ -203,6 +205,22 @@ default configuration of Clippy. By default, any configuration will replace the
 * [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names)
 
 
+### semicolon-inside-block-ignore-singleline
+Whether to lint only if it's multiline.
+
+**Default Value:** `false` (`bool`)
+
+* [semicolon_inside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block)
+
+
+### semicolon-outside-block-ignore-multiline
+Whether to lint only if it's singleline.
+
+**Default Value:** `false` (`bool`)
+
+* [semicolon_outside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block)
+
+
 ### doc-valid-idents
 The list of words this lint should not consider as identifiers needing ticks. The value
 `".."` can be used as part of the list to indicate, that the configured values should be appended to the
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 573ffe349ec..48dbecc9f6a 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -933,7 +933,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
     store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
-    store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
+    let semicolon_inside_block_ignore_singleline = conf.semicolon_inside_block_ignore_singleline;
+    let semicolon_outside_block_ignore_multiline = conf.semicolon_outside_block_ignore_multiline;
+    store.register_late_pass(move |_| {
+        Box::new(semicolon_block::SemicolonBlock::new(
+            semicolon_inside_block_ignore_singleline,
+            semicolon_outside_block_ignore_multiline,
+        ))
+    });
     store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
     store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
     store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs
index 34a3e5ddf4f..419d7991f0e 100644
--- a/clippy_lints/src/semicolon_block.rs
+++ b/clippy_lints/src/semicolon_block.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -64,7 +64,78 @@ declare_clippy_lint! {
     restriction,
     "add a semicolon outside the block"
 }
-declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+impl_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+
+#[derive(Copy, Clone)]
+pub struct SemicolonBlock {
+    semicolon_inside_block_ignore_singleline: bool,
+    semicolon_outside_block_ignore_multiline: bool,
+}
+
+impl SemicolonBlock {
+    pub fn new(semicolon_inside_block_ignore_singleline: bool, semicolon_outside_block_ignore_multiline: bool) -> Self {
+        Self {
+            semicolon_inside_block_ignore_singleline,
+            semicolon_outside_block_ignore_multiline,
+        }
+    }
+
+    fn semicolon_inside_block(self, cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
+        let insert_span = tail.span.source_callsite().shrink_to_hi();
+        let remove_span = semi_span.with_lo(block.span.hi());
+
+        if self.semicolon_inside_block_ignore_singleline && get_line(cx, remove_span) == get_line(cx, insert_span) {
+            return;
+        }
+
+        span_lint_and_then(
+            cx,
+            SEMICOLON_INSIDE_BLOCK,
+            semi_span,
+            "consider moving the `;` inside the block for consistent formatting",
+            |diag| {
+                multispan_sugg_with_applicability(
+                    diag,
+                    "put the `;` here",
+                    Applicability::MachineApplicable,
+                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
+                );
+            },
+        );
+    }
+
+    fn semicolon_outside_block(
+        self,
+        cx: &LateContext<'_>,
+        block: &Block<'_>,
+        tail_stmt_expr: &Expr<'_>,
+        semi_span: Span,
+    ) {
+        let insert_span = block.span.with_lo(block.span.hi());
+        // account for macro calls
+        let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
+        let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
+
+        if self.semicolon_outside_block_ignore_multiline && get_line(cx, remove_span) != get_line(cx, insert_span) {
+            return;
+        }
+
+        span_lint_and_then(
+            cx,
+            SEMICOLON_OUTSIDE_BLOCK,
+            block.span,
+            "consider moving the `;` outside the block for consistent formatting",
+            |diag| {
+                multispan_sugg_with_applicability(
+                    diag,
+                    "put the `;` here",
+                    Applicability::MachineApplicable,
+                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
+                );
+            },
+        );
+    }
+}
 
 impl LateLintPass<'_> for SemicolonBlock {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
@@ -83,55 +154,23 @@ impl LateLintPass<'_> for SemicolonBlock {
                     span,
                     ..
                 } = stmt else { return };
-                semicolon_outside_block(cx, block, expr, span);
+                self.semicolon_outside_block(cx, block, expr, span);
             },
             StmtKind::Semi(Expr {
                 kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _),
                 ..
-            }) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span),
+            }) if !block.span.from_expansion() => {
+                self.semicolon_inside_block(cx, block, tail, stmt.span);
+            },
             _ => (),
         }
     }
 }
 
-fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
-    let insert_span = tail.span.source_callsite().shrink_to_hi();
-    let remove_span = semi_span.with_lo(block.span.hi());
-
-    span_lint_and_then(
-        cx,
-        SEMICOLON_INSIDE_BLOCK,
-        semi_span,
-        "consider moving the `;` inside the block for consistent formatting",
-        |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "put the `;` here",
-                Applicability::MachineApplicable,
-                [(remove_span, String::new()), (insert_span, ";".to_owned())],
-            );
-        },
-    );
-}
-
-fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) {
-    let insert_span = block.span.with_lo(block.span.hi());
-    // account for macro calls
-    let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
-    let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
+fn get_line(cx: &LateContext<'_>, span: Span) -> Option<usize> {
+    if let Ok(line) = cx.sess().source_map().lookup_line(span.lo()) {
+        return Some(line.line);
+    }
 
-    span_lint_and_then(
-        cx,
-        SEMICOLON_OUTSIDE_BLOCK,
-        block.span,
-        "consider moving the `;` outside the block for consistent formatting",
-        |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "put the `;` here",
-                Applicability::MachineApplicable,
-                [(remove_span, String::new()), (insert_span, ";".to_owned())],
-            );
-        },
-    );
+    None
 }
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 67bb499c455..5f05d971fce 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -277,6 +277,14 @@ define_Conf! {
     /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
     /// default configuration of Clippy. By default, any configuration will replace the default value.
     (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
+    /// Lint: SEMICOLON_INSIDE_BLOCK.
+    ///
+    /// Whether to lint only if it's multiline.
+    (semicolon_inside_block_ignore_singleline: bool = false),
+    /// Lint: SEMICOLON_OUTSIDE_BLOCK.
+    ///
+    /// Whether to lint only if it's singleline.
+    (semicolon_outside_block_ignore_multiline: bool = false),
     /// Lint: DOC_MARKDOWN.
     ///
     /// The list of words this lint should not consider as identifiers needing ticks. The value
diff --git a/tests/ui-toml/semicolon_block/both.fixed b/tests/ui-toml/semicolon_block/both.fixed
new file mode 100644
index 00000000000..fc8038a0907
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/both.fixed
@@ -0,0 +1,86 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()) };
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/both.rs b/tests/ui-toml/semicolon_block/both.rs
new file mode 100644
index 00000000000..52ce1f0387e
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/both.rs
@@ -0,0 +1,86 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/both.stderr b/tests/ui-toml/semicolon_block/both.stderr
new file mode 100644
index 00000000000..2f58842eab0
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/both.stderr
@@ -0,0 +1,55 @@
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:43:5
+   |
+LL |     { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block(); }
+LL +     { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:44:5
+   |
+LL |     unsafe { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block(); }
+LL +     unsafe { unit_fn_block() };
+   |
+
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/both.rs:49:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block()
+LL | |     };
+   | |______^
+   |
+   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL ~         unit_fn_block();
+LL ~     }
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:63:5
+   |
+LL |     { m!(()); }
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()); }
+LL +     { m!(()) };
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui-toml/semicolon_block/clippy.toml b/tests/ui-toml/semicolon_block/clippy.toml
new file mode 100644
index 00000000000..4d03e88deba
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/clippy.toml
@@ -0,0 +1,2 @@
+semicolon-inside-block-ignore-singleline = true
+semicolon-outside-block-ignore-multiline = true
diff --git a/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed b/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed
new file mode 100644
index 00000000000..23df9830177
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/semicolon_inside_block.rs b/tests/ui-toml/semicolon_block/semicolon_inside_block.rs
new file mode 100644
index 00000000000..e8516f79b20
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_inside_block.rs
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr b/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr
new file mode 100644
index 00000000000..2569dc4b4e4
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr
@@ -0,0 +1,18 @@
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:48:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block()
+LL | |     };
+   | |______^
+   |
+   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL ~         unit_fn_block();
+LL ~     }
+   |
+
+error: aborting due to previous error
+
diff --git a/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed b/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed
new file mode 100644
index 00000000000..7e9055e7110
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()) };
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/semicolon_outside_block.rs b/tests/ui-toml/semicolon_block/semicolon_outside_block.rs
new file mode 100644
index 00000000000..4dc956d8a4b
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_outside_block.rs
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr b/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr
new file mode 100644
index 00000000000..6dd3577dd09
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr
@@ -0,0 +1,39 @@
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:42:5
+   |
+LL |     { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block(); }
+LL +     { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:43:5
+   |
+LL |     unsafe { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block(); }
+LL +     unsafe { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:62:5
+   |
+LL |     { m!(()); }
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()); }
+LL +     { m!(()) };
+   |
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 36b372b36f4..44710b09648 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -37,6 +37,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            missing-docs-in-crate-items
            msrv
            pass-by-value-size-limit
+           semicolon-inside-block-ignore-singleline
+           semicolon-outside-block-ignore-multiline
            single-char-binding-names-threshold
            standard-macro-braces
            suppress-restriction-lint-in-const