Repository: analysis-dev/diktat (kotlin)

Issue:
KotlinParseException: Text is not valid: [res as TranslationsSuccess.apply {}]
## Describe the bug
During diktatFix the follow error is logged and the process exits unsuccesfully:
```
[ERROR] 2021-12-15 14:30:23 Internal error has occurred in rule [class-compact-initialization]. Please make an issue on this bug at https://github.com/cqfn/diKTat/. 
                       As a workaround you can disable these inspections in yml config: <[COMPACT_OBJECT_INITIALIZATION]>.
                       Root cause of the problem is in [TranslationAdapterTest.kt] file.
org.cqfn.diktat.ruleset.utils.KotlinParseException: Text is not valid: [res as TranslationsSuccess.apply {}]
```
## Expected behavior
diktatFix successfully formats the file
## Observed behavior

## Steps to Reproduce
Format Code with sealed class and use `as` for typecasting:
```
package de.core.adapter.driven.translation

import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.shouldBe
import io.micronaut.http.HttpStatus
import org.junit.jupiter.api.Test

internal class TranslationTest {

    @Test
    fun `translate text`() {
        val res = translateText(text = "dummy")
        (res is TranslationsSuccess) shouldBe true
        val translationsSuccess = res as TranslationsSuccess
        translationsSuccess.translations shouldHaveSize 1
    }

    fun translateText(
        text: String
    ): TranslationsResult = TranslationsSuccess(translations = emptyList())

    internal sealed class TranslationsResult

    internal data class TranslationsSuccess(
        val translations: List<String>
    ) : TranslationsResult()

    internal data class TranslationsFailure(
        val statusCode: HttpStatus,
        val message: String?
    ) : TranslationsResult()
}

```
## Environment information
* diktat version: 1.0.0
* build tool (maven/gradle):gradle
* how is diktat run (CLI, plugin, etc.):    id "org.cqfn.diktat.diktat-gradle-plugin" version "1.0.0"
* kotlin version:1.5.21
* operating system: macOS 12.0.1

Pull request:
…arenthesized

### What's done:
* Fix logic
* Add tests

This pull request closes #1150

Patch:
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/classes/CompactInitialization.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/classes/CompactInitialization.kt
index ecabc48285..9a4e2dfe71 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/classes/CompactInitialization.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/classes/CompactInitialization.kt
@@ -24,7 +24,10 @@ import org.jetbrains.kotlin.psi.KtCallExpression
 import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
 import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
 import org.jetbrains.kotlin.psi.KtNameReferenceExpression
+import org.jetbrains.kotlin.psi.KtParenthesizedExpression
 import org.jetbrains.kotlin.psi.KtProperty
+import org.jetbrains.kotlin.psi.KtQualifiedExpression
+import org.jetbrains.kotlin.psi.KtReferenceExpression
 import org.jetbrains.kotlin.psi.psiUtil.siblings
 import org.jetbrains.kotlin.psi.psiUtil.startOffset
 import org.slf4j.LoggerFactory
@@ -145,12 +148,33 @@ class CompactInitialization(configRules: List<RulesConfig>) : DiktatRule(
         ?: run {
             // add apply block
             property.node.run {
-                val newInitializerNode = kotlinParser.createNode("${property.initializer!!.text}.apply {}")
+                val newInitializerNodeText = buildInitializerNodeText(property)
+                val newInitializerNode = kotlinParser.createNode(newInitializerNodeText)
                 replaceChild(property.initializer!!.node, newInitializerNode)
             }
             (property.initializer as KtDotQualifiedExpression).selectorExpression!! as KtCallExpression
         }
 
+    @Suppress("UnsafeCallOnNullableType")
+    private fun buildInitializerNodeText(property: KtProperty): String {
+        val isRequiresParentheses = property.initializer.let {
+            // list of expression types, that can be directly followed by a dot-qualified call
+            // e.g. val x = foo()  ->  val x = foo().apply {}
+            // e.g. val x = foo + bar  ->  val x = (foo + bar).apply {}
+            it is KtParenthesizedExpression || it is KtQualifiedExpression || it is KtReferenceExpression
+        }.not()
+        return buildString {
+            if (isRequiresParentheses) {
+                append("(")
+            }
+            append(property.initializer!!.text)
+            if (isRequiresParentheses) {
+                append(")")
+            }
+            append(".apply {}")
+        }
+    }
+
     /**
      * convert `apply(::foo)` to `apply { foo(this) }` if necessary
      */


Test patch:
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/CompactInitializationFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/CompactInitializationFixTest.kt
index cbf2c873cd..2232e308b5 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/CompactInitializationFixTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/CompactInitializationFixTest.kt
@@ -37,4 +37,10 @@ class CompactInitializationFixTest : FixTestBase("test/chapter6/compact_initiali
     fun `should rename field in apply block to this keyword`() {
         fixAndCompare("StatementUseFieldMultipleTimesExpected.kt", "StatementUseFieldMultipleTimesTest.kt")
     }
+
+    @Test
+    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)
+    fun `should wrap receiver in parentheses if required`() {
+        fixAndCompare("ParenthesizedReceiverExpected.kt", "ParenthesizedReceiverTest.kt")
+    }
 }
diff --git a/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ParenthesizedReceiverExpected.kt b/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ParenthesizedReceiverExpected.kt
new file mode 100644
index 0000000000..8c20c9d4ba
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ParenthesizedReceiverExpected.kt
@@ -0,0 +1,6 @@
+fun `translate text`() {
+    val res = translateText(text = "dummy")
+    (res is TranslationsSuccess) shouldBe true
+    val translationsSuccess = (res as TranslationsSuccess).apply {
+    translations shouldHaveSize 1}
+}
diff --git a/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ParenthesizedReceiverTest.kt b/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ParenthesizedReceiverTest.kt
new file mode 100644
index 0000000000..d7eb1c12b3
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ParenthesizedReceiverTest.kt
@@ -0,0 +1,6 @@
+fun `translate text`() {
+    val res = translateText(text = "dummy")
+    (res is TranslationsSuccess) shouldBe true
+    val translationsSuccess = res as TranslationsSuccess
+    translationsSuccess.translations shouldHaveSize 1
+}