[FIR] Make SimpleFlow (old implementation) implement abstract Flow
This commit is contained in:
+18
-80
@@ -50,6 +50,10 @@ class DelegatingFlow(
|
||||
return result
|
||||
}
|
||||
|
||||
override fun removeConditionalInfos(variable: DataFlowVariable): Collection<ConditionalFirDataFlowInfo> {
|
||||
return conditionalInfos.removeAll(variable)
|
||||
}
|
||||
|
||||
private inline fun collect(block: (DelegatingFlow) -> Boolean) {
|
||||
var flow: DelegatingFlow? = this
|
||||
while (flow != null) {
|
||||
@@ -95,6 +99,12 @@ private class ImmutableMultimap<K, V>(private val original: Multimap<K, V>) : Mu
|
||||
}
|
||||
|
||||
abstract class DelegatingLogicSystem(context: DataFlowInferenceContext) : LogicSystem(context) {
|
||||
override val Flow.approvedInfos: MutableApprovedInfos
|
||||
get() = (this as DelegatingFlow).approvedInfos
|
||||
|
||||
override val Flow.conditionalInfos: ConditionalInfos
|
||||
get() = (this as DelegatingFlow).conditionalInfos
|
||||
|
||||
override fun createEmptyFlow(): Flow {
|
||||
return DelegatingFlow(null)
|
||||
}
|
||||
@@ -104,11 +114,16 @@ abstract class DelegatingLogicSystem(context: DataFlowInferenceContext) : LogicS
|
||||
return DelegatingFlow(flow)
|
||||
}
|
||||
|
||||
override fun collectInfoForBooleanOperator(leftFlow: Flow, rightFlow: Flow): InfoForBooleanOperator {
|
||||
override fun collectInfoForBooleanOperator(
|
||||
leftFlow: Flow,
|
||||
leftVariable: DataFlowVariable,
|
||||
rightFlow: Flow,
|
||||
rightVariable: DataFlowVariable
|
||||
): InfoForBooleanOperator {
|
||||
require(leftFlow is DelegatingFlow && rightFlow is DelegatingFlow)
|
||||
return InfoForBooleanOperator(
|
||||
leftFlow.previousFlow!!.conditionalInfosFromTopFlow(),
|
||||
rightFlow.conditionalInfosFromTopFlow(),
|
||||
leftFlow.previousFlow!!.conditionalInfosFromTopFlow()[leftVariable],
|
||||
rightFlow.conditionalInfosFromTopFlow()[rightVariable],
|
||||
rightFlow.approvedInfosFromTopFlow()
|
||||
)
|
||||
}
|
||||
@@ -148,83 +163,6 @@ abstract class DelegatingLogicSystem(context: DataFlowInferenceContext) : LogicS
|
||||
return commonFlow
|
||||
}
|
||||
|
||||
override fun changeVariableForConditionFlow(
|
||||
flow: Flow,
|
||||
sourceVariable: DataFlowVariable,
|
||||
newVariable: DataFlowVariable,
|
||||
transform: ((ConditionalFirDataFlowInfo) -> ConditionalFirDataFlowInfo)?
|
||||
) {
|
||||
require(flow is DelegatingFlow)
|
||||
var infos = flow.getConditionalInfos(sourceVariable)
|
||||
if (transform != null) {
|
||||
infos = infos.map(transform)
|
||||
}
|
||||
flow.conditionalInfos.putAll(newVariable, infos)
|
||||
if (sourceVariable.isSynthetic()) {
|
||||
flow.conditionalInfos.removeAll(sourceVariable)
|
||||
}
|
||||
}
|
||||
|
||||
override fun approveFactsInsideFlow(
|
||||
variable: DataFlowVariable,
|
||||
condition: Condition,
|
||||
flow: Flow,
|
||||
shouldForkFlow: Boolean,
|
||||
shouldRemoveSynthetics: Boolean
|
||||
): Flow {
|
||||
require(flow is DelegatingFlow)
|
||||
|
||||
val notApprovedFacts: Collection<ConditionalFirDataFlowInfo> = if (shouldRemoveSynthetics && variable.isSynthetic()) {
|
||||
flow.conditionalInfos.removeAll(variable)
|
||||
} else {
|
||||
flow.getConditionalInfos(variable)
|
||||
}
|
||||
|
||||
val resultFlow = if (shouldForkFlow) forkFlow(flow) else flow
|
||||
if (notApprovedFacts.isEmpty()) {
|
||||
return resultFlow
|
||||
}
|
||||
|
||||
val newFacts = ArrayListMultimap.create<RealDataFlowVariable, FirDataFlowInfo>()
|
||||
notApprovedFacts.forEach {
|
||||
if (it.condition == condition) {
|
||||
newFacts.put(it.variable, it.info)
|
||||
}
|
||||
}
|
||||
|
||||
val updatedReceivers = mutableSetOf<RealDataFlowVariable>()
|
||||
|
||||
newFacts.asMap().forEach { (variable, infos) ->
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val info = MutableFirDataFlowInfo()
|
||||
infos.forEach {
|
||||
info += it
|
||||
}
|
||||
if (variable.isThisReference) {
|
||||
updatedReceivers += variable
|
||||
}
|
||||
addApprovedInfo(resultFlow, variable, info)
|
||||
}
|
||||
updatedReceivers.forEach {
|
||||
processUpdatedReceiverVariable(resultFlow, it)
|
||||
}
|
||||
return resultFlow
|
||||
}
|
||||
|
||||
override fun addApprovedInfo(flow: Flow, variable: RealDataFlowVariable, info: FirDataFlowInfo) {
|
||||
assert(info is MutableFirDataFlowInfo)
|
||||
require(flow is DelegatingFlow)
|
||||
flow.approvedInfos.addInfo(variable, info)
|
||||
if (variable.isThisReference) {
|
||||
processUpdatedReceiverVariable(flow, variable)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addConditionalInfo(flow: Flow, variable: DataFlowVariable, info: ConditionalFirDataFlowInfo) {
|
||||
require(flow is DelegatingFlow)
|
||||
flow.conditionalInfos.put(variable, info)
|
||||
}
|
||||
|
||||
// ------------------------------- Util functions -------------------------------
|
||||
|
||||
private fun lowestCommonFlow(left: DelegatingFlow, right: DelegatingFlow): DelegatingFlow {
|
||||
|
||||
+7
-8
@@ -569,17 +569,16 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
||||
|
||||
val (conditionalFromLeft, conditionalFromRight, approvedFromRight) = logicSystem.collectInfoForBooleanOperator(
|
||||
flowFromLeft,
|
||||
flowFromRight
|
||||
leftVariable,
|
||||
flowFromRight,
|
||||
rightVariable
|
||||
)
|
||||
|
||||
val conditionalFromLeftArgument = conditionalFromLeft[leftVariable]
|
||||
val conditionalFromRightArgument = conditionalFromRight[rightVariable]
|
||||
|
||||
// left && right == True
|
||||
// left || right == False
|
||||
val approvedIfTrue: MutableApprovedInfos = mutableMapOf()
|
||||
logicSystem.approveFactTo(approvedIfTrue, bothEvaluated, conditionalFromLeftArgument)
|
||||
logicSystem.approveFactTo(approvedIfTrue, bothEvaluated, conditionalFromRightArgument)
|
||||
logicSystem.approveFactTo(approvedIfTrue, bothEvaluated, conditionalFromLeft)
|
||||
logicSystem.approveFactTo(approvedIfTrue, bothEvaluated, conditionalFromRight)
|
||||
approvedFromRight.forEach { (variable, info) ->
|
||||
approvedIfTrue.addInfo(variable, info)
|
||||
}
|
||||
@@ -590,8 +589,8 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
||||
// left && right == False
|
||||
// left || right == True
|
||||
val approvedIfFalse: MutableApprovedInfos = mutableMapOf()
|
||||
val leftIsFalse = logicSystem.approveFact(onlyLeftEvaluated, conditionalFromLeftArgument)
|
||||
val rightIsFalse = logicSystem.approveFact(onlyLeftEvaluated, conditionalFromRightArgument)
|
||||
val leftIsFalse = logicSystem.approveFact(onlyLeftEvaluated, conditionalFromLeft)
|
||||
val rightIsFalse = logicSystem.approveFact(onlyLeftEvaluated, conditionalFromRight)
|
||||
approvedIfFalse.mergeInfo(logicSystem.orForVerifiedFacts(leftIsFalse, rightIsFalse))
|
||||
approvedIfFalse.forEach { (variable, info) ->
|
||||
logicSystem.addConditionalInfo(flow, andVariable, info.toConditional(onlyLeftEvaluated, variable))
|
||||
|
||||
@@ -68,6 +68,7 @@ data class MutableFirDataFlowInfo(
|
||||
exactNotType += info.exactNotType
|
||||
}
|
||||
|
||||
fun copy(): MutableFirDataFlowInfo = MutableFirDataFlowInfo(exactType.toMutableSet(), exactNotType.toMutableSet())
|
||||
}
|
||||
|
||||
operator fun FirDataFlowInfo.plus(other: FirDataFlowInfo?): FirDataFlowInfo = other?.let { this + other } ?: this
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.dfa
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
|
||||
interface Flow {
|
||||
@@ -12,17 +13,29 @@ interface Flow {
|
||||
fun getConditionalInfos(variable: DataFlowVariable): Collection<ConditionalFirDataFlowInfo>
|
||||
|
||||
fun getVariablesInApprovedInfos(): Collection<RealDataFlowVariable>
|
||||
|
||||
fun removeConditionalInfos(variable: DataFlowVariable): Collection<ConditionalFirDataFlowInfo>
|
||||
}
|
||||
|
||||
abstract class LogicSystem(private val context: DataFlowInferenceContext) {
|
||||
|
||||
// ------------------------------- Flow operations -------------------------------
|
||||
|
||||
abstract fun createEmptyFlow(): Flow
|
||||
abstract fun forkFlow(flow: Flow): Flow
|
||||
abstract fun joinFlow(flows: Collection<Flow>): Flow
|
||||
|
||||
abstract fun addApprovedInfo(flow: Flow, variable: RealDataFlowVariable, info: FirDataFlowInfo)
|
||||
abstract fun addConditionalInfo(flow: Flow, variable: DataFlowVariable, info: ConditionalFirDataFlowInfo)
|
||||
open fun addApprovedInfo(flow: Flow, variable: RealDataFlowVariable, info: FirDataFlowInfo) {
|
||||
assert(info is MutableFirDataFlowInfo)
|
||||
flow.approvedInfos.addInfo(variable, info)
|
||||
if (variable.isThisReference) {
|
||||
processUpdatedReceiverVariable(flow, variable)
|
||||
}
|
||||
}
|
||||
|
||||
open fun addConditionalInfo(flow: Flow, variable: DataFlowVariable, info: ConditionalFirDataFlowInfo) {
|
||||
flow.conditionalInfos.put(variable, info)
|
||||
}
|
||||
|
||||
/*
|
||||
* used for:
|
||||
@@ -30,35 +43,90 @@ abstract class LogicSystem(private val context: DataFlowInferenceContext) {
|
||||
* 2. b = x is String
|
||||
* 3. !b | b.not() for Booleans
|
||||
*/
|
||||
abstract fun changeVariableForConditionFlow(
|
||||
open fun changeVariableForConditionFlow(
|
||||
flow: Flow,
|
||||
sourceVariable: DataFlowVariable,
|
||||
newVariable: DataFlowVariable,
|
||||
transform: ((ConditionalFirDataFlowInfo) -> ConditionalFirDataFlowInfo)? = null
|
||||
)
|
||||
) {
|
||||
var infos = flow.getConditionalInfos(sourceVariable)
|
||||
if (transform != null) {
|
||||
infos = infos.map(transform)
|
||||
}
|
||||
flow.conditionalInfos.putAll(newVariable, infos)
|
||||
if (sourceVariable.isSynthetic()) {
|
||||
flow.conditionalInfos.removeAll(sourceVariable)
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun approveFactsInsideFlow(
|
||||
open fun approveFactsInsideFlow(
|
||||
variable: DataFlowVariable,
|
||||
condition: Condition,
|
||||
flow: Flow,
|
||||
shouldForkFlow: Boolean,
|
||||
shouldRemoveSynthetics: Boolean
|
||||
): Flow
|
||||
): Flow {
|
||||
val notApprovedFacts: Collection<ConditionalFirDataFlowInfo> = if (shouldRemoveSynthetics && variable.isSynthetic()) {
|
||||
flow.removeConditionalInfos(variable)
|
||||
} else {
|
||||
flow.getConditionalInfos(variable)
|
||||
}
|
||||
|
||||
val resultFlow = if (shouldForkFlow) forkFlow(flow) else flow
|
||||
if (notApprovedFacts.isEmpty()) {
|
||||
return resultFlow
|
||||
}
|
||||
|
||||
val newFacts = ArrayListMultimap.create<RealDataFlowVariable, FirDataFlowInfo>()
|
||||
notApprovedFacts.forEach {
|
||||
if (it.condition == condition) {
|
||||
newFacts.put(it.variable, it.info)
|
||||
}
|
||||
}
|
||||
|
||||
val updatedReceivers = mutableSetOf<RealDataFlowVariable>()
|
||||
|
||||
newFacts.asMap().forEach { (variable, infos) ->
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val info = MutableFirDataFlowInfo()
|
||||
infos.forEach {
|
||||
info += it
|
||||
}
|
||||
if (variable.isThisReference) {
|
||||
updatedReceivers += variable
|
||||
}
|
||||
addApprovedInfo(resultFlow, variable, info)
|
||||
}
|
||||
updatedReceivers.forEach {
|
||||
processUpdatedReceiverVariable(resultFlow, it)
|
||||
}
|
||||
return resultFlow
|
||||
}
|
||||
|
||||
// ------------------------------- Callbacks for updating implicit receiver stack -------------------------------
|
||||
|
||||
abstract fun processUpdatedReceiverVariable(flow: Flow, variable: RealDataFlowVariable)
|
||||
abstract fun updateAllReceivers(flow: Flow)
|
||||
|
||||
// ------------------------------- Accessors to flow implementation -------------------------------
|
||||
|
||||
protected abstract val Flow.approvedInfos: MutableApprovedInfos
|
||||
protected abstract val Flow.conditionalInfos: ConditionalInfos
|
||||
|
||||
// ------------------------------- Public DataFlowInfo util functions -------------------------------
|
||||
|
||||
data class InfoForBooleanOperator(
|
||||
val conditionalFromLeft: ConditionalInfos,
|
||||
val conditionalFromRight: ConditionalInfos,
|
||||
val conditionalFromLeft: Collection<ConditionalFirDataFlowInfo>,
|
||||
val conditionalFromRight: Collection<ConditionalFirDataFlowInfo>,
|
||||
val approvedFromRight: ApprovedInfos
|
||||
)
|
||||
|
||||
abstract fun collectInfoForBooleanOperator(leftFlow: Flow, rightFlow: Flow): InfoForBooleanOperator
|
||||
abstract fun collectInfoForBooleanOperator(
|
||||
leftFlow: Flow,
|
||||
leftVariable: DataFlowVariable,
|
||||
rightFlow: Flow,
|
||||
rightVariable: DataFlowVariable
|
||||
): InfoForBooleanOperator
|
||||
|
||||
fun orForVerifiedFacts(
|
||||
left: ApprovedInfos,
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.dfa
|
||||
|
||||
import com.google.common.collect.HashMultimap
|
||||
|
||||
class SimpleFlow private constructor(
|
||||
val approvedInfos: MutableMap<RealDataFlowVariable, FirDataFlowInfo>,
|
||||
val conditionalInfos: HashMultimap<DataFlowVariable, ConditionalFirDataFlowInfo>,
|
||||
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 = SimpleFlow(mutableMapOf(), HashMultimap.create(), State.Frozen)
|
||||
}
|
||||
|
||||
private val isFrozen: Boolean get() = state == State.Frozen
|
||||
|
||||
fun freeze() {
|
||||
state = State.Frozen
|
||||
}
|
||||
|
||||
fun addApprovedFact(variable: RealDataFlowVariable, info: FirDataFlowInfo): SimpleFlow {
|
||||
if (isFrozen) return copyForBuilding().addApprovedFact(variable, info)
|
||||
approvedInfos.compute(variable) { _, existingInfo ->
|
||||
if (existingInfo == null) info
|
||||
else existingInfo + info
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun addNotApprovedFact(variable: DataFlowVariable, info: ConditionalFirDataFlowInfo): SimpleFlow {
|
||||
if (isFrozen) return copyForBuilding().addNotApprovedFact(variable, info)
|
||||
conditionalInfos.put(variable, info)
|
||||
return this
|
||||
}
|
||||
|
||||
fun copyNotApprovedFacts(
|
||||
from: DataFlowVariable,
|
||||
to: DataFlowVariable,
|
||||
transform: ((ConditionalFirDataFlowInfo) -> ConditionalFirDataFlowInfo)? = null
|
||||
): SimpleFlow {
|
||||
if (isFrozen) {
|
||||
return copyForBuilding().copyNotApprovedFacts(from, to, transform)
|
||||
}
|
||||
|
||||
var facts = if (from.isSynthetic()) {
|
||||
conditionalInfos.removeAll(from)
|
||||
} else {
|
||||
conditionalInfos[from]
|
||||
}
|
||||
if (transform != null) {
|
||||
facts = facts.mapTo(mutableSetOf(), transform)
|
||||
}
|
||||
conditionalInfos.putAll(to, facts)
|
||||
return this
|
||||
}
|
||||
|
||||
fun approvedFacts(variable: RealDataFlowVariable): FirDataFlowInfo? {
|
||||
return approvedInfos[variable]
|
||||
}
|
||||
|
||||
fun removeVariableFromFlow(variable: DataFlowVariable): SimpleFlow {
|
||||
if (isFrozen) return copyForBuilding().removeVariableFromFlow(variable)
|
||||
conditionalInfos.removeAll(variable)
|
||||
approvedInfos.remove(variable)
|
||||
return this
|
||||
}
|
||||
|
||||
private enum class State {
|
||||
Building, Frozen
|
||||
}
|
||||
|
||||
fun copy(): SimpleFlow {
|
||||
return when (state) {
|
||||
State.Frozen -> this
|
||||
State.Building -> copyForBuilding()
|
||||
}
|
||||
}
|
||||
|
||||
fun copyForBuilding(): SimpleFlow {
|
||||
return SimpleFlow(approvedInfos.toMutableMap(), conditionalInfos.copy(), State.Building)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <K, V> HashMultimap<K, V>.copy(): HashMultimap<K, V> = HashMultimap.create(this)
|
||||
+75
-108
@@ -5,134 +5,101 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.dfa
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap
|
||||
import com.google.common.collect.HashMultimap
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import com.google.common.collect.Multimap
|
||||
|
||||
class SimpleLogicSystem(private val context: DataFlowInferenceContext) {
|
||||
private fun <E> List<Set<E>>.intersectSets(): Set<E> = takeIf { isNotEmpty() }?.reduce { x, y -> x.intersect(y) } ?: emptySet()
|
||||
private class SimpleFlow(
|
||||
val approvedInfos: MutableApprovedInfos = mutableMapOf(),
|
||||
val conditionalInfos: ConditionalInfos = HashMultimap.create()
|
||||
) : Flow {
|
||||
override fun getApprovedInfo(variable: RealDataFlowVariable): FirDataFlowInfo? {
|
||||
return approvedInfos[variable]
|
||||
}
|
||||
|
||||
fun or(storages: Collection<SimpleFlow>): SimpleFlow {
|
||||
storages.singleOrNull()?.let {
|
||||
return it
|
||||
}
|
||||
val approvedFacts = mutableMapOf<RealDataFlowVariable, FirDataFlowInfo>()
|
||||
storages.map { it.approvedInfos.keys }
|
||||
override fun getConditionalInfos(variable: DataFlowVariable): Collection<ConditionalFirDataFlowInfo> {
|
||||
return conditionalInfos[variable]
|
||||
}
|
||||
|
||||
override fun getVariablesInApprovedInfos(): Collection<RealDataFlowVariable> {
|
||||
return approvedInfos.keys
|
||||
}
|
||||
|
||||
override fun removeConditionalInfos(variable: DataFlowVariable): Collection<ConditionalFirDataFlowInfo> {
|
||||
return conditionalInfos.removeAll(variable)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SimpleLogicSystem(context: DataFlowInferenceContext) : LogicSystem(context) {
|
||||
override val Flow.approvedInfos: MutableApprovedInfos
|
||||
get() = (this as SimpleFlow).approvedInfos
|
||||
|
||||
override val Flow.conditionalInfos: ConditionalInfos
|
||||
get() = (this as SimpleFlow).conditionalInfos
|
||||
|
||||
override fun createEmptyFlow(): Flow {
|
||||
return SimpleFlow()
|
||||
}
|
||||
|
||||
override fun forkFlow(flow: Flow): Flow {
|
||||
require(flow is SimpleFlow)
|
||||
return SimpleFlow(
|
||||
flow.approvedInfos.mapValuesTo(mutableMapOf()) { (_, info) -> info.copy() },
|
||||
flow.conditionalInfos.copy()
|
||||
)
|
||||
}
|
||||
|
||||
override fun joinFlow(flows: Collection<Flow>): Flow {
|
||||
@Suppress("UNCHECKED_CAST", "NAME_SHADOWING")
|
||||
val flows = flows as Collection<SimpleFlow>
|
||||
flows.singleOrNull()?.let { return it }
|
||||
val approvedFacts: MutableApprovedInfos = mutableMapOf()
|
||||
flows.map { it.approvedInfos.keys }
|
||||
.intersectSets()
|
||||
.forEach { variable ->
|
||||
val infos = storages.map { it.approvedInfos[variable]!! }
|
||||
val infos = flows.map { it.approvedInfos[variable]!! }
|
||||
if (infos.isNotEmpty()) {
|
||||
approvedFacts[variable] = or(infos)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val notApprovedFacts = HashMultimap.create<DataFlowVariable, ConditionalFirDataFlowInfo>()
|
||||
storages.map { it.conditionalInfos.keySet() }
|
||||
val notApprovedFacts: ConditionalInfos = ArrayListMultimap.create()
|
||||
flows.map { it.conditionalInfos.keySet() }
|
||||
.intersectSets()
|
||||
.forEach { variable ->
|
||||
val infos = storages.map { it.conditionalInfos[variable] }.intersectSets()
|
||||
val infos = flows.map { it.conditionalInfos[variable] }.intersectSets()
|
||||
if (infos.isNotEmpty()) {
|
||||
notApprovedFacts.putAll(variable, infos)
|
||||
}
|
||||
}
|
||||
|
||||
return SimpleFlow(approvedFacts, notApprovedFacts)
|
||||
val result = SimpleFlow(approvedFacts, notApprovedFacts)
|
||||
updateAllReceivers(result)
|
||||
return result
|
||||
}
|
||||
|
||||
fun andForVerifiedFacts(
|
||||
left: Map<RealDataFlowVariable, FirDataFlowInfo>?,
|
||||
right: Map<RealDataFlowVariable, FirDataFlowInfo>?
|
||||
): Map<RealDataFlowVariable, FirDataFlowInfo>? {
|
||||
if (left.isNullOrEmpty()) return right
|
||||
if (right.isNullOrEmpty()) return left
|
||||
override fun collectInfoForBooleanOperator(
|
||||
leftFlow: Flow,
|
||||
leftVariable: DataFlowVariable,
|
||||
rightFlow: Flow,
|
||||
rightVariable: DataFlowVariable
|
||||
): InfoForBooleanOperator {
|
||||
require(leftFlow is SimpleFlow && rightFlow is SimpleFlow)
|
||||
return InfoForBooleanOperator(
|
||||
leftFlow.conditionalInfos[leftVariable],
|
||||
rightFlow.conditionalInfos[rightVariable],
|
||||
rightFlow.approvedInfos - leftFlow.approvedInfos
|
||||
)
|
||||
}
|
||||
|
||||
val map = mutableMapOf<RealDataFlowVariable, FirDataFlowInfo>()
|
||||
for (variable in left.keys.union(right.keys)) {
|
||||
val leftInfo = left[variable]
|
||||
val rightInfo = right[variable]
|
||||
map[variable] = and(listOfNotNull(leftInfo, rightInfo))
|
||||
private operator fun ApprovedInfos.minus(other: ApprovedInfos): ApprovedInfos {
|
||||
val result: MutableApprovedInfos = mutableMapOf()
|
||||
forEach { (variable, info) ->
|
||||
require(info is MutableFirDataFlowInfo)
|
||||
result[variable] = other[variable]?.let { info - it } ?: info
|
||||
}
|
||||
return map
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
fun orForVerifiedFacts(
|
||||
left: Map<RealDataFlowVariable, FirDataFlowInfo>?,
|
||||
right: Map<RealDataFlowVariable, FirDataFlowInfo>?
|
||||
): Map<RealDataFlowVariable, FirDataFlowInfo>? {
|
||||
if (left.isNullOrEmpty() || right.isNullOrEmpty()) return null
|
||||
val map = mutableMapOf<RealDataFlowVariable, FirDataFlowInfo>()
|
||||
for (variable in left.keys.intersect(right.keys)) {
|
||||
val leftInfo = left[variable]!!
|
||||
val rightInfo = right[variable]!!
|
||||
map[variable] = or(listOf(leftInfo, rightInfo))
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
fun approveFactsInsideFlow(variable: DataFlowVariable, condition: Condition, flow: SimpleFlow): Pair<SimpleFlow, Collection<RealDataFlowVariable>> {
|
||||
val notApprovedFacts: Set<ConditionalFirDataFlowInfo> = flow.conditionalInfos[variable]
|
||||
if (notApprovedFacts.isEmpty()) {
|
||||
return flow to emptyList()
|
||||
}
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val flow = flow.copyForBuilding()
|
||||
val newFacts = HashMultimap.create<RealDataFlowVariable, FirDataFlowInfo>()
|
||||
notApprovedFacts.forEach {
|
||||
if (it.condition == condition) {
|
||||
newFacts.put(it.variable, it.info)
|
||||
}
|
||||
}
|
||||
val updatedReceivers = mutableSetOf<RealDataFlowVariable>()
|
||||
|
||||
newFacts.asMap().forEach { (variable, infos) ->
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val infos = ArrayList(infos)
|
||||
flow.approvedInfos[variable]?.let {
|
||||
infos.add(it)
|
||||
}
|
||||
flow.approvedInfos[variable] = and(infos)
|
||||
if (variable.isThisReference) {
|
||||
updatedReceivers += variable
|
||||
}
|
||||
}
|
||||
return flow to updatedReceivers
|
||||
}
|
||||
|
||||
fun approveFact(variable: DataFlowVariable, condition: Condition, flow: SimpleFlow): MutableMap<RealDataFlowVariable, FirDataFlowInfo> {
|
||||
val notApprovedFacts: Set<ConditionalFirDataFlowInfo> = flow.conditionalInfos[variable]
|
||||
if (notApprovedFacts.isEmpty()) {
|
||||
return mutableMapOf()
|
||||
}
|
||||
val newFacts = HashMultimap.create<RealDataFlowVariable, FirDataFlowInfo>()
|
||||
notApprovedFacts.forEach {
|
||||
if (it.condition == condition) {
|
||||
newFacts.put(it.variable, it.info)
|
||||
}
|
||||
}
|
||||
return newFacts.asMap().mapValuesTo(mutableMapOf()) { (_, infos) -> and(infos) }
|
||||
}
|
||||
|
||||
private fun or(infos: Collection<FirDataFlowInfo>): FirDataFlowInfo {
|
||||
infos.singleOrNull()?.let { return it }
|
||||
val exactType = orTypes(infos.map { it.exactType })
|
||||
val exactNotType = orTypes(infos.map { it.exactNotType })
|
||||
return FirDataFlowInfo(exactType, exactNotType)
|
||||
}
|
||||
|
||||
private fun orTypes(types: Collection<Set<ConeKotlinType>>): Set<ConeKotlinType> {
|
||||
if (types.any { it.isEmpty() }) return emptySet()
|
||||
val allTypes = types.flatMapTo(mutableSetOf()) { it }
|
||||
val commonTypes = allTypes.toMutableSet()
|
||||
types.forEach { commonTypes.retainAll(it) }
|
||||
val differentTypes = allTypes - commonTypes
|
||||
context.commonSuperTypeOrNull(differentTypes.toList())?.let { commonTypes += it }
|
||||
return commonTypes
|
||||
}
|
||||
|
||||
private fun and(infos: Collection<FirDataFlowInfo>): FirDataFlowInfo {
|
||||
infos.singleOrNull()?.let { return it }
|
||||
val exactType = infos.flatMapTo(mutableSetOf()) { it.exactType }
|
||||
val exactNotType = infos.flatMapTo(mutableSetOf()) { it.exactNotType }
|
||||
return FirDataFlowInfo(exactType, exactNotType)
|
||||
}
|
||||
}
|
||||
private fun <K, V> Multimap<K, V>.copy(): Multimap<K, V> = ArrayListMultimap.create(this)
|
||||
Reference in New Issue
Block a user