FIR DFA: extract approveStatementsInsideFlow(variable notEq null)
I'm not sure how this fixes a test. Magic!
This commit is contained in:
+12
-36
@@ -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,
|
||||||
|
|||||||
+1
-1
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user