Repository: detekt/detekt (kotlin)

Issue:
Invalid SARIF on EmptyKtFile
<!-- The bug you're experiencing might have already be reported! -->
<!-- Please search in the [issues](https://github.com/detekt/detekt/issues) before creating one. -->

## Expected Behavior
<!-- Tell us what should happen -->
A valid SARIF report with details about the empty file.

## Observed Behavior
<!-- Tell us what happens instead of the expected behavior -->
SARIF report is invalid and if you are using GitHub SARIF uploading is failing due to that.

## Steps to Reproduce
<!-- Provide a link to a live example, or an unambiguous set of steps to -->
<!-- reproduce this bug. Include code to reproduce, if relevant -->
1. Configure detekt to recognise `EmptyKtFile`
2. Create an Empty.kt file (Encoding or line ending of the file does not matter)
3. Run cli command `detekt-cli-1.23.5\bin\detekt-cli.bat --config ../config.yml --report sarif:..\empty.sarif`
```
MyApplication\app\src\main\java\com\example\myapplication\Empty.kt:-1:0: The empty Kotlin file MyApplication\app\src\main\java\com\example\myapplication\Empty.kt can be removed. [EmptyKtFile]

Analysis failed with 1 weighted issues.
```
5. Validate the SARIF report or if possible try using the upload to github. For outside validation I used [this](https://sarifweb.azurewebsites.net/Validation) online tool I am not aware if there is something more official available.
(Code of MyApplication doesn't really matter it was a dummy android studio project)

## Context
<!-- How has this issue affected you? What are you trying to accomplish? -->
<!-- Providing context helps us come up with a solution that is most useful in the real world -->
Issue identified when GitHub was failing to display the SARIF results inside the PR reviewing tool trying to identified why happening I narrowed down the issue to the fact that erroneously due to some renamings or movements of files in our repository we had some empty `*.kt` files. 

## Your Environment
<!-- Include as many relevant details about the environment you experienced the bug in -->
* Version of detekt used: 1.23.5
* Version of Gradle used (if applicable): cli tool used
* Gradle scan link (add `--scan` option when running the gradle task):
* Operating System and version: Windows OS 10, MacOS, Ubuntu
* Link to your project (if it's a public repository): Not public

## Attached
The files I used for this issue report reproduction.
- config.yml : The minimum config that enable the  `EmptyKtFile` rule
- empty.sarif : The produced report by running the command in the preproduction step
- Empty.kt : The empty file I created, you can also just delete all contents of any .kt file you have
[ReproductionFiles.zip](https://github.com/detekt/detekt/files/14514964/ReproductionFiles.zip)

Pull request:
Fix #7024

A line or column value less than 1 is not valid. Detekt didn't check this but sarif those so we were generating invalid sarif.

Other way to solve the issue is to move this code to the sarif serializer but I think that it's more correct to fix it in our own code and don't allow to point to a source location that doesn't exist.

Patch:
diff --git a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Location.kt b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Location.kt
index 2b206e3ce004..8c45fe936b84 100644
--- a/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Location.kt
+++ b/detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Location.kt
@@ -60,7 +60,7 @@ class Location(
 
         private fun lineAndColumn(element: PsiElement, range: TextRange): PsiDiagnosticUtils.LineAndColumn {
             return getLineAndColumnInPsiFile(element.containingFile, range)
-                ?: PsiDiagnosticUtils.LineAndColumn(-1, -1, null)
+                ?: PsiDiagnosticUtils.LineAndColumn(1, 1, null)
         }
     }
 }
@@ -70,6 +70,11 @@ class Location(
  */
 @Poko
 class SourceLocation(val line: Int, val column: Int) {
+    init {
+        require(line > 0) { "The source location line must be greater than 0" }
+        require(column > 0) { "The source location column must be greater than 0" }
+    }
+
     override fun toString(): String = "$line:$column"
 }
 
diff --git a/detekt-psi-utils/src/main/kotlin/io/github/detekt/psi/KtFiles.kt b/detekt-psi-utils/src/main/kotlin/io/github/detekt/psi/KtFiles.kt
index 1c434e58db55..a1debdb182b1 100644
--- a/detekt-psi-utils/src/main/kotlin/io/github/detekt/psi/KtFiles.kt
+++ b/detekt-psi-utils/src/main/kotlin/io/github/detekt/psi/KtFiles.kt
@@ -83,10 +83,14 @@ fun PsiFile.toFilePath(): FilePath {
 
 // #3317 If any rule mutates the PsiElement, searching the original PsiElement may throw an exception.
 fun getLineAndColumnInPsiFile(file: PsiFile, range: TextRange): PsiDiagnosticUtils.LineAndColumn? {
-    return runCatching {
-        @Suppress("ForbiddenMethodCall")
-        DiagnosticUtils.getLineAndColumnInPsiFile(file, range)
-    }.getOrNull()
+    return if (file.textLength == 0) {
+        null
+    } else {
+        runCatching {
+            @Suppress("ForbiddenMethodCall")
+            DiagnosticUtils.getLineAndColumnInPsiFile(file, range)
+        }.getOrNull()
+    }
 }
 
 private fun buildPlatformSpecificSuffixes(platforms: List<String>): List<String> =


Test patch:
diff --git a/detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/suppressors/Builders.kt b/detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/suppressors/Builders.kt
index 1fbe008de70c..3adece9f48cb 100644
--- a/detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/suppressors/Builders.kt
+++ b/detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/suppressors/Builders.kt
@@ -21,7 +21,7 @@ private fun buildEmptyEntity(): Entity = Entity(
     name = "",
     signature = "",
     location = Location(
-        source = SourceLocation(0, 0),
+        source = SourceLocation(1, 1),
         text = TextLocation(0, 0),
         filePath = FilePath.fromAbsolute(Path("/"))
     ),
diff --git a/detekt-rules-empty/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyKotlinFileSpec.kt b/detekt-rules-empty/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyKotlinFileSpec.kt
index 9497369d2a24..44f3ab4d4784 100644
--- a/detekt-rules-empty/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyKotlinFileSpec.kt
+++ b/detekt-rules-empty/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyKotlinFileSpec.kt
@@ -9,29 +9,31 @@ import org.junit.jupiter.api.Test
 class EmptyKotlinFileSpec {
     private val subject = EmptyKotlinFile(Config.empty)
 
-    private val codeWithPackageStatement = """
-            package my.packagee
-    """.trimIndent()
-
-    private val codeWithFunction = """
-            package my.packagee
-            
-            fun myFunction() {}
-    """.trimIndent()
-
     @Test
     fun `reports empty if file is blank`() {
         val code = ""
-        assertThat(subject.lint(code)).hasSize(1)
+        assertThat(subject.lint(code))
+            .singleElement()
+            .hasSourceLocation(1, 1)
     }
 
     @Test
     fun `does report file with package statement`() {
-        assertThat(subject.compileAndLint(codeWithPackageStatement)).hasSize(1)
+        val codeWithPackageStatement = """
+            package my.packagee
+        """.trimIndent()
+        assertThat(subject.compileAndLint(codeWithPackageStatement))
+            .singleElement()
+            .hasSourceLocation(1, 1)
     }
 
     @Test
     fun `does not report file with code`() {
-        assertThat(subject.compileAndLint(codeWithFunction)).hasSize(0)
+        val code = """
+            package my.packagee
+
+            fun myFunction() {}
+        """.trimIndent()
+        assertThat(subject.compileAndLint(code)).isEmpty()
     }
 }