11use clippy_config:: Conf ;
22use clippy_utils:: diagnostics:: { span_lint_and_sugg, span_lint_and_then} ;
33use clippy_utils:: msrvs:: { self , Msrv } ;
4- use clippy_utils:: source:: { IntoSpan as _, SpanRangeExt , snippet, snippet_block , snippet_block_with_applicability} ;
5- use clippy_utils:: span_contains_non_comment ;
4+ use clippy_utils:: source:: { IntoSpan as _, SpanRangeExt , snippet, snippet_block_with_applicability} ;
5+ use clippy_utils:: span_contains_non_whitespace ;
66use rustc_ast:: BinOpKind ;
77use rustc_errors:: Applicability ;
88use rustc_hir:: { Block , Expr , ExprKind , Stmt , StmtKind } ;
@@ -81,24 +81,24 @@ declare_clippy_lint! {
8181pub struct CollapsibleIf {
8282 msrv : Msrv ,
8383 lint_commented_code : bool ,
84+ lint_commented_else_if : bool ,
8485}
8586
8687impl CollapsibleIf {
8788 pub fn new ( conf : & ' static Conf ) -> Self {
8889 Self {
8990 msrv : conf. msrv ,
9091 lint_commented_code : conf. lint_commented_code ,
92+ lint_commented_else_if : conf. lint_commented_else_if ,
9193 }
9294 }
9395
94- fn check_collapsible_else_if ( cx : & LateContext < ' _ > , then_span : Span , else_block : & Block < ' _ > ) {
95- if !block_starts_with_comment ( cx, else_block)
96- && let Some ( else_) = expr_block ( else_block)
96+ fn check_collapsible_else_if ( & self , cx : & LateContext < ' _ > , then_span : Span , else_block : & Block < ' _ > ) {
97+ if let Some ( else_) = expr_block ( else_block)
9798 && cx. tcx . hir_attrs ( else_. hir_id ) . is_empty ( )
9899 && !else_. span . from_expansion ( )
99100 && let ExprKind :: If ( ..) = else_. kind
100- && let up_to_if = else_block. span . until ( else_. span )
101- && !span_contains_non_comment ( cx, up_to_if. with_lo ( BytePos ( up_to_if. lo ( ) . 0 + 1 ) ) )
101+ && !block_starts_with_significant_tokens ( cx, else_block, else_, self . lint_commented_else_if )
102102 {
103103 // Prevent "elseif"
104104 // Check that the "else" is followed by whitespace
@@ -133,7 +133,7 @@ impl CollapsibleIf {
133133 && self . eligible_condition ( cx, check_inner)
134134 && let ctxt = expr. span . ctxt ( )
135135 && inner. span . ctxt ( ) == ctxt
136- && ( self . lint_commented_code || ! block_starts_with_comment ( cx, then) )
136+ && ! block_starts_with_significant_tokens ( cx, then, inner , self . lint_commented_code )
137137 {
138138 span_lint_and_then (
139139 cx,
@@ -182,7 +182,7 @@ impl LateLintPass<'_> for CollapsibleIf {
182182 if let Some ( else_) = else_
183183 && let ExprKind :: Block ( else_, None ) = else_. kind
184184 {
185- Self :: check_collapsible_else_if ( cx, then. span , else_) ;
185+ self . check_collapsible_else_if ( cx, then. span , else_) ;
186186 } else if else_. is_none ( )
187187 && self . eligible_condition ( cx, cond)
188188 && let ExprKind :: Block ( then, None ) = then. kind
@@ -193,12 +193,16 @@ impl LateLintPass<'_> for CollapsibleIf {
193193 }
194194}
195195
196- fn block_starts_with_comment ( cx : & LateContext < ' _ > , block : & Block < ' _ > ) -> bool {
197- // We trim all opening braces and whitespaces and then check if the next string is a comment.
198- let trimmed_block_text = snippet_block ( cx, block. span , ".." , None )
199- . trim_start_matches ( |c : char | c. is_whitespace ( ) || c == '{' )
200- . to_owned ( ) ;
201- trimmed_block_text. starts_with ( "//" ) || trimmed_block_text. starts_with ( "/*" )
196+ // Check that nothing significant can be found but whitespaces between the initial `{` of `block`
197+ // and the beginning of `stop_at`.
198+ fn block_starts_with_significant_tokens (
199+ cx : & LateContext < ' _ > ,
200+ block : & Block < ' _ > ,
201+ stop_at : & Expr < ' _ > ,
202+ lint_commented_code : bool ,
203+ ) -> bool {
204+ let span = block. span . split_at ( 1 ) . 1 . until ( stop_at. span ) ;
205+ span_contains_non_whitespace ( cx, span, lint_commented_code)
202206}
203207
204208/// If `block` is a block with either one expression or a statement containing an expression,
0 commit comments