Repository: analysis-dev/diktat (kotlin)

Issue:
False positive with single expression functions that use multiple `return` keywords
## Describe the bug

Diktat rewrites the following code:

```kotlin
data class Demo(val value: String) {
    companion object {
        fun from(string: String?): Demo? {
            return Demo(string ?: return null)
        }
    }
}
```

into

```kotlin
data class Demo(val value: String) {
    companion object {
        fun from(string: String?): Demo? = Demo(string ?: return null)
    }
}
```

## Expected behavior

Ditkat does not rewrite the above code, because it is not valid Kotlin to use the return keyword when a function is a single expression. The single expression function body is necessary to support the null input case.

## Observed behavior

Diktat rewrites the code causing a compilation error

## Steps to Reproduce

Write any function body which consists of a single expression but uses patterns like `?: return foo` which would not be supported as a single expression function

Adding any comment inside the function body stops diktat from rewriting the code, but this is not ideal since there is not always a need for such a comment.

## Environment information
* diktat version: 1.2.1
* build tool (maven/gradle): gradle
* how is diktat run (CLI, plugin, etc.): spotless (spotlessApply task)
* kotlin version: 1.7.10
* operating system: macOS
* link to a project (if your project is public): NA

Pull request description:
### What's done:
- added check for multiple return keywords

Closes #1588

Patch:
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt
index 68c1a378cb..01624e603a 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt
@@ -405,8 +405,10 @@ class NewlinesRule(configRules: List<RulesConfig>) : DiktatRule(
     private fun handleReturnStatement(node: ASTNode) {
         val blockNode = node.treeParent.takeIf { it.elementType == BLOCK && it.treeParent.elementType == FUN }
         val returnsUnit = node.children().count() == 1  // the only child is RETURN_KEYWORD
-        if (blockNode == null || returnsUnit) {
+        val hasMultipleReturn = node.findAllDescendantsWithSpecificType(RETURN_KEYWORD).count() > 1
+        if (blockNode == null || returnsUnit || hasMultipleReturn) {
             // function is either already with expression body or definitely can't be converted to it
+            // or the function has more than one keyword `return` inside it
             return
         }
         blockNode


Test patch:
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleWarnTest.kt
index 3281a0d679..6df9da27dd 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleWarnTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleWarnTest.kt
@@ -597,6 +597,18 @@ class NewlinesRuleWarnTest : LintTestBase(::NewlinesRule) {
         )
     }
 
+    @Test
+    @Tag(WarningNames.WRONG_NEWLINES)
+    fun `shouldn't warn if function consists of a single return statement with a nested return`() {
+        lintMethod(
+            """
+                    |fun foo(): String {
+                    |    return Demo(string ?: return null)
+                    |}
+            """.trimMargin(),
+        )
+    }
+
     @Test
     @Tag(WarningNames.WRONG_NEWLINES)
     @Suppress("TOO_LONG_FUNCTION")