Repository: detekt/detekt (kotlin)

Issue:
`ExpressionBodySyntax` false positive when more than one return statement
<!-- The bug you're experiencing might have already be reported! -->
<!-- Please search in the [issues](https://github.com/detekt/detekt/issues) before creating one. -->

## Expected Behavior
When function has more than one return statement, `ExpressionBodySyntax` should not be triggered.

## Observed Behavior
It is.

## Steps to Reproduce
Example code:

```kotlin
class PromoCodeSummaryMapper {
    fun PromoApplied.toPresentable(currency: Currency): PromoCodeSummary? {
        return PromoCodeSummary(
            code = code,
            type = when {
                promoFreeDelivery == true -> PromoCodeSummary.FreeDelivery
                promoDiscountAmount != null -> PromoCodeSummary.Discount(Amount(-promoDiscountAmount, currency))
                else -> return null
            },
        )
    }
}
```

> .../PromoCodeSummaryMapper.kt:11:9: Functions with exact one statement, the return statement, can be rewritten with ExpressionBodySyntax. [ExpressionBodySyntax]

When I do as suggested by the issue, I get IDE error:

<img width="846" alt="Screenshot 2024-12-10 at 10 22 02" src="https://github.com/user-attachments/assets/7cbfd543-86c1-4299-bc68-f416b1a49ebf">


## Context
<!-- How has this issue affected you? What are you trying to accomplish? -->
<!-- Providing context helps us come up with a solution that is most useful in the real world -->

## Your Environment
<!-- Include as many relevant details about the environment you experienced the bug in -->
* Version of detekt used: 1.23.7
* Version of Gradle used (if applicable): 8.10
* Gradle scan link (add `--scan` option when running the gradle task):
* Operating System and version:
* Link to your project (if it's a public repository):

Pull request:
This PR fixes #7829, not reporting a `ExpressionBodySyntax` if there are multiple return expressions in `when` statements.

This code is now compliant:
```kotlin
    fun stuff(): Pair<String, String>? {
        return Pair(
            first = "",
            second = when {
                true -> ""
                else -> return null 
            }
        )
    }
```

Patch:
diff --git a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/ExpressionBodySyntax.kt b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/ExpressionBodySyntax.kt
index dcd0bcc38b03..cdc273f3986e 100644
--- a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/ExpressionBodySyntax.kt
+++ b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/ExpressionBodySyntax.kt
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.psi.KtExpression
 import org.jetbrains.kotlin.psi.KtNamedFunction
 import org.jetbrains.kotlin.psi.KtProperty
 import org.jetbrains.kotlin.psi.KtReturnExpression
+import org.jetbrains.kotlin.psi.KtWhenEntry
 import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
 
 /**
@@ -59,7 +60,9 @@ class ExpressionBodySyntax(config: Config) : Rule(
     private fun KtDeclarationWithBody.checkForExpressionBodySyntax() {
         val stmt = bodyExpression
             ?.singleReturnStatement()
-            ?.takeUnless { it.containsReturnStmtsInNullableArguments() }
+            ?.takeUnless {
+                it.containsReturnStmtsInNullableArguments() || it.containsReturnInWhenExpressions()
+            }
 
         if (stmt != null && (includeLineWrapping || !isLineWrapped(stmt))) {
             report(CodeSmell(Entity.from(stmt), description))
@@ -69,6 +72,11 @@ class ExpressionBodySyntax(config: Config) : Rule(
     private fun KtExpression.singleReturnStatement(): KtReturnExpression? =
         (this as? KtBlockExpression)?.statements?.singleOrNull() as? KtReturnExpression
 
+    private fun KtReturnExpression.containsReturnInWhenExpressions(): Boolean =
+        anyDescendantOfType<KtReturnExpression> {
+            it.parent is KtWhenEntry
+        }
+
     private fun KtReturnExpression.containsReturnStmtsInNullableArguments(): Boolean =
         anyDescendantOfType<KtReturnExpression> { (it.parent as? KtBinaryExpression)?.operationToken == KtTokens.ELVIS }
 


Test patch:
diff --git a/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/ExpressionBodySyntaxSpec.kt b/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/ExpressionBodySyntaxSpec.kt
index cf0aadab2e24..c834a90271d2 100644
--- a/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/ExpressionBodySyntaxSpec.kt
+++ b/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/ExpressionBodySyntaxSpec.kt
@@ -163,6 +163,32 @@ class ExpressionBodySyntaxSpec {
         }
     }
 
+    @Nested
+    inner class `multiple return in when expression` {
+        val code = """
+            fun stuff(): Pair<String, String>? {
+                return Pair(
+                    first = "",
+                    second = when {
+                        true -> ""
+                        else -> return null 
+                    }
+                )
+            }
+        """.trimIndent()
+
+        @Test
+        fun `does not report with the default configuration`() {
+            assertThat(subject.compileAndLint(code)).isEmpty()
+        }
+
+        @Test
+        fun `does not report with includeLineWrapping = true configuration`() {
+            val config = TestConfig(INCLUDE_LINE_WRAPPING to "true")
+            assertThat(ExpressionBodySyntax(config).compileAndLint(code)).isEmpty()
+        }
+    }
+
     @Nested
     inner class `several return statements with multiline if expression` {