Skip to content

Add configuration for semicolon_block lints #10656

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,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_if_multiline = conf.semicolon_inside_block_if_multiline;
let semicolon_outside_block_if_singleline = conf.semicolon_outside_block_if_singleline;
store.register_late_pass(move |_| {
Box::new(semicolon_block::SemicolonBlock::new(
semicolon_inside_block_if_multiline,
semicolon_outside_block_if_singleline,
))
});
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));
Expand Down
57 changes: 51 additions & 6 deletions clippy_lints/src/semicolon_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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! {
Expand Down Expand Up @@ -64,7 +64,22 @@ 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_if_multiline: bool,
semicolon_outside_block_if_singleline: bool,
}

impl SemicolonBlock {
pub fn new(semicolon_inside_block_if_multiline: bool, semicolon_outside_block_if_singleline: bool) -> Self {
Self {
semicolon_inside_block_if_multiline,
semicolon_outside_block_if_singleline,
}
}
}

impl LateLintPass<'_> for SemicolonBlock {
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
Expand All @@ -83,21 +98,33 @@ impl LateLintPass<'_> for SemicolonBlock {
span,
..
} = stmt else { return };
semicolon_outside_block(cx, block, expr, span);
semicolon_outside_block(self, 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() => {
semicolon_inside_block(self, cx, block, tail, stmt.span);
},
_ => (),
}
}
}

fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
fn semicolon_inside_block(
conf: &mut SemicolonBlock,
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 conf.semicolon_inside_block_if_multiline && get_line(cx, remove_span) == get_line(cx, insert_span) {
return;
}

span_lint_and_then(
cx,
SEMICOLON_INSIDE_BLOCK,
Expand All @@ -114,12 +141,22 @@ fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'
);
}

fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) {
fn semicolon_outside_block(
conf: &mut SemicolonBlock,
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 conf.semicolon_outside_block_if_singleline && get_line(cx, remove_span) != get_line(cx, insert_span) {
return;
}

span_lint_and_then(
cx,
SEMICOLON_OUTSIDE_BLOCK,
Expand All @@ -135,3 +172,11 @@ fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_ex
},
);
}

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);
}

None
}
8 changes: 8 additions & 0 deletions clippy_lints/src/utils/conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_if_multiline: bool = false),
/// Lint: SEMICOLON_OUTSIDE_BLOCK.
///
/// Whether to lint only if it's singleline.
(semicolon_outside_block_if_singleline: bool = false),
/// Lint: DOC_MARKDOWN.
///
/// The list of words this lint should not consider as identifiers needing ticks. The value
Expand Down
86 changes: 86 additions & 0 deletions tests/ui-toml/semicolon_block/both.fixed
Original file line number Diff line number Diff line change
@@ -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()
}
86 changes: 86 additions & 0 deletions tests/ui-toml/semicolon_block/both.rs
Original file line number Diff line number Diff line change
@@ -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()
}
55 changes: 55 additions & 0 deletions tests/ui-toml/semicolon_block/both.stderr
Original file line number Diff line number Diff line change
@@ -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

2 changes: 2 additions & 0 deletions tests/ui-toml/semicolon_block/clippy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
semicolon-inside-block-if-multiline = true
semicolon-outside-block-if-singleline = true
Loading