All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.fir.resolve.dfa.DataFlowVariable.kt Maven / Gradle / Ivy

/*
 * Copyright 2010-2019 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.fir.resolve.dfa

import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract

/*
 * isSynthetic = false for variables that represents actual variables in fir
 * isSynthetic = true for complex expressions (like when expression)
 */
sealed class DataFlowVariable(private val variableIndexForDebug: Int, val fir: FirElement) {
    final override fun toString(): String {
        return "d$variableIndexForDebug"
    }
}

open class RealDataFlowVariable(index: Int, fir: FirElement, val isThisReference: Boolean) : DataFlowVariable(index, fir)

class SyntheticDataFlowVariable(index: Int, fir: FirElement) : DataFlowVariable(index, fir)

class AliasedDataFlowVariable(
    index: Int,
    fir: FirElement,
    var delegate: RealDataFlowVariable
) : RealDataFlowVariable(index, fir, delegate.isThisReference)

// -------------------------------------------------------------------------------------------------------------------------

@UseExperimental(ExperimentalContracts::class)
fun DataFlowVariable.isSynthetic(): Boolean {
    contract {
        returns(true) implies (this@isSynthetic is SyntheticDataFlowVariable)
    }
    return this is SyntheticDataFlowVariable
}

@UseExperimental(ExperimentalContracts::class)
fun DataFlowVariable.isAliasVariable(): Boolean {
    contract {
        returns(true) implies (this@isAliasVariable is AliasedDataFlowVariable)
    }
    return this is AliasedDataFlowVariable
}

val RealDataFlowVariable.variableUnderAlias: RealDataFlowVariable
    get() {
        var variable = this
        while (variable.isAliasVariable()) {
            variable = variable.delegate
        }
        return variable
    }

// -------------------------------------------------------------------------------------------------------------------------

class DataFlowVariableStorage {
    private val fir2DfiMap: MutableMap = mutableMapOf()
    private var debugIndexCounter: Int = 1

    fun getOrCreateNewRealVariable(symbol: AbstractFirBasedSymbol<*>): RealDataFlowVariable {
        return getOrCreateNewRealVariableImpl(symbol, false)
    }

    fun getOrCreateNewThisRealVariable(symbol: AbstractFirBasedSymbol<*>): RealDataFlowVariable {
        return getOrCreateNewRealVariableImpl(symbol, true)
    }

    private fun getOrCreateNewRealVariableImpl(symbol: AbstractFirBasedSymbol<*>, isThisReference: Boolean): RealDataFlowVariable {
        val fir = symbol.fir
        get(fir)?.let { return it as RealDataFlowVariable }
        return RealDataFlowVariable(debugIndexCounter++, fir, isThisReference).also { storeVariable(it, fir) }
    }

    fun getOrCreateNewSyntheticVariable(fir: FirElement): SyntheticDataFlowVariable {
        get(fir)?.let { return it as SyntheticDataFlowVariable }
        return SyntheticDataFlowVariable(debugIndexCounter++, fir).also { storeVariable(it, fir) }
    }

    fun createAliasVariable(symbol: AbstractFirBasedSymbol<*>, variable: RealDataFlowVariable) {
        createAliasVariable(symbol.fir, variable)
    }

    private fun createAliasVariable(fir: FirElement, variable: RealDataFlowVariable) {
        AliasedDataFlowVariable(debugIndexCounter++, fir, variable).also { storeVariable(it, fir) }
    }

    fun rebindAliasVariable(aliasVariable: RealDataFlowVariable, newVariable: RealDataFlowVariable) {
        val fir = removeVariable(aliasVariable)
        requireNotNull(fir)
        createAliasVariable(fir, newVariable)
    }

    fun removeRealVariable(symbol: AbstractFirBasedSymbol<*>) {
        removeSyntheticVariable(symbol.fir)
    }

    fun removeSyntheticVariable(fir: FirElement) {
        val variable = fir2DfiMap[fir] ?: return
        removeVariable(variable)
    }

    fun removeVariable(variable: DataFlowVariable): FirElement? {
        return variable.fir.also {
            fir2DfiMap.remove(it)
        }
    }

    fun removeVariableIfSynthetic(variable: DataFlowVariable): FirElement? {
        if (variable is SyntheticDataFlowVariable) {
            return removeVariable(variable)
        }
        return null
    }

    operator fun get(variable: DataFlowVariable): FirElement? {
        return variable.fir
    }

    operator fun get(firElement: FirElement): DataFlowVariable? {
        return fir2DfiMap[firElement]
    }

    operator fun get(symbol: AbstractFirBasedSymbol<*>): RealDataFlowVariable? {
        return fir2DfiMap[symbol.fir] as RealDataFlowVariable?
    }

    fun reset() {
        fir2DfiMap.clear()
        debugIndexCounter = 1
    }

    private fun storeVariable(variable: DataFlowVariable, fir: FirElement) {
        fir2DfiMap[fir] = variable
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy