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

org.jetbrains.kotlin.fir.analysis.cfa.CfaUtils.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2020 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.analysis.cfa

import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentMapOf
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol

abstract class EventOccurrencesRangeInfo, K : Any>(
    map: PersistentMap = persistentMapOf()
) : ControlFlowInfo(map) {

    override fun merge(other: E): E {
        @Suppress("UNCHECKED_CAST")
        var result = this as E
        for (symbol in keys.union(other.keys)) {
            val kind1 = this[symbol] ?: EventOccurrencesRange.ZERO
            val kind2 = other[symbol] ?: EventOccurrencesRange.ZERO
            result = result.put(symbol, kind1 or kind2)
        }
        return result
    }
}

class PropertyInitializationInfo(
    map: PersistentMap = persistentMapOf()
) : EventOccurrencesRangeInfo(map) {
    companion object {
        val EMPTY = PropertyInitializationInfo()
    }

    override val constructor: (PersistentMap) -> PropertyInitializationInfo =
        ::PropertyInitializationInfo

    override val empty: () -> PropertyInitializationInfo =
        ::EMPTY
}

class LocalPropertyCollector private constructor() : ControlFlowGraphVisitorVoid() {
    companion object {
        fun collect(graph: ControlFlowGraph): MutableSet {
            val collector = LocalPropertyCollector()
            graph.traverse(TraverseDirection.Forward, collector)
            return collector.symbols
        }
    }

    private val symbols: MutableSet = mutableSetOf()

    override fun visitNode(node: CFGNode<*>) {}

    override fun visitVariableDeclarationNode(node: VariableDeclarationNode) {
        symbols += node.fir.symbol
    }
}

class PathAwarePropertyInitializationInfo(
    map: PersistentMap = persistentMapOf()
) : PathAwareControlFlowInfo(map) {
    companion object {
        val EMPTY = PathAwarePropertyInitializationInfo(persistentMapOf(NormalPath to PropertyInitializationInfo.EMPTY))
    }

    override val constructor: (PersistentMap) -> PathAwarePropertyInitializationInfo =
        ::PathAwarePropertyInitializationInfo

    override val empty: () -> PathAwarePropertyInitializationInfo =
        ::EMPTY
}

class PropertyInitializationInfoCollector(private val localProperties: Set) :
    ControlFlowGraphVisitor>>() {
    override fun visitNode(
        node: CFGNode<*>,
        data: Collection>
    ): PathAwarePropertyInitializationInfo {
        if (data.isEmpty()) return PathAwarePropertyInitializationInfo.EMPTY
        return data.map { (label, info) -> info.applyLabel(node, label) }
            .reduce(PathAwarePropertyInitializationInfo::merge)
    }

    override fun visitVariableAssignmentNode(
        node: VariableAssignmentNode,
        data: Collection>
    ): PathAwarePropertyInitializationInfo {
        val dataForNode = visitNode(node, data)
        val reference = node.fir.lValue as? FirResolvedNamedReference ?: return dataForNode
        val symbol = reference.resolvedSymbol as? FirPropertySymbol ?: return dataForNode
        return if (symbol !in localProperties) {
            dataForNode
        } else {
            processVariableWithAssignment(dataForNode, symbol)
        }
    }

    override fun visitVariableDeclarationNode(
        node: VariableDeclarationNode,
        data: Collection>
    ): PathAwarePropertyInitializationInfo {
        val dataForNode = visitNode(node, data)
        return if (node.fir.initializer == null && node.fir.delegate == null) {
            dataForNode
        } else {
            processVariableWithAssignment(dataForNode, node.fir.symbol)
        }
    }

    fun getData(graph: ControlFlowGraph) =
        graph.collectPathAwareDataForNode(
            TraverseDirection.Forward,
            PathAwarePropertyInitializationInfo.EMPTY,
            this
        )

    private fun processVariableWithAssignment(
        dataForNode: PathAwarePropertyInitializationInfo,
        symbol: FirPropertySymbol
    ): PathAwarePropertyInitializationInfo {
        assert(dataForNode.keys.isNotEmpty())
        return addRange(dataForNode, symbol, EventOccurrencesRange.EXACTLY_ONCE, ::PathAwarePropertyInitializationInfo)
    }
}

internal fun 

, S : ControlFlowInfo, K : Any> addRange( info: P, key: K, range: EventOccurrencesRange, constructor: (PersistentMap) -> P ): P { var resultMap = persistentMapOf() // before: { |-> { p1 |-> PI1 }, l1 |-> { p2 |-> PI2 } } for (label in info.keys) { val dataPerLabel = info[label]!! val existingKind = dataPerLabel[key] ?: EventOccurrencesRange.ZERO val kind = existingKind + range resultMap = resultMap.put(label, dataPerLabel.put(key, kind)) } // after (if key is p1): // { |-> { p1 |-> PI1 + r }, l1 |-> { p1 |-> r, p2 |-> PI2 } } return constructor(resultMap) }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy