Repository: analysis-dev/diktat (kotlin)

Issue:
Bug in [COMPACT_OBJECT_INITIALIZATION]
## Describe the bug

In function extension, if you use `this` keyword, and `COMPACT_OBJECT_INITIALIZATION` applied, it's hides
the `this` from top level.

Consider the following code:

```kotlin
fun String.createPluginConfig() {
      val pluginConfig = TomlDecoder.decode<T>(
          serializer(),
          fakeFileNode,
          DecoderConf()
      )
      pluginConfig.configLocation = this.toPath()
}
```
## Expected behavior
It's shouldn't  be created `apply` block, if `this` exist, or should use annotations:

```kotlin
fun String.createPluginConfig() {
    val pluginConfig = TomlDecoder.decode<T>(
        serializer(),
        fakeFileNode,
        DecoderConf()
    ).apply {
        configLocation = this@createPluginConfig.toPath()
    }
}
```
## Observed behavior
```kotlin
fun String.createPluginConfig() {
    val pluginConfig = TomlDecoder.decode<T>(
        serializer(),
        fakeFileNode,
        DecoderConf()
    ).apply {
        configLocation = this.toPath() // <---- bug
    }
}
```

Pull request:
### What's done:
* Fix big in COMPACT_OBJECT_INITIALIZATION: Previously `apply` block could shadowed the assignment label, if it contain `this` keyword, such behavior led to the incorrect code. For now such cases will be ignored.
* Add test

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 1ae3475ed6..b0ca67dbfe 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
@@ -4,9 +4,14 @@ import org.cqfn.diktat.common.config.rules.RulesConfig
 import org.cqfn.diktat.ruleset.constants.Warnings.COMPACT_OBJECT_INITIALIZATION
 import org.cqfn.diktat.ruleset.rules.DiktatRule
 import org.cqfn.diktat.ruleset.utils.KotlinParser
+import org.cqfn.diktat.ruleset.utils.findLeafWithSpecificType
 import org.cqfn.diktat.ruleset.utils.getFunctionName
 
+import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT
+import com.pinterest.ktlint.core.ast.ElementType.EOL_COMMENT
+import com.pinterest.ktlint.core.ast.ElementType.KDOC
 import com.pinterest.ktlint.core.ast.ElementType.LBRACE
+import com.pinterest.ktlint.core.ast.ElementType.THIS_KEYWORD
 import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE
 import com.pinterest.ktlint.core.ast.isPartOfComment
 import org.jetbrains.kotlin.com.intellij.lang.ASTNode
@@ -63,6 +68,9 @@ class CompactInitialization(configRules: List<RulesConfig>) : DiktatRule(
                     it as KtBinaryExpression to (it.left as KtDotQualifiedExpression).selectorExpression!!
                 }
         }
+            .filter { (assignment, _) ->
+                assignment.node.findLeafWithSpecificType(THIS_KEYWORD) == null
+            }
             .toList()
             .forEach { (assignment, field) ->
                 COMPACT_OBJECT_INITIALIZATION.warnAndFix(
@@ -94,7 +102,7 @@ class CompactInitialization(configRules: List<RulesConfig>) : DiktatRule(
                     assignment
                         .node
                         .siblings(forward = false)
-                        .takeWhile { it != property.node }
+                        .takeWhile { it.elementType in listOf(WHITE_SPACE, EOL_COMMENT, BLOCK_COMMENT, KDOC) }
                         .toList()
                         .reversed()
                         .forEachIndexed { index, it ->


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 32200570a6..6314741b7b 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
@@ -25,4 +25,10 @@ class CompactInitializationFixTest : FixTestBase("test/chapter6/compact_initiali
     fun `should wrap properties into apply - existing apply with value argument`() {
         fixAndCompare("ApplyWithValueArgumentExpected.kt", "ApplyWithValueArgumentTest.kt")
     }
+
+    @Test
+    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)
+    fun `should not move statements with this keyword into apply block`() {
+        fixAndCompare("ApplyOnStatementsWithThisKeywordExpected.kt", "ApplyOnStatementsWithThisKeywordTest.kt")
+    }
 }
diff --git a/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ApplyOnStatementsWithThisKeywordExpected.kt b/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ApplyOnStatementsWithThisKeywordExpected.kt
new file mode 100644
index 0000000000..8bf284872e
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ApplyOnStatementsWithThisKeywordExpected.kt
@@ -0,0 +1,14 @@
+fun String.createPluginConfig() {
+    val pluginConfig = TomlDecoder.decode<T>(
+        serializer(),
+        fakeFileNode,
+        DecoderConf()
+    ).apply {
+    prop1 = property1
+    // comment2
+    prop2 = property2}
+    pluginConfig.configLocation = this.toPath()
+    // comment1
+    pluginConfig.configLocation2 = this.toPath()
+}
+
diff --git a/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ApplyOnStatementsWithThisKeywordTest.kt b/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ApplyOnStatementsWithThisKeywordTest.kt
new file mode 100644
index 0000000000..ca0980bd32
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/chapter6/compact_initialization/ApplyOnStatementsWithThisKeywordTest.kt
@@ -0,0 +1,14 @@
+fun String.createPluginConfig() {
+    val pluginConfig = TomlDecoder.decode<T>(
+        serializer(),
+        fakeFileNode,
+        DecoderConf()
+    )
+    pluginConfig.configLocation = this.toPath()
+    pluginConfig.prop1 = property1
+    // comment1
+    pluginConfig.configLocation2 = this.toPath()
+    // comment2
+    pluginConfig.prop2 = property2
+}
+