Repository: detekt/detekt (kotlin)

Issue:
False positive `SwallowedException` when exception is used as a receiver
<!-- 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
`SwallowedException` should not trigger

## Observed Behavior
`SwallowedException` triggers

## Steps to Reproduce

Analyze following code:

```
private fun Exception.transformException(): Exception {
   return this
}

private fun demo() {
   try {
      TODO()
   } catch (e: Exception) {
      throw e.transformException()
   }
}
```

## Context

`Exception.transformException()` is functionally equivalent to the `transformException(source: Exception)` (which does not trigger this rule), so the rule should be satisfied with it.

## Your Environment
<!-- Include as many relevant details about the environment you experienced the bug in -->
* Version of detekt used: 1.23.6

Pull request:
Fixes #7281

Patch:
diff --git a/detekt-rules-exceptions/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/exceptions/SwallowedException.kt b/detekt-rules-exceptions/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/exceptions/SwallowedException.kt
index 0e9eabfb27b9..bb402e3f9c7c 100644
--- a/detekt-rules-exceptions/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/exceptions/SwallowedException.kt
+++ b/detekt-rules-exceptions/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/exceptions/SwallowedException.kt
@@ -105,11 +105,11 @@ class SwallowedException(config: Config) : Rule(
 
     private fun isExceptionSwallowed(catchClause: KtCatchClause): Boolean {
         val parameterName = catchClause.catchParameter?.name
-        val catchBody = catchClause.catchBody
-        return catchBody?.anyDescendantOfType<KtThrowExpression> { throwExpr ->
-            val parameterReferences = throwExpr.parameterReferences(parameterName, catchBody)
-            parameterReferences.isNotEmpty() && parameterReferences.all { it is KtDotQualifiedExpression }
-        } == true
+        val catchBody = catchClause.catchBody ?: return false
+        return catchBody.anyDescendantOfType<KtThrowExpression> { throwExpr ->
+            val refs = throwExpr.parameterReferences(parameterName, catchBody)
+            refs.isNotEmpty() && refs.all { it is KtDotQualifiedExpression && it.parent !is KtThrowExpression }
+        }
     }
 
     private fun KtThrowExpression.parameterReferences(


Test patch:
diff --git a/detekt-rules-exceptions/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/exceptions/SwallowedExceptionSpec.kt b/detekt-rules-exceptions/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/exceptions/SwallowedExceptionSpec.kt
index 78f29479e28c..62d6ce7bc246 100644
--- a/detekt-rules-exceptions/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/exceptions/SwallowedExceptionSpec.kt
+++ b/detekt-rules-exceptions/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/exceptions/SwallowedExceptionSpec.kt
@@ -266,6 +266,23 @@ class SwallowedExceptionSpec {
         assertThat(subject.compileAndLint(code)).isEmpty()
     }
 
+    @Test
+    fun `does not report when an exception is used as a receiver and the return value is thrown`() {
+        val code = """
+            fun Exception.transformException(): Exception {
+               return this
+            }
+            
+            fun test() {
+               try {
+               } catch (e: Exception) {
+                  throw e.transformException()
+               }
+            }
+        """.trimIndent()
+        assertThat(subject.compileAndLint(code)).isEmpty()
+    }
+
     @ParameterizedTest(name = "ignores {0} in the catch clause by default")
     @MethodSource("io.gitlab.arturbosch.detekt.rules.exceptions.SwallowedException#getEXCEPTIONS_IGNORED_BY_DEFAULT")
     fun `ignores $exceptionName in the catch clause by default`(exceptionName: String) {