Skip to content

Commit 8a03ad3

Browse files
committed
Added semicolon_inside_block lint
1 parent 5ec80f3 commit 8a03ad3

File tree

5 files changed

+186
-0
lines changed

5 files changed

+186
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2639,6 +2639,7 @@ Released 2018-09-13
26392639
[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
26402640
[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
26412641
[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
2642+
[`semicolon_inside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block
26422643
[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
26432644
[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
26442645
[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same

clippy_lints/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ mod repeat_once;
323323
mod returns;
324324
mod self_assignment;
325325
mod semicolon_if_nothing_returned;
326+
mod semicolon_inside_block;
326327
mod serde_api;
327328
mod shadow;
328329
mod single_component_path_imports;
@@ -887,6 +888,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
887888
returns::NEEDLESS_RETURN,
888889
self_assignment::SELF_ASSIGNMENT,
889890
semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
891+
semicolon_inside_block::SEMICOLON_INSIDE_BLOCK,
890892
serde_api::SERDE_API_MISUSE,
891893
shadow::SHADOW_REUSE,
892894
shadow::SHADOW_SAME,
@@ -1111,6 +1113,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11111113
LintId::of(redundant_else::REDUNDANT_ELSE),
11121114
LintId::of(ref_option_ref::REF_OPTION_REF),
11131115
LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
1116+
LintId::of(semicolon_inside_block::SEMICOLON_INSIDE_BLOCK),
11141117
LintId::of(shadow::SHADOW_UNRELATED),
11151118
LintId::of(strings::STRING_ADD_ASSIGN),
11161119
LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
@@ -2049,6 +2052,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
20492052
store.register_late_pass(|| box manual_ok_or::ManualOkOr);
20502053
store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
20512054
store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
2055+
store.register_late_pass(|| box semicolon_inside_block::SemicolonInsideBlock);
20522056
store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
20532057
let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
20542058
store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use crate::rustc_lint::LintContext;
2+
use clippy_utils::diagnostics::span_lint_and_sugg;
3+
use clippy_utils::in_macro;
4+
use clippy_utils::source::snippet_with_macro_callsite;
5+
use if_chain::if_chain;
6+
use rustc_errors::Applicability;
7+
use rustc_hir::{Block, ExprKind};
8+
use rustc_lint::{LateContext, LateLintPass};
9+
use rustc_session::{declare_lint_pass, declare_tool_lint};
10+
11+
declare_clippy_lint! {
12+
/// **What it does:** For () returning expressions, check that the semicolon is inside the block.
13+
///
14+
/// **Why is this bad?** For consistency it's best to have the semicolon inside/outside the block. Either way is fine and this lint suggests inside the block.
15+
/// Take a look at `semicolon_outside_block` for the other alternative.
16+
///
17+
/// **Known problems:** None.
18+
///
19+
/// **Example:**
20+
///
21+
/// ```rust
22+
/// unsafe { f(x) };
23+
/// ```
24+
/// Use instead:
25+
/// ```rust
26+
/// unsafe { f(x); }
27+
/// ```
28+
pub SEMICOLON_INSIDE_BLOCK,
29+
pedantic,
30+
"add a semicolon inside the block"
31+
}
32+
33+
declare_lint_pass!(SemicolonInsideBlock => [SEMICOLON_INSIDE_BLOCK]);
34+
35+
impl LateLintPass<'_> for SemicolonInsideBlock {
36+
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
37+
if_chain! {
38+
if !in_macro(block.span);
39+
if let Some(expr) = block.expr;
40+
let t_expr = cx.typeck_results().expr_ty(expr);
41+
if t_expr.is_unit();
42+
if let snippet = snippet_with_macro_callsite(cx, expr.span, "}");
43+
if !snippet.ends_with("};") && !snippet.ends_with('}');
44+
then {
45+
// filter out the desugared `for` loop
46+
if let ExprKind::DropTemps(..) = &expr.kind {
47+
return;
48+
}
49+
50+
let expr_snip = snippet_with_macro_callsite(cx, expr.span, "..");
51+
52+
// check for the right suggestion and span, differs if the block spans
53+
// multiple lines
54+
let (suggestion, span) = if cx.sess().source_map().is_multiline(block.span) {
55+
(format!("{};", expr_snip), expr.span.source_callsite())
56+
} else {
57+
let block_with_pot_sem = cx.sess().source_map().span_extend_to_next_char(block.span, '\n', false);
58+
let block_snip = snippet_with_macro_callsite(cx, block.span, "..");
59+
60+
(block_snip.replace(expr_snip.as_ref(), &format!("{};", expr_snip)), block_with_pot_sem)
61+
};
62+
63+
span_lint_and_sugg(
64+
cx,
65+
SEMICOLON_INSIDE_BLOCK,
66+
span,
67+
"consider moving the `;` inside the block for consistent formatting",
68+
"put the `;` here",
69+
suggestion,
70+
Applicability::MaybeIncorrect,
71+
);
72+
}
73+
}
74+
}
75+
}

tests/ui/semicolon_inside_block.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#![warn(clippy::semicolon_inside_block)]
2+
3+
unsafe fn f(arg: u32) {}
4+
5+
fn main() {
6+
let x = 32;
7+
8+
unsafe { f(x) };
9+
}
10+
11+
fn get_unit() {}
12+
13+
fn fooooo() {
14+
unsafe { f(32) }
15+
}
16+
17+
fn moin() {
18+
println!("Hello")
19+
}
20+
21+
fn hello() {
22+
get_unit()
23+
}
24+
25+
fn basic101(x: i32) {
26+
let y: i32;
27+
y = x + 1
28+
}
29+
30+
#[rustfmt::skip]
31+
fn closure_error() {
32+
let _d = || {
33+
hello()
34+
};
35+
}
36+
37+
fn my_own_block() {
38+
let x: i32;
39+
{
40+
let y = 42;
41+
x = y + 1;
42+
basic101(x)
43+
}
44+
assert_eq!(43, 43)
45+
}
46+
47+
#[rustfmt::skip]
48+
fn one_line_block() { println!("Foo") }
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
error: consider moving the `;` inside the block for consistent formatting
2+
--> $DIR/semicolon_inside_block.rs:8:5
3+
|
4+
LL | unsafe { f(x) };
5+
| ^^^^^^^^^^^^^^^^ help: put the `;` here: `unsafe { f(x); }`
6+
|
7+
= note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
8+
9+
error: consider moving the `;` inside the block for consistent formatting
10+
--> $DIR/semicolon_inside_block.rs:14:5
11+
|
12+
LL | unsafe { f(32) }
13+
| ^^^^^^^^^^^^^^^^ help: put the `;` here: `unsafe { f(32); }`
14+
15+
error: consider moving the `;` inside the block for consistent formatting
16+
--> $DIR/semicolon_inside_block.rs:18:5
17+
|
18+
LL | println!("Hello")
19+
| ^^^^^^^^^^^^^^^^^ help: put the `;` here: `println!("Hello");`
20+
21+
error: consider moving the `;` inside the block for consistent formatting
22+
--> $DIR/semicolon_inside_block.rs:22:5
23+
|
24+
LL | get_unit()
25+
| ^^^^^^^^^^ help: put the `;` here: `get_unit();`
26+
27+
error: consider moving the `;` inside the block for consistent formatting
28+
--> $DIR/semicolon_inside_block.rs:27:5
29+
|
30+
LL | y = x + 1
31+
| ^^^^^^^^^ help: put the `;` here: `y = x + 1;`
32+
33+
error: consider moving the `;` inside the block for consistent formatting
34+
--> $DIR/semicolon_inside_block.rs:33:9
35+
|
36+
LL | hello()
37+
| ^^^^^^^ help: put the `;` here: `hello();`
38+
39+
error: consider moving the `;` inside the block for consistent formatting
40+
--> $DIR/semicolon_inside_block.rs:44:5
41+
|
42+
LL | assert_eq!(43, 43)
43+
| ^^^^^^^^^^^^^^^^^^ help: put the `;` here: `assert_eq!(43, 43);`
44+
45+
error: consider moving the `;` inside the block for consistent formatting
46+
--> $DIR/semicolon_inside_block.rs:42:9
47+
|
48+
LL | basic101(x)
49+
| ^^^^^^^^^^^ help: put the `;` here: `basic101(x);`
50+
51+
error: consider moving the `;` inside the block for consistent formatting
52+
--> $DIR/semicolon_inside_block.rs:48:21
53+
|
54+
LL | fn one_line_block() { println!("Foo") }
55+
| ^^^^^^^^^^^^^^^^^^^ help: put the `;` here: `{ println!("Foo"); }`
56+
57+
error: aborting due to 9 previous errors
58+

0 commit comments

Comments
 (0)