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