[FIR] Reduce coping of flow and inline default value of it
This commit is contained in:
+84
-98
@@ -37,7 +37,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
private val graphBuilder = ControlFlowGraphBuilder()
|
private val graphBuilder = ControlFlowGraphBuilder()
|
||||||
private val logicSystem = LogicSystem(context)
|
private val logicSystem = LogicSystem(context)
|
||||||
private val variableStorage = DataFlowVariableStorage()
|
private val variableStorage = DataFlowVariableStorage()
|
||||||
private val edges = mutableMapOf<CFGNode<*>, Flow>().withDefault { Flow.EMPTY }
|
private val edges = mutableMapOf<CFGNode<*>, Flow>()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is no types from smartcasts function returns null
|
* If there is no types from smartcasts function returns null
|
||||||
@@ -92,7 +92,6 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
if (previousNode != null) {
|
if (previousNode != null) {
|
||||||
node.flow = logicSystem.approveFactsInsideFlow(previousNode.variable, EqTrue, node.flow)
|
node.flow = logicSystem.approveFactsInsideFlow(previousNode.variable, EqTrue, node.flow)
|
||||||
}
|
}
|
||||||
node.flow.freeze()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exitBlock(block: FirBlock) {
|
fun exitBlock(block: FirBlock) {
|
||||||
@@ -111,89 +110,81 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
|
|
||||||
fun exitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall) {
|
fun exitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall) {
|
||||||
val node = graphBuilder.exitTypeOperatorCall(typeOperatorCall).passFlow(false)
|
val node = graphBuilder.exitTypeOperatorCall(typeOperatorCall).passFlow(false)
|
||||||
try {
|
if (typeOperatorCall.operation !in FirOperation.TYPES) return
|
||||||
if (typeOperatorCall.operation !in FirOperation.TYPES) return
|
val symbol: FirCallableSymbol<*> = typeOperatorCall.argument.getResolvedSymbol() ?: return
|
||||||
val symbol: FirCallableSymbol<*> = typeOperatorCall.argument.getResolvedSymbol() ?: return
|
|
||||||
val type = typeOperatorCall.conversionTypeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
val type = typeOperatorCall.conversionTypeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
||||||
val varVariable = getRealVariable(symbol)
|
val varVariable = getRealVariable(symbol)
|
||||||
|
|
||||||
var flow = node.flow
|
var flow = node.flow
|
||||||
when (typeOperatorCall.operation) {
|
when (typeOperatorCall.operation) {
|
||||||
FirOperation.IS, FirOperation.NOT_IS -> {
|
FirOperation.IS, FirOperation.NOT_IS -> {
|
||||||
val expressionVariable = getSyntheticVariable(typeOperatorCall)
|
val expressionVariable = getSyntheticVariable(typeOperatorCall)
|
||||||
|
|
||||||
val trueInfo = FirDataFlowInfo(setOf(type), emptySet())
|
val trueInfo = FirDataFlowInfo(setOf(type), emptySet())
|
||||||
val falseInfo = FirDataFlowInfo(emptySet(), setOf(type))
|
val falseInfo = FirDataFlowInfo(emptySet(), setOf(type))
|
||||||
|
|
||||||
fun chooseInfo(trueBranch: Boolean) =
|
fun chooseInfo(trueBranch: Boolean) =
|
||||||
if ((typeOperatorCall.operation == FirOperation.IS) == trueBranch) trueInfo else falseInfo
|
if ((typeOperatorCall.operation == FirOperation.IS) == trueBranch) trueInfo else falseInfo
|
||||||
|
|
||||||
flow = flow.addNotApprovedFact(
|
flow = flow.addNotApprovedFact(
|
||||||
expressionVariable,
|
expressionVariable,
|
||||||
UnapprovedFirDataFlowInfo(
|
UnapprovedFirDataFlowInfo(
|
||||||
EqTrue, varVariable, chooseInfo(true)
|
EqTrue, varVariable, chooseInfo(true)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
flow = flow.addNotApprovedFact(
|
flow = flow.addNotApprovedFact(
|
||||||
expressionVariable,
|
expressionVariable,
|
||||||
UnapprovedFirDataFlowInfo(
|
UnapprovedFirDataFlowInfo(
|
||||||
EqFalse, varVariable, chooseInfo(false)
|
EqFalse, varVariable, chooseInfo(false)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
|
|
||||||
FirOperation.AS -> {
|
|
||||||
flow = flow.addApprovedFact(varVariable, FirDataFlowInfo(setOf(type), emptySet()))
|
|
||||||
}
|
|
||||||
|
|
||||||
FirOperation.SAFE_AS -> {
|
|
||||||
val expressionVariable = getSyntheticVariable(typeOperatorCall)
|
|
||||||
flow = flow.addNotApprovedFact(
|
|
||||||
expressionVariable,
|
|
||||||
UnapprovedFirDataFlowInfo(
|
|
||||||
NotEqNull, varVariable, FirDataFlowInfo(setOf(type), emptySet())
|
|
||||||
)
|
|
||||||
).addNotApprovedFact(
|
|
||||||
expressionVariable,
|
|
||||||
UnapprovedFirDataFlowInfo(
|
|
||||||
EqNull, varVariable, FirDataFlowInfo(emptySet(), setOf(type))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> throw IllegalStateException()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node.flow = flow
|
FirOperation.AS -> {
|
||||||
} finally {
|
flow = flow.addApprovedFact(varVariable, FirDataFlowInfo(setOf(type), emptySet()))
|
||||||
node.flow.freeze()
|
}
|
||||||
|
|
||||||
|
FirOperation.SAFE_AS -> {
|
||||||
|
val expressionVariable = getSyntheticVariable(typeOperatorCall)
|
||||||
|
flow = flow.addNotApprovedFact(
|
||||||
|
expressionVariable,
|
||||||
|
UnapprovedFirDataFlowInfo(
|
||||||
|
NotEqNull, varVariable, FirDataFlowInfo(setOf(type), emptySet())
|
||||||
|
)
|
||||||
|
).addNotApprovedFact(
|
||||||
|
expressionVariable,
|
||||||
|
UnapprovedFirDataFlowInfo(
|
||||||
|
EqNull, varVariable, FirDataFlowInfo(emptySet(), setOf(type))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node.flow = flow
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exitOperatorCall(operatorCall: FirOperatorCall) {
|
fun exitOperatorCall(operatorCall: FirOperatorCall) {
|
||||||
val node = graphBuilder.exitOperatorCall(operatorCall).passFlow(false)
|
val node = graphBuilder.exitOperatorCall(operatorCall).passFlow(false)
|
||||||
try {
|
when (val operation = operatorCall.operation) {
|
||||||
when (val operation = operatorCall.operation) {
|
FirOperation.EQ, FirOperation.NOT_EQ, FirOperation.IDENTITY, FirOperation.NOT_IDENTITY -> {
|
||||||
FirOperation.EQ, FirOperation.NOT_EQ, FirOperation.IDENTITY, FirOperation.NOT_IDENTITY -> {
|
val leftOperand = operatorCall.arguments[0]
|
||||||
val leftOperand = operatorCall.arguments[0]
|
val rightOperand = operatorCall.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?.kind == IrConstKind.Null -> processEqNull(node, rightOperand, operation)
|
leftConst?.kind == IrConstKind.Null -> processEqNull(node, rightOperand, operation)
|
||||||
rightConst?.kind == IrConstKind.Null -> processEqNull(node, leftOperand, operation)
|
rightConst?.kind == IrConstKind.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)
|
||||||
operation != FirOperation.EQ && operation != FirOperation.IDENTITY -> return
|
operation != FirOperation.EQ && operation != FirOperation.IDENTITY -> return
|
||||||
else -> processEq(node, leftOperand, rightOperand, operation)
|
else -> processEq(node, leftOperand, rightOperand, operation)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
node.flow.freeze()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +318,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun exitWhenBranchCondition(whenBranch: FirWhenBranch) {
|
fun exitWhenBranchCondition(whenBranch: FirWhenBranch) {
|
||||||
val node = graphBuilder.exitWhenBranchCondition(whenBranch).passFlow()
|
val node = graphBuilder.exitWhenBranchCondition(whenBranch).passFlow(true)
|
||||||
|
|
||||||
val conditionVariable = getVariable(whenBranch.condition)
|
val conditionVariable = getVariable(whenBranch.condition)
|
||||||
node.variable = conditionVariable
|
node.variable = conditionVariable
|
||||||
@@ -336,7 +327,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
fun exitWhenBranchResult(whenBranch: FirWhenBranch) {
|
fun exitWhenBranchResult(whenBranch: FirWhenBranch) {
|
||||||
val node = graphBuilder.exitWhenBranchResult(whenBranch).passFlow(false)
|
val node = graphBuilder.exitWhenBranchResult(whenBranch).passFlow(false)
|
||||||
val conditionVariable = getVariable(whenBranch.condition)
|
val conditionVariable = getVariable(whenBranch.condition)
|
||||||
node.flow = node.flow.removeSyntheticVariable(conditionVariable)
|
node.flow = node.flow.removeSyntheticVariable(conditionVariable).apply { freeze() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exitWhenExpression(whenExpression: FirWhenExpression) {
|
fun exitWhenExpression(whenExpression: FirWhenExpression) {
|
||||||
@@ -448,31 +439,26 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
|
|
||||||
fun exitVariableDeclaration(variable: FirVariable<*>) {
|
fun exitVariableDeclaration(variable: FirVariable<*>) {
|
||||||
val node = graphBuilder.exitVariableDeclaration(variable).passFlow(false)
|
val node = graphBuilder.exitVariableDeclaration(variable).passFlow(false)
|
||||||
try {
|
val initializer = variable.initializer ?: return
|
||||||
val initializer = variable.initializer ?: return
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* That part is needed for cases like that:
|
* That part is needed for cases like that:
|
||||||
*
|
*
|
||||||
* val b = x is String
|
* val b = x is String
|
||||||
* ...
|
* ...
|
||||||
* if (b) {
|
* if (b) {
|
||||||
* x.length
|
* x.length
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
variableStorage[initializer]?.let { initializerVariable ->
|
variableStorage[initializer]?.let { initializerVariable ->
|
||||||
assert(initializerVariable.isSynthetic)
|
assert(initializerVariable.isSynthetic)
|
||||||
val realVariable = getRealVariable(variable.symbol)
|
val realVariable = getRealVariable(variable.symbol)
|
||||||
node.flow = node.flow.copyNotApprovedFacts(initializerVariable, realVariable)
|
node.flow = node.flow.copyNotApprovedFacts(initializerVariable, realVariable)
|
||||||
}
|
}
|
||||||
|
|
||||||
initializer.resolvedSymbol?.let { initializerSymbol: FirBasedSymbol<*> ->
|
initializer.resolvedSymbol?.let { initializerSymbol: FirBasedSymbol<*> ->
|
||||||
val rhsVariable = variableStorage[initializerSymbol]?.takeIf { !it.isSynthetic } ?: return
|
val rhsVariable = variableStorage[initializerSymbol]?.takeIf { !it.isSynthetic } ?: return
|
||||||
variableStorage.createAliasVariable(variable.symbol, rhsVariable)
|
variableStorage.createAliasVariable(variable.symbol, rhsVariable)
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
node.flow.freeze()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +481,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
|
|
||||||
fun exitLeftBinaryAndArgument(binaryLogicExpression: FirBinaryLogicExpression) {
|
fun exitLeftBinaryAndArgument(binaryLogicExpression: FirBinaryLogicExpression) {
|
||||||
val (leftNode, rightNode) = graphBuilder.exitLeftBinaryAndArgument(binaryLogicExpression)
|
val (leftNode, rightNode) = graphBuilder.exitLeftBinaryAndArgument(binaryLogicExpression)
|
||||||
leftNode.passFlow()
|
leftNode.passFlow(true)
|
||||||
rightNode.passFlow(false)
|
rightNode.passFlow(false)
|
||||||
val leftOperandVariable = getVariable(leftNode.previousNodes.first().fir)
|
val leftOperandVariable = getVariable(leftNode.previousNodes.first().fir)
|
||||||
rightNode.flow = logicSystem.approveFactsInsideFlow(leftOperandVariable, EqTrue, rightNode.flow).also { it.freeze() }
|
rightNode.flow = logicSystem.approveFactsInsideFlow(leftOperandVariable, EqTrue, rightNode.flow).also { it.freeze() }
|
||||||
@@ -531,7 +517,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
flow.addNotApprovedFact(andVariable, UnapprovedFirDataFlowInfo(EqFalse, variable, info))
|
flow.addNotApprovedFact(andVariable, UnapprovedFirDataFlowInfo(EqFalse, variable, info))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.flow = flow.removeSyntheticVariable(leftVariable).removeSyntheticVariable(rightVariable).also { it.freeze() }
|
node.flow = flow.removeSyntheticVariable(leftVariable).removeSyntheticVariable(rightVariable)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun enterBinaryOr(binaryLogicExpression: FirBinaryLogicExpression) {
|
fun enterBinaryOr(binaryLogicExpression: FirBinaryLogicExpression) {
|
||||||
@@ -540,7 +526,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
|
|
||||||
fun exitLeftBinaryOrArgument(binaryLogicExpression: FirBinaryLogicExpression) {
|
fun exitLeftBinaryOrArgument(binaryLogicExpression: FirBinaryLogicExpression) {
|
||||||
val (leftNode, rightNode) = graphBuilder.exitLeftBinaryOrArgument(binaryLogicExpression)
|
val (leftNode, rightNode) = graphBuilder.exitLeftBinaryOrArgument(binaryLogicExpression)
|
||||||
leftNode.passFlow()
|
leftNode.passFlow(true)
|
||||||
rightNode.passFlow(false)
|
rightNode.passFlow(false)
|
||||||
val leftOperandVariable = getVariable(leftNode.previousNodes.first().fir)
|
val leftOperandVariable = getVariable(leftNode.previousNodes.first().fir)
|
||||||
rightNode.flow = logicSystem.approveFactsInsideFlow(leftOperandVariable, EqFalse, rightNode.flow).also { it.freeze() }
|
rightNode.flow = logicSystem.approveFactsInsideFlow(leftOperandVariable, EqFalse, rightNode.flow).also { it.freeze() }
|
||||||
@@ -571,13 +557,13 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
flow.addNotApprovedFact(orVariable, UnapprovedFirDataFlowInfo(EqFalse, variable, info))
|
flow.addNotApprovedFact(orVariable, UnapprovedFirDataFlowInfo(EqFalse, variable, info))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.flow = flow.removeSyntheticVariable(leftVariable).removeSyntheticVariable(rightVariable).also { it.freeze() }
|
node.flow = flow.removeSyntheticVariable(leftVariable).removeSyntheticVariable(rightVariable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun exitBooleanNot(functionCall: FirFunctionCall, node: FunctionCallNode) {
|
private fun exitBooleanNot(functionCall: FirFunctionCall, node: FunctionCallNode) {
|
||||||
val booleanExpressionVariable = getVariable(node.previousNodes.first().fir)
|
val booleanExpressionVariable = getVariable(node.previousNodes.first().fir)
|
||||||
val variable = getVariable(functionCall)
|
val variable = getVariable(functionCall)
|
||||||
node.flow = node.flow.copyNotApprovedFacts(booleanExpressionVariable, variable) { it.invert() }.also { it.freeze() }
|
node.flow = node.flow.copyNotApprovedFacts(booleanExpressionVariable, variable) { it.invert() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------- Annotations -----------------------------------
|
// ----------------------------------- Annotations -----------------------------------
|
||||||
@@ -609,12 +595,12 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
getVariable(leftOperand) to getVariable(rightOperand)
|
getVariable(leftOperand) to getVariable(rightOperand)
|
||||||
|
|
||||||
private var CFGNode<*>.flow: Flow
|
private var CFGNode<*>.flow: Flow
|
||||||
get() = edges.getValue(this)
|
get() = edges[this] ?: Flow.EMPTY
|
||||||
set(value) {
|
set(value) {
|
||||||
edges[this] = value
|
edges[this] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T : CFGNode<*>> T.passFlow(shouldFreeze: Boolean = true): T = this.also { node ->
|
private fun <T : CFGNode<*>> T.passFlow(shouldFreeze: Boolean = false): T = this.also { node ->
|
||||||
node.flow = logicSystem.or(node.usefulPreviousNodes.map { it.flow }).also {
|
node.flow = logicSystem.or(node.usefulPreviousNodes.map { it.flow }).also {
|
||||||
if (shouldFreeze) it.freeze()
|
if (shouldFreeze) it.freeze()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class LogicSystem(private val context: DataFlowInferenceContext) {
|
|||||||
|
|
||||||
fun or(storages: Collection<Flow>): Flow {
|
fun or(storages: Collection<Flow>): Flow {
|
||||||
storages.singleOrNull()?.let {
|
storages.singleOrNull()?.let {
|
||||||
return it.copy()
|
return it
|
||||||
}
|
}
|
||||||
val approvedFacts = mutableMapOf<DataFlowVariable, FirDataFlowInfo>().apply {
|
val approvedFacts = mutableMapOf<DataFlowVariable, FirDataFlowInfo>().apply {
|
||||||
storages.map { it.approvedFacts.keys }
|
storages.map { it.approvedFacts.keys }
|
||||||
|
|||||||
Reference in New Issue
Block a user