Repository: analysis-dev/diktat (kotlin)

Issue:
[ERROR] Internal error has occurred in package-naming: java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
In case you will run mvn diktat:check in the root of diktat you will see this issue.

```
 if (realNameParts.isNotEmpty() && packageNameParts.map { node -> node.text } != realNameParts) {
            val realPackageNameStr = realNameParts.joinToString(PACKAGE_SEPARATOR)
            // issue happens here if there is no package name for the file
            val offset = packageNameParts[0].startOffset
            PACKAGE_NAME_INCORRECT_PATH.warnAndFix(configRules, emitWarn, isFixMode,
                realPackageNameStr, offset, packageNameParts[0]) {
                insertNewPackageName(packageDirective, realPackageNameStr)
            }
        }
```

Pull request description:
### What's done:
* Changed logic
* Updated smoke tests

This pull request closes #861

Patch:
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt
index 6e22883fbd..63f8202f38 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt
@@ -48,6 +48,15 @@ class PackageNaming(configRules: List<RulesConfig>) : DiktatRule(
             domainName = it
             if (node.elementType == PACKAGE_DIRECTIVE) {
                 val filePath = node.getRootNode().getFilePath()
+
+                // getting all identifiers from existing package name into the list like [org, diktat, project]
+                val wordsInPackageName = node.findAllDescendantsWithSpecificType(IDENTIFIER)
+
+                if (wordsInPackageName.isEmpty() && filePath.isKotlinScript()) {
+                    // kotlin scripts are allowed to have empty package; in this case we don't suggest a new one and don't run checks
+                    return
+                }
+
                 // calculating package name based on the directory where the file is placed
                 val realPackageName = calculateRealPackageName(filePath, configuration)
 
@@ -57,9 +66,6 @@ class PackageNaming(configRules: List<RulesConfig>) : DiktatRule(
                     return
                 }
 
-                // getting all identifiers from existing package name into the list like [org, diktat, project]
-                val wordsInPackageName = node.findAllDescendantsWithSpecificType(IDENTIFIER)
-
                 // no need to check that packageIdentifiers is empty, because in this case parsing will fail
                 checkPackageName(wordsInPackageName, node)
                 // fix in checkFilePathMatchesWithPackageName is much more aggressive than fixes in checkPackageName, they can conflict
@@ -126,7 +132,7 @@ class PackageNaming(configRules: List<RulesConfig>) : DiktatRule(
             }
 
         // package name should start from a company's domain name
-        if (wordsInPackageName.isNotEmpty() && !isDomainMatches(wordsInPackageName)) {
+        if (!isDomainMatches(wordsInPackageName)) {
             PACKAGE_NAME_INCORRECT_PREFIX.warnAndFix(configRules, emitWarn, isFixMode, domainName,
                 wordsInPackageName[0].startOffset, wordsInPackageName[0]) {
                 val oldPackageName = wordsInPackageName.joinToString(PACKAGE_SEPARATOR) { it.text }


Test patch:
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 0eea44680a..a766625e9c 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
@@ -26,7 +26,9 @@ import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Tag
 import org.junit.jupiter.api.Test
 
+import java.io.File
 import java.time.LocalDate
+
 import kotlin.io.path.ExperimentalPathApi
 import kotlin.io.path.createTempFile
 import kotlinx.serialization.encodeToString
@@ -204,10 +206,31 @@ class DiktatSmokeTest : FixTestBase("test/smoke/src/main/kotlin",
                     "extendedIndentOfParameters" to "false",
                 )
             )
-        )  // so that trailing newline isn't checked
+        )  // so that trailing newline isn't checked, because it's incorrectly read in tests and we are comparing file with itself
         // file name is `gradle_` so that IDE doesn't suggest to import gradle project
-        fixAndCompare("../../../build.gradle_.kts", "../../../build.gradle_.kts")
+        val tmpTestFile = javaClass.classLoader.getResource("$resourceFilePath/../../../build.gradle_.kts")!!.toURI().let {
+            val tmpTestFile = File(it).parentFile.resolve("build.gradle.kts")
+            File(it).copyTo(tmpTestFile)
+            tmpTestFile
+        }
+        val tmpFilePath = "../../../build.gradle.kts"
+        fixAndCompare(tmpFilePath, tmpFilePath)
         Assertions.assertTrue(unfixedLintErrors.isEmpty())
+        tmpTestFile.delete()
+    }
+
+    @Test
+    @Tag("DiktatRuleSetProvider")
+    fun `smoke test with kts files #2`() {
+        fixAndCompare("script/SimpleRunInScriptExpected.kts", "script/SimpleRunInScriptTest.kts")
+        Assertions.assertEquals(3, unfixedLintErrors.size)
+    }
+
+    @Test
+    @Tag("DiktatRuleSetProvider")
+    fun `smoke test with kts files with package name`() {
+        fixAndCompare("script/PackageInScriptExpected.kts", "script/PackageInScriptTest.kts")
+        Assertions.assertEquals(3, unfixedLintErrors.size)
     }
 
     @Test
diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/PackageInScriptExpected.kts b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/PackageInScriptExpected.kts
new file mode 100644
index 0000000000..ec203fc711
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/PackageInScriptExpected.kts
@@ -0,0 +1,20 @@
+package org.cqfn.diktat.script
+
+run {
+    println("hello world!")
+}
+
+fun foo() {
+    println()
+}
+
+val q = Config()
+
+run {
+    println("a")
+}
+
+also {
+    println("a")
+}
+
diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/PackageInScriptTest.kts b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/PackageInScriptTest.kts
new file mode 100644
index 0000000000..0eb929bd91
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/PackageInScriptTest.kts
@@ -0,0 +1,19 @@
+package org.cqfn.diktat.script
+
+run {
+    println("hello world!")
+}
+
+fun foo() {
+    println()
+}
+
+val q = Config()
+
+run {
+    println("a")
+}
+
+also {
+    println("a")
+}
diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/SimpleRunInScriptExpected.kts b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/SimpleRunInScriptExpected.kts
new file mode 100644
index 0000000000..20f40c7a52
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/SimpleRunInScriptExpected.kts
@@ -0,0 +1,19 @@
+
+run {
+    println("hello world!")
+}
+
+fun foo() {
+    println()
+}
+
+val q = Config()
+
+run {
+    println("a")
+}
+
+also {
+    println("a")
+}
+
diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/SimpleRunInScriptTest.kts b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/SimpleRunInScriptTest.kts
new file mode 100644
index 0000000000..285d668e58
--- /dev/null
+++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/script/SimpleRunInScriptTest.kts
@@ -0,0 +1,16 @@
+
+println("hello world!")
+
+fun foo() {
+    println()
+}
+
+val q = Config()
+
+run {
+    println("a")
+}
+
+also {
+    println("a")
+}