Auto merge of #10656 - Centri3:master, r=xFrednet

Add configuration for `semicolon_block` lints

Does exactly what it says on the tin, suggests moving a block's final semicolon inside if it's multiline and outside if it's singleline.

I don't really like how this is implemented so I'm not too sure if this is ready yet. Alas, it might be ok.

---

fixes #10654

changelog: Enhancement: [`semicolon_inside_block`]: Added `semicolon-inside-block-ignore-singleline` as a new config value.
[#10656](https://github.com/rust-lang/rust-clippy/pull/10656)
changelog: Enhancement: [`semicolon_outside_block`]: Added `semicolon-outside-block-ignore-multiline` as a new config value.
[#10656](https://github.com/rust-lang/rust-clippy/pull/10656)
<!-- changelog_checked -->
This commit is contained in:
bors 2023-04-25 20:12:00 +00:00
commit 990bbdc2be
15 changed files with 744 additions and 44 deletions

View file

@ -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

View file

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

View file

@ -2,7 +2,7 @@
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 @@
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 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
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());
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_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());
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
}

View file

@ -277,6 +277,14 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// `".."` 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

View file

@ -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()
}

View file

@ -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()
}

View file

@ -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

View file

@ -0,0 +1,2 @@
semicolon-inside-block-ignore-singleline = true
semicolon-outside-block-ignore-multiline = true

View file

@ -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()
}

View file

@ -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()
}

View file

@ -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

View file

@ -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()
}

View file

@ -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()
}

View file

@ -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

View file

@ -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