Generify key type parameter of ControlFlowInfo
Previously only `VariableDescriptor` was key of `ControlFlowInfo`. Now it's generic parameter `K: Any`, so there is a possibility of using different object's inside CFA
This commit is contained in:
@@ -16,41 +16,40 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.cfg
|
package org.jetbrains.kotlin.cfg
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
|
||||||
import org.jetbrains.kotlin.util.javaslang.ImmutableHashMap
|
import org.jetbrains.kotlin.util.javaslang.ImmutableHashMap
|
||||||
import org.jetbrains.kotlin.util.javaslang.ImmutableMap
|
import org.jetbrains.kotlin.util.javaslang.ImmutableMap
|
||||||
|
|
||||||
interface ReadOnlyControlFlowInfo<D : Any> {
|
interface ReadOnlyControlFlowInfo<K : Any, D : Any> {
|
||||||
fun getOrNull(variableDescriptor: VariableDescriptor): D?
|
fun getOrNull(key: K): D?
|
||||||
// Only used in tests
|
// Only used in tests
|
||||||
fun asMap(): ImmutableMap<VariableDescriptor, D>
|
fun asMap(): ImmutableMap<K, D>
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ControlFlowInfo<S : ControlFlowInfo<S, D>, D : Any>
|
abstract class ControlFlowInfo<S : ControlFlowInfo<S, K, D>, K : Any, D : Any>
|
||||||
internal constructor(
|
internal constructor(
|
||||||
protected val map: ImmutableMap<VariableDescriptor, D> = ImmutableHashMap.empty()
|
protected val map: ImmutableMap<K, D> = ImmutableHashMap.empty()
|
||||||
) : ImmutableMap<VariableDescriptor, D> by map, ReadOnlyControlFlowInfo<D> {
|
) : ImmutableMap<K, D> by map, ReadOnlyControlFlowInfo<K, D> {
|
||||||
protected abstract fun copy(newMap: ImmutableMap<VariableDescriptor, D>): S
|
protected abstract fun copy(newMap: ImmutableMap<K, D>): S
|
||||||
|
|
||||||
override fun put(key: VariableDescriptor, value: D): S = put(key, value, this[key].getOrElse(null as D?))
|
override fun put(key: K, value: D): S = put(key, value, this[key].getOrElse(null as D?))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This overload exists just for sake of optimizations: in some cases we've just retrieved the old value,
|
* This overload exists just for sake of optimizations: in some cases we've just retrieved the old value,
|
||||||
* so we don't need to scan through the persistent hashmap again
|
* so we don't need to scan through the persistent hashmap again
|
||||||
*/
|
*/
|
||||||
fun put(key: VariableDescriptor, value: D, oldValue: D?): S {
|
fun put(key: K, value: D, oldValue: D?): S {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
// Avoid a copy instance creation if new value is the same
|
// Avoid a copy instance creation if new value is the same
|
||||||
if (value == oldValue) return this as S
|
if (value == oldValue) return this as S
|
||||||
return copy(map.put(key, value))
|
return copy(map.put(key, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getOrNull(variableDescriptor: VariableDescriptor): D? = this[variableDescriptor].getOrElse(null as D?)
|
override fun getOrNull(key: K): D? = this[key].getOrElse(null as D?)
|
||||||
override fun asMap() = this
|
override fun asMap() = this
|
||||||
|
|
||||||
fun retainAll(predicate: (VariableDescriptor) -> Boolean): S = copy(map.removeAll(map.keySet().filterNot(predicate)))
|
fun retainAll(predicate: (K) -> Boolean): S = copy(map.removeAll(map.keySet().filterNot(predicate)))
|
||||||
|
|
||||||
override fun equals(other: Any?) = map == (other as? ControlFlowInfo<*, *>)?.map
|
override fun equals(other: Any?) = map == (other as? ControlFlowInfo<*, *, *>)?.map
|
||||||
|
|
||||||
override fun hashCode() = map.hashCode()
|
override fun hashCode() = map.hashCode()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
* that can be found in the license/LICENSE.txt file.
|
* that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.cfg.TailRecursionKind.*
|
import org.jetbrains.kotlin.cfg.TailRecursionKind.*
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
|
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeUtil
|
import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeUtil
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.containingDeclarationForPseudocode
|
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.KtElementInstruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.KtElementInstruction
|
||||||
@@ -32,7 +31,6 @@ import org.jetbrains.kotlin.diagnostics.Errors.*
|
|||||||
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
||||||
@@ -326,8 +324,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val reportedDiagnosticMap = hashMapOf<Instruction, DiagnosticFactory<*>>()
|
val reportedDiagnosticMap = hashMapOf<Instruction, DiagnosticFactory<*>>()
|
||||||
|
|
||||||
pseudocode.traverse(TraversalOrder.FORWARD, initializers) { instruction: Instruction,
|
pseudocode.traverse(TraversalOrder.FORWARD, initializers) { instruction: Instruction,
|
||||||
enterData: ReadOnlyInitControlFlowInfo,
|
enterData: VariableInitReadOnlyControlFlowInfo,
|
||||||
exitData: ReadOnlyInitControlFlowInfo ->
|
exitData: VariableInitReadOnlyControlFlowInfo ->
|
||||||
|
|
||||||
val ctxt = VariableInitContext(instruction, reportedDiagnosticMap, enterData, exitData, blockScopeVariableInfo)
|
val ctxt = VariableInitContext(instruction, reportedDiagnosticMap, enterData, exitData, blockScopeVariableInfo)
|
||||||
if (ctxt.variableDescriptor == null) return@traverse
|
if (ctxt.variableDescriptor == null) return@traverse
|
||||||
@@ -603,7 +601,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
|
|
||||||
private fun recordInitializedVariables(
|
private fun recordInitializedVariables(
|
||||||
pseudocode: Pseudocode,
|
pseudocode: Pseudocode,
|
||||||
initializersMap: Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>>
|
initializersMap: Map<Instruction, Edges<VariableInitReadOnlyControlFlowInfo>>
|
||||||
) {
|
) {
|
||||||
val initializers = initializersMap[pseudocode.exitInstruction] ?: return
|
val initializers = initializersMap[pseudocode.exitInstruction] ?: return
|
||||||
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false)
|
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false)
|
||||||
@@ -624,8 +622,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val unusedValueExpressions = hashMapOf<KtExpression, Pair<VariableDescriptor, VariableUseContext>>()
|
val unusedValueExpressions = hashMapOf<KtExpression, Pair<VariableDescriptor, VariableUseContext>>()
|
||||||
val usedValueExpressions = hashSetOf<KtExpression>()
|
val usedValueExpressions = hashSetOf<KtExpression>()
|
||||||
pseudocode.traverse(TraversalOrder.BACKWARD, variableStatusData) { instruction: Instruction,
|
pseudocode.traverse(TraversalOrder.BACKWARD, variableStatusData) { instruction: Instruction,
|
||||||
enterData: ReadOnlyUseControlFlowInfo,
|
enterData: VariableUsageReadOnlyControlInfo,
|
||||||
_: ReadOnlyUseControlFlowInfo ->
|
_: VariableUsageReadOnlyControlInfo ->
|
||||||
|
|
||||||
val ctxt = VariableUseContext(instruction, reportedDiagnosticMap)
|
val ctxt = VariableUseContext(instruction, reportedDiagnosticMap)
|
||||||
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false)
|
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false)
|
||||||
@@ -1071,8 +1069,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
private inner class VariableInitContext(
|
private inner class VariableInitContext(
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
map: MutableMap<Instruction, DiagnosticFactory<*>>,
|
map: MutableMap<Instruction, DiagnosticFactory<*>>,
|
||||||
`in`: ReadOnlyInitControlFlowInfo,
|
`in`: VariableInitReadOnlyControlFlowInfo,
|
||||||
out: ReadOnlyInitControlFlowInfo,
|
out: VariableInitReadOnlyControlFlowInfo,
|
||||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||||
) : VariableContext(instruction, map) {
|
) : VariableContext(instruction, map) {
|
||||||
internal val enterInitState = initialize(variableDescriptor, blockScopeVariableInfo, `in`)
|
internal val enterInitState = initialize(variableDescriptor, blockScopeVariableInfo, `in`)
|
||||||
@@ -1081,7 +1079,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
private fun initialize(
|
private fun initialize(
|
||||||
variableDescriptor: VariableDescriptor?,
|
variableDescriptor: VariableDescriptor?,
|
||||||
blockScopeVariableInfo: BlockScopeVariableInfo,
|
blockScopeVariableInfo: BlockScopeVariableInfo,
|
||||||
map: ReadOnlyInitControlFlowInfo
|
map: VariableInitReadOnlyControlFlowInfo
|
||||||
): VariableControlFlowState? {
|
): VariableControlFlowState? {
|
||||||
val state = map.getOrNull(variableDescriptor ?: return null)
|
val state = map.getOrNull(variableDescriptor ?: return null)
|
||||||
if (state != null) return state
|
if (state != null) return state
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ fun <D> Pseudocode.traverse(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <I : ControlFlowInfo<*, *>> Pseudocode.collectData(
|
fun <I : ControlFlowInfo<*, *, *>> Pseudocode.collectData(
|
||||||
traversalOrder: TraversalOrder,
|
traversalOrder: TraversalOrder,
|
||||||
mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
|
mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
|
||||||
updateEdge: (Instruction, Instruction, I) -> I,
|
updateEdge: (Instruction, Instruction, I) -> I,
|
||||||
@@ -76,7 +76,7 @@ fun <I : ControlFlowInfo<*, *>> Pseudocode.collectData(
|
|||||||
return edgesMap
|
return edgesMap
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <I : ControlFlowInfo<*, *>> Pseudocode.collectDataFromSubgraph(
|
private fun <I : ControlFlowInfo<*, *, *>> Pseudocode.collectDataFromSubgraph(
|
||||||
traversalOrder: TraversalOrder,
|
traversalOrder: TraversalOrder,
|
||||||
edgesMap: MutableMap<Instruction, Edges<I>>,
|
edgesMap: MutableMap<Instruction, Edges<I>>,
|
||||||
mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
|
mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
|
||||||
@@ -154,7 +154,7 @@ private fun getPreviousIncludingSubGraphInstructions(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <I : ControlFlowInfo<*, *>> updateEdgeDataForInstruction(
|
private fun <I : ControlFlowInfo<*, *, *>> updateEdgeDataForInstruction(
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
previousValue: Edges<I>?,
|
previousValue: Edges<I>?,
|
||||||
newValue: Edges<I>?,
|
newValue: Edges<I>?,
|
||||||
|
|||||||
+2
-3
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.cfg.variable
|
package org.jetbrains.kotlin.cfg.variable
|
||||||
|
|
||||||
import org.jetbrains.kotlin.cfg.ControlFlowInfo
|
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
|
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.BlockScope
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.BlockScope
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
||||||
@@ -24,7 +23,7 @@ class PseudocodeVariableDataCollector(
|
|||||||
) {
|
) {
|
||||||
val blockScopeVariableInfo = computeBlockScopeVariableInfo(pseudocode)
|
val blockScopeVariableInfo = computeBlockScopeVariableInfo(pseudocode)
|
||||||
|
|
||||||
fun <I : ControlFlowInfo<*, *>> collectData(
|
fun <I : VariableUsageControlFlowInfo<*, *>> collectData(
|
||||||
traversalOrder: TraversalOrder,
|
traversalOrder: TraversalOrder,
|
||||||
initialInfo: I,
|
initialInfo: I,
|
||||||
instructionDataMergeStrategy: (Instruction, Collection<I>) -> Edges<I>
|
instructionDataMergeStrategy: (Instruction, Collection<I>) -> Edges<I>
|
||||||
@@ -37,7 +36,7 @@ class PseudocodeVariableDataCollector(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <I : ControlFlowInfo<*, *>> filterOutVariablesOutOfScope(
|
private fun <I : VariableUsageControlFlowInfo<*, *>> filterOutVariablesOutOfScope(
|
||||||
from: Instruction,
|
from: Instruction,
|
||||||
to: Instruction,
|
to: Instruction,
|
||||||
info: I
|
info: I
|
||||||
|
|||||||
+22
-22
@@ -45,7 +45,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations = true)
|
getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
val variableInitializers: Map<Instruction, Edges<ReadOnlyInitVariableControlFlowInfo>> by lazy {
|
val variableInitializers: Map<Instruction, Edges<VariableInitReadOnlyControlFlowInfo>> by lazy {
|
||||||
computeVariableInitializers()
|
computeVariableInitializers()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
|
|
||||||
// variable initializers
|
// variable initializers
|
||||||
|
|
||||||
private fun computeVariableInitializers(): Map<Instruction, Edges<ReadOnlyInitVariableControlFlowInfo>> {
|
private fun computeVariableInitializers(): Map<Instruction, Edges<VariableInitReadOnlyControlFlowInfo>> {
|
||||||
|
|
||||||
val blockScopeVariableInfo = pseudocodeVariableDataCollector.blockScopeVariableInfo
|
val blockScopeVariableInfo = pseudocodeVariableDataCollector.blockScopeVariableInfo
|
||||||
|
|
||||||
@@ -143,8 +143,8 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
|
|
||||||
return pseudocodeVariableDataCollector.collectData(
|
return pseudocodeVariableDataCollector.collectData(
|
||||||
TraversalOrder.FORWARD,
|
TraversalOrder.FORWARD,
|
||||||
InitVariableControlFlowInfo()
|
VariableInitControlFlowInfo()
|
||||||
) { instruction: Instruction, incomingEdgesData: Collection<InitVariableControlFlowInfo> ->
|
) { instruction: Instruction, incomingEdgesData: Collection<VariableInitControlFlowInfo> ->
|
||||||
|
|
||||||
val enterInstructionData =
|
val enterInstructionData =
|
||||||
mergeIncomingEdgesDataForInitializers(
|
mergeIncomingEdgesDataForInitializers(
|
||||||
@@ -197,8 +197,8 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
private inner class ReadOnlyInitVariableControlFlowInfoImpl(
|
private inner class ReadOnlyInitVariableControlFlowInfoImpl(
|
||||||
val declaredSet: ImmutableSet<VariableDescriptor>,
|
val declaredSet: ImmutableSet<VariableDescriptor>,
|
||||||
val initSet: ImmutableSet<VariableDescriptor>,
|
val initSet: ImmutableSet<VariableDescriptor>,
|
||||||
private val delegate: ReadOnlyInitVariableControlFlowInfo?
|
private val delegate: VariableInitReadOnlyControlFlowInfo?
|
||||||
) : ReadOnlyInitVariableControlFlowInfo {
|
) : VariableInitReadOnlyControlFlowInfo {
|
||||||
override fun getOrNull(key: VariableDescriptor): VariableControlFlowState? {
|
override fun getOrNull(key: VariableDescriptor): VariableControlFlowState? {
|
||||||
if (key in declaredSet) {
|
if (key in declaredSet) {
|
||||||
return VariableControlFlowState.create(isInitialized = key in initSet, isDeclared = true)
|
return VariableControlFlowState.create(isInitialized = key in initSet, isDeclared = true)
|
||||||
@@ -206,10 +206,10 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
return delegate?.getOrNull(key)
|
return delegate?.getOrNull(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitVariableControlFlowInfo): Boolean =
|
override fun checkDefiniteInitializationInWhen(merge: VariableInitReadOnlyControlFlowInfo): Boolean =
|
||||||
delegate?.checkDefiniteInitializationInWhen(merge) ?: false
|
delegate?.checkDefiniteInitializationInWhen(merge) ?: false
|
||||||
|
|
||||||
fun replaceDelegate(newDelegate: ReadOnlyInitVariableControlFlowInfo): ReadOnlyInitVariableControlFlowInfo =
|
fun replaceDelegate(newDelegate: VariableInitReadOnlyControlFlowInfo): VariableInitReadOnlyControlFlowInfo =
|
||||||
ReadOnlyInitVariableControlFlowInfoImpl(declaredSet, initSet, newDelegate)
|
ReadOnlyInitVariableControlFlowInfoImpl(declaredSet, initSet, newDelegate)
|
||||||
|
|
||||||
override fun asMap(): ImmutableMap<VariableDescriptor, VariableControlFlowState> {
|
override fun asMap(): ImmutableMap<VariableDescriptor, VariableControlFlowState> {
|
||||||
@@ -243,9 +243,9 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
|
|
||||||
private fun addVariableInitStateFromCurrentInstructionIfAny(
|
private fun addVariableInitStateFromCurrentInstructionIfAny(
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
enterInstructionData: InitVariableControlFlowInfo,
|
enterInstructionData: VariableInitControlFlowInfo,
|
||||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||||
): InitVariableControlFlowInfo {
|
): VariableInitControlFlowInfo {
|
||||||
if (instruction is MagicInstruction) {
|
if (instruction is MagicInstruction) {
|
||||||
if (instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
|
if (instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
|
||||||
return enterInstructionData.iterator().fold(enterInstructionData) { result, (key, value) ->
|
return enterInstructionData.iterator().fold(enterInstructionData) { result, (key, value) ->
|
||||||
@@ -297,11 +297,11 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
|
|
||||||
// variable use
|
// variable use
|
||||||
|
|
||||||
val variableUseStatusData: Map<Instruction, Edges<ReadOnlyUseVariableControlFlowInfo>>
|
val variableUseStatusData: Map<Instruction, Edges<VariableUsageReadOnlyControlInfo>>
|
||||||
get() {
|
get() {
|
||||||
val edgesForTrivialVals = computeUseInfoForTrivialVals()
|
val edgesForTrivialVals = computeUseInfoForTrivialVals()
|
||||||
if (rootVariables.nonTrivialVariables.isEmpty()) {
|
if (rootVariables.nonTrivialVariables.isEmpty()) {
|
||||||
return hashMapOf<Instruction, Edges<ReadOnlyUseVariableControlFlowInfo>>().apply {
|
return hashMapOf<Instruction, Edges<VariableUsageReadOnlyControlInfo>>().apply {
|
||||||
pseudocode.traverse(TraversalOrder.FORWARD) { instruction ->
|
pseudocode.traverse(TraversalOrder.FORWARD) { instruction ->
|
||||||
put(instruction, edgesForTrivialVals)
|
put(instruction, edgesForTrivialVals)
|
||||||
}
|
}
|
||||||
@@ -310,13 +310,13 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
|
|
||||||
return pseudocodeVariableDataCollector.collectData(
|
return pseudocodeVariableDataCollector.collectData(
|
||||||
TraversalOrder.BACKWARD,
|
TraversalOrder.BACKWARD,
|
||||||
UseVariableControlFlowInfo()
|
UsageVariableControlFlowInfo()
|
||||||
) { instruction: Instruction, incomingEdgesData: Collection<UseVariableControlFlowInfo> ->
|
) { instruction: Instruction, incomingEdgesData: Collection<UsageVariableControlFlowInfo> ->
|
||||||
|
|
||||||
val enterResult: UseVariableControlFlowInfo = if (incomingEdgesData.size == 1) {
|
val enterResult: UsageVariableControlFlowInfo = if (incomingEdgesData.size == 1) {
|
||||||
incomingEdgesData.single()
|
incomingEdgesData.single()
|
||||||
} else {
|
} else {
|
||||||
incomingEdgesData.fold(UseVariableControlFlowInfo()) { result, edgeData ->
|
incomingEdgesData.fold(UsageVariableControlFlowInfo()) { result, edgeData ->
|
||||||
edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) ->
|
edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) ->
|
||||||
subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor)))
|
subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor)))
|
||||||
}
|
}
|
||||||
@@ -377,14 +377,14 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
|
|
||||||
private inner class ReadOnlyUseControlFlowInfoImpl(
|
private inner class ReadOnlyUseControlFlowInfoImpl(
|
||||||
val used: Set<VariableDescriptor>,
|
val used: Set<VariableDescriptor>,
|
||||||
val delegate: ReadOnlyUseVariableControlFlowInfo?
|
val delegate: VariableUsageReadOnlyControlInfo?
|
||||||
) : ReadOnlyUseVariableControlFlowInfo {
|
) : VariableUsageReadOnlyControlInfo {
|
||||||
override fun getOrNull(key: VariableDescriptor): VariableUseState? {
|
override fun getOrNull(key: VariableDescriptor): VariableUseState? {
|
||||||
if (key in used) return VariableUseState.READ
|
if (key in used) return VariableUseState.READ
|
||||||
return delegate?.getOrNull(key)
|
return delegate?.getOrNull(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun replaceDelegate(newDelegate: ReadOnlyUseVariableControlFlowInfo): ReadOnlyUseVariableControlFlowInfo =
|
fun replaceDelegate(newDelegate: VariableUsageReadOnlyControlInfo): VariableUsageReadOnlyControlInfo =
|
||||||
ReadOnlyUseControlFlowInfoImpl(used, newDelegate)
|
ReadOnlyUseControlFlowInfoImpl(used, newDelegate)
|
||||||
|
|
||||||
override fun asMap(): ImmutableMap<VariableDescriptor, VariableUseState> {
|
override fun asMap(): ImmutableMap<VariableDescriptor, VariableUseState> {
|
||||||
@@ -431,13 +431,13 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
return VariableControlFlowState.create(isInitialized = declaredOutsideThisDeclaration)
|
return VariableControlFlowState.create(isInitialized = declaredOutsideThisDeclaration)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val EMPTY_INIT_CONTROL_FLOW_INFO = InitVariableControlFlowInfo()
|
private val EMPTY_INIT_CONTROL_FLOW_INFO = VariableInitControlFlowInfo()
|
||||||
|
|
||||||
private fun mergeIncomingEdgesDataForInitializers(
|
private fun mergeIncomingEdgesDataForInitializers(
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
incomingEdgesData: Collection<InitVariableControlFlowInfo>,
|
incomingEdgesData: Collection<VariableInitControlFlowInfo>,
|
||||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||||
): InitVariableControlFlowInfo {
|
): VariableInitControlFlowInfo {
|
||||||
if (incomingEdgesData.size == 1) return incomingEdgesData.single()
|
if (incomingEdgesData.size == 1) return incomingEdgesData.single()
|
||||||
if (incomingEdgesData.isEmpty()) return EMPTY_INIT_CONTROL_FLOW_INFO
|
if (incomingEdgesData.isEmpty()) return EMPTY_INIT_CONTROL_FLOW_INFO
|
||||||
val variablesInScope = linkedSetOf<VariableDescriptor>()
|
val variablesInScope = linkedSetOf<VariableDescriptor>()
|
||||||
|
|||||||
+21
-12
@@ -8,26 +8,33 @@ package org.jetbrains.kotlin.cfg.variable
|
|||||||
import org.jetbrains.kotlin.cfg.ControlFlowInfo
|
import org.jetbrains.kotlin.cfg.ControlFlowInfo
|
||||||
import org.jetbrains.kotlin.cfg.ReadOnlyControlFlowInfo
|
import org.jetbrains.kotlin.cfg.ReadOnlyControlFlowInfo
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
|
import org.jetbrains.kotlin.util.javaslang.ImmutableHashMap
|
||||||
|
import org.jetbrains.kotlin.util.javaslang.ImmutableMap
|
||||||
import org.jetbrains.kotlin.util.javaslang.component1
|
import org.jetbrains.kotlin.util.javaslang.component1
|
||||||
import org.jetbrains.kotlin.util.javaslang.component2
|
import org.jetbrains.kotlin.util.javaslang.component2
|
||||||
|
|
||||||
interface ReadOnlyInitControlFlowInfo : ReadOnlyControlFlowInfo<VariableControlFlowState> {
|
typealias VariableUsageReadOnlyControlInfo = ReadOnlyControlFlowInfo<VariableDescriptor, VariableUseState>
|
||||||
fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean
|
typealias VariableUsageControlFlowInfo<S, D> = ControlFlowInfo<S, VariableDescriptor, D>
|
||||||
|
|
||||||
|
interface VariableInitReadOnlyControlFlowInfo :
|
||||||
|
ReadOnlyControlFlowInfo<VariableDescriptor, VariableControlFlowState> {
|
||||||
|
fun checkDefiniteInitializationInWhen(merge: VariableInitReadOnlyControlFlowInfo): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias ReadOnlyUseControlFlowInfo = ReadOnlyControlFlowInfo<VariableUseState>
|
class VariableInitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlFlowState> = ImmutableHashMap.empty()) :
|
||||||
|
VariableUsageControlFlowInfo<VariableInitControlFlowInfo, VariableControlFlowState>(map),
|
||||||
class InitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlFlowState> = ImmutableHashMap.empty()) :
|
VariableInitReadOnlyControlFlowInfo {
|
||||||
ControlFlowInfo<InitControlFlowInfo, VariableControlFlowState>(map), ReadOnlyInitControlFlowInfo {
|
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableControlFlowState>) =
|
||||||
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableControlFlowState>) = InitControlFlowInfo(newMap)
|
VariableInitControlFlowInfo(newMap)
|
||||||
|
|
||||||
// this = output of EXHAUSTIVE_WHEN_ELSE instruction
|
// this = output of EXHAUSTIVE_WHEN_ELSE instruction
|
||||||
// merge = input of MergeInstruction
|
// merge = input of MergeInstruction
|
||||||
// returns true if definite initialization in when happens here
|
// returns true if definite initialization in when happens here
|
||||||
override fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean {
|
override fun checkDefiniteInitializationInWhen(merge: VariableInitReadOnlyControlFlowInfo): Boolean {
|
||||||
for ((key, value) in iterator()) {
|
for ((key, value) in iterator()) {
|
||||||
if (value.initState == InitState.INITIALIZED_EXHAUSTIVELY &&
|
if (value.initState == InitState.INITIALIZED_EXHAUSTIVELY &&
|
||||||
merge.getOrNull(key)?.initState == InitState.INITIALIZED) {
|
merge.getOrNull(key)?.initState == InitState.INITIALIZED
|
||||||
|
) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,9 +42,11 @@ class InitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UseControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableUseState> = ImmutableHashMap.empty()) :
|
class UsageVariableControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableUseState> = ImmutableHashMap.empty()) :
|
||||||
ControlFlowInfo<UseControlFlowInfo, VariableUseState>(map), ReadOnlyUseControlFlowInfo {
|
VariableUsageControlFlowInfo<UsageVariableControlFlowInfo, VariableUseState>(map),
|
||||||
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableUseState>) = UseControlFlowInfo(newMap)
|
VariableUsageReadOnlyControlInfo {
|
||||||
|
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableUseState>) =
|
||||||
|
UsageVariableControlFlowInfo(newMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class InitState(private val s: String) {
|
enum class InitState(private val s: String) {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeImpl;
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction;
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction;
|
||||||
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.Edges;
|
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.Edges;
|
||||||
import org.jetbrains.kotlin.cfg.variable.PseudocodeVariablesData;
|
import org.jetbrains.kotlin.cfg.variable.PseudocodeVariablesData;
|
||||||
import org.jetbrains.kotlin.cfg.variable.ReadOnlyInitControlFlowInfo;
|
import org.jetbrains.kotlin.cfg.variable.VariableInitReadOnlyControlFlowInfo;
|
||||||
import org.jetbrains.kotlin.cfg.variable.VariableUseState;
|
import org.jetbrains.kotlin.cfg.variable.VariableUseState;
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor;
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor;
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
@@ -42,9 +42,9 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
|||||||
@NotNull BindingContext bindingContext
|
@NotNull BindingContext bindingContext
|
||||||
) {
|
) {
|
||||||
PseudocodeVariablesData pseudocodeVariablesData = new PseudocodeVariablesData(pseudocode.getRootPseudocode(), bindingContext);
|
PseudocodeVariablesData pseudocodeVariablesData = new PseudocodeVariablesData(pseudocode.getRootPseudocode(), bindingContext);
|
||||||
Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>> variableInitializers =
|
Map<Instruction, Edges<VariableInitReadOnlyControlFlowInfo>> variableInitializers =
|
||||||
pseudocodeVariablesData.getVariableInitializers();
|
pseudocodeVariablesData.getVariableInitializers();
|
||||||
Map<Instruction, Edges<ReadOnlyControlFlowInfo<VariableUseState>>> useStatusData =
|
Map<Instruction, Edges<ReadOnlyControlFlowInfo<VariableDescriptor, VariableUseState>>> useStatusData =
|
||||||
pseudocodeVariablesData.getVariableUseStatusData();
|
pseudocodeVariablesData.getVariableUseStatusData();
|
||||||
String initPrefix = " INIT:";
|
String initPrefix = " INIT:";
|
||||||
String usePrefix = " USE:";
|
String usePrefix = " USE:";
|
||||||
@@ -53,16 +53,16 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
|||||||
|
|
||||||
dumpInstructions(pseudocode, out, (instruction, next, prev) -> {
|
dumpInstructions(pseudocode, out, (instruction, next, prev) -> {
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
Edges<ReadOnlyInitControlFlowInfo> initializersEdges = variableInitializers.get(instruction);
|
Edges<VariableInitReadOnlyControlFlowInfo> initializersEdges = variableInitializers.get(instruction);
|
||||||
Edges<ReadOnlyInitControlFlowInfo> previousInitializersEdges = variableInitializers.get(prev);
|
Edges<VariableInitReadOnlyControlFlowInfo> previousInitializersEdges = variableInitializers.get(prev);
|
||||||
String initializersData = "";
|
String initializersData = "";
|
||||||
if (initializersEdges != null && !initializersEdges.equals(previousInitializersEdges)) {
|
if (initializersEdges != null && !initializersEdges.equals(previousInitializersEdges)) {
|
||||||
initializersData = dumpEdgesData(initPrefix, initializersEdges, pseudocodeVariablesData);
|
initializersData = dumpEdgesData(initPrefix, initializersEdges, pseudocodeVariablesData);
|
||||||
}
|
}
|
||||||
result.append(String.format("%1$-" + initializersColumnWidth + "s", initializersData));
|
result.append(String.format("%1$-" + initializersColumnWidth + "s", initializersData));
|
||||||
|
|
||||||
Edges<ReadOnlyControlFlowInfo<VariableUseState>> useStatusEdges = useStatusData.get(instruction);
|
Edges<ReadOnlyControlFlowInfo<VariableDescriptor, VariableUseState>> useStatusEdges = useStatusData.get(instruction);
|
||||||
Edges<ReadOnlyControlFlowInfo<VariableUseState>> nextUseStatusEdges = useStatusData.get(next);
|
Edges<ReadOnlyControlFlowInfo<VariableDescriptor, VariableUseState>> nextUseStatusEdges = useStatusData.get(next);
|
||||||
if (useStatusEdges != null && !useStatusEdges.equals(nextUseStatusEdges)) {
|
if (useStatusEdges != null && !useStatusEdges.equals(nextUseStatusEdges)) {
|
||||||
result.append(dumpEdgesData(usePrefix, useStatusEdges, pseudocodeVariablesData));
|
result.append(dumpEdgesData(usePrefix, useStatusEdges, pseudocodeVariablesData));
|
||||||
}
|
}
|
||||||
@@ -73,12 +73,12 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
|||||||
private static int countDataColumnWidth(
|
private static int countDataColumnWidth(
|
||||||
@NotNull String prefix,
|
@NotNull String prefix,
|
||||||
@NotNull List<Instruction> instructions,
|
@NotNull List<Instruction> instructions,
|
||||||
@NotNull Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>> data,
|
@NotNull Map<Instruction, Edges<VariableInitReadOnlyControlFlowInfo>> data,
|
||||||
@NotNull PseudocodeVariablesData variablesData
|
@NotNull PseudocodeVariablesData variablesData
|
||||||
) {
|
) {
|
||||||
int maxWidth = 0;
|
int maxWidth = 0;
|
||||||
for (Instruction instruction : instructions) {
|
for (Instruction instruction : instructions) {
|
||||||
Edges<ReadOnlyInitControlFlowInfo> edges = data.get(instruction);
|
Edges<VariableInitReadOnlyControlFlowInfo> edges = data.get(instruction);
|
||||||
if (edges == null) continue;
|
if (edges == null) continue;
|
||||||
int length = dumpEdgesData(prefix, edges, variablesData).length();
|
int length = dumpEdgesData(prefix, edges, variablesData).length();
|
||||||
if (maxWidth < length) {
|
if (maxWidth < length) {
|
||||||
@@ -90,7 +90,7 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static <S, I extends ReadOnlyControlFlowInfo<S>> String dumpEdgesData(
|
private static <S, I extends ReadOnlyControlFlowInfo<VariableDescriptor, S>> String dumpEdgesData(
|
||||||
String prefix,
|
String prefix,
|
||||||
@NotNull Edges<I> edges,
|
@NotNull Edges<I> edges,
|
||||||
@NotNull PseudocodeVariablesData variablesData
|
@NotNull PseudocodeVariablesData variablesData
|
||||||
|
|||||||
Reference in New Issue
Block a user