1313//! This lint is **warn** by default
1414
1515use clippy_utils:: diagnostics:: { span_lint_and_sugg, span_lint_and_then} ;
16- use clippy_utils:: source:: { snippet_block, snippet_block_with_applicability} ;
16+ use clippy_utils:: source:: { snippet , snippet_block, snippet_block_with_applicability} ;
1717use clippy_utils:: sugg:: Sugg ;
1818use if_chain:: if_chain;
1919use rustc_ast:: ast;
2020use rustc_errors:: Applicability ;
2121use rustc_lint:: { EarlyContext , EarlyLintPass } ;
2222use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
23+ use rustc_span:: Span ;
2324
2425declare_clippy_lint ! {
2526 /// ### What it does
@@ -102,7 +103,7 @@ impl EarlyLintPass for CollapsibleIf {
102103fn check_if ( cx : & EarlyContext < ' _ > , expr : & ast:: Expr ) {
103104 if let ast:: ExprKind :: If ( check, then, else_) = & expr. kind {
104105 if let Some ( else_) = else_ {
105- check_collapsible_maybe_if_let ( cx, else_) ;
106+ check_collapsible_maybe_if_let ( cx, then . span , else_) ;
106107 } else if let ast:: ExprKind :: Let ( ..) = check. kind {
107108 // Prevent triggering on `if let a = b { if c { .. } }`.
108109 } else {
@@ -119,7 +120,7 @@ fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool {
119120 trimmed_block_text. starts_with ( "//" ) || trimmed_block_text. starts_with ( "/*" )
120121}
121122
122- fn check_collapsible_maybe_if_let ( cx : & EarlyContext < ' _ > , else_ : & ast:: Expr ) {
123+ fn check_collapsible_maybe_if_let ( cx : & EarlyContext < ' _ > , then_span : Span , else_ : & ast:: Expr ) {
123124 if_chain ! {
124125 if let ast:: ExprKind :: Block ( ref block, _) = else_. kind;
125126 if !block_starts_with_comment( cx, block) ;
@@ -128,14 +129,23 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) {
128129 if !else_. span. from_expansion( ) ;
129130 if let ast:: ExprKind :: If ( ..) = else_. kind;
130131 then {
132+ // Prevent "elseif"
133+ // Check that the "else" is followed by whitespace
134+ let up_to_else = then_span. between( block. span) ;
135+ let requires_space = if let Some ( c) = snippet( cx, up_to_else, ".." ) . chars( ) . last( ) { !c. is_whitespace( ) } else { false } ;
136+
131137 let mut applicability = Applicability :: MachineApplicable ;
132138 span_lint_and_sugg(
133139 cx,
134140 COLLAPSIBLE_ELSE_IF ,
135141 block. span,
136142 "this `else { if .. }` block can be collapsed" ,
137143 "collapse nested if block" ,
138- snippet_block_with_applicability( cx, else_. span, ".." , Some ( block. span) , & mut applicability) . into_owned( ) ,
144+ format!(
145+ "{}{}" ,
146+ if requires_space { " " } else { "" } ,
147+ snippet_block_with_applicability( cx, else_. span, ".." , Some ( block. span) , & mut applicability)
148+ ) ,
139149 applicability,
140150 ) ;
141151 }
0 commit comments