Repository: analysis-dev/diktat (kotlin)

Issue:
Bug in fix mode of `WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES` rule
Consider the following code

```kotlin
package com.test

class MyClass {
    private val classSimpleName = SarifFixAdapter::class.simpleName!!
    private val log = KotlinLogging.logger(classSimpleName)
    private val tmpDir = createTempDir(classSimpleName)
}
```

Diktat fixes it in the following way:

```kotlin
package com.test

class MyClass {
    private val log = KotlinLogging.logger(classSimpleName)
    private val classSimpleName = SarifFixAdapter::class.simpleName!!
    private val tmpDir = createTempDir(classSimpleName)
}
```

However, `log` depends on `classSimpleName`, and these changes **breaks the code**, since after fix `classSimpleName` is below than `log`

Pull request description:

Patch:
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/ClassLikeStructuresOrderRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/ClassLikeStructuresOrderRule.kt
index 1b47ce6b48..facf5d6f67 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/ClassLikeStructuresOrderRule.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/ClassLikeStructuresOrderRule.kt
@@ -180,10 +180,11 @@ class ClassLikeStructuresOrderRule(configRules: List<RulesConfig>) : DiktatRule(
      * @property properties all other properties
      * @property lateInitProperties `lateinit var`s
      */
-    private data class AllProperties(val loggers: List<ASTNode>,
-                                     val constProperties: List<ASTNode>,
-                                     val properties: List<ASTNode>,
-                                     val lateInitProperties: List<ASTNode>
+    private data class AllProperties(
+        val loggers: List<ASTNode>,
+        val constProperties: List<ASTNode>,
+        val properties: List<ASTNode>,
+        val lateInitProperties: List<ASTNode>
     ) {
         companion object {
             /**
@@ -197,6 +198,7 @@ class ClassLikeStructuresOrderRule(configRules: List<RulesConfig>) : DiktatRule(
                 val allProperties = node.getAllChildrenWithType(PROPERTY)
                 val constProperties = allProperties.filterByModifier(CONST_KEYWORD)
                 val lateInitProperties = allProperties.filterByModifier(LATEINIT_KEYWORD)
+                val referencesFromSameScope = allProperties.mapNotNull { it.getIdentifierName()?.text }
                 val loggers = allProperties.filterByModifier(PRIVATE_KEYWORD)
                     .filterNot { astNode ->
                         /*
@@ -213,9 +215,27 @@ class ClassLikeStructuresOrderRule(configRules: List<RulesConfig>) : DiktatRule(
                     .filter { astNode ->
                         astNode.getIdentifierName()?.text?.matches(loggerPropertyRegex) ?: false
                     }
+                    .let {
+                        getLoggerDependencyNames(it)
+                    }
+                    .filter { (_, dependencyReferences) ->
+                        dependencyReferences.all {
+                            it !in referencesFromSameScope
+                        }
+                    }
+                    .keys
+                    .toList()
+
                 val properties = allProperties.filter { it !in lateInitProperties && it !in loggers && it !in constProperties }
                 return AllProperties(loggers, constProperties, properties, lateInitProperties)
             }
+
+            @Suppress("TYPE_ALIAS")
+            private fun getLoggerDependencyNames(loggers: List<ASTNode>): Map<ASTNode, List<String>> = loggers.map { astNode ->
+                astNode to astNode.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION, false)
+            }.associate { (astNode, possibleDependencies) ->
+                astNode to possibleDependencies.map { it.text }
+            }
         }
     }
 
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt
index 1f8e6f27d0..76478f76b4 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt
@@ -132,7 +132,7 @@ fun ASTNode.getAllChildrenWithType(elementType: IElementType): List<ASTNode> =
 /**
  * Generates a sequence of this ASTNode's children in reversed order
  *
- * @return a reevrsed sequence of children
+ * @return a reversed sequence of children
  */
 fun ASTNode.reversedChildren(): Sequence<ASTNode> = sequence {
     var node = lastChildNode


Test patch:
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/ClassLikeStructuresOrderFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/ClassLikeStructuresOrderFixTest.kt
index 1e1bef6fa0..7666177329 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/ClassLikeStructuresOrderFixTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/ClassLikeStructuresOrderFixTest.kt
@@ -26,4 +26,10 @@ class ClassLikeStructuresOrderFixTest : FixTestBase("test/paragraph3/file_struct
     fun `regression - should not remove enum members`() {
         fixAndCompare("OrderWithEnumsExpected.kt", "OrderWithEnumsTest.kt")
     }
+
+    @Test
+    @Tags(Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES))
+    fun `regression - should not move loggers that depend on other variables from scope`() {
+        fixAndCompare("LoggerOrderExpected.kt", "LoggerOrderTest.kt")
+    }
 }
diff --git a/diktat-rules/src/test/resources/test/paragraph3/file_structure/DeclarationsInClassOrderExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/file_structure/DeclarationsInClassOrderExpected.kt
index c2429b41a7..589b6ac0ae 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/file_structure/DeclarationsInClassOrderExpected.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/file_structure/DeclarationsInClassOrderExpected.kt
@@ -32,4 +32,4 @@ class Example {
     }
 
     class UnusedNested { }
-}
\ No newline at end of file
+}
diff --git a/diktat-rules/src/test/resources/test/paragraph3/file_structure/DeclarationsInClassOrderTest.kt b/diktat-rules/src/test/resources/test/paragraph3/file_structure/DeclarationsInClassOrderTest.kt
index efa1d15242..893db36628 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/file_structure/DeclarationsInClassOrderTest.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/file_structure/DeclarationsInClassOrderTest.kt
@@ -32,4 +32,4 @@ class Example {
      * Dolor sit amet
      */
     private val BAZ = 44
-}
\ No newline at end of file
+}
diff --git a/diktat-rules/src/test/resources/test/paragraph3/file_structure/LoggerOrderExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/file_structure/LoggerOrderExpected.kt
new file mode 100644
index 0000000000..9e95a588c1
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/paragraph3/file_structure/LoggerOrderExpected.kt
@@ -0,0 +1,55 @@
+package test.paragraph3.file_structure
+
+import org.junit.platform.commons.logging.LoggerFactory
+
+class LoggerOrderExample {
+    private val logger = getLogger("string template")
+    private val logger = getLogger("""string template""")
+    private val logger = getLogger("""
+string template
+""")
+    private val logger = getLogger(this.javaClass)
+    private val logger = getLogger(this.javaClass.name)
+    private val logger = getLogger(javaClass)
+    private val logger = getLogger(javaClass.name)
+    private val logger = getLogger(Foo::class.java)
+    private val logger = getLogger(Foo::class.java.name)
+    private val logger = getLogger(Foo::class)
+    private val logger = getLogger(Foo::class.name)
+    private val logger = getLogger<Foo>()
+    private val logger = getLogger({}.javaClass)
+    private val a = "a"
+    private val b = "b"
+    private val c = "c"
+    private val d = "d"
+    private val e = "e"
+    private val f = "f"
+    private val g = "g"
+    private val h = "h"
+    private val i = "i"
+    private val j = "j"
+    private val k = "k"
+    private val l = "l"
+    private val m = "m"
+    private val logger = LoggerFactory.getLogger(m)
+    private val n = "n"
+    private val logger = n.getLogger()
+    private val o = "o"
+    private val logger = o { get() }
+    private val p = "p"
+    private val logger = p::class.java.enclosingClass
+    private val q = "q"
+    private val logger = q::class.java
+    private val r = "r"
+    private val logger = r::javaClass
+    private val s = "s"
+    private val t = "t"
+    private val logger = getLogger("$s$t")
+    private val u = "u"
+    private val v = "v"
+    private val w = "w"
+    private val x = "x"
+    private val y = "y"
+    private val z = "z"
+    private val logger = getLogger("$s$t$u$v$w") { x + y + z }
+}
diff --git a/diktat-rules/src/test/resources/test/paragraph3/file_structure/LoggerOrderTest.kt b/diktat-rules/src/test/resources/test/paragraph3/file_structure/LoggerOrderTest.kt
new file mode 100644
index 0000000000..2a253d96bd
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/paragraph3/file_structure/LoggerOrderTest.kt
@@ -0,0 +1,55 @@
+package test.paragraph3.file_structure
+
+import org.junit.platform.commons.logging.LoggerFactory
+
+class LoggerOrderExample {
+    private val logger = getLogger("string template")
+    private val a = "a"
+    private val logger = getLogger("""string template""")
+    private val b = "b"
+    private val logger = getLogger("""
+string template
+""")
+    private val c = "c"
+    private val logger = getLogger(this.javaClass)
+    private val d = "d"
+    private val logger = getLogger(this.javaClass.name)
+    private val e = "e"
+    private val logger = getLogger(javaClass)
+    private val f = "f"
+    private val logger = getLogger(javaClass.name)
+    private val g = "g"
+    private val logger = getLogger(Foo::class.java)
+    private val h = "h"
+    private val logger = getLogger(Foo::class.java.name)
+    private val i = "i"
+    private val logger = getLogger(Foo::class)
+    private val j = "j"
+    private val logger = getLogger(Foo::class.name)
+    private val k = "k"
+    private val logger = getLogger<Foo>()
+    private val l = "l"
+    private val logger = getLogger({}.javaClass)
+    private val m = "m"
+    private val logger = LoggerFactory.getLogger(m)
+    private val n = "n"
+    private val logger = n.getLogger()
+    private val o = "o"
+    private val logger = o { get() }
+    private val p = "p"
+    private val logger = p::class.java.enclosingClass
+    private val q = "q"
+    private val logger = q::class.java
+    private val r = "r"
+    private val logger = r::javaClass
+    private val s = "s"
+    private val t = "t"
+    private val logger = getLogger("$s$t")
+    private val u = "u"
+    private val v = "v"
+    private val w = "w"
+    private val x = "x"
+    private val y = "y"
+    private val z = "z"
+    private val logger = getLogger("$s$t$u$v$w") { x + y + z }
+}