@@ -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,49 +64,22 @@ declare_clippy_lint! {
6464 restriction,
6565 "add a semicolon outside the block"
6666}
67- declare_clippy_lint ! {
68- /// ### What it does
69- ///
70- /// Suggests moving the semicolon from a block's final expression outside of
71- /// the block if it's singleline, and inside the block if it's multiline.
72- ///
73- /// ### Why is this bad?
74- ///
75- /// Some may prefer if the semicolon is outside of a block if it is only one
76- /// expression, as this allows rustfmt to make it singleline (and may just be
77- /// more readable). In the case that it isn't, it should be inside.
78- /// Take a look at both `semicolon_inside_block` and `semicolon_outside_block`
79- /// for alternatives.
80- ///
81- /// ### Example
82- ///
83- /// ```rust
84- /// # fn f(_: u32) {}
85- /// # let x = 0;
86- /// unsafe { f(x); }
87- ///
88- /// unsafe {
89- /// let x = 1;
90- /// f(x)
91- /// };
92- /// ```
93- /// Use instead:
94- /// ```rust
95- /// # fn f(_: u32) {}
96- /// # let x = 0;
97- /// unsafe { f(x) };
98- ///
99- /// unsafe {
100- /// let x = 1;
101- /// f(x);
102- /// }
103- /// ```
104- #[ clippy:: version = "1.68.0" ]
105- pub SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE ,
106- restriction,
107- "add a semicolon inside the block if it's singleline, otherwise outside"
67+ impl_lint_pass ! ( SemicolonBlock => [ SEMICOLON_INSIDE_BLOCK , SEMICOLON_OUTSIDE_BLOCK ] ) ;
68+
69+ #[ derive( Copy , Clone ) ]
70+ pub struct SemicolonBlock {
71+ semicolon_inside_block_if_multiline : bool ,
72+ semicolon_outside_block_if_singleline : bool ,
73+ }
74+
75+ impl SemicolonBlock {
76+ pub fn new ( semicolon_inside_block_if_multiline : bool , semicolon_outside_block_if_singleline : bool ) -> Self {
77+ Self {
78+ semicolon_inside_block_if_multiline,
79+ semicolon_outside_block_if_singleline,
80+ }
81+ }
10882}
109- declare_lint_pass ! ( SemicolonBlock => [ SEMICOLON_INSIDE_BLOCK , SEMICOLON_OUTSIDE_BLOCK , SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE ] ) ;
11083
11184impl LateLintPass < ' _ > for SemicolonBlock {
11285 fn check_stmt ( & mut self , cx : & LateContext < ' _ > , stmt : & Stmt < ' _ > ) {
@@ -125,24 +98,34 @@ impl LateLintPass<'_> for SemicolonBlock {
12598 span,
12699 ..
127100 } = stmt else { return } ;
128- semicolon_outside_block ( cx, block, expr, span) ;
101+ semicolon_outside_block ( self , cx, block, expr, span) ;
129102 } ,
130103 StmtKind :: Semi ( Expr {
131104 kind : ExprKind :: Block ( block @ Block { expr : Some ( tail) , .. } , _) ,
132105 ..
133106 } ) if !block. span . from_expansion ( ) => {
134- semicolon_inside_block ( cx, block, tail, stmt. span ) ;
107+ semicolon_inside_block ( self , cx, block, tail, stmt. span ) ;
135108 } ,
136109 _ => ( ) ,
137110 }
138111 }
139112}
140113
141- fn semicolon_inside_block ( cx : & LateContext < ' _ > , block : & Block < ' _ > , tail : & Expr < ' _ > , semi_span : Span ) {
114+ fn semicolon_inside_block (
115+ conf : & mut SemicolonBlock ,
116+ cx : & LateContext < ' _ > ,
117+ block : & Block < ' _ > ,
118+ tail : & Expr < ' _ > ,
119+ semi_span : Span ,
120+ ) {
142121 let insert_span = tail. span . source_callsite ( ) . shrink_to_hi ( ) ;
143122 let remove_span = semi_span. with_lo ( block. span . hi ( ) ) ;
144123
145- semicolon_outside_block_if_singleline ( cx, block, remove_span, insert_span, true , "inside" ) ;
124+ if conf. semicolon_inside_block_if_multiline {
125+ if get_line ( cx, remove_span) == get_line ( cx, insert_span) {
126+ return ;
127+ }
128+ }
146129
147130 span_lint_and_then (
148131 cx,
@@ -160,13 +143,17 @@ fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'
160143 ) ;
161144}
162145
163- fn semicolon_outside_block ( cx : & LateContext < ' _ > , block : & Block < ' _ > , tail_stmt_expr : & Expr < ' _ > , semi_span : Span ) {
146+ fn semicolon_outside_block ( conf : & mut SemicolonBlock , cx : & LateContext < ' _ > , block : & Block < ' _ > , tail_stmt_expr : & Expr < ' _ > , semi_span : Span ) {
164147 let insert_span = block. span . with_lo ( block. span . hi ( ) ) ;
165148 // account for macro calls
166149 let semi_span = cx. sess ( ) . source_map ( ) . stmt_span ( semi_span, block. span ) ;
167150 let remove_span = semi_span. with_lo ( tail_stmt_expr. span . source_callsite ( ) . hi ( ) ) ;
168151
169- semicolon_outside_block_if_singleline ( cx, block, remove_span, insert_span, false , "outside" ) ;
152+ if conf. semicolon_outside_block_if_singleline {
153+ if get_line ( cx, remove_span) != get_line ( cx, insert_span) {
154+ return ;
155+ }
156+ }
170157
171158 span_lint_and_then (
172159 cx,
@@ -184,44 +171,10 @@ fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_ex
184171 ) ;
185172}
186173
187- fn semicolon_outside_block_if_singleline (
188- cx : & LateContext < ' _ > ,
189- block : & Block < ' _ > ,
190- remove_span : Span ,
191- insert_span : Span ,
192- inequality : bool ,
193- ty : & str ,
194- ) {
195- let ( remove_line, insert_line) = ( get_line ( cx, remove_span) , get_line ( cx, insert_span) ) ;
196-
197- let eq = if inequality {
198- remove_line != insert_line
199- } else {
200- remove_line == insert_line
201- } ;
202-
203- if eq {
204- span_lint_and_then (
205- cx,
206- SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE ,
207- block. span ,
208- & format ! ( "consider moving the `;` {ty} the block for consistent formatting" ) ,
209- |diag| {
210- multispan_sugg_with_applicability (
211- diag,
212- "put the `;` here" ,
213- Applicability :: MachineApplicable ,
214- [ ( remove_span, String :: new ( ) ) , ( insert_span, ";" . to_owned ( ) ) ] ,
215- ) ;
216- } ,
217- ) ;
174+ fn get_line ( cx : & LateContext < ' _ > , span : Span ) -> Option < usize > {
175+ if let Ok ( line) = cx. sess ( ) . source_map ( ) . lookup_line ( span. lo ( ) ) {
176+ return Some ( line. line ) ;
218177 }
219- }
220178
221- fn get_line ( cx : & LateContext < ' _ > , span : Span ) -> usize {
222- cx. sess ( )
223- . source_map ( )
224- . lookup_line ( span. lo ( ) )
225- . expect ( "failed to get span's line" )
226- . line
179+ None
227180}
0 commit comments