about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgranddaifuku <daifukuformac@gmail.com>2024-03-25 02:17:56 +0900
committergranddaifuku <daifukuformac@gmail.com>2024-03-25 02:17:56 +0900
commit2a62200b8d5ba65d583199a296c3fbbf8e58aa25 (patch)
tree7f1bd1ba52bb03f4bc4acdc7af49ba225c8fb921
parent95c62ffae9bbce793f68a6f1473e3fc24af19bdd (diff)
downloadrust-2a62200b8d5ba65d583199a296c3fbbf8e58aa25.tar.gz
rust-2a62200b8d5ba65d583199a296c3fbbf8e58aa25.zip
fix: suspicious_else_formatting false positive when else is included in comments
-rw-r--r--clippy_lints/src/formatting.rs43
-rw-r--r--tests/ui/suspicious_else_formatting.rs28
2 files changed, 70 insertions, 1 deletions
diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs
index c3ef6f180c9..5b8d4ea8956 100644
--- a/clippy_lints/src/formatting.rs
+++ b/clippy_lints/src/formatting.rs
@@ -214,7 +214,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
         // the snippet should look like " else \n    " with maybe comments anywhere
         // it’s bad when there is a ‘\n’ after the “else”
         && let Some(else_snippet) = snippet_opt(cx, else_span)
-        && let Some((pre_else, post_else)) = else_snippet.split_once("else")
+        && let Some((pre_else, post_else)) = split_once_with_else(&else_snippet)
         && let Some((_, post_else_post_eol)) = post_else.split_once('\n')
     {
         // Allow allman style braces `} \n else \n {`
@@ -323,3 +323,44 @@ fn is_block(expr: &Expr) -> bool {
 fn is_if(expr: &Expr) -> bool {
     matches!(expr.kind, ExprKind::If(..))
 }
+
+fn split_once_with_else(base: &str) -> Option<(&str, &str)> {
+    let else_str = "else";
+
+    let indices: Vec<_> = base.match_indices(else_str).map(|(i, _)| i).collect();
+
+    match indices.len() {
+        0 => return None,
+        1 => return base.split_once(else_str),
+        _ => {},
+    }
+
+    let mut i = 0;
+    let mut is_in_comment = false;
+
+    for line in base.lines() {
+        if let Some(else_pos) = line.find(else_str) {
+            if let Some(pos) = line.find("//") {
+                if pos > else_pos {
+                    return Some(base.split_at(indices[i]));
+                }
+            } else if let Some(pos) = line.find("/*") {
+                if pos > else_pos {
+                    return Some(base.split_at(indices[i]));
+                }
+                is_in_comment = true;
+            } else if let Some(pos) = line.find("*/") {
+                if pos < else_pos {
+                    return Some(base.split_at(indices[i]));
+                }
+                is_in_comment = false;
+            } else if !is_in_comment {
+                return Some(base.split_at(indices[i]));
+            }
+
+            i += 1;
+        }
+    }
+
+    None
+}
diff --git a/tests/ui/suspicious_else_formatting.rs b/tests/ui/suspicious_else_formatting.rs
index c0856427eae..3d5c892eb60 100644
--- a/tests/ui/suspicious_else_formatting.rs
+++ b/tests/ui/suspicious_else_formatting.rs
@@ -120,6 +120,34 @@ fn main() {
     /* whelp */
     {
     }
+
+    // #12497 Don't trigger lint as rustfmt wants it
+    if true {
+        println!("true");
+    }
+    /*else if false {
+}*/
+    else {
+        println!("false");
+    }
+
+    if true {
+        println!("true");
+    } // else if false {}
+    else {
+        println!("false");
+    }
+
+    if true {
+        println!("true");
+    } /* if true {
+        println!("true");
+}
+    */
+    else {
+        println!("false");
+    }
+
 }
 
 // #7650 - Don't lint. Proc-macro using bad spans for `if` expressions.