[FIR] Add new equalityOperatorCall node in control flow graph

This commit is contained in:
Ivan Kylchik
2020-07-15 21:43:42 +03:00
parent d23e9940ec
commit def47bdd9d
7 changed files with 43 additions and 40 deletions
@@ -344,30 +344,29 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
graphBuilder.exitComparisonExpression(comparisonExpression).mergeIncomingFlow() graphBuilder.exitComparisonExpression(comparisonExpression).mergeIncomingFlow()
} }
fun exitOperatorCall(operatorCall: FirOperatorCall) { fun exitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall) {
val node = graphBuilder.exitOperatorCall(operatorCall).mergeIncomingFlow() val node = graphBuilder.exitEqualityOperatorCall(equalityOperatorCall).mergeIncomingFlow()
when (val operation = operatorCall.operation) { val operation = equalityOperatorCall.operation
FirOperation.EQ, FirOperation.NOT_EQ, FirOperation.IDENTITY, FirOperation.NOT_IDENTITY -> { val leftOperand = equalityOperatorCall.arguments[0]
val leftOperand = operatorCall.arguments[0] val rightOperand = equalityOperatorCall.arguments[1]
val rightOperand = operatorCall.arguments[1]
val leftConst = leftOperand as? FirConstExpression<*> val leftConst = leftOperand as? FirConstExpression<*>
val rightConst = rightOperand as? FirConstExpression<*> val rightConst = rightOperand as? FirConstExpression<*>
when { when {
leftConst != null && rightConst != null -> return leftConst != null && rightConst != null -> return
leftConst?.kind == FirConstKind.Null -> processEqNull(node, rightOperand, operation) leftConst?.kind == FirConstKind.Null -> processEqNull(node, rightOperand, operation)
rightConst?.kind == FirConstKind.Null -> processEqNull(node, leftOperand, operation) rightConst?.kind == FirConstKind.Null -> processEqNull(node, leftOperand, operation)
leftConst != null -> processEqWithConst(node, rightOperand, leftConst, operation) leftConst != null -> processEqWithConst(node, rightOperand, leftConst, operation)
rightConst != null -> processEqWithConst(node, leftOperand, rightConst, operation) rightConst != null -> processEqWithConst(node, leftOperand, rightConst, operation)
else -> processEq(node, leftOperand, rightOperand, operation) else -> processEq(node, leftOperand, rightOperand, operation)
}
}
} }
} }
// const != null // const != null
private fun processEqWithConst(node: OperatorCallNode, operand: FirExpression, const: FirConstExpression<*>, operation: FirOperation) { private fun processEqWithConst(
node: EqualityOperatorCallNode, operand: FirExpression, const: FirConstExpression<*>, operation: FirOperation
) {
val isEq = operation.isEq() val isEq = operation.isEq()
val expressionVariable = variableStorage.createSyntheticVariable(node.fir) val expressionVariable = variableStorage.createSyntheticVariable(node.fir)
val flow = node.flow val flow = node.flow
@@ -402,7 +401,9 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
} }
} }
private fun processEq(node: OperatorCallNode, leftOperand: FirExpression, rightOperand: FirExpression, operation: FirOperation) { private fun processEq(
node: EqualityOperatorCallNode, leftOperand: FirExpression, rightOperand: FirExpression, operation: FirOperation
) {
val leftIsNullable = leftOperand.coneType.isMarkedNullable val leftIsNullable = leftOperand.coneType.isMarkedNullable
val rightIsNullable = rightOperand.coneType.isMarkedNullable val rightIsNullable = rightOperand.coneType.isMarkedNullable
// left == right && right not null -> left != null // left == right && right not null -> left != null
@@ -417,7 +418,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
} }
} }
private fun processEqNull(node: OperatorCallNode, operand: FirExpression, operation: FirOperation) { private fun processEqNull(node: EqualityOperatorCallNode, operand: FirExpression, operation: FirOperation) {
val flow = node.flow val flow = node.flow
val expressionVariable = variableStorage.createSyntheticVariable(node.fir) val expressionVariable = variableStorage.createSyntheticVariable(node.fir)
val operandVariable = variableStorage.getOrCreateVariable(node.previousFlow, operand) val operandVariable = variableStorage.getOrCreateVariable(node.previousFlow, operand)
@@ -448,7 +449,9 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
node.flow = flow node.flow = flow
} }
private fun processIdentity(node: OperatorCallNode, leftOperand: FirExpression, rightOperand: FirExpression, operation: FirOperation) { private fun processIdentity(
node: EqualityOperatorCallNode, leftOperand: FirExpression, rightOperand: FirExpression, operation: FirOperation
) {
val flow = node.flow val flow = node.flow
val expressionVariable = variableStorage.getOrCreateVariable(node.previousFlow, node.fir) val expressionVariable = variableStorage.getOrCreateVariable(node.previousFlow, node.fir)
val leftOperandVariable = variableStorage.getOrCreateVariable(node.previousFlow, leftOperand) val leftOperandVariable = variableStorage.getOrCreateVariable(node.previousFlow, leftOperand)
@@ -456,18 +456,18 @@ class TypeOperatorCallNode(owner: ControlFlowGraph, override val fir: FirTypeOpe
} }
} }
class OperatorCallNode(owner: ControlFlowGraph, override val fir: FirOperatorCall, level: Int, id: Int) : AbstractBinaryExitNode<FirOperatorCall>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitOperatorCallNode(this, data)
}
}
class ComparisonExpressionNode(owner: ControlFlowGraph, override val fir: FirComparisonExpression, level: Int, id: Int) : CFGNode<FirComparisonExpression>(owner, level, id) { class ComparisonExpressionNode(owner: ControlFlowGraph, override val fir: FirComparisonExpression, level: Int, id: Int) : CFGNode<FirComparisonExpression>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R { override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitComparisonExpressionNode(this, data) return visitor.visitComparisonExpressionNode(this, data)
} }
} }
class EqualityOperatorCallNode(owner: ControlFlowGraph, override val fir: FirEqualityOperatorCall, level: Int, id: Int) : AbstractBinaryExitNode<FirEqualityOperatorCall>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitEqualityOperatorCallNode(this, data)
}
}
// ----------------------------------- Jump ----------------------------------- // ----------------------------------- Jump -----------------------------------
class JumpNode(owner: ControlFlowGraph, override val fir: FirJump<*>, level: Int, id: Int) : CFGNode<FirJump<*>>(owner, level, id) { class JumpNode(owner: ControlFlowGraph, override val fir: FirJump<*>, level: Int, id: Int) : CFGNode<FirJump<*>>(owner, level, id) {
@@ -40,9 +40,9 @@ fun CFGNode<*>.render(): String =
is QualifiedAccessNode -> "Access variable ${fir.calleeReference.render(CfgRenderMode)}" is QualifiedAccessNode -> "Access variable ${fir.calleeReference.render(CfgRenderMode)}"
is ResolvedQualifierNode -> "Access qualifier ${fir.classId}" is ResolvedQualifierNode -> "Access qualifier ${fir.classId}"
is OperatorCallNode -> "Operator ${fir.operation.operator}"
is ComparisonExpressionNode -> "Comparison ${fir.operation.operator}" is ComparisonExpressionNode -> "Comparison ${fir.operation.operator}"
is TypeOperatorCallNode -> "Type operator: \"${fir.render(CfgRenderMode)}\"" is TypeOperatorCallNode -> "Type operator: \"${fir.render(CfgRenderMode)}\""
is EqualityOperatorCallNode -> "Equality operator ${fir.operation.operator}"
is JumpNode -> "Jump: ${fir.render()}" is JumpNode -> "Jump: ${fir.render()}"
is StubNode -> "Stub" is StubNode -> "Stub"
is CheckNotNullCallNode -> "Check not null: ${fir.render(CfgRenderMode)}" is CheckNotNullCallNode -> "Check not null: ${fir.render(CfgRenderMode)}"
@@ -495,14 +495,14 @@ class ControlFlowGraphBuilder {
return createTypeOperatorCallNode(typeOperatorCall).also { addNewSimpleNode(it) } return createTypeOperatorCallNode(typeOperatorCall).also { addNewSimpleNode(it) }
} }
fun exitOperatorCall(operatorCall: FirOperatorCall): OperatorCallNode {
return createOperatorCallNode(operatorCall).also { addNewSimpleNode(it) }
}
fun exitComparisonExpression(comparisonExpression: FirComparisonExpression): ComparisonExpressionNode { fun exitComparisonExpression(comparisonExpression: FirComparisonExpression): ComparisonExpressionNode {
return createComparisonExpressionNode(comparisonExpression).also { addNewSimpleNode(it) } return createComparisonExpressionNode(comparisonExpression).also { addNewSimpleNode(it) }
} }
fun exitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall): EqualityOperatorCallNode {
return createEqualityOperatorCallNode(equalityOperatorCall).also { addNewSimpleNode(it) }
}
// ----------------------------------- Jump ----------------------------------- // ----------------------------------- Jump -----------------------------------
fun exitJump(jump: FirJump<*>): JumpNode { fun exitJump(jump: FirJump<*>): JumpNode {
@@ -27,8 +27,8 @@ fun ControlFlowGraphBuilder.createInitBlockExitNode(fir: FirAnonymousInitializer
fun ControlFlowGraphBuilder.createTypeOperatorCallNode(fir: FirTypeOperatorCall): TypeOperatorCallNode = fun ControlFlowGraphBuilder.createTypeOperatorCallNode(fir: FirTypeOperatorCall): TypeOperatorCallNode =
TypeOperatorCallNode(currentGraph, fir, levelCounter, createId()) TypeOperatorCallNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createOperatorCallNode(fir: FirOperatorCall): OperatorCallNode = fun ControlFlowGraphBuilder.createEqualityOperatorCallNode(fir: FirEqualityOperatorCall): EqualityOperatorCallNode =
OperatorCallNode(currentGraph, fir, levelCounter, createId()) EqualityOperatorCallNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createWhenBranchConditionExitNode(fir: FirWhenBranch): WhenBranchConditionExitNode = fun ControlFlowGraphBuilder.createWhenBranchConditionExitNode(fir: FirWhenBranch): WhenBranchConditionExitNode =
WhenBranchConditionExitNode(currentGraph, fir, levelCounter, createId()) WhenBranchConditionExitNode(currentGraph, fir, levelCounter, createId())
@@ -229,11 +229,11 @@ abstract class ControlFlowGraphVisitor<out R, in D> {
return visitNode(node, data) return visitNode(node, data)
} }
open fun visitOperatorCallNode(node: OperatorCallNode, data: D): R { open fun visitComparisonExpressionNode(node: ComparisonExpressionNode, data: D): R {
return visitNode(node, data) return visitNode(node, data)
} }
open fun visitComparisonExpressionNode(node: ComparisonExpressionNode, data: D): R { open fun visitEqualityOperatorCallNode(node: EqualityOperatorCallNode, data: D): R {
return visitNode(node, data) return visitNode(node, data)
} }
@@ -207,11 +207,11 @@ abstract class ControlFlowGraphVisitorVoid : ControlFlowGraphVisitor<Unit, Nothi
visitNode(node) visitNode(node)
} }
open fun visitOperatorCallNode(node: OperatorCallNode) { open fun visitComparisonExpressionNode(node: ComparisonExpressionNode) {
visitNode(node) visitNode(node)
} }
open fun visitComparisonExpressionNode(node: ComparisonExpressionNode) { open fun visitEqualityOperatorCallNode(node: EqualityOperatorCallNode) {
visitNode(node) visitNode(node)
} }
@@ -496,8 +496,8 @@ abstract class ControlFlowGraphVisitorVoid : ControlFlowGraphVisitor<Unit, Nothi
visitTypeOperatorCallNode(node) visitTypeOperatorCallNode(node)
} }
final override fun visitOperatorCallNode(node: OperatorCallNode, data: Nothing?) { final override fun visitEqualityOperatorCallNode(node: EqualityOperatorCallNode, data: Nothing?) {
visitOperatorCallNode(node) visitEqualityOperatorCallNode(node)
} }
final override fun visitComparisonExpressionNode(node: ComparisonExpressionNode, data: Nothing?) { final override fun visitComparisonExpressionNode(node: ComparisonExpressionNode, data: Nothing?) {