Repository: detekt/detekt (kotlin)

Issue:
False positive: `VarCouldBeVal`
## Expected Behavior
A property that is reasigned shouldn't be flagged even if it is inside an unknown type.

## Observed Behavior
It is flagged.

## Steps to Reproduce
```kotlin
@Test
fun `does not report private variables that are re-assigned inside an unknown type`() {
    val code = """
        private var a = 1

        fun foo() {
            with(UnknownReference) {
                a = 2
            }
        }
    """

    assertThat(subject.lintWithContext(env, code)).isEmpty()
}
```

## Context
In my code `UnkownReference` is a `ViewBinding` that detekt right now can't handle. Probably #4723 will help

## Your Environment
* Version of detekt used: 1.20.0 & main

Pull request description:
Attempt at fixing false positives for ValShouldBeVar when the assignment is inside an unknown type. This is the only logical solution I can think of at the moment. It basically assumes that if we can't resolve the type of the assignment, then it is from the inside of an unknown context (like a with-statement). Let me know if there is something I'm missing, and we can close/reject this PR...

Fixes #4736

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 6a98d79a3c5d..8bc2fc7c2f48 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
@@ -105,7 +105,10 @@ 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?.original == declarationDescriptor
+                it.getResolvedCall(bindingContext)?.resultingDescriptor?.original == declarationDescriptor ||
+                    // inside an unknown types context? (example: with-statement with unknown type)
+                    // (i.e, it can't be resolved if the assignment is from the context or from an outer variable)
+                    it.getResolvedCall(bindingContext) == null
             }
         }
 


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 17e89eb46805..e20de06b217a 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
@@ -4,6 +4,7 @@ import io.gitlab.arturbosch.detekt.rules.KotlinCoreEnvironmentTest
 import io.gitlab.arturbosch.detekt.test.TestConfig
 import io.gitlab.arturbosch.detekt.test.compileAndLint
 import io.gitlab.arturbosch.detekt.test.compileAndLintWithContext
+import io.gitlab.arturbosch.detekt.test.lintWithContext
 import org.assertj.core.api.Assertions.assertThat
 import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
 import org.junit.jupiter.api.Nested
@@ -50,6 +51,39 @@ class VarCouldBeValSpec(val env: KotlinCoreEnvironment) {
 
             assertThat(subject.compileAndLintWithContext(env, code)).isEmpty()
         }
+
+        @Test
+        fun `does not report private variables that are re-assigned inside an unknown type`() {
+            val code = """
+            private var a = 1
+
+            fun foo() {
+                with(UnknownReference) {
+                    a = 2
+                }
+            }
+            """
+
+            assertThat(subject.lintWithContext(env, code)).isEmpty()
+        }
+
+        @Test
+        fun `reports private variables that have the same name as those re-assigned within a known type`() {
+            val code = """
+            class MyClass(var a: Int)
+
+            private var a = 1
+            private val myObj = MyClass(1)
+
+            fun foo() {
+                with(myObj) {
+                    a = 2
+                }
+            }
+            """
+
+            assertThat(subject.compileAndLintWithContext(env, code)).hasSize(1)
+        }
     }
 
     @Nested