saveourtool / diktat

Strict coding standard for Kotlin and a custom set of rules for detecting code smells, code style issues and bugs
https://diktat.saveourtool.com
MIT License
544 stars 39 forks source link

false positive when assigning to a declared val with a branch null check #1844

Closed Skeletonxf closed 11 months ago

Skeletonxf commented 12 months ago

Describe the bug

False positive in class init block when assigning to a declared val with a branch null check.

Expected behavior

Diktat does not rewrite the following code:

class Demo {
  val one: Int
  val two: String

  init {
    val number = get()
    if (number != null) {
      one = number.toInt()
      two = number
    } else {
      one = 0
      two = "0"
    }
  }

  private fun get(): String? = if (Math.random() > 0.5) { "1" } else { null }
}

Observed behavior

Diktat rewrites the init block to

val number = get()
number?.let {
  one = number.toInt()
  two = number
} ?: run {
  one = 0
  two = "0"
}

which does not compile as the kotlin compiler complains that "val cannot be reassigned" (even though we can see that it wouldn't be in this case)

Steps to Reproduce

Assign to a declared val in both branches of a null check

Environment information

orchestr7 commented 11 months ago

@Skeletonxf thank you for your report! Your particular case is definitely a bug, because we did not expect that run will be called as extension function inside of init block, but actually it does not work even with kotlin.run function. And that is a bug in a design of Kotlin, as I think.

We will workaround it, by removing this false positive in particular scopes. But I have anyway reported it to Kotlin: https://youtrack.jetbrains.com/issue/KT-64174/kotlin.run-inconsistent-behaviour-inside-of-scope-structures-like-init

orchestr7 commented 11 months ago

@Skeletonxf indeed, Kotlin team has reviewed it. And it appeared that the bug in Kotlin we are talking about was reported 5 years ago: https://youtrack.jetbrains.com/issue/KT-28511