Repository: square/leakcanary
File: shark/shark-android/src/main/java/shark/AndroidObjectInspectors.kt (Kotlin)

Code before:
      reporter.whenInstanceOf("androidx.compose.runtime.CompositionImpl") { instance ->
        // Try the old "disposed" boolean field first (older Compose versions)
        val disposedField = instance["androidx.compose.runtime.CompositionImpl", "disposed"]
        if (disposedField != null) {
          val disposed = disposedField.value.asBoolean
          if (disposed != null && disposed) {
            leakingReasons += "Composition disposed"
          } else {
            notLeakingReasons += "Composition not disposed"
          }
        } else {
          // Try the new "state" field (newer Compose versions)
          // State is an int with constants: RUNNING=0, DEACTIVATED=1, INCONSISTENT=2, DISPOSED=3
          val stateField = instance["androidx.compose.runtime.CompositionImpl", "state"]
          if (stateField != null) {
            val stateValue = stateField.value.asInt
            if (stateValue != null) {
              when (stateValue) {
                3 -> leakingReasons += "Composition disposed" // DISPOSED state
                0 -> notLeakingReasons += "Composition running" // RUNNING state
                1 -> labels += "Composition deactivated" // DEACTIVATED state
                2 -> labels += "Composition inconsistent" // INCONSISTENT state
                else -> labels += "Composition state: $stateValue"
              }
            } else {
              labels += "Composition state field exists but value is null"
            }
          } else {
            // Neither field exists - can't determine composition state
            labels += "Composition disposal state unknown (no disposed or state field)"
          }
        }
      }
    }
  },

  ANIMATOR {
    override fun inspect(reporter: ObjectReporter) {
      reporter.whenInstanceOf("android.animation.Animator") { instance ->
        val mListeners = instance["android.animation.Animator", "mListeners"]!!.valueAsInstance
        if (mListeners != null) {
          val listenerValues = InternalSharkCollectionsHelper.arrayListValues(mListeners).toList()
          if (listenerValues.isNotEmpty()) {
            listenerValues.forEach { value ->
              labels += "mListeners$value"
            }
          } else {
            labels += "mListeners is empty"
          }
        } else {
          labels += "mListeners = null"

Review comment (suggestion):
The `state` field is an Int, a primitive field, primitives can never be null, only references can. if `asInt` returns null it means the state field is not an int. I would do the same as above and do `asInt!!` instead.

Code after:
      reporter.whenInstanceOf("androidx.compose.runtime.CompositionImpl") { instance ->
        // Try the old "disposed" boolean field first (older Compose versions)
        val disposedField = instance["androidx.compose.runtime.CompositionImpl", "disposed"]
        if (disposedField != null) {
          if (disposedField.value.asBoolean!!) {
            leakingReasons += "Composition disposed"
          } else {
            notLeakingReasons += "Composition not disposed"
          }
        } else {
          // Try the new "state" field (newer Compose versions)
          // State is an int with constants: RUNNING=0, DEACTIVATED=1, INCONSISTENT=2, DISPOSED=3
          val stateField = instance["androidx.compose.runtime.CompositionImpl", "state"]
          if (stateField != null) {
            when (val stateValue = stateField.value.asInt!!) {
              3 -> leakingReasons += "Composition disposed" // DISPOSED state
              0 -> notLeakingReasons += "Composition running" // RUNNING state
              1 -> labels += "Composition deactivated" // DEACTIVATED state
              2 -> labels += "Composition inconsistent" // INCONSISTENT state
              else -> labels += "Composition state: $stateValue"
            }
          } else {
            // Neither field exists - can't determine composition state
            labels += "Composition disposal state unknown (no disposed or state field)"
          }
        }
      }
    }
  },

  ANIMATOR {
    override fun inspect(reporter: ObjectReporter) {
      reporter.whenInstanceOf("android.animation.Animator") { instance ->
        val mListeners = instance["android.animation.Animator", "mListeners"]!!.valueAsInstance
        if (mListeners != null) {
          val listenerValues = InternalSharkCollectionsHelper.arrayListValues(mListeners).toList()
          if (listenerValues.isNotEmpty()) {
            listenerValues.forEach { value ->
              labels += "mListeners$value"
            }
          } else {
            labels += "mListeners is empty"
          }
        } else {
          labels += "mListeners = null"
        }
      }
    }
  },

  OBJECT_ANIMATOR {