Skip to content

Commit dc9bc69

Browse files
committed
Use multi-span suggestions
1 parent d2039c8 commit dc9bc69

5 files changed

+124
-84
lines changed

clippy_lints/src/semicolon_block.rs

+65-62
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::source::snippet_with_macro_callsite;
3-
use clippy_utils::{get_parent_expr_for_hir, get_parent_node};
1+
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
42
use rustc_errors::Applicability;
5-
use rustc_hir::{Block, Expr, ExprKind, Node, Stmt, StmtKind};
3+
use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
64
use rustc_lint::{LateContext, LateLintPass};
75
use rustc_session::{declare_lint_pass, declare_tool_lint};
6+
use rustc_span::Span;
87

98
declare_clippy_lint! {
109
/// ### What it does
@@ -65,69 +64,73 @@ declare_clippy_lint! {
6564
declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
6665

6766
impl LateLintPass<'_> for SemicolonBlock {
68-
fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) {
69-
semicolon_inside_block(cx, block);
70-
semicolon_outside_block(cx, block);
71-
}
72-
}
73-
74-
fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>) {
75-
if !block.span.from_expansion()
76-
&& let Some(tail) = block.expr
77-
&& let Some(block_expr @ Expr { kind: ExprKind::Block(_, _), ..}) = get_parent_expr_for_hir(cx, block.hir_id)
78-
&& let Some(Node::Stmt(Stmt { kind: StmtKind::Semi(_), span, .. })) = get_parent_node(cx.tcx, block_expr.hir_id)
79-
{
80-
let expr_snip = snippet_with_macro_callsite(cx, tail.span, "..");
81-
82-
let mut suggestion: String = snippet_with_macro_callsite(cx, block.span, "..").to_string();
83-
84-
if let Some((expr_offset, _)) = suggestion.rmatch_indices(&*expr_snip).next() {
85-
suggestion.insert(expr_offset + expr_snip.len(), ';');
86-
} else {
87-
return;
67+
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
68+
match stmt.kind {
69+
StmtKind::Expr(Expr {
70+
kind:
71+
ExprKind::Block(
72+
block @ Block {
73+
expr: None,
74+
stmts:
75+
&[
76+
..,
77+
Stmt {
78+
kind: StmtKind::Semi(expr),
79+
span,
80+
..
81+
},
82+
],
83+
..
84+
},
85+
_,
86+
),
87+
..
88+
}) if !block.span.from_expansion() => semicolon_outside_block(cx, block, expr, span),
89+
StmtKind::Semi(Expr {
90+
kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _),
91+
..
92+
}) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span),
93+
_ => (),
8894
}
89-
90-
span_lint_and_sugg(
91-
cx,
92-
SEMICOLON_INSIDE_BLOCK,
93-
*span,
94-
"consider moving the `;` inside the block for consistent formatting",
95-
"put the `;` here",
96-
suggestion,
97-
Applicability::MaybeIncorrect,
98-
);
9995
}
10096
}
10197

102-
fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>) {
103-
if !block.span.from_expansion()
104-
&& block.expr.is_none()
105-
&& let [.., Stmt { kind: StmtKind::Semi(expr), .. }] = block.stmts
106-
&& let Some(block_expr @ Expr { kind: ExprKind::Block(_, _), ..}) = get_parent_expr_for_hir(cx,block.hir_id)
107-
&& let Some(Node::Stmt(Stmt { kind: StmtKind::Expr(_), .. })) = get_parent_node(cx.tcx, block_expr.hir_id)
108-
{
109-
let expr_snip = snippet_with_macro_callsite(cx, expr.span, "..");
110-
111-
let mut suggestion: String = snippet_with_macro_callsite(cx, block.span, "..").to_string();
98+
fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
99+
let insert_span = tail.span.with_lo(tail.span.hi());
100+
let remove_span = semi_span.with_lo(block.span.hi());
112101

113-
if let Some((expr_offset, _)) = suggestion.rmatch_indices(&*expr_snip).next()
114-
&& let Some(semi_offset) = suggestion[expr_offset + expr_snip.len()..].find(';')
115-
{
116-
suggestion.remove(expr_offset + expr_snip.len() + semi_offset);
117-
} else {
118-
return;
119-
}
102+
span_lint_and_then(
103+
cx,
104+
SEMICOLON_INSIDE_BLOCK,
105+
semi_span,
106+
"consider moving the `;` inside the block for consistent formatting",
107+
|diag| {
108+
multispan_sugg_with_applicability(
109+
diag,
110+
"put the `;` here",
111+
Applicability::MachineApplicable,
112+
[(remove_span, String::new()), (insert_span, ";".to_owned())],
113+
);
114+
},
115+
);
116+
}
120117

121-
suggestion.push(';');
118+
fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) {
119+
let insert_span = block.span.with_lo(block.span.hi());
120+
let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
122121

123-
span_lint_and_sugg(
124-
cx,
125-
SEMICOLON_OUTSIDE_BLOCK,
126-
block.span,
127-
"consider moving the `;` outside the block for consistent formatting",
128-
"put the `;` outside the block",
129-
suggestion,
130-
Applicability::MaybeIncorrect,
131-
);
132-
}
122+
span_lint_and_then(
123+
cx,
124+
SEMICOLON_OUTSIDE_BLOCK,
125+
block.span,
126+
"consider moving the `;` outside the block for consistent formatting",
127+
|diag| {
128+
multispan_sugg_with_applicability(
129+
diag,
130+
"put the `;` here",
131+
Applicability::MachineApplicable,
132+
[(remove_span, String::new()), (insert_span, ";".to_owned())],
133+
);
134+
},
135+
);
133136
}

tests/ui/semicolon_inside_block.fixed

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
macro_rules! m {
1212
(()) => {
13-
()
13+
();
1414
};
1515
(0) => {{
1616
0
@@ -58,7 +58,7 @@ fn main() {
5858
unit_fn_block();
5959
};
6060

61-
{ m!(()); }
61+
{ m!(()) }
6262
{ m!(()); }
6363
{ m!(()); };
6464
m!(0);

tests/ui/semicolon_inside_block.stderr

+25-7
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,26 @@ error: consider moving the `;` inside the block for consistent formatting
22
--> $DIR/semicolon_inside_block.rs:39:5
33
|
44
LL | { unit_fn_block() };
5-
| ^^^^^^^^^^^^^^^^^^^^ help: put the `;` here: `{ unit_fn_block(); }`
5+
| ^^^^^^^^^^^^^^^^^^^^
66
|
77
= note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
8+
help: put the `;` here
9+
|
10+
LL - { unit_fn_block() };
11+
LL + { unit_fn_block(); }
12+
|
813

914
error: consider moving the `;` inside the block for consistent formatting
1015
--> $DIR/semicolon_inside_block.rs:40:5
1116
|
1217
LL | unsafe { unit_fn_block() };
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: put the `;` here: `unsafe { unit_fn_block(); }`
18+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
19+
|
20+
help: put the `;` here
21+
|
22+
LL - unsafe { unit_fn_block() };
23+
LL + unsafe { unit_fn_block(); }
24+
|
1425

1526
error: consider moving the `;` inside the block for consistent formatting
1627
--> $DIR/semicolon_inside_block.rs:48:5
@@ -23,17 +34,24 @@ LL | | };
2334
|
2435
help: put the `;` here
2536
|
26-
LL ~ {
27-
LL + unit_fn_block();
28-
LL + unit_fn_block();
29-
LL + }
37+
LL ~ unit_fn_block();
38+
LL ~ }
3039
|
3140

3241
error: consider moving the `;` inside the block for consistent formatting
3342
--> $DIR/semicolon_inside_block.rs:61:5
3443
|
3544
LL | { m!(()) };
36-
| ^^^^^^^^^^^ help: put the `;` here: `{ m!(()); }`
45+
| ^^^^^^^^^^^
46+
|
47+
help: put the `;` here
48+
|
49+
LL ~ ();
50+
LL | };
51+
...
52+
LL |
53+
LL ~ { m!(()) }
54+
|
3755

3856
error: aborting due to 4 previous errors
3957

tests/ui/semicolon_outside_block.fixed

+9-5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ macro_rules! m {
2121
(2) => {{
2222
2;
2323
}};
24+
(stmt) => {
25+
stmt;
26+
};
2427
}
2528

2629
fn unit_fn_block() {
@@ -39,8 +42,8 @@ fn main() {
3942
{ unit_fn_block() };
4043
unsafe { unit_fn_block() };
4144

42-
{ unit_fn_block() };
43-
unsafe { unit_fn_block() };
45+
{ unit_fn_block(); }
46+
unsafe { unit_fn_block(); }
4447

4548
{ unit_fn_block(); };
4649
unsafe { unit_fn_block(); };
@@ -51,19 +54,20 @@ fn main() {
5154
};
5255
{
5356
unit_fn_block();
54-
unit_fn_block()
55-
};
57+
unit_fn_block();
58+
}
5659
{
5760
unit_fn_block();
5861
unit_fn_block();
5962
};
6063

6164
{ m!(()) };
62-
{ m!(()) };
65+
{ m!(()); }
6366
{ m!(()); };
6467
m!(0);
6568
m!(1);
6669
m!(2);
70+
{ m!(stmt) };
6771

6872
for _ in [()] {
6973
unit_fn_block();

tests/ui/semicolon_outside_block.stderr

+23-8
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,26 @@ error: consider moving the `;` outside the block for consistent formatting
22
--> $DIR/semicolon_outside_block.rs:42:5
33
|
44
LL | { unit_fn_block(); }
5-
| ^^^^^^^^^^^^^^^^^^^^ help: put the `;` outside the block: `{ unit_fn_block() };`
5+
| ^^^^^^^^^^^^^^^^^^^^
66
|
77
= note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
8+
help: put the `;` here
9+
|
10+
LL - { unit_fn_block(); }
11+
LL + { unit_fn_block() };
12+
|
813

914
error: consider moving the `;` outside the block for consistent formatting
1015
--> $DIR/semicolon_outside_block.rs:43:5
1116
|
1217
LL | unsafe { unit_fn_block(); }
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: put the `;` outside the block: `unsafe { unit_fn_block() };`
18+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
19+
|
20+
help: put the `;` here
21+
|
22+
LL - unsafe { unit_fn_block(); }
23+
LL + unsafe { unit_fn_block() };
24+
|
1425

1526
error: consider moving the `;` outside the block for consistent formatting
1627
--> $DIR/semicolon_outside_block.rs:52:5
@@ -21,19 +32,23 @@ LL | | unit_fn_block();
2132
LL | | }
2233
| |_____^
2334
|
24-
help: put the `;` outside the block
35+
help: put the `;` here
2536
|
26-
LL ~ {
27-
LL + unit_fn_block();
28-
LL + unit_fn_block()
29-
LL + };
37+
LL ~ unit_fn_block()
38+
LL ~ };
3039
|
3140

3241
error: consider moving the `;` outside the block for consistent formatting
3342
--> $DIR/semicolon_outside_block.rs:62:5
3443
|
3544
LL | { m!(()); }
36-
| ^^^^^^^^^^^ help: put the `;` outside the block: `{ m!(()) };`
45+
| ^^^^^^^^^^^
46+
|
47+
help: put the `;` here
48+
|
49+
LL - ()
50+
LL + (); };
51+
|
3752

3853
error: aborting due to 4 previous errors
3954

0 commit comments

Comments
 (0)