Repository: intellij-rust/intellij-rust
Issue: DemorgansLawIntention may not work with multiple boolean operators

## Environment

* **IntelliJ Rust plugin version:** 0.4.159.4199-212-nightly
* **Rust toolchain version:** 1.55.0 (c8dfcfe04 2021-09-06) x86_64-unknown-linux-gnu
* **IDE name and version:** CLion 2021.2.3 (CL-212.5457.51)
* **Operating system:** Linux 5.14.14-zen1-1-zen
* **Macro expansion engine:** new
* **Name resolution engine:** new

## Steps to reproduce
```rust
fn func() -> bool {
    a /*caret*/&& b && c
}
```

Applying Demorgan intention doesn't change the code. Expected result:
```rust
fn func() -> bool {
    !(!a || !b || !c)
}
```

Changed files:
src/main/kotlin/org/rust/ide/intentions/DemorgansLawIntention.kt, src/test/kotlin/org/rust/ide/intentions/DemorgansLawIntentionTest.kt

diff --git a/src/main/kotlin/org/rust/ide/intentions/DemorgansLawIntention.kt b/src/main/kotlin/org/rust/ide/intentions/DemorgansLawIntention.kt
index 1179c5435..50dd831b7 100644
--- a/src/main/kotlin/org/rust/ide/intentions/DemorgansLawIntention.kt
+++ b/src/main/kotlin/org/rust/ide/intentions/DemorgansLawIntention.kt
@@ -42,28 +42,17 @@ class DemorgansLawIntention : RsElementBaseIntentionAction<DemorgansLawIntention
     }
 
     override fun invoke(project: Project, editor: Editor, ctx: Context) {
-        val (binExpr, opType) = ctx
-
-        var topBinExpr = binExpr
-        var isAllSameOpType = true
-        while (topBinExpr.parent is RsBinaryExpr
-            || (topBinExpr.parent is RsParenExpr
-                && topBinExpr.parent.parent.isNegation()
-                && topBinExpr.parent.parent.parent is RsBinaryExpr)) {
-            topBinExpr = if (topBinExpr.parent is RsBinaryExpr) topBinExpr.parent as RsBinaryExpr else topBinExpr.parent.parent.parent as RsBinaryExpr
-            isAllSameOpType = topBinExpr.parent is RsBinaryExpr && topBinExpr.operatorType == opType
-        }
+        val (binaryExpr, opType) = ctx
+        val topBinaryExpr = binaryExpr.getTopmostBinaryExprWithSameOpType()
+        applyDemorgan(project, topBinaryExpr, opType)
+    }
 
-        if (isAllSameOpType) {
-            applyDemorgan(project, topBinExpr, opType)
+    private fun RsBinaryExpr.getTopmostBinaryExprWithSameOpType(): RsBinaryExpr {
+        val parent = parent
+        return if (parent is RsBinaryExpr && parent.binaryOp.op == binaryOp.op) {
+            parent.getTopmostBinaryExprWithSameOpType()
         } else {
-            val binaryExprs = topBinExpr.descendantsOfType<RsBinaryExpr>().filter { e ->
-                !(e.operatorType != opType || e.parent is RsBinaryExpr && (e.parent as RsBinaryExpr).operatorType == opType)
-            }
-
-            binaryExprs.forEach {
-                applyDemorgan(project, it, opType)
-            }
+            this
         }
     }
 
diff --git a/src/test/kotlin/org/rust/ide/intentions/DemorgansLawIntentionTest.kt b/src/test/kotlin/org/rust/ide/intentions/DemorgansLawIntentionTest.kt
index 49b04ff23..028ae9341 100644
--- a/src/test/kotlin/org/rust/ide/intentions/DemorgansLawIntentionTest.kt
+++ b/src/test/kotlin/org/rust/ide/intentions/DemorgansLawIntentionTest.kt
@@ -63,7 +63,7 @@ class DemorgansLawIntentionTest : RsIntentionTestBase(DemorgansLawIntention::cla
         }
     """, """
         fn main() {
-            if !(!(2 + 2 != 2 /*caret*/|| !(foo.bar() || !(78 < 90 || 90 > 78))) || (!(20 < 50 || ((40 == 20))))) {}
+            if !(!(2 + 2 != 2 /*caret*/|| !(foo.bar() || !(78 < 90 || 90 > 78))) || (20 >= 50 && ((40 != 20)))) {}
         }
     """)
 
@@ -77,6 +77,16 @@ class DemorgansLawIntentionTest : RsIntentionTestBase(DemorgansLawIntention::cla
         }
     """)
 
+    fun `test complex 5`() = doAvailableTest("""
+        fn main() {
+            !(a /*caret*/&& b) || (c && d);
+        }
+    """, """
+        fn main() {
+            !a || !b || (c && d);
+        }
+    """)
+
     fun `test constant`() = doAvailableSymmetricTest("""
         fn main() {
             let _ = b /*caret*/|| true;
@@ -86,4 +96,24 @@ class DemorgansLawIntentionTest : RsIntentionTestBase(DemorgansLawIntention::cla
             let _ = !(!b /*caret*/&& !true);
         }
     """)
+
+    fun `test triple 1`() = doAvailableTest("""
+        fn main() {
+            a /*caret*/&& b && c;
+        }
+    """, """
+        fn main() {
+            !(!a || !b || !c);
+        }
+    """)
+
+    fun `test triple 2`() = doAvailableTest("""
+        fn main() {
+            a && b /*caret*/&& c;
+        }
+    """, """
+        fn main() {
+            !(!a || !b || !c);
+        }
+    """)
 }