about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2025-01-31 23:25:26 +0100
committerSamuel Tardieu <sam@rfc1149.net>2025-02-09 02:11:37 +0100
commitac0a11a8bc80befca52af0712e015b4c42ee3769 (patch)
tree64d91219c95756b9a180b0bb33cfcc9d38b1898d
parentaad3686823ea20280dc461dfae935fdffdaf5162 (diff)
downloadrust-ac0a11a8bc80befca52af0712e015b4c42ee3769.tar.gz
rust-ac0a11a8bc80befca52af0712e015b4c42ee3769.zip
Fix `obfuscated_if_else` suggestion on left side of a binary expr
An `if … { … } else { … }` used as the left operand of a binary
expression requires parentheses to be parsed as an expression.
-rw-r--r--clippy_lints/src/methods/obfuscated_if_else.rs12
-rw-r--r--tests/ui/obfuscated_if_else.fixed26
-rw-r--r--tests/ui/obfuscated_if_else.rs26
-rw-r--r--tests/ui/obfuscated_if_else.stderr50
4 files changed, 113 insertions, 1 deletions
diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs
index b71f79f8482..2272e03ef26 100644
--- a/clippy_lints/src/methods/obfuscated_if_else.rs
+++ b/clippy_lints/src/methods/obfuscated_if_else.rs
@@ -1,6 +1,7 @@
 use super::OBFUSCATED_IF_ELSE;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
+use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use rustc_errors::Applicability;
@@ -41,6 +42,17 @@ pub(super) fn check<'tcx>(
             snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability)
         );
 
+        // To be parsed as an expression, the `if { … } else { … }` as the left operand of a binary operator
+        // requires parentheses.
+        let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr)
+            && let ExprKind::Binary(_, left, _) = parent_expr.kind
+            && left.hir_id == expr.hir_id
+        {
+            format!("({sugg})")
+        } else {
+            sugg
+        };
+
         span_lint_and_sugg(
             cx,
             OBFUSCATED_IF_ELSE,
diff --git a/tests/ui/obfuscated_if_else.fixed b/tests/ui/obfuscated_if_else.fixed
index 4fe48c5ca54..2cdbee90d52 100644
--- a/tests/ui/obfuscated_if_else.fixed
+++ b/tests/ui/obfuscated_if_else.fixed
@@ -22,3 +22,29 @@ fn main() {
     if true { () } else { a += 2 };
     //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
 }
+
+fn issue11141() {
+    // Parentheses are required around the left side of a binary expression
+    let _ = (if true { 40 } else { 17 }) | 2;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are required only for the leftmost expression
+    let _ = (if true { 30 } else { 17 }) | if true { 2 } else { 3 } | if true { 10 } else { 1 };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required around the right side of a binary expression
+    let _ = 2 | if true { 40 } else { 17 };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a cast
+    let _ = if true { 42 } else { 17 } as u8;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a deref
+    let _ = *if true { &42 } else { &17 };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a deref followed by a cast
+    let _ = *if true { &42 } else { &17 } as u8;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+}
diff --git a/tests/ui/obfuscated_if_else.rs b/tests/ui/obfuscated_if_else.rs
index e1de6d0f4cf..20c67e72992 100644
--- a/tests/ui/obfuscated_if_else.rs
+++ b/tests/ui/obfuscated_if_else.rs
@@ -22,3 +22,29 @@ fn main() {
     true.then_some(()).unwrap_or(a += 2);
     //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
 }
+
+fn issue11141() {
+    // Parentheses are required around the left side of a binary expression
+    let _ = true.then_some(40).unwrap_or(17) | 2;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are required only for the leftmost expression
+    let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required around the right side of a binary expression
+    let _ = 2 | true.then_some(40).unwrap_or(17);
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a cast
+    let _ = true.then_some(42).unwrap_or(17) as u8;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a deref
+    let _ = *true.then_some(&42).unwrap_or(&17);
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a deref followed by a cast
+    let _ = *true.then_some(&42).unwrap_or(&17) as u8;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+}
diff --git a/tests/ui/obfuscated_if_else.stderr b/tests/ui/obfuscated_if_else.stderr
index 175d57b4957..9b1aebb5894 100644
--- a/tests/ui/obfuscated_if_else.stderr
+++ b/tests/ui/obfuscated_if_else.stderr
@@ -37,5 +37,53 @@ error: this method chain can be written more clearly with `if .. else ..`
 LL |     true.then_some(()).unwrap_or(a += 2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { () } else { a += 2 }`
 
-error: aborting due to 6 previous errors
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:28:13
+   |
+LL |     let _ = true.then_some(40).unwrap_or(17) | 2;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 40 } else { 17 })`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:32:13
+   |
+LL |     let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 30 } else { 17 })`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:32:48
+   |
+LL |     let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
+   |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 2 } else { 3 }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:32:81
+   |
+LL |     let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
+   |                                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 10 } else { 1 }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:36:17
+   |
+LL |     let _ = 2 | true.then_some(40).unwrap_or(17);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 40 } else { 17 }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:40:13
+   |
+LL |     let _ = true.then_some(42).unwrap_or(17) as u8;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 42 } else { 17 }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:44:14
+   |
+LL |     let _ = *true.then_some(&42).unwrap_or(&17);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:48:14
+   |
+LL |     let _ = *true.then_some(&42).unwrap_or(&17) as u8;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }`
+
+error: aborting due to 14 previous errors