[FIR] Hide modifications of CFG from public API
This commit is contained in:
+35
-12
@@ -3,6 +3,8 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("Reformat")
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.dfa.cfg
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
@@ -15,9 +17,18 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||
|
||||
class ControlFlowGraph(val name: String, val kind: Kind) {
|
||||
val nodes = mutableListOf<CFGNode<*>>()
|
||||
private val _nodes: MutableList<CFGNode<*>> = mutableListOf()
|
||||
|
||||
val nodes: List<CFGNode<*>> get() = _nodes
|
||||
|
||||
internal fun addNode(node: CFGNode<*>) {
|
||||
_nodes += node
|
||||
}
|
||||
|
||||
lateinit var enterNode: CFGNode<*>
|
||||
internal set
|
||||
lateinit var exitNode: CFGNode<*>
|
||||
internal set
|
||||
|
||||
enum class Kind {
|
||||
Function, ClassInitializer, PropertyInitializer, TopLevel
|
||||
@@ -30,12 +41,12 @@ enum class EdgeKind {
|
||||
|
||||
sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level: Int, private val id: Int) {
|
||||
companion object {
|
||||
fun addEdge(from: CFGNode<*>, to: CFGNode<*>, kind: EdgeKind, propagateDeadness: Boolean) {
|
||||
from.followingNodes += to
|
||||
to.previousNodes += from
|
||||
internal fun addEdge(from: CFGNode<*>, to: CFGNode<*>, kind: EdgeKind, propagateDeadness: Boolean) {
|
||||
from._followingNodes += to
|
||||
to._previousNodes += from
|
||||
if (kind != EdgeKind.Simple) {
|
||||
from.outgoingEdges[to] = kind
|
||||
to.incomingEdges[from] = kind
|
||||
from._outgoingEdges[to] = kind
|
||||
to._incomingEdges[from] = kind
|
||||
}
|
||||
if (propagateDeadness && kind == EdgeKind.Dead) {
|
||||
to.isDead = true
|
||||
@@ -44,19 +55,29 @@ sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level:
|
||||
}
|
||||
|
||||
init {
|
||||
owner.nodes += this
|
||||
@Suppress("LeakingThis")
|
||||
owner.addNode(this)
|
||||
}
|
||||
|
||||
val previousNodes: MutableList<CFGNode<*>> = mutableListOf()
|
||||
val followingNodes: MutableList<CFGNode<*>> = mutableListOf()
|
||||
private val _previousNodes: MutableList<CFGNode<*>> = mutableListOf()
|
||||
private val _followingNodes: MutableList<CFGNode<*>> = mutableListOf()
|
||||
|
||||
val incomingEdges = mutableMapOf<CFGNode<*>, EdgeKind>().withDefault { EdgeKind.Simple }
|
||||
val outgoingEdges = mutableMapOf<CFGNode<*>, EdgeKind>().withDefault { EdgeKind.Simple }
|
||||
val previousNodes: List<CFGNode<*>> get() = _previousNodes
|
||||
val followingNodes: List<CFGNode<*>> get() = _followingNodes
|
||||
|
||||
val firstPreviousNode: CFGNode<*> get() = previousNodes.first()
|
||||
private val _incomingEdges = mutableMapOf<CFGNode<*>, EdgeKind>().withDefault { EdgeKind.Simple }
|
||||
private val _outgoingEdges = mutableMapOf<CFGNode<*>, EdgeKind>().withDefault { EdgeKind.Simple }
|
||||
|
||||
val incomingEdges: Map<CFGNode<*>, EdgeKind> get() = _incomingEdges
|
||||
val outgoingEdges: Map<CFGNode<*>, EdgeKind> get() = _outgoingEdges
|
||||
|
||||
abstract val fir: E
|
||||
var isDead: Boolean = false
|
||||
protected set
|
||||
|
||||
internal fun updateDeadStatus() {
|
||||
isDead = incomingEdges.size == previousNodes.size && incomingEdges.values.all { it == EdgeKind.Dead }
|
||||
}
|
||||
|
||||
final override fun equals(other: Any?): Boolean {
|
||||
if (other !is CFGNode<*>) return false
|
||||
@@ -68,6 +89,8 @@ sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level:
|
||||
}
|
||||
}
|
||||
|
||||
val CFGNode<*>.firstPreviousNode: CFGNode<*> get() = previousNodes.first()
|
||||
|
||||
interface EnterNode
|
||||
interface ExitNode
|
||||
|
||||
|
||||
+11
-15
@@ -131,7 +131,7 @@ class ControlFlowGraphBuilder {
|
||||
}
|
||||
lexicalScopes.pop()
|
||||
}
|
||||
exitNode.markAsDeadIfNecessary()
|
||||
exitNode.updateDeadStatus()
|
||||
val graph = if (!isInplace) {
|
||||
graphs.pop()
|
||||
} else {
|
||||
@@ -175,7 +175,7 @@ class ControlFlowGraphBuilder {
|
||||
functionExitNodes.top().also {
|
||||
addEdge(lastNodes.pop(), it)
|
||||
lastNodes.push(it)
|
||||
it.markAsDeadIfNecessary()
|
||||
it.updateDeadStatus()
|
||||
}
|
||||
} else {
|
||||
levelCounter--
|
||||
@@ -201,7 +201,7 @@ class ControlFlowGraphBuilder {
|
||||
fun exitProperty(property: FirProperty): Pair<PropertyInitializerExitNode, ControlFlowGraph> {
|
||||
val topLevelVariableExitNode = topLevelVariableInitializerExitNodes.pop().also {
|
||||
addNewSimpleNode(it)
|
||||
it.markAsDeadIfNecessary()
|
||||
it.updateDeadStatus()
|
||||
}
|
||||
levelCounter--
|
||||
exitNodes.pop()
|
||||
@@ -285,7 +285,7 @@ class ControlFlowGraphBuilder {
|
||||
addEdge(this, whenExitNode)
|
||||
}
|
||||
} else null
|
||||
whenExitNode.markAsDeadIfNecessary()
|
||||
whenExitNode.updateDeadStatus()
|
||||
lastNodes.push(whenExitNode)
|
||||
levelCounter--
|
||||
return whenExitNode to syntheticElseBranchNode
|
||||
@@ -332,7 +332,7 @@ class ControlFlowGraphBuilder {
|
||||
addEdge(loopBlockExitNode, conditionEnterNode, propagateDeadness = false)
|
||||
}
|
||||
val loopExitNode = loopExitNodes.pop()
|
||||
loopExitNode.markAsDeadIfNecessary()
|
||||
loopExitNode.updateDeadStatus()
|
||||
lastNodes.push(loopExitNode)
|
||||
levelCounter--
|
||||
return loopBlockExitNode to loopExitNode
|
||||
@@ -373,7 +373,7 @@ class ControlFlowGraphBuilder {
|
||||
addEdge(conditionExitNode, blockEnterNode, propagateDeadness = false, isDead = conditionBooleanValue == false)
|
||||
val loopExit = loopExitNodes.pop()
|
||||
addEdge(conditionExitNode, loopExit, propagateDeadness = false, isDead = conditionBooleanValue == true)
|
||||
loopExit.markAsDeadIfNecessary()
|
||||
loopExit.updateDeadStatus()
|
||||
lastNodes.push(loopExit)
|
||||
levelCounter--
|
||||
return conditionExitNode to loopExit
|
||||
@@ -410,7 +410,7 @@ class ControlFlowGraphBuilder {
|
||||
return binaryAndExitNodes.pop().also {
|
||||
val rightNode = lastNodes.pop()
|
||||
addEdge(rightNode, it, propagateDeadness = false, isDead = it.leftOperandNode.booleanConstValue == false)
|
||||
it.markAsDeadIfNecessary()
|
||||
it.updateDeadStatus()
|
||||
lastNodes.push(it)
|
||||
}
|
||||
}
|
||||
@@ -456,7 +456,7 @@ class ControlFlowGraphBuilder {
|
||||
return binaryOrExitNodes.pop().also {
|
||||
val rightNode = lastNodes.pop()
|
||||
addEdge(rightNode, it, propagateDeadness = false)
|
||||
it.markAsDeadIfNecessary()
|
||||
it.updateDeadStatus()
|
||||
lastNodes.push(it)
|
||||
}
|
||||
}
|
||||
@@ -531,7 +531,7 @@ class ControlFlowGraphBuilder {
|
||||
levelCounter--
|
||||
catchNodeStorages.pop()
|
||||
val node = tryExitNodes.pop()
|
||||
node.markAsDeadIfNecessary()
|
||||
node.updateDeadStatus()
|
||||
lastNodes.push(node)
|
||||
return node
|
||||
}
|
||||
@@ -616,7 +616,7 @@ class ControlFlowGraphBuilder {
|
||||
levelCounter--
|
||||
return initBlockExitNodes.pop().also {
|
||||
addNewSimpleNode(it)
|
||||
it.markAsDeadIfNecessary()
|
||||
it.updateDeadStatus()
|
||||
lexicalScopes.pop()
|
||||
exitNodes.pop()
|
||||
graphs.pop()
|
||||
@@ -639,16 +639,12 @@ class ControlFlowGraphBuilder {
|
||||
fun exitSafeCall(qualifiedAccess: FirQualifiedAccess): ExitSafeCallNode {
|
||||
return exitSafeCallNodes.pop().also {
|
||||
addNewSimpleNode(it)
|
||||
it.markAsDeadIfNecessary()
|
||||
it.updateDeadStatus()
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
private fun CFGNode<*>.markAsDeadIfNecessary() {
|
||||
isDead = incomingEdges.size == previousNodes.size && incomingEdges.values.all { it == EdgeKind.Dead }
|
||||
}
|
||||
|
||||
private fun addNodeThatReturnsNothing(node: CFGNode<*>) {
|
||||
/*
|
||||
* `return` is temporary solution that is needed for init block
|
||||
|
||||
Reference in New Issue
Block a user