FIR DFA: extract approveStatementsInsideFlow(variable notEq null)

I'm not sure how this fixes a test. Magic!
This commit is contained in:
pyos
2022-11-08 15:53:23 +01:00
committed by teamcity
parent 623dfdd5a3
commit 1ff968eca2
2 changed files with 13 additions and 37 deletions
@@ -447,12 +447,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
flow.addTypeStatement(operandVariable typeEq type) flow.addTypeStatement(operandVariable typeEq type)
} }
if (!type.canBeNull) { if (!type.canBeNull) {
logicSystem.approveStatementsInsideFlow( flow.assumeNotNull(operandVariable, shouldForkFlow = false, shouldRemoveSynthetics = true)
flow,
operandVariable notEq null,
shouldRemoveSynthetics = true,
shouldForkFlow = false
)
} else { } else {
val expressionVariable = variableStorage.createSyntheticVariable(typeOperatorCall) val expressionVariable = variableStorage.createSyntheticVariable(typeOperatorCall)
flow.addImplication((expressionVariable notEq null) implies (operandVariable notEq null)) flow.addImplication((expressionVariable notEq null) implies (operandVariable notEq null))
@@ -525,9 +520,6 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val operandVariable = variableStorage.getOrCreateVariable(node.previousFlow, operand) val operandVariable = variableStorage.getOrCreateVariable(node.previousFlow, operand)
// expression == const -> expression != null // expression == const -> expression != null
flow.addImplication((expressionVariable eq isEq) implies (operandVariable notEq null)) flow.addImplication((expressionVariable eq isEq) implies (operandVariable notEq null))
if (operandVariable.isReal()) {
flow.addImplication((expressionVariable eq isEq) implies (operandVariable typeEq any))
}
// propagating facts for (... == true) and (... == false) // propagating facts for (... == true) and (... == false)
when (const.kind) { when (const.kind) {
@@ -691,17 +683,11 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
unionNode?.let { unionFlowFromArguments(it) } unionNode?.let { unionFlowFromArguments(it) }
} }
fun FirExpression.propagateNotNullInfo(node: CFGNode<*>) { private fun FirExpression.propagateNotNullInfo(node: CFGNode<*>) {
val symbol = this.symbol val symbol = this.symbol
if (symbol != null) { if (symbol != null) {
variableStorage.getOrCreateRealVariable(node.previousFlow, symbol, this)?.let { operandVariable -> variableStorage.getOrCreateRealVariable(node.previousFlow, symbol, this)?.let { operandVariable ->
node.flow.addTypeStatement(operandVariable typeEq any) node.flow.assumeNotNull(operandVariable, shouldForkFlow = false, shouldRemoveSynthetics = true)
logicSystem.approveStatementsInsideFlow(
node.flow,
operandVariable notEq null,
shouldRemoveSynthetics = true,
shouldForkFlow = false
)
} }
} }
when (this) { when (this) {
@@ -714,6 +700,13 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
} }
} }
private fun FLOW.assumeNotNull(variable: DataFlowVariable, shouldForkFlow: Boolean, shouldRemoveSynthetics: Boolean): FLOW =
logicSystem.approveStatementsInsideFlow(this, variable notEq null, shouldForkFlow, shouldRemoveSynthetics,).also {
if (variable is RealVariable) {
it.addTypeStatement(variable typeEq any andTypeNotEq nullableNothing)
}
}
// ----------------------------------- When ----------------------------------- // ----------------------------------- When -----------------------------------
fun enterWhenExpression(whenExpression: FirWhenExpression) { fun enterWhenExpression(whenExpression: FirWhenExpression) {
@@ -943,12 +936,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
} }
flow.addTypeStatement(variable typeEq type) flow.addTypeStatement(variable typeEq type)
} }
flow = logicSystem.approveStatementsInsideFlow( flow = flow.assumeNotNull(variable, shouldFork, shouldRemoveSynthetics = false)
flow,
variable notEq null,
shouldFork,
shouldRemoveSynthetics = false
)
} }
node.flow = flow node.flow = flow
@@ -966,9 +954,6 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
is SyntheticVariable -> variableStorage.getOrCreateVariable(flow, safeCall.receiver) is SyntheticVariable -> variableStorage.getOrCreateVariable(flow, safeCall.receiver)
} }
flow.addImplication((variable notEq null) implies (receiverVariable notEq null)) flow.addImplication((variable notEq null) implies (receiverVariable notEq null))
if (receiverVariable.isReal()) {
flow.addImplication((variable notEq null) implies (receiverVariable typeEq any))
}
} }
fun exitResolvedQualifierNode(resolvedQualifier: FirResolvedQualifier) { fun exitResolvedQualifierNode(resolvedQualifier: FirResolvedQualifier) {
@@ -1379,16 +1364,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
lhsExitNode.mergeIncomingFlow() lhsExitNode.mergeIncomingFlow()
val flow = lhsExitNode.flow val flow = lhsExitNode.flow
val lhsVariable = variableStorage.getOrCreateVariable(flow, elvisExpression.lhs) val lhsVariable = variableStorage.getOrCreateVariable(flow, elvisExpression.lhs)
lhsIsNotNullNode.flow = logicSystem.approveStatementsInsideFlow( lhsIsNotNullNode.flow = flow.assumeNotNull(lhsVariable, shouldForkFlow = true, shouldRemoveSynthetics = false)
flow,
lhsVariable notEq null,
shouldForkFlow = true,
shouldRemoveSynthetics = false
).also {
if (lhsVariable.isReal()) {
it.addTypeStatement(lhsVariable typeEq any)
}
}
rhsEnterNode.flow = logicSystem.approveStatementsInsideFlow( rhsEnterNode.flow = logicSystem.approveStatementsInsideFlow(
flow, flow,
lhsVariable eq null, lhsVariable eq null,
@@ -8,7 +8,7 @@ fun calc(x: String?, y: String?): Int {
// x is not null in condition but we do not see it yet // x is not null in condition but we do not see it yet
} while (x.length > 0) } while (x.length > 0)
// y is nullable because of break // y is nullable because of break
y.length y<!UNSAFE_CALL!>.<!>length
// x is not null, at least in theory // x is not null, at least in theory
return x.length return x.length
} }