[FIR] Refactor DataFlowVariables

Make inheritors of DataFlowVariable public, replace flags in DFV with types
This commit is contained in:
Dmitriy Novozhilov
2019-09-04 18:46:35 +03:00
parent f9d45d2f2a
commit 15ff86fc50
5 changed files with 98 additions and 74 deletions
@@ -7,76 +7,90 @@ package org.jetbrains.kotlin.fir.resolve.dfa
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
/* /*
* isSynthetic = false for variables that represents actual variables in fir * isSynthetic = false for variables that represents actual variables in fir
* isSynthetic = true for complex expressions (like when expression) * isSynthetic = true for complex expressions (like when expression)
*/ */
sealed class DataFlowVariable(val variableIndexForDebug: Int, val fir: FirElement) { sealed class DataFlowVariable(private val variableIndexForDebug: Int, val fir: FirElement) {
abstract val isSynthetic: Boolean
abstract val aliasedVariable: DataFlowVariable
abstract val isThisReference: Boolean
final override fun toString(): String { final override fun toString(): String {
return "d$variableIndexForDebug" return "d$variableIndexForDebug"
} }
} }
private class RealDataFlowVariable(index: Int, fir: FirElement, override val isThisReference: Boolean) : DataFlowVariable(index, fir) { open class RealDataFlowVariable(index: Int, fir: FirElement, val isThisReference: Boolean) : DataFlowVariable(index, fir)
override val isSynthetic: Boolean get() = false
override val aliasedVariable: DataFlowVariable get() = this class SyntheticDataFlowVariable(index: Int, fir: FirElement) : DataFlowVariable(index, fir)
class AliasedDataFlowVariable(
index: Int,
fir: FirElement,
var delegate: RealDataFlowVariable
) : RealDataFlowVariable(index, fir, delegate.isThisReference)
// -------------------------------------------------------------------------------------------------------------------------
@UseExperimental(ExperimentalContracts::class)
fun DataFlowVariable.isSynthetic(): Boolean {
contract {
returns(true) implies (this@isSynthetic is SyntheticDataFlowVariable)
}
return this is SyntheticDataFlowVariable
} }
private class SyntheticDataFlowVariable(index: Int, fir: FirElement) : DataFlowVariable(index, fir) { @UseExperimental(ExperimentalContracts::class)
override val isSynthetic: Boolean get() = true fun DataFlowVariable.isAliasVariable(): Boolean {
contract {
override val aliasedVariable: DataFlowVariable get() = this returns(true) implies (this@isAliasVariable is AliasedDataFlowVariable)
}
override val isThisReference: Boolean get() = false return this is AliasedDataFlowVariable
} }
private class AliasedDataFlowVariable(index: Int, fir: FirElement, var delegate: DataFlowVariable) : DataFlowVariable(index, fir) { val RealDataFlowVariable.variableUnderAlias: RealDataFlowVariable
override val isSynthetic: Boolean get() = delegate.isSynthetic get() {
var variable = this
override val aliasedVariable: DataFlowVariable get() = delegate.aliasedVariable while (variable.isAliasVariable()) {
variable = variable.delegate
override val isThisReference: Boolean get() = false }
} return variable
}
// -------------------------------------------------------------------------------------------------------------------------
class DataFlowVariableStorage { class DataFlowVariableStorage {
private val fir2DfiMap: MutableMap<FirElement, DataFlowVariable> = mutableMapOf() private val fir2DfiMap: MutableMap<FirElement, DataFlowVariable> = mutableMapOf()
private var debugIndexCounter: Int = 1 private var debugIndexCounter: Int = 1
fun getOrCreateNewRealVariable(symbol: FirBasedSymbol<*>): DataFlowVariable { fun getOrCreateNewRealVariable(symbol: FirBasedSymbol<*>): RealDataFlowVariable {
return getOrCreateNewRealVariableImpl(symbol, false) return getOrCreateNewRealVariableImpl(symbol, false)
} }
fun getOrCreateNewThisRealVariable(symbol: FirBasedSymbol<*>): DataFlowVariable { fun getOrCreateNewThisRealVariable(symbol: FirBasedSymbol<*>): RealDataFlowVariable {
return getOrCreateNewRealVariableImpl(symbol, true) return getOrCreateNewRealVariableImpl(symbol, true)
} }
private fun getOrCreateNewRealVariableImpl(symbol: FirBasedSymbol<*>, isThisReference: Boolean): DataFlowVariable { private fun getOrCreateNewRealVariableImpl(symbol: FirBasedSymbol<*>, isThisReference: Boolean): RealDataFlowVariable {
val fir = symbol.fir val fir = symbol.fir
get(fir)?.let { return it } get(fir)?.let { return it as RealDataFlowVariable }
return RealDataFlowVariable(debugIndexCounter++, fir, isThisReference).also { storeVariable(it, fir) } return RealDataFlowVariable(debugIndexCounter++, fir, isThisReference).also { storeVariable(it, fir) }
} }
fun getOrCreateNewSyntheticVariable(fir: FirElement): DataFlowVariable { fun getOrCreateNewSyntheticVariable(fir: FirElement): SyntheticDataFlowVariable {
get(fir)?.let { return it } get(fir)?.let { return it as SyntheticDataFlowVariable }
return SyntheticDataFlowVariable(debugIndexCounter++, fir).also { storeVariable(it, fir) } return SyntheticDataFlowVariable(debugIndexCounter++, fir).also { storeVariable(it, fir) }
} }
fun createAliasVariable(symbol: FirBasedSymbol<*>, variable: DataFlowVariable) { fun createAliasVariable(symbol: FirBasedSymbol<*>, variable: RealDataFlowVariable) {
createAliasVariable(symbol.fir, variable) createAliasVariable(symbol.fir, variable)
} }
private fun createAliasVariable(fir: FirElement, variable: DataFlowVariable) { private fun createAliasVariable(fir: FirElement, variable: RealDataFlowVariable) {
AliasedDataFlowVariable(debugIndexCounter++, fir, variable).also { storeVariable(it, fir) } AliasedDataFlowVariable(debugIndexCounter++, fir, variable).also { storeVariable(it, fir) }
} }
fun rebindAliasVariable(aliasVariable: DataFlowVariable, newVariable: DataFlowVariable) { fun rebindAliasVariable(aliasVariable: RealDataFlowVariable, newVariable: RealDataFlowVariable) {
val fir = removeVariable(aliasVariable) val fir = removeVariable(aliasVariable)
requireNotNull(fir) requireNotNull(fir)
createAliasVariable(fir, newVariable) createAliasVariable(fir, newVariable)
@@ -105,8 +119,8 @@ class DataFlowVariableStorage {
return fir2DfiMap[firElement] return fir2DfiMap[firElement]
} }
operator fun get(symbol: FirBasedSymbol<*>): DataFlowVariable? { operator fun get(symbol: FirBasedSymbol<*>): RealDataFlowVariable? {
return fir2DfiMap[symbol.fir] return fir2DfiMap[symbol.fir] as RealDataFlowVariable?
} }
fun reset() { fun reset() {
@@ -23,7 +23,10 @@ import org.jetbrains.kotlin.fir.symbols.FirSymbolOwner
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.fir.types.isMarkedNullable
import org.jetbrains.kotlin.ir.expressions.IrConstKind import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -52,7 +55,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
* DataFlowAnalyzer holds variables only for declarations that have some smartcast (or can have) * DataFlowAnalyzer holds variables only for declarations that have some smartcast (or can have)
* If there is no useful information there is no data flow variable also * If there is no useful information there is no data flow variable also
*/ */
val variable = qualifiedAccessExpression.variable?.aliasedVariable ?: return null val variable = qualifiedAccessExpression.realVariable?.variableUnderAlias ?: return null
return graphBuilder.lastNode.flow.approvedFacts(variable)?.exactType ?: return null return graphBuilder.lastNode.flow.approvedFacts(variable)?.exactType ?: return null
} }
@@ -109,7 +112,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
if (typeOperatorCall.operation !in FirOperation.TYPES) return if (typeOperatorCall.operation !in FirOperation.TYPES) return
val type = typeOperatorCall.conversionTypeRef.coneTypeSafe<ConeKotlinType>() ?: return val type = typeOperatorCall.conversionTypeRef.coneTypeSafe<ConeKotlinType>() ?: return
val operandVariable = getOrCreateRealVariable(typeOperatorCall.argument)?.aliasedVariable ?: return val operandVariable = getOrCreateRealVariable(typeOperatorCall.argument)?.variableUnderAlias ?: return
var flow = node.flow var flow = node.flow
when (typeOperatorCall.operation) { when (typeOperatorCall.operation) {
@@ -457,7 +460,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
* } * }
*/ */
variableStorage[initializer]?.let { initializerVariable -> variableStorage[initializer]?.let { initializerVariable ->
assert(initializerVariable.isSynthetic) assert(initializerVariable.isSynthetic())
val realVariable = getOrCreateRealVariable(variable.symbol) val realVariable = getOrCreateRealVariable(variable.symbol)
node.flow = node.flow.copyNotApprovedFacts(initializerVariable, realVariable) node.flow = node.flow.copyNotApprovedFacts(initializerVariable, realVariable)
} }
@@ -471,7 +474,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
fun exitVariableAssignment(assignment: FirVariableAssignment) { fun exitVariableAssignment(assignment: FirVariableAssignment) {
graphBuilder.exitVariableAssignment(assignment).mergeIncomingFlow() graphBuilder.exitVariableAssignment(assignment).mergeIncomingFlow()
val lhsVariable = variableStorage[assignment.resolvedSymbol ?: return] ?: return val lhsVariable = variableStorage[assignment.resolvedSymbol ?: return] ?: return
val rhsVariable = variableStorage[assignment.rValue.resolvedSymbol ?: return]?.takeIf { !it.isSynthetic } ?: return val rhsVariable = variableStorage[assignment.rValue.resolvedSymbol ?: return]?.takeIf { !it.isSynthetic() } ?: return
variableStorage.rebindAliasVariable(lhsVariable, rhsVariable) variableStorage.rebindAliasVariable(lhsVariable, rhsVariable)
} }
@@ -598,7 +601,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
private fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableMap<DataFlowVariable, FirDataFlowInfo>? = private fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableMap<RealDataFlowVariable, FirDataFlowInfo>? =
logicSystem.approveFact(variable, condition, flow) logicSystem.approveFact(variable, condition, flow)
private fun FirBinaryLogicExpression.getVariables(): Pair<DataFlowVariable, DataFlowVariable> = private fun FirBinaryLogicExpression.getVariables(): Pair<DataFlowVariable, DataFlowVariable> =
@@ -628,9 +631,9 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
} }
// -------------------------------- get or create variable -------------------------------- // -------------------------------- get or create variable --------------------------------
private fun getOrCreateSyntheticVariable(fir: FirElement): DataFlowVariable = variableStorage.getOrCreateNewSyntheticVariable(fir) private fun getOrCreateSyntheticVariable(fir: FirElement): SyntheticDataFlowVariable = variableStorage.getOrCreateNewSyntheticVariable(fir)
private fun getOrCreateRealVariable(fir: FirElement): DataFlowVariable? { private fun getOrCreateRealVariable(fir: FirElement): RealDataFlowVariable? {
if (fir is FirThisReceiverExpressionImpl) { if (fir is FirThisReceiverExpressionImpl) {
return variableStorage.getOrCreateNewThisRealVariable(fir.calleeReference.boundSymbol ?: return null) return variableStorage.getOrCreateNewThisRealVariable(fir.calleeReference.boundSymbol ?: return null)
} }
@@ -638,8 +641,8 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
return variableStorage.getOrCreateNewRealVariable(symbol) return variableStorage.getOrCreateNewRealVariable(symbol)
} }
private fun getOrCreateRealVariable(symbol: FirBasedSymbol<*>): DataFlowVariable = private fun getOrCreateRealVariable(symbol: FirBasedSymbol<*>): RealDataFlowVariable =
variableStorage.getOrCreateNewRealVariable(symbol).aliasedVariable variableStorage.getOrCreateNewRealVariable(symbol).variableUnderAlias
private fun getOrCreateVariable(fir: FirElement): DataFlowVariable { private fun getOrCreateVariable(fir: FirElement): DataFlowVariable {
val symbol = fir.resolvedSymbol val symbol = fir.resolvedSymbol
@@ -651,7 +654,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
// -------------------------------- get variable -------------------------------- // -------------------------------- get variable --------------------------------
private val FirElement.variable: DataFlowVariable? private val FirElement.realVariable: RealDataFlowVariable?
get() { get() {
val symbol: FirBasedSymbol<*> = if (this is FirThisReceiverExpressionImpl) { val symbol: FirBasedSymbol<*> = if (this is FirThisReceiverExpressionImpl) {
calleeReference.boundSymbol calleeReference.boundSymbol
@@ -661,8 +664,8 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
return variableStorage[symbol] return variableStorage[symbol]
} }
private fun getRealVariablesForSafeCallChain(call: FirExpression): Collection<DataFlowVariable> { private fun getRealVariablesForSafeCallChain(call: FirExpression): Collection<RealDataFlowVariable> {
val result = mutableListOf<DataFlowVariable>() val result = mutableListOf<RealDataFlowVariable>()
fun collect(call: FirExpression) { fun collect(call: FirExpression) {
when (call) { when (call) {
@@ -713,7 +716,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
} }
private fun addApprovedFact(flow: Flow, variable: DataFlowVariable, info: FirDataFlowInfo): Flow { private fun addApprovedFact(flow: Flow, variable: RealDataFlowVariable, info: FirDataFlowInfo): Flow {
return flow.addApprovedFact(variable, info).also { return flow.addApprovedFact(variable, info).also {
if (variable.isThisReference) { if (variable.isThisReference) {
updateReceiverType(flow, variable) updateReceiverType(flow, variable)
@@ -727,7 +730,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
} }
private fun Flow.removeSyntheticVariable(variable: DataFlowVariable): Flow { private fun Flow.removeSyntheticVariable(variable: DataFlowVariable): Flow {
if (!variable.isSynthetic) return this if (!variable.isSynthetic()) return this
return removeVariable(variable) return removeVariable(variable)
} }
} }
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.fir.types.render
data class ConditionalFirDataFlowInfo( data class ConditionalFirDataFlowInfo(
val condition: Condition, val condition: Condition,
val variable: DataFlowVariable, val variable: RealDataFlowVariable,
val info: FirDataFlowInfo val info: FirDataFlowInfo
) { ) {
fun invert(): ConditionalFirDataFlowInfo { fun invert(): ConditionalFirDataFlowInfo {
@@ -7,18 +7,27 @@ package org.jetbrains.kotlin.fir.resolve.dfa
import com.google.common.collect.HashMultimap import com.google.common.collect.HashMultimap
class Flow( class Flow private constructor(
val approvedInfos: MutableMap<DataFlowVariable, FirDataFlowInfo> = mutableMapOf(), val approvedInfos: MutableMap<RealDataFlowVariable, FirDataFlowInfo>,
val conditionalInfos: HashMultimap<DataFlowVariable, ConditionalFirDataFlowInfo> = HashMultimap.create(), val conditionalInfos: HashMultimap<DataFlowVariable, ConditionalFirDataFlowInfo>,
private var state: State = State.Building private var state: State = State.Building
) { ) {
constructor(
approvedInfos: MutableMap<RealDataFlowVariable, FirDataFlowInfo> = mutableMapOf(),
conditionalInfos: HashMultimap<DataFlowVariable, ConditionalFirDataFlowInfo> = HashMultimap.create()
) : this(approvedInfos, conditionalInfos, State.Building)
companion object {
val EMPTY = Flow(mutableMapOf(), HashMultimap.create(), State.Frozen)
}
private val isFrozen: Boolean get() = state == State.Frozen private val isFrozen: Boolean get() = state == State.Frozen
fun freeze() { fun freeze() {
state = State.Frozen state = State.Frozen
} }
fun addApprovedFact(variable: DataFlowVariable, info: FirDataFlowInfo): Flow { fun addApprovedFact(variable: RealDataFlowVariable, info: FirDataFlowInfo): Flow {
if (isFrozen) return copyForBuilding().addApprovedFact(variable, info) if (isFrozen) return copyForBuilding().addApprovedFact(variable, info)
approvedInfos.compute(variable) { _, existingInfo -> approvedInfos.compute(variable) { _, existingInfo ->
if (existingInfo == null) info if (existingInfo == null) info
@@ -38,9 +47,11 @@ class Flow(
to: DataFlowVariable, to: DataFlowVariable,
transform: ((ConditionalFirDataFlowInfo) -> ConditionalFirDataFlowInfo)? = null transform: ((ConditionalFirDataFlowInfo) -> ConditionalFirDataFlowInfo)? = null
): Flow { ): Flow {
if (isFrozen) if (isFrozen) {
return copyForBuilding().copyNotApprovedFacts(from, to, transform) return copyForBuilding().copyNotApprovedFacts(from, to, transform)
var facts = if (from.isSynthetic) { }
var facts = if (from.isSynthetic()) {
conditionalInfos.removeAll(from) conditionalInfos.removeAll(from)
} else { } else {
conditionalInfos[from] conditionalInfos[from]
@@ -52,7 +63,7 @@ class Flow(
return this return this
} }
fun approvedFacts(variable: DataFlowVariable): FirDataFlowInfo? { fun approvedFacts(variable: RealDataFlowVariable): FirDataFlowInfo? {
return approvedInfos[variable] return approvedInfos[variable]
} }
@@ -63,11 +74,7 @@ class Flow(
return this return this
} }
companion object { private enum class State {
val EMPTY = Flow(mutableMapOf(), HashMultimap.create(), State.Frozen)
}
enum class State {
Building, Frozen Building, Frozen
} }
@@ -14,7 +14,7 @@ class LogicSystem(private val context: DataFlowInferenceContext) {
storages.singleOrNull()?.let { storages.singleOrNull()?.let {
return it return it
} }
val approvedFacts = mutableMapOf<DataFlowVariable, FirDataFlowInfo>() val approvedFacts = mutableMapOf<RealDataFlowVariable, FirDataFlowInfo>()
storages.map { it.approvedInfos.keys } storages.map { it.approvedInfos.keys }
.intersectSets() .intersectSets()
.forEach { variable -> .forEach { variable ->
@@ -39,13 +39,13 @@ class LogicSystem(private val context: DataFlowInferenceContext) {
} }
fun andForVerifiedFacts( fun andForVerifiedFacts(
left: Map<DataFlowVariable, FirDataFlowInfo>?, left: Map<RealDataFlowVariable, FirDataFlowInfo>?,
right: Map<DataFlowVariable, FirDataFlowInfo>? right: Map<RealDataFlowVariable, FirDataFlowInfo>?
): Map<DataFlowVariable, FirDataFlowInfo>? { ): Map<RealDataFlowVariable, FirDataFlowInfo>? {
if (left.isNullOrEmpty()) return right if (left.isNullOrEmpty()) return right
if (right.isNullOrEmpty()) return left if (right.isNullOrEmpty()) return left
val map = mutableMapOf<DataFlowVariable, FirDataFlowInfo>() val map = mutableMapOf<RealDataFlowVariable, FirDataFlowInfo>()
for (variable in left.keys.union(right.keys)) { for (variable in left.keys.union(right.keys)) {
val leftInfo = left[variable] val leftInfo = left[variable]
val rightInfo = right[variable] val rightInfo = right[variable]
@@ -55,11 +55,11 @@ class LogicSystem(private val context: DataFlowInferenceContext) {
} }
fun orForVerifiedFacts( fun orForVerifiedFacts(
left: Map<DataFlowVariable, FirDataFlowInfo>?, left: Map<RealDataFlowVariable, FirDataFlowInfo>?,
right: Map<DataFlowVariable, FirDataFlowInfo>? right: Map<RealDataFlowVariable, FirDataFlowInfo>?
): Map<DataFlowVariable, FirDataFlowInfo>? { ): Map<RealDataFlowVariable, FirDataFlowInfo>? {
if (left.isNullOrEmpty() || right.isNullOrEmpty()) return null if (left.isNullOrEmpty() || right.isNullOrEmpty()) return null
val map = mutableMapOf<DataFlowVariable, FirDataFlowInfo>() val map = mutableMapOf<RealDataFlowVariable, FirDataFlowInfo>()
for (variable in left.keys.intersect(right.keys)) { for (variable in left.keys.intersect(right.keys)) {
val leftInfo = left[variable]!! val leftInfo = left[variable]!!
val rightInfo = right[variable]!! val rightInfo = right[variable]!!
@@ -68,20 +68,20 @@ class LogicSystem(private val context: DataFlowInferenceContext) {
return map return map
} }
fun approveFactsInsideFlow(variable: DataFlowVariable, condition: Condition, flow: Flow): Pair<Flow, Collection<DataFlowVariable>> { fun approveFactsInsideFlow(variable: DataFlowVariable, condition: Condition, flow: Flow): Pair<Flow, Collection<RealDataFlowVariable>> {
val notApprovedFacts: Set<ConditionalFirDataFlowInfo> = flow.conditionalInfos[variable] val notApprovedFacts: Set<ConditionalFirDataFlowInfo> = flow.conditionalInfos[variable]
if (notApprovedFacts.isEmpty()) { if (notApprovedFacts.isEmpty()) {
return flow to emptyList() return flow to emptyList()
} }
@Suppress("NAME_SHADOWING") @Suppress("NAME_SHADOWING")
val flow = flow.copyForBuilding() val flow = flow.copyForBuilding()
val newFacts = HashMultimap.create<DataFlowVariable, FirDataFlowInfo>() val newFacts = HashMultimap.create<RealDataFlowVariable, FirDataFlowInfo>()
notApprovedFacts.forEach { notApprovedFacts.forEach {
if (it.condition == condition) { if (it.condition == condition) {
newFacts.put(it.variable, it.info) newFacts.put(it.variable, it.info)
} }
} }
val updatedReceivers = mutableSetOf<DataFlowVariable>() val updatedReceivers = mutableSetOf<RealDataFlowVariable>()
newFacts.asMap().forEach { (variable, infos) -> newFacts.asMap().forEach { (variable, infos) ->
@Suppress("NAME_SHADOWING") @Suppress("NAME_SHADOWING")
@@ -97,12 +97,12 @@ class LogicSystem(private val context: DataFlowInferenceContext) {
return flow to updatedReceivers return flow to updatedReceivers
} }
fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableMap<DataFlowVariable, FirDataFlowInfo> { fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableMap<RealDataFlowVariable, FirDataFlowInfo> {
val notApprovedFacts: Set<ConditionalFirDataFlowInfo> = flow.conditionalInfos[variable] val notApprovedFacts: Set<ConditionalFirDataFlowInfo> = flow.conditionalInfos[variable]
if (notApprovedFacts.isEmpty()) { if (notApprovedFacts.isEmpty()) {
return mutableMapOf() return mutableMapOf()
} }
val newFacts = HashMultimap.create<DataFlowVariable, FirDataFlowInfo>() val newFacts = HashMultimap.create<RealDataFlowVariable, FirDataFlowInfo>()
notApprovedFacts.forEach { notApprovedFacts.forEach {
if (it.condition == condition) { if (it.condition == condition) {
newFacts.put(it.variable, it.info) newFacts.put(it.variable, it.info)