/*
 * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.analysis.low.level.api.fir.caches

import org.jetbrains.kotlin.analysis.low.level.api.fir.caches.cleanable.ValueReferenceCleaner
import java.io.Serializable

/**
 * A value with a [CleanupMarker] to be used in [CleanableValueReferenceCache][org.jetbrains.kotlin.analysis.low.level.api.fir.caches.cleanable.CleanableValueReferenceCache]
 * tests.
 *
 * This class implements [Serializable] so that it can be contained in scenarios generated by Lincheck.
 */
class ValueWithCleanup(val name: String) : Serializable {
    val cleanupMarker: CleanupMarker = CleanupMarker()

    val isCleanedUp: Boolean get() = cleanupMarker.isCleanedUp

    // This equality implementation is needed as we want to check that `compute` doesn't clean up a replaced value that is referentially
    // equal to the new value, but does clean up a replaced value that is only equal to the new value by `equals`, not reference.
    override fun equals(other: Any?): Boolean = (other as? ValueWithCleanup)?.name == name

    override fun hashCode(): Int = name.hashCode()

    override fun toString(): String = "ValueWithCleanup:'$name'"
}

/**
 * Tracks whether the associated [ValueWithCleanup] has been cleaned up yet.
 *
 * [ValueWithCleanup] shouldn't be referenced from its [ValueReferenceCleaner], because this would make the value strongly reachable from
 * the reference held by [CleanableValueReferenceCache][org.jetbrains.kotlin.analysis.low.level.api.fir.caches.cleanable.CleanableValueReferenceCache].
 * Instead, we need to keep [isCleanedUp] in this separate class.
 *
 * We cannot check the cleanup count in this test because `CleanableValueReferenceCache` does not guarantee any specific number of cleanup
 * calls.
 */
class CleanupMarker : ValueReferenceCleaner<ValueWithCleanup>, Serializable {
    var isCleanedUp: Boolean = false

    override fun cleanUp(value: ValueWithCleanup?) {
        isCleanedUp = true
    }
}
