Repository: analysis-dev/diktat (kotlin)

Issue:
Bugs during autofix of KDoc
## Describe the bug
Initial code:
```kotlin
    /**
     * Creates a docker container with [file], prepared to execute it
     *
     * @param runConfiguration a [RunConfiguration] for the supplied binary
     * @param file a file that will be included as an executable
     * @param resources additional resources
     * @throws DockerException if docker daemon has returned an error
     * @throws DockerException if docker daemon has returned an error
     * @throws RuntimeException if an exception not specific to docker has occurred
     * @return id of created container or null if it wasn't created
     */
    internal fun createWithFile(runConfiguration: RunConfiguration,
                                containerName: String,
                                file: File,
                                resources: Collection<File> = emptySet()): String {}
```
result after `diktatFix`:
```kotlin
    /**
     * Creates a docker container with [file], prepared to execute it
     *
     * @param runConfiguration a [RunConfiguration] for the supplied binary
     * @return id of created container or null if it wasn't created
     * @throws DockerException if docker daemon has returned an error
     * @throws DockerException if docker daemon has returned an error
     * @throws DockerException if docker daemon has returned an error
     * @throws RuntimeException if an exception not specific to docker has occurred
     * @param containerName
     * @return id of created container or null if it wasn't created
     */
    internal fun createWithFile(runConfiguration: RunConfiguration,
                                containerName: String,
                                file: File,
                                resources: Collection<File> = emptySet()): String {}
```

## Environment information
* diktat version: 0.4.0

Pull request description:
### What's done:
* [x] Rewrote algorithm 
* [x] Added tests
* [x] closes #768

Patch:
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocFormatting.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocFormatting.kt
index e958a8a0fb..5d85013673 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocFormatting.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocFormatting.kt
@@ -170,7 +170,7 @@ class KdocFormatting(configRules: List<RulesConfig>) : DiktatRule(
         }
     )
 
-    @Suppress("UnsafeCallOnNullableType")
+    @Suppress("UnsafeCallOnNullableType", "TOO_LONG_FUNCTION")
     private fun checkBasicTagsOrder(node: ASTNode) {
         val kdocTags = node.kDocTags()
         // distinct basic tags which are present in current KDoc, in proper order
@@ -202,10 +202,13 @@ class KdocFormatting(configRules: List<RulesConfig>) : DiktatRule(
                     .filter { basicTagsOrdered.contains(it.knownTag) }
                     .map { it.node }
 
-                basicTagsOrdered.forEachIndexed { index, tag ->
-                    val tagNode = kdocTags.find { it.knownTag == tag }!!.node
-                    kdocSection.addChild(tagNode.clone() as CompositeElement, basicTagChildren[index])
-                    kdocSection.removeChild(basicTagChildren[index])
+                val correctKdocOrder = basicTags
+                    .sortedBy { basicTagsOrdered.indexOf(it.knownTag) }
+                    .map { it.node }
+
+                basicTagChildren.mapIndexed { index, astNode ->
+                    kdocSection.addChild(correctKdocOrder[index].clone() as CompositeElement, astNode)
+                    kdocSection.removeChild(astNode)
                 }
             }
         }


Test patch:
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocFormattingFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocFormattingFixTest.kt
index 4011181830..9c7e6a15f0 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocFormattingFixTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocFormattingFixTest.kt
@@ -50,4 +50,10 @@ class KdocFormattingFixTest : FixTestBase("test/paragraph2/kdoc/", ::KdocFormatt
     fun `KdocFormatting - all warnings`() {
         fixAndCompare("KdocFormattingFullExpected.kt", "KdocFormattingFullTest.kt")
     }
+
+    @Test
+    @Tags(Tag(WarningNames.KDOC_NO_DEPRECATED_TAG), Tag(WarningNames.KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS))
+    fun `KdocFormatting - sort order`() {
+        fixAndCompare("KdocFormattingOrderExpected.kt", "KdocFormattingOrderTest.kt")
+    }
 }
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt
index ba81e98b34..1bd5a84e29 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt
@@ -8,6 +8,7 @@ import org.cqfn.diktat.ruleset.constants.Warnings.EMPTY_BLOCK_STRUCTURE_ERROR
 import org.cqfn.diktat.ruleset.constants.Warnings.FILE_NAME_MATCH_CLASS
 import org.cqfn.diktat.ruleset.constants.Warnings.HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE
 import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_NO_EMPTY_TAGS
+import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_WITHOUT_PARAM_TAG
 import org.cqfn.diktat.ruleset.constants.Warnings.MISSING_KDOC_CLASS_ELEMENTS
 import org.cqfn.diktat.ruleset.constants.Warnings.MISSING_KDOC_ON_FUNCTION
 import org.cqfn.diktat.ruleset.constants.Warnings.MISSING_KDOC_TOP_LEVEL
@@ -160,7 +161,11 @@ class DiktatSmokeTest : FixTestBase("test/smoke/src/main/kotlin",
     fun `smoke test #2`() {
         fixAndCompare("Example2Expected.kt", "Example2Test.kt")
         unfixedLintErrors.assertEquals(
-            LintError(1, 1, "$DIKTAT_RULE_SET_ID:header-comment", "${HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE.warnText()} there are 2 declared classes and/or objects", false)
+            LintError(1, 1, "$DIKTAT_RULE_SET_ID:header-comment", "${HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE.warnText()} there are 2 declared classes and/or objects", false),
+            LintError(15, 23, "$DIKTAT_RULE_SET_ID:kdoc-methods",
+                "${KDOC_WITHOUT_PARAM_TAG.warnText()} createWithFile (containerName)", true),
+            LintError(31, 13, "$DIKTAT_RULE_SET_ID:empty-block-structure",
+                "${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} empty blocks are forbidden unless it is function with override keyword", false)
         )
     }
 
diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingOrderExpected.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingOrderExpected.kt
new file mode 100644
index 0000000000..4c33868daf
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingOrderExpected.kt
@@ -0,0 +1,17 @@
+package test.paragraph2.kdoc
+
+/**
+ * Creates a docker container with [file], prepared to execute it
+ *
+ * @param runConfiguration a [RunConfiguration] for the supplied binary
+ * @param file a file that will be included as an executable
+ * @param resources additional resources
+ * @return id of created container or null if it wasn't created
+ * @throws DockerException if docker daemon has returned an error
+ * @throws DockerException if docker daemon has returned an error
+ * @throws RuntimeException if an exception not specific to docker has occurred
+ */
+internal fun createWithFile(runConfiguration: RunConfiguration,
+                            containerName: String,
+                            file: File,
+                            resources: Collection<File> = emptySet()): String {}
\ No newline at end of file
diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingOrderTest.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingOrderTest.kt
new file mode 100644
index 0000000000..b1a515e31e
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingOrderTest.kt
@@ -0,0 +1,17 @@
+package test.paragraph2.kdoc
+
+/**
+ * Creates a docker container with [file], prepared to execute it
+ *
+ * @param runConfiguration a [RunConfiguration] for the supplied binary
+ * @param file a file that will be included as an executable
+ * @param resources additional resources
+ * @throws DockerException if docker daemon has returned an error
+ * @throws DockerException if docker daemon has returned an error
+ * @throws RuntimeException if an exception not specific to docker has occurred
+ * @return id of created container or null if it wasn't created
+ */
+internal fun createWithFile(runConfiguration: RunConfiguration,
+                            containerName: String,
+                            file: File,
+                            resources: Collection<File> = emptySet()): String {}
\ No newline at end of file
diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Expected.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Expected.kt
index 2dc345d30b..ad5f9be991 100644
--- a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Expected.kt
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Expected.kt
@@ -15,6 +15,23 @@ private class TestException : Exception()
 /* this class is unused */
 // private class Test : RuntimeException()
 
+/**
+ * Creates a docker container with [file], prepared to execute it
+ *
+ * @param runConfiguration a [RunConfiguration] for the supplied binary
+ * @param file a file that will be included as an executable
+ * @param resources additional resources
+ * @param containerName
+ * @return id of created container or null if it wasn't created
+ * @throws DockerException if docker daemon has returned an error
+ * @throws DockerException if docker daemon has returned an error
+ * @throws RuntimeException if an exception not specific to docker has occurred
+ */
+internal fun createWithFile(runConfiguration: RunConfiguration,
+                            containerName: String,
+                            file: File,
+                            resources: Collection<File> = emptySet()) {}
+
 private fun foo(node: ASTNode) {
     when (node.elementType) {
         CLASS, FUN, PRIMARY_CONSTRUCTOR, SECONDARY_CONSTRUCTOR -> checkAnnotation(node)
diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Test.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Test.kt
index 680550b06a..b6fe5ccc3e 100644
--- a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Test.kt
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example2Test.kt
@@ -11,6 +11,22 @@ private class Test : Exception()
 /*    this class is unused */
 //private class Test : RuntimeException()
 
+/**
+ * Creates a docker container with [file], prepared to execute it
+ *
+ * @param runConfiguration a [RunConfiguration] for the supplied binary
+ * @param file a file that will be included as an executable
+ * @param resources additional resources
+ * @throws DockerException if docker daemon has returned an error
+ * @throws DockerException if docker daemon has returned an error
+ * @throws RuntimeException if an exception not specific to docker has occurred
+ * @return id of created container or null if it wasn't created
+ */
+internal fun createWithFile(runConfiguration: RunConfiguration,
+                            containerName: String,
+                            file: File,
+                            resources: Collection<File> = emptySet()) {}
+
 private fun foo (node: ASTNode) {
     when (node.elementType) {
         CLASS, FUN, PRIMARY_CONSTRUCTOR, SECONDARY_CONSTRUCTOR -> checkAnnotation(node)
@@ -24,4 +40,4 @@ private fun foo (node: ASTNode) {
         foo()
 
     setOf<Object>(IOException(), Properties(), LoggerFactory())
-}
\ No newline at end of file
+}