Repository: detekt/detekt (kotlin)

Issue:
False positive on `VarCouldBeVal` in generic classes
<!-- The bug you're experiencing might have already be reported! -->
<!-- Please search in the [issues](https://github.com/detekt/detekt/issues) before creating one. -->

## Observed Behavior
`Expecting empty but was: [CodeSmell(issue=Issue(id='VarCouldBeVal', severity=Maintainability, debt=5min), entity=Entity(name=a, signature=Test.kt$A$private var a = 1, location=Location(source=2:5, text=17:34, file=Test.kt, filePath=FilePath(absolutePath=Test.kt, basePath=null, relativePath=null)), ktElement=PROPERTY), message=Variable 'a' could be val., metrics=[], references=[], severity=WARNING, id='VarCouldBeVal')]`

## Steps to Reproduce
```kt
        @Test
        fun `does not report variables that are re-assigned in generic class with receiver`() {
            val code = """
                class A<T> {
                    private var a = 1
                    
                    fun foo(): A<T> = apply {
                        a = 2
                    }
                }
            """.trimIndent()
            assertThat(subject.compileAndLintWithContext(env, code)).isEmpty()
        }
```

## 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 -->
Interestingly, declaring the return type as generic and the fact that it's in a receiver block are important to getting the lint error to report.
```kt
class A<T> {
    private var a = 1

    // fun foo() = apply { a = 2 }         // no error
    // fun foo2(): A = apply { a = 3 }     // no error

    fun foo3(): A<T> = apply { a = 4 }  // error

    // no error
    /*
    fun foo4(): A<T> {
        a = 5
        return this
    }
    */
}
```

## Your Environment
<!-- Include as many relevant details about the environment you experienced the bug in -->
* Version of detekt used: 1.20.0
* Link to your project (if it's a public repository): https://github.com/aws/aws-toolkit-jetbrains/blob/7853ede42bb44a585b786b0ad49c81d27d24c9cc/jetbrains-core/src/software/aws/toolkits/jetbrains/ui/ResourceSelector.kt#L232-L267

Pull request:
Fixes #4730

Patch:
diff --git a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/VarCouldBeVal.kt b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/VarCouldBeVal.kt
index 0108094cd057..e602d19640fe 100644
--- a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/VarCouldBeVal.kt
+++ b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/VarCouldBeVal.kt
@@ -96,7 +96,7 @@ class VarCouldBeVal(config: Config = Config.empty) : Rule(config) {
             if (assignments.isNullOrEmpty()) return false
             val declarationDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, this]
             return assignments.any {
-                it.getResolvedCall(bindingContext)?.resultingDescriptor == declarationDescriptor
+                it.getResolvedCall(bindingContext)?.resultingDescriptor?.original == declarationDescriptor
             }
         }
 


Test patch:
diff --git a/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/VarCouldBeValSpec.kt b/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/VarCouldBeValSpec.kt
index c94cfa094fb0..8982aab7f031 100644
--- a/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/VarCouldBeValSpec.kt
+++ b/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/VarCouldBeValSpec.kt
@@ -97,6 +97,20 @@ class VarCouldBeValSpec(val env: KotlinCoreEnvironment) {
             assertThat(subject.compileAndLintWithContext(env, code)).isEmpty()
         }
 
+        @Test
+        fun `does not report variables that are re-assigned in generic class with receiver`() {
+            val code = """
+                class A<T> {
+                    private var a = 1
+                    
+                    fun foo(): A<T> = apply {
+                        a = 2
+                    }
+                }
+            """.trimIndent()
+            assertThat(subject.compileAndLintWithContext(env, code)).isEmpty()
+        }
+
         @Test
         fun `reports variables that are not re-assigned`() {
             val code = """