[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)
|
val (whenExitNode, syntheticElseNode) = graphBuilder.exitWhenExpression(whenExpression)
|
||||||
if (syntheticElseNode != null) {
|
if (syntheticElseNode != null) {
|
||||||
syntheticElseNode.mergeIncomingFlow()
|
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
|
// 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
|
// in that case there will be when enter or subject access node
|
||||||
if (previousConditionExitNode != null) {
|
if (previousConditionExitNode != null) {
|
||||||
@@ -474,11 +474,11 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
private fun enterSafeCall(qualifiedAccess: FirQualifiedAccess) {
|
private fun enterSafeCall(qualifiedAccess: FirQualifiedAccess) {
|
||||||
if (!qualifiedAccess.safe) return
|
if (!qualifiedAccess.safe) return
|
||||||
val node = graphBuilder.enterSafeCall(qualifiedAccess).mergeIncomingFlow()
|
val node = graphBuilder.enterSafeCall(qualifiedAccess).mergeIncomingFlow()
|
||||||
val previousNode = node.alivePreviousNodes.first()
|
val previousNode = node.firstPreviousNode
|
||||||
val shouldFork: Boolean
|
val shouldFork: Boolean
|
||||||
var flow = if (previousNode is ExitSafeCallNode) {
|
var flow = if (previousNode is ExitSafeCallNode) {
|
||||||
shouldFork = false
|
shouldFork = false
|
||||||
previousNode.alivePreviousNodes.getOrNull(1)?.flow ?: node.flow
|
previousNode.secondPreviousNode?.flow ?: node.flow
|
||||||
} else {
|
} else {
|
||||||
shouldFork = true
|
shouldFork = true
|
||||||
node.flow
|
node.flow
|
||||||
@@ -684,9 +684,9 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun exitLeftArgumentOfBinaryBooleanOperator(leftNode: CFGNode<*>, rightNode: CFGNode<*>, isAnd: Boolean) {
|
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)
|
leftNode.flow = logicSystem.forkFlow(parentFlow)
|
||||||
val leftOperandVariable = variableStorage.getOrCreateVariable(leftNode.previousNodes.first().fir)
|
val leftOperandVariable = variableStorage.getOrCreateVariable(leftNode.firstPreviousNode.fir)
|
||||||
rightNode.flow = logicSystem.approveStatementsInsideFlow(
|
rightNode.flow = logicSystem.approveStatementsInsideFlow(
|
||||||
parentFlow,
|
parentFlow,
|
||||||
leftOperandVariable eq isAnd,
|
leftOperandVariable eq isAnd,
|
||||||
@@ -751,7 +751,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
|
|
||||||
|
|
||||||
private fun exitBooleanNot(functionCall: FirFunctionCall, node: FunctionCallNode) {
|
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)
|
val variable = variableStorage.getOrCreateVariable(functionCall)
|
||||||
logicSystem.replaceVariableFromConditionInStatements(
|
logicSystem.replaceVariableFromConditionInStatements(
|
||||||
node.flow,
|
node.flow,
|
||||||
@@ -789,10 +789,13 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
flowOnNodes[this.origin] = value
|
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 ->
|
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)
|
val flow = logicSystem.joinFlow(previousFlows)
|
||||||
if (updateReceivers) {
|
if (updateReceivers) {
|
||||||
logicSystem.updateAllReceivers(flow)
|
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 previousNodes = mutableListOf<CFGNode<*>>()
|
||||||
val followingNodes = mutableListOf<CFGNode<*>>()
|
val followingNodes = mutableListOf<CFGNode<*>>()
|
||||||
|
|
||||||
|
val firstPreviousNode: CFGNode<*> get() = previousNodes.first()
|
||||||
|
|
||||||
abstract val fir: E
|
abstract val fir: E
|
||||||
var isDead: Boolean = false
|
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 EnterNode
|
||||||
interface ExitNode
|
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 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 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 -----------------------------------
|
// ----------------------------------- Other -----------------------------------
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -148,8 +148,8 @@ class ControlFlowGraphBuilder {
|
|||||||
|
|
||||||
fun CFGNode<*>.extractArgument(): FirElement? = when(this) {
|
fun CFGNode<*>.extractArgument(): FirElement? = when(this) {
|
||||||
is FunctionEnterNode, is TryMainBlockEnterNode, is CatchClauseEnterNode -> null
|
is FunctionEnterNode, is TryMainBlockEnterNode, is CatchClauseEnterNode -> null
|
||||||
is ExitSafeCallNode -> previousNodes.last().extractArgument()
|
is ExitSafeCallNode -> lastPreviousNode.extractArgument()
|
||||||
is StubNode -> previousNodes.first().extractArgument()
|
is StubNode -> firstPreviousNode.extractArgument()
|
||||||
else -> fir.extractArgument()
|
else -> fir.extractArgument()
|
||||||
}
|
}
|
||||||
return exitsOfAnonymousFunctions.getValue(function).previousNodes.mapNotNull {
|
return exitsOfAnonymousFunctions.getValue(function).previousNodes.mapNotNull {
|
||||||
|
|||||||
Reference in New Issue
Block a user