[FIR] Get rid of alivePreviousNodes in control flow graph
This commit is contained in:
+11
-8
@@ -366,7 +366,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
||||
val (whenExitNode, syntheticElseNode) = graphBuilder.exitWhenExpression(whenExpression)
|
||||
if (syntheticElseNode != null) {
|
||||
syntheticElseNode.mergeIncomingFlow()
|
||||
val previousConditionExitNode = syntheticElseNode.previousNodes.single() as? WhenBranchConditionExitNode
|
||||
val previousConditionExitNode = syntheticElseNode.firstPreviousNode as? WhenBranchConditionExitNode
|
||||
// previous node for syntheticElseNode can be not WhenBranchConditionExitNode in case of `when` without any branches
|
||||
// in that case there will be when enter or subject access node
|
||||
if (previousConditionExitNode != null) {
|
||||
@@ -474,11 +474,11 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
||||
private fun enterSafeCall(qualifiedAccess: FirQualifiedAccess) {
|
||||
if (!qualifiedAccess.safe) return
|
||||
val node = graphBuilder.enterSafeCall(qualifiedAccess).mergeIncomingFlow()
|
||||
val previousNode = node.alivePreviousNodes.first()
|
||||
val previousNode = node.firstPreviousNode
|
||||
val shouldFork: Boolean
|
||||
var flow = if (previousNode is ExitSafeCallNode) {
|
||||
shouldFork = false
|
||||
previousNode.alivePreviousNodes.getOrNull(1)?.flow ?: node.flow
|
||||
previousNode.secondPreviousNode?.flow ?: node.flow
|
||||
} else {
|
||||
shouldFork = true
|
||||
node.flow
|
||||
@@ -684,9 +684,9 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
||||
}
|
||||
|
||||
private fun exitLeftArgumentOfBinaryBooleanOperator(leftNode: CFGNode<*>, rightNode: CFGNode<*>, isAnd: Boolean) {
|
||||
val parentFlow = leftNode.alivePreviousNodes.first().flow
|
||||
val parentFlow = leftNode.firstPreviousNode.flow
|
||||
leftNode.flow = logicSystem.forkFlow(parentFlow)
|
||||
val leftOperandVariable = variableStorage.getOrCreateVariable(leftNode.previousNodes.first().fir)
|
||||
val leftOperandVariable = variableStorage.getOrCreateVariable(leftNode.firstPreviousNode.fir)
|
||||
rightNode.flow = logicSystem.approveStatementsInsideFlow(
|
||||
parentFlow,
|
||||
leftOperandVariable eq isAnd,
|
||||
@@ -751,7 +751,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
||||
|
||||
|
||||
private fun exitBooleanNot(functionCall: FirFunctionCall, node: FunctionCallNode) {
|
||||
val booleanExpressionVariable = variableStorage.getOrCreateVariable(node.previousNodes.first().fir)
|
||||
val booleanExpressionVariable = variableStorage.getOrCreateVariable(node.firstPreviousNode.fir)
|
||||
val variable = variableStorage.getOrCreateVariable(functionCall)
|
||||
logicSystem.replaceVariableFromConditionInStatements(
|
||||
node.flow,
|
||||
@@ -789,10 +789,13 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
||||
flowOnNodes[this.origin] = value
|
||||
}
|
||||
|
||||
private val CFGNode<*>.origin: CFGNode<*> get() = if (this is StubNode) previousNodes.first() else this
|
||||
private val CFGNode<*>.origin: CFGNode<*> get() = if (this is StubNode) firstPreviousNode else this
|
||||
|
||||
private fun <T : CFGNode<*>> T.mergeIncomingFlow(updateReceivers: Boolean = false): T = this.also { node ->
|
||||
val previousFlows = node.alivePreviousNodes.map { it.flow }
|
||||
val previousFlows = if (node.isDead)
|
||||
node.previousNodes.map { it.flow }
|
||||
else
|
||||
node.previousNodes.mapNotNull { prev -> prev.takeIf { !it.isDead }?.flow }
|
||||
val flow = logicSystem.joinFlow(previousFlows)
|
||||
if (updateReceivers) {
|
||||
logicSystem.updateAllReceivers(flow)
|
||||
|
||||
+6
-3
@@ -32,6 +32,8 @@ sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level:
|
||||
val previousNodes = mutableListOf<CFGNode<*>>()
|
||||
val followingNodes = mutableListOf<CFGNode<*>>()
|
||||
|
||||
val firstPreviousNode: CFGNode<*> get() = previousNodes.first()
|
||||
|
||||
abstract val fir: E
|
||||
var isDead: Boolean = false
|
||||
|
||||
@@ -45,8 +47,6 @@ sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level:
|
||||
}
|
||||
}
|
||||
|
||||
val CFGNode<*>.aliveFollowingNodes: List<CFGNode<*>> get() = if (isDead) followingNodes else followingNodes.filterNot { it.isDead }
|
||||
val CFGNode<*>.alivePreviousNodes: List<CFGNode<*>> get() = if (isDead) previousNodes else previousNodes.filterNot { it.isDead }
|
||||
|
||||
interface EnterNode
|
||||
interface ExitNode
|
||||
@@ -173,7 +173,10 @@ class EnterContractNode(owner: ControlFlowGraph, override val fir: FirFunctionCa
|
||||
class ExitContractNode(owner: ControlFlowGraph, override val fir: FirFunctionCall, level: Int, id: Int) : CFGNode<FirFunctionCall>(owner, level, id), ExitNode
|
||||
|
||||
class EnterSafeCallNode(owner: ControlFlowGraph, override val fir: FirQualifiedAccess, level: Int, id: Int) : CFGNode<FirQualifiedAccess>(owner, level, id)
|
||||
class ExitSafeCallNode(owner: ControlFlowGraph, override val fir: FirQualifiedAccess, level: Int, id: Int) : CFGNode<FirQualifiedAccess>(owner, level, id)
|
||||
class ExitSafeCallNode(owner: ControlFlowGraph, override val fir: FirQualifiedAccess, level: Int, id: Int) : CFGNode<FirQualifiedAccess>(owner, level, id) {
|
||||
val lastPreviousNode: CFGNode<*> get() = previousNodes.last()
|
||||
val secondPreviousNode: CFGNode<*>? get() = previousNodes.getOrNull(1)
|
||||
}
|
||||
|
||||
// ----------------------------------- Other -----------------------------------
|
||||
|
||||
|
||||
+2
-2
@@ -148,8 +148,8 @@ class ControlFlowGraphBuilder {
|
||||
|
||||
fun CFGNode<*>.extractArgument(): FirElement? = when(this) {
|
||||
is FunctionEnterNode, is TryMainBlockEnterNode, is CatchClauseEnterNode -> null
|
||||
is ExitSafeCallNode -> previousNodes.last().extractArgument()
|
||||
is StubNode -> previousNodes.first().extractArgument()
|
||||
is ExitSafeCallNode -> lastPreviousNode.extractArgument()
|
||||
is StubNode -> firstPreviousNode.extractArgument()
|
||||
else -> fir.extractArgument()
|
||||
}
|
||||
return exitsOfAnonymousFunctions.getValue(function).previousNodes.mapNotNull {
|
||||
|
||||
Reference in New Issue
Block a user