1 use clippy_utils
::diagnostics
::{multispan_sugg_with_applicability, span_lint_and_then}
;
2 use rustc_errors
::Applicability
;
3 use rustc_hir
::{Block, Expr, ExprKind, Stmt, StmtKind}
;
4 use rustc_lint
::{LateContext, LateLintPass, LintContext}
;
5 use rustc_session
::impl_lint_pass
;
11 /// Suggests moving the semicolon after a block to the inside of the block, after its last
14 /// ### Why is this bad?
16 /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
17 /// and this lint suggests inside the block.
18 /// Take a look at `semicolon_outside_block` for the other alternative.
33 #[clippy::version = "1.68.0"]
34 pub SEMICOLON_INSIDE_BLOCK
,
36 "add a semicolon inside the block"
38 declare_clippy_lint
! {
41 /// Suggests moving the semicolon from a block's final expression outside of the block.
43 /// ### Why is this bad?
45 /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
46 /// and this lint suggests outside the block.
47 /// Take a look at `semicolon_inside_block` for the other alternative.
62 #[clippy::version = "1.68.0"]
63 pub SEMICOLON_OUTSIDE_BLOCK
,
65 "add a semicolon outside the block"
67 impl_lint_pass
!(SemicolonBlock
=> [SEMICOLON_INSIDE_BLOCK
, SEMICOLON_OUTSIDE_BLOCK
]);
69 #[derive(Copy, Clone)]
70 pub struct SemicolonBlock
{
71 semicolon_inside_block_ignore_singleline
: bool
,
72 semicolon_outside_block_ignore_multiline
: bool
,
76 pub fn new(semicolon_inside_block_ignore_singleline
: bool
, semicolon_outside_block_ignore_multiline
: bool
) -> Self {
78 semicolon_inside_block_ignore_singleline
,
79 semicolon_outside_block_ignore_multiline
,
83 fn semicolon_inside_block(self, cx
: &LateContext
<'_
>, block
: &Block
<'_
>, tail
: &Expr
<'_
>, semi_span
: Span
) {
84 let insert_span
= tail
.span
.source_callsite().shrink_to_hi();
85 let remove_span
= semi_span
.with_lo(block
.span
.hi());
87 if self.semicolon_inside_block_ignore_singleline
&& get_line(cx
, remove_span
) == get_line(cx
, insert_span
) {
93 SEMICOLON_INSIDE_BLOCK
,
95 "consider moving the `;` inside the block for consistent formatting",
97 multispan_sugg_with_applicability(
100 Applicability
::MachineApplicable
,
101 [(remove_span
, String
::new()), (insert_span
, ";".to_owned())],
107 fn semicolon_outside_block(
109 cx
: &LateContext
<'_
>,
111 tail_stmt_expr
: &Expr
<'_
>,
114 let insert_span
= block
.span
.with_lo(block
.span
.hi());
115 // account for macro calls
116 let semi_span
= cx
.sess().source_map().stmt_span(semi_span
, block
.span
);
117 let remove_span
= semi_span
.with_lo(tail_stmt_expr
.span
.source_callsite().hi());
119 if self.semicolon_outside_block_ignore_multiline
&& get_line(cx
, remove_span
) != get_line(cx
, insert_span
) {
125 SEMICOLON_OUTSIDE_BLOCK
,
127 "consider moving the `;` outside the block for consistent formatting",
129 multispan_sugg_with_applicability(
132 Applicability
::MachineApplicable
,
133 [(remove_span
, String
::new()), (insert_span
, ";".to_owned())],
140 impl LateLintPass
<'_
> for SemicolonBlock
{
141 fn check_stmt(&mut self, cx
: &LateContext
<'_
>, stmt
: &Stmt
<'_
>) {
143 StmtKind
::Expr(Expr
{
144 kind
: ExprKind
::Block(block
, _
),
146 }) if !block
.span
.from_expansion() => {
156 kind
: StmtKind
::Semi(expr
),
163 self.semicolon_outside_block(cx
, block
, expr
, span
);
165 StmtKind
::Semi(Expr
{
166 kind
: ExprKind
::Block(block @ Block { expr: Some(tail), .. }
, _
),
168 }) if !block
.span
.from_expansion() => {
169 self.semicolon_inside_block(cx
, block
, tail
, stmt
.span
);
176 fn get_line(cx
: &LateContext
<'_
>, span
: Span
) -> Option
<usize> {
177 if let Ok(line
) = cx
.sess().source_map().lookup_line(span
.lo()) {
178 return Some(line
.line
);