@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and
22use rustc_errors:: Applicability ;
33use rustc_hir:: { Block , Expr , ExprKind , Stmt , StmtKind } ;
44use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
5- use rustc_session:: { declare_lint_pass , declare_tool_lint } ;
5+ use rustc_session:: { declare_tool_lint , impl_lint_pass } ;
66use rustc_span:: Span ;
77
88declare_clippy_lint ! {
@@ -64,7 +64,78 @@ declare_clippy_lint! {
6464 restriction,
6565 "add a semicolon outside the block"
6666}
67- declare_lint_pass ! ( SemicolonBlock => [ SEMICOLON_INSIDE_BLOCK , SEMICOLON_OUTSIDE_BLOCK ] ) ;
67+ impl_lint_pass ! ( SemicolonBlock => [ SEMICOLON_INSIDE_BLOCK , SEMICOLON_OUTSIDE_BLOCK ] ) ;
68+
69+ #[ derive( Copy , Clone ) ]
70+ pub struct SemicolonBlock {
71+ semicolon_inside_block_ignore_singleline : bool ,
72+ semicolon_outside_block_ignore_multiline : bool ,
73+ }
74+
75+ impl SemicolonBlock {
76+ pub fn new ( semicolon_inside_block_ignore_singleline : bool , semicolon_outside_block_ignore_multiline : bool ) -> Self {
77+ Self {
78+ semicolon_inside_block_ignore_singleline,
79+ semicolon_outside_block_ignore_multiline,
80+ }
81+ }
82+
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 ( ) ) ;
86+
87+ if self . semicolon_inside_block_ignore_singleline && get_line ( cx, remove_span) == get_line ( cx, insert_span) {
88+ return ;
89+ }
90+
91+ span_lint_and_then (
92+ cx,
93+ SEMICOLON_INSIDE_BLOCK ,
94+ semi_span,
95+ "consider moving the `;` inside the block for consistent formatting" ,
96+ |diag| {
97+ multispan_sugg_with_applicability (
98+ diag,
99+ "put the `;` here" ,
100+ Applicability :: MachineApplicable ,
101+ [ ( remove_span, String :: new ( ) ) , ( insert_span, ";" . to_owned ( ) ) ] ,
102+ ) ;
103+ } ,
104+ ) ;
105+ }
106+
107+ fn semicolon_outside_block (
108+ self ,
109+ cx : & LateContext < ' _ > ,
110+ block : & Block < ' _ > ,
111+ tail_stmt_expr : & Expr < ' _ > ,
112+ semi_span : Span ,
113+ ) {
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 ( ) ) ;
118+
119+ if self . semicolon_outside_block_ignore_multiline && get_line ( cx, remove_span) != get_line ( cx, insert_span) {
120+ return ;
121+ }
122+
123+ span_lint_and_then (
124+ cx,
125+ SEMICOLON_OUTSIDE_BLOCK ,
126+ block. span ,
127+ "consider moving the `;` outside the block for consistent formatting" ,
128+ |diag| {
129+ multispan_sugg_with_applicability (
130+ diag,
131+ "put the `;` here" ,
132+ Applicability :: MachineApplicable ,
133+ [ ( remove_span, String :: new ( ) ) , ( insert_span, ";" . to_owned ( ) ) ] ,
134+ ) ;
135+ } ,
136+ ) ;
137+ }
138+ }
68139
69140impl LateLintPass < ' _ > for SemicolonBlock {
70141 fn check_stmt ( & mut self , cx : & LateContext < ' _ > , stmt : & Stmt < ' _ > ) {
@@ -83,55 +154,23 @@ impl LateLintPass<'_> for SemicolonBlock {
83154 span,
84155 ..
85156 } = stmt else { return } ;
86- semicolon_outside_block ( cx, block, expr, span) ;
157+ self . semicolon_outside_block ( cx, block, expr, span) ;
87158 } ,
88159 StmtKind :: Semi ( Expr {
89160 kind : ExprKind :: Block ( block @ Block { expr : Some ( tail) , .. } , _) ,
90161 ..
91- } ) if !block. span . from_expansion ( ) => semicolon_inside_block ( cx, block, tail, stmt. span ) ,
162+ } ) if !block. span . from_expansion ( ) => {
163+ self . semicolon_inside_block ( cx, block, tail, stmt. span ) ;
164+ } ,
92165 _ => ( ) ,
93166 }
94167 }
95168}
96169
97- fn semicolon_inside_block ( cx : & LateContext < ' _ > , block : & Block < ' _ > , tail : & Expr < ' _ > , semi_span : Span ) {
98- let insert_span = tail. span . source_callsite ( ) . shrink_to_hi ( ) ;
99- let remove_span = semi_span. with_lo ( block. span . hi ( ) ) ;
100-
101- span_lint_and_then (
102- cx,
103- SEMICOLON_INSIDE_BLOCK ,
104- semi_span,
105- "consider moving the `;` inside the block for consistent formatting" ,
106- |diag| {
107- multispan_sugg_with_applicability (
108- diag,
109- "put the `;` here" ,
110- Applicability :: MachineApplicable ,
111- [ ( remove_span, String :: new ( ) ) , ( insert_span, ";" . to_owned ( ) ) ] ,
112- ) ;
113- } ,
114- ) ;
115- }
116-
117- fn semicolon_outside_block ( cx : & LateContext < ' _ > , block : & Block < ' _ > , tail_stmt_expr : & Expr < ' _ > , semi_span : Span ) {
118- let insert_span = block. span . with_lo ( block. span . hi ( ) ) ;
119- // account for macro calls
120- let semi_span = cx. sess ( ) . source_map ( ) . stmt_span ( semi_span, block. span ) ;
121- let remove_span = semi_span. with_lo ( tail_stmt_expr. span . source_callsite ( ) . hi ( ) ) ;
170+ fn get_line ( cx : & LateContext < ' _ > , span : Span ) -> Option < usize > {
171+ if let Ok ( line) = cx. sess ( ) . source_map ( ) . lookup_line ( span. lo ( ) ) {
172+ return Some ( line. line ) ;
173+ }
122174
123- span_lint_and_then (
124- cx,
125- SEMICOLON_OUTSIDE_BLOCK ,
126- block. span ,
127- "consider moving the `;` outside the block for consistent formatting" ,
128- |diag| {
129- multispan_sugg_with_applicability (
130- diag,
131- "put the `;` here" ,
132- Applicability :: MachineApplicable ,
133- [ ( remove_span, String :: new ( ) ) , ( insert_span, ";" . to_owned ( ) ) ] ,
134- ) ;
135- } ,
136- ) ;
175+ None
137176}
0 commit comments