ControlFlowInfo introduced to store variable states, related refactoring
This commit is contained in:
committed by
Mikhail Glukhikh
parent
0f3997c6ca
commit
52c3fb03a2
@@ -16,6 +16,35 @@
|
||||
|
||||
package org.jetbrains.kotlin.cfg
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import java.util.*
|
||||
|
||||
open class ControlFlowInfo<D> internal constructor(protected val map: MutableMap<VariableDescriptor, D> = hashMapOf()) :
|
||||
MutableMap<VariableDescriptor, D> by map {
|
||||
open fun copy() = ControlFlowInfo(HashMap(map))
|
||||
|
||||
fun retainAll(predicate: (VariableDescriptor) -> Boolean): ControlFlowInfo<D> {
|
||||
map.keys.retainAll(predicate)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun equals(other: Any?) = map == (other as? ControlFlowInfo<*>)?.map
|
||||
|
||||
override fun hashCode() = map.hashCode()
|
||||
|
||||
override fun toString() = map.toString()
|
||||
}
|
||||
|
||||
class InitControlFlowInfo(map: MutableMap<VariableDescriptor, VariableControlFlowState> = hashMapOf()) :
|
||||
ControlFlowInfo<VariableControlFlowState>(map) {
|
||||
override fun copy() = InitControlFlowInfo(HashMap(map))
|
||||
}
|
||||
|
||||
class UseControlFlowInfo(map: MutableMap<VariableDescriptor, VariableUseState> = hashMapOf()) :
|
||||
ControlFlowInfo<VariableUseState>(map) {
|
||||
override fun copy() = UseControlFlowInfo(HashMap(map))
|
||||
}
|
||||
|
||||
enum class InitState(private val s: String) {
|
||||
// Definitely initialized
|
||||
INITIALIZED("I"),
|
||||
|
||||
@@ -301,7 +301,7 @@ public class ControlFlowInformationProvider {
|
||||
final boolean processClassOrObject = subroutine instanceof KtClassOrObject;
|
||||
|
||||
PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData();
|
||||
Map<Instruction, Edges<Map<VariableDescriptor, VariableControlFlowState>>> initializers =
|
||||
Map<Instruction, Edges<InitControlFlowInfo>> initializers =
|
||||
pseudocodeVariablesData.getVariableInitializers();
|
||||
final Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, true);
|
||||
final LexicalScopeVariableInfo lexicalScopeVariableInfo = pseudocodeVariablesData.getLexicalScopeVariableInfo();
|
||||
@@ -350,8 +350,7 @@ public class ControlFlowInformationProvider {
|
||||
public void recordInitializedVariables() {
|
||||
PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData();
|
||||
Pseudocode pseudocode = pseudocodeVariablesData.getPseudocode();
|
||||
Map<Instruction, Edges<Map<VariableDescriptor, VariableControlFlowState>>> initializers =
|
||||
pseudocodeVariablesData.getVariableInitializers();
|
||||
Map<Instruction, Edges<InitControlFlowInfo>> initializers = pseudocodeVariablesData.getVariableInitializers();
|
||||
recordInitializedVariables(pseudocode, initializers);
|
||||
for (LocalFunctionDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) {
|
||||
recordInitializedVariables(instruction.getBody(), initializers);
|
||||
@@ -517,9 +516,9 @@ public class ControlFlowInformationProvider {
|
||||
|
||||
private void recordInitializedVariables(
|
||||
@NotNull Pseudocode pseudocode,
|
||||
@NotNull Map<Instruction, Edges<Map<VariableDescriptor, VariableControlFlowState>>> initializersMap
|
||||
@NotNull Map<Instruction, Edges<InitControlFlowInfo>> initializersMap
|
||||
) {
|
||||
Edges<Map<VariableDescriptor, VariableControlFlowState>> initializers = initializersMap.get(pseudocode.getExitInstruction());
|
||||
Edges<InitControlFlowInfo> initializers = initializersMap.get(pseudocode.getExitInstruction());
|
||||
if (initializers == null) return;
|
||||
Set<VariableDescriptor> declaredVariables = getPseudocodeVariablesData().getDeclaredVariables(pseudocode, false);
|
||||
for (VariableDescriptor variable : declaredVariables) {
|
||||
@@ -536,8 +535,7 @@ public class ControlFlowInformationProvider {
|
||||
|
||||
public void markUnusedVariables() {
|
||||
final PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData();
|
||||
Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> variableStatusData =
|
||||
pseudocodeVariablesData.getVariableUseStatusData();
|
||||
Map<Instruction, Edges<UseControlFlowInfo>> variableStatusData = pseudocodeVariablesData.getVariableUseStatusData();
|
||||
final Map<Instruction, DiagnosticFactory<?>> reportedDiagnosticMap = Maps.newHashMap();
|
||||
InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseState>> variableStatusAnalyzeStrategy =
|
||||
new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseState>>() {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.cfg.pseudocodeTraverser
|
||||
|
||||
import org.jetbrains.kotlin.cfg.ControlFlowInfo
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.*
|
||||
import java.util.*
|
||||
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder.FORWARD
|
||||
@@ -54,16 +55,16 @@ public fun <D> Pseudocode.traverse(
|
||||
}
|
||||
}
|
||||
|
||||
public fun <D> Pseudocode.collectData(
|
||||
public fun <I : ControlFlowInfo<*>> Pseudocode.collectData(
|
||||
traversalOrder: TraversalOrder,
|
||||
mergeDataWithLocalDeclarations: Boolean,
|
||||
mergeEdges: (Instruction, Collection<D>) -> Edges<D>,
|
||||
updateEdge: (Instruction, Instruction, D) -> D,
|
||||
initialDataValue: D
|
||||
): Map<Instruction, Edges<D>> {
|
||||
val edgesMap = LinkedHashMap<Instruction, Edges<D>>()
|
||||
initializeEdgesMap(edgesMap, initialDataValue)
|
||||
edgesMap.put(getStartInstruction(traversalOrder), Edges(initialDataValue, initialDataValue))
|
||||
mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
|
||||
updateEdge: (Instruction, Instruction, I) -> I,
|
||||
initialInfo: I
|
||||
): Map<Instruction, Edges<I>> {
|
||||
val edgesMap = LinkedHashMap<Instruction, Edges<I>>()
|
||||
initializeEdgesMap(edgesMap, initialInfo)
|
||||
edgesMap.put(getStartInstruction(traversalOrder), Edges(initialInfo, initialInfo))
|
||||
|
||||
val changed = BooleanArray(1)
|
||||
changed[0] = true
|
||||
@@ -76,26 +77,26 @@ public fun <D> Pseudocode.collectData(
|
||||
return edgesMap
|
||||
}
|
||||
|
||||
private fun <D> Pseudocode.initializeEdgesMap(
|
||||
edgesMap: MutableMap<Instruction, Edges<D>>,
|
||||
initialDataValue: D
|
||||
private fun <I> Pseudocode.initializeEdgesMap(
|
||||
edgesMap: MutableMap<Instruction, Edges<I>>,
|
||||
initialInfo: I
|
||||
) {
|
||||
val instructions = getInstructions()
|
||||
val initialEdge = Edges(initialDataValue, initialDataValue)
|
||||
val initialEdge = Edges(initialInfo, initialInfo)
|
||||
for (instruction in instructions) {
|
||||
edgesMap.put(instruction, initialEdge)
|
||||
if (instruction is LocalFunctionDeclarationInstruction) {
|
||||
instruction.body.initializeEdgesMap(edgesMap, initialDataValue)
|
||||
instruction.body.initializeEdgesMap(edgesMap, initialInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D> Pseudocode.collectDataFromSubgraph(
|
||||
private fun <I : ControlFlowInfo<*>> Pseudocode.collectDataFromSubgraph(
|
||||
traversalOrder: TraversalOrder,
|
||||
mergeDataWithLocalDeclarations: Boolean,
|
||||
edgesMap: MutableMap<Instruction, Edges<D>>,
|
||||
mergeEdges: (Instruction, Collection<D>) -> Edges<D>,
|
||||
updateEdge: (Instruction, Instruction, D) -> D,
|
||||
edgesMap: MutableMap<Instruction, Edges<I>>,
|
||||
mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
|
||||
updateEdge: (Instruction, Instruction, I) -> I,
|
||||
previousSubGraphInstructions: Collection<Instruction>,
|
||||
changed: BooleanArray,
|
||||
isLocal: Boolean
|
||||
@@ -120,8 +121,8 @@ private fun <D> Pseudocode.collectDataFromSubgraph(
|
||||
val previousInstructions = getPreviousIncludingSubGraphInstructions()
|
||||
|
||||
fun updateEdgeDataForInstruction(
|
||||
previousValue: Edges<D>?,
|
||||
newValue: Edges<D>?
|
||||
previousValue: Edges<I>?,
|
||||
newValue: Edges<I>?
|
||||
) {
|
||||
if (previousValue != newValue && newValue != null) {
|
||||
changed[0] = true
|
||||
@@ -151,7 +152,7 @@ private fun <D> Pseudocode.collectDataFromSubgraph(
|
||||
}
|
||||
val previousDataValue = edgesMap.get(instruction)
|
||||
|
||||
val incomingEdgesData = HashSet<D>()
|
||||
val incomingEdgesData = HashSet<I>()
|
||||
|
||||
for (previousInstruction in previousInstructions) {
|
||||
val previousData = edgesMap.get(previousInstruction)
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
import java.util.HashMap
|
||||
|
||||
public class PseudocodeVariableDataCollector(
|
||||
@@ -36,40 +35,38 @@ public class PseudocodeVariableDataCollector(
|
||||
) {
|
||||
val lexicalScopeVariableInfo = computeLexicalScopeVariableInfo(pseudocode)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public fun <D> collectData(
|
||||
public fun <I : ControlFlowInfo<*>> collectData(
|
||||
traversalOrder: TraversalOrder,
|
||||
mergeDataWithLocalDeclarations: Boolean,
|
||||
instructionDataMergeStrategy: InstructionDataMergeStrategy<D>
|
||||
): MutableMap<Instruction, Edges<MutableMap<VariableDescriptor, D>>> {
|
||||
val result = pseudocode.collectData(
|
||||
initialInfo: I,
|
||||
instructionDataMergeStrategy: (Instruction, Collection<I>) -> Edges<I>
|
||||
): Map<Instruction, Edges<I>> {
|
||||
return pseudocode.collectData(
|
||||
traversalOrder, mergeDataWithLocalDeclarations,
|
||||
//see KT-4605
|
||||
instructionDataMergeStrategy as
|
||||
(Instruction, Collection<Map<VariableDescriptor, D>>) -> Edges<Map<VariableDescriptor, D>>,
|
||||
{ from, to, data -> filterOutVariablesOutOfScope(from, to, data)},
|
||||
Collections.emptyMap<VariableDescriptor, D>())
|
||||
//see KT-4605
|
||||
return result as MutableMap<Instruction, Edges<MutableMap<VariableDescriptor, D>>>
|
||||
instructionDataMergeStrategy,
|
||||
{ from, to, info -> filterOutVariablesOutOfScope(from, to, info) },
|
||||
initialInfo
|
||||
)
|
||||
}
|
||||
|
||||
private fun <D> filterOutVariablesOutOfScope(
|
||||
private fun <I : ControlFlowInfo<*>> filterOutVariablesOutOfScope(
|
||||
from: Instruction,
|
||||
to: Instruction,
|
||||
data: Map<VariableDescriptor, D>
|
||||
): Map<VariableDescriptor, D> {
|
||||
info: I
|
||||
): I {
|
||||
// If an edge goes from deeper lexical scope to a less deep one, this means that it points outside of the deeper scope.
|
||||
val toDepth = to.lexicalScope.depth
|
||||
if (toDepth >= from.lexicalScope.depth) return data
|
||||
if (toDepth >= from.lexicalScope.depth) return info
|
||||
|
||||
// Variables declared in an inner (deeper) scope can't be accessed from an outer scope.
|
||||
// Thus they can be filtered out upon leaving the inner scope.
|
||||
return data.filterKeys { variable ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return info.copy().retainAll { variable ->
|
||||
val lexicalScope = lexicalScopeVariableInfo.declaredIn[variable]
|
||||
// '-1' for variables declared outside this pseudocode
|
||||
val depth = lexicalScope?.depth ?: -1
|
||||
depth <= toDepth
|
||||
}
|
||||
} as I
|
||||
}
|
||||
|
||||
fun computeLexicalScopeVariableInfo(pseudocode: Pseudocode): LexicalScopeVariableInfo {
|
||||
@@ -96,10 +93,6 @@ public class PseudocodeVariableDataCollector(
|
||||
}
|
||||
}
|
||||
|
||||
//todo may be a type alias
|
||||
interface InstructionDataMergeStrategy<D> :
|
||||
(Instruction, Collection<MutableMap<VariableDescriptor, D>>) -> Edges<MutableMap<VariableDescriptor, D>>
|
||||
|
||||
public interface LexicalScopeVariableInfo {
|
||||
val declaredIn : Map<VariableDescriptor, LexicalScope>
|
||||
val scopeVariables : Map<LexicalScope, Collection<VariableDescriptor>>
|
||||
|
||||
@@ -21,10 +21,7 @@ import com.google.common.collect.Sets
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeUtil
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicInstruction
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.ReadValueInstruction
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.WriteValueInstruction
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.VariableDeclarationInstruction
|
||||
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.Edges
|
||||
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder
|
||||
@@ -38,7 +35,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
|
||||
private val declaredVariablesForDeclaration = Maps.newHashMap<Pseudocode, Set<VariableDescriptor>>()
|
||||
|
||||
val variableInitializers: MutableMap<Instruction, Edges<MutableMap<VariableDescriptor, VariableControlFlowState>>> by lazy {
|
||||
val variableInitializers: Map<Instruction, Edges<InitControlFlowInfo>> by lazy {
|
||||
computeVariableInitializers()
|
||||
}
|
||||
|
||||
@@ -64,7 +61,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
}
|
||||
|
||||
private fun getUpperLevelDeclaredVariables(pseudocode: Pseudocode): Set<VariableDescriptor> {
|
||||
var declaredVariables: Set<VariableDescriptor>? = declaredVariablesForDeclaration[pseudocode]
|
||||
var declaredVariables = declaredVariablesForDeclaration[pseudocode]
|
||||
if (declaredVariables == null) {
|
||||
declaredVariables = computeDeclaredVariablesForPseudocode(pseudocode)
|
||||
declaredVariablesForDeclaration.put(pseudocode, declaredVariables)
|
||||
@@ -89,34 +86,29 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
|
||||
// variable initializers
|
||||
|
||||
private fun computeVariableInitializers(): MutableMap<Instruction, Edges<MutableMap<VariableDescriptor, VariableControlFlowState>>> {
|
||||
private fun computeVariableInitializers(): Map<Instruction, Edges<InitControlFlowInfo>> {
|
||||
|
||||
val lexicalScopeVariableInfo = pseudocodeVariableDataCollector.lexicalScopeVariableInfo
|
||||
|
||||
return pseudocodeVariableDataCollector.collectData(
|
||||
TraversalOrder.FORWARD, /*mergeDataWithLocalDeclarations=*/ true,
|
||||
object : InstructionDataMergeStrategy<VariableControlFlowState> {
|
||||
override operator fun invoke(
|
||||
instruction: Instruction,
|
||||
incomingEdgesData: Collection<MutableMap<VariableDescriptor, VariableControlFlowState>>
|
||||
): Edges<MutableMap<VariableDescriptor, VariableControlFlowState>> {
|
||||
TraversalOrder.FORWARD, /*mergeDataWithLocalDeclarations=*/ true, InitControlFlowInfo()
|
||||
) {
|
||||
instruction: Instruction, incomingEdgesData: Collection<InitControlFlowInfo> ->
|
||||
|
||||
val enterInstructionData = mergeIncomingEdgesDataForInitializers(incomingEdgesData)
|
||||
val exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny(
|
||||
instruction, enterInstructionData, lexicalScopeVariableInfo)
|
||||
return Edges(enterInstructionData, exitInstructionData)
|
||||
}
|
||||
})
|
||||
val enterInstructionData = mergeIncomingEdgesDataForInitializers(incomingEdgesData)
|
||||
val exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny(
|
||||
instruction, enterInstructionData, lexicalScopeVariableInfo)
|
||||
Edges(enterInstructionData, exitInstructionData)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addVariableInitStateFromCurrentInstructionIfAny(
|
||||
instruction: Instruction,
|
||||
enterInstructionData: MutableMap<VariableDescriptor, VariableControlFlowState>,
|
||||
lexicalScopeVariableInfo: LexicalScopeVariableInfo
|
||||
): MutableMap<VariableDescriptor, VariableControlFlowState> {
|
||||
enterInstructionData: InitControlFlowInfo,
|
||||
lexicalScopeVariableInfo: LexicalScopeVariableInfo): InitControlFlowInfo {
|
||||
if (instruction is MagicInstruction) {
|
||||
if (instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
|
||||
val exitInstructionData = Maps.newHashMap(enterInstructionData)
|
||||
val exitInstructionData = enterInstructionData.copy()
|
||||
for (entry in enterInstructionData.entries) {
|
||||
if (!entry.value.definitelyInitialized()) {
|
||||
exitInstructionData.put(entry.key,
|
||||
@@ -130,7 +122,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
return enterInstructionData
|
||||
}
|
||||
val variable = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, bindingContext) ?: return enterInstructionData
|
||||
val exitInstructionData = Maps.newHashMap(enterInstructionData)
|
||||
val exitInstructionData = enterInstructionData.copy()
|
||||
if (instruction is WriteValueInstruction) {
|
||||
// if writing to already initialized object
|
||||
if (!PseudocodeUtil.isThisOrNoDispatchReceiver(instruction, bindingContext)) {
|
||||
@@ -158,48 +150,43 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
|
||||
// variable use
|
||||
|
||||
/*mergeDataWithLocalDeclarations=*///instruction instanceof WriteValueInstruction
|
||||
val variableUseStatusData: MutableMap<Instruction, Edges<MutableMap<VariableDescriptor, VariableUseState>>>
|
||||
val variableUseStatusData: Map<Instruction, Edges<UseControlFlowInfo>>
|
||||
get() = pseudocodeVariableDataCollector.collectData(
|
||||
TraversalOrder.BACKWARD, true,
|
||||
object : InstructionDataMergeStrategy<VariableUseState> {
|
||||
override operator fun invoke(
|
||||
instruction: Instruction,
|
||||
incomingEdgesData: Collection<MutableMap<VariableDescriptor, VariableUseState>>
|
||||
): Edges<MutableMap<VariableDescriptor, VariableUseState>> {
|
||||
|
||||
val enterResult = Maps.newHashMap<VariableDescriptor, VariableUseState>()
|
||||
for (edgeData in incomingEdgesData) {
|
||||
for (entry in edgeData.entries) {
|
||||
val variableDescriptor = entry.key
|
||||
val variableUseState = entry.value
|
||||
enterResult.put(variableDescriptor, variableUseState.merge(enterResult[variableDescriptor]))
|
||||
}
|
||||
}
|
||||
val variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(
|
||||
instruction, true, bindingContext)
|
||||
if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) {
|
||||
return Edges(enterResult, enterResult)
|
||||
}
|
||||
val exitResult = Maps.newHashMap(enterResult)
|
||||
if (instruction is ReadValueInstruction) {
|
||||
exitResult.put(variableDescriptor, VariableUseState.READ)
|
||||
}
|
||||
else {
|
||||
var variableUseState: VariableUseState? = enterResult[variableDescriptor]
|
||||
if (variableUseState == null) {
|
||||
variableUseState = VariableUseState.UNUSED
|
||||
}
|
||||
when (variableUseState) {
|
||||
VariableUseState.UNUSED, VariableUseState.ONLY_WRITTEN_NEVER_READ ->
|
||||
exitResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ)
|
||||
VariableUseState.WRITTEN_AFTER_READ, VariableUseState.READ ->
|
||||
exitResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ)
|
||||
}
|
||||
}
|
||||
return Edges(enterResult, exitResult)
|
||||
TraversalOrder.BACKWARD, true, UseControlFlowInfo()
|
||||
) {
|
||||
instruction: Instruction, incomingEdgesData: Collection<UseControlFlowInfo> ->
|
||||
val enterResult = UseControlFlowInfo()
|
||||
for (edgeData in incomingEdgesData) {
|
||||
for (entry in edgeData.entries) {
|
||||
val variableDescriptor = entry.key
|
||||
val variableUseState = entry.value
|
||||
enterResult.put(variableDescriptor, variableUseState.merge(enterResult[variableDescriptor]))
|
||||
}
|
||||
}
|
||||
val variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, bindingContext)
|
||||
if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) {
|
||||
Edges(enterResult, enterResult)
|
||||
}
|
||||
else {
|
||||
val exitResult = enterResult.copy()
|
||||
if (instruction is ReadValueInstruction) {
|
||||
exitResult.put(variableDescriptor, VariableUseState.READ)
|
||||
}
|
||||
else {
|
||||
var variableUseState: VariableUseState? = enterResult[variableDescriptor]
|
||||
if (variableUseState == null) {
|
||||
variableUseState = VariableUseState.UNUSED
|
||||
}
|
||||
})
|
||||
when (variableUseState) {
|
||||
VariableUseState.UNUSED, VariableUseState.ONLY_WRITTEN_NEVER_READ ->
|
||||
exitResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ)
|
||||
VariableUseState.WRITTEN_AFTER_READ, VariableUseState.READ ->
|
||||
exitResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ)
|
||||
}
|
||||
}
|
||||
Edges(enterResult, exitResult)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -207,30 +194,32 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
fun getDefaultValueForInitializers(
|
||||
variable: VariableDescriptor,
|
||||
instruction: Instruction,
|
||||
lexicalScopeVariableInfo: LexicalScopeVariableInfo): VariableControlFlowState {
|
||||
lexicalScopeVariableInfo: LexicalScopeVariableInfo
|
||||
): VariableControlFlowState {
|
||||
//todo: think of replacing it with "MapWithDefaultValue"
|
||||
val declaredIn = lexicalScopeVariableInfo.declaredIn[variable]
|
||||
val declaredOutsideThisDeclaration = declaredIn == null //declared outside this pseudocode
|
||||
|| declaredIn.lexicalScopeForContainingDeclaration != instruction.lexicalScope.lexicalScopeForContainingDeclaration
|
||||
val declaredOutsideThisDeclaration =
|
||||
declaredIn == null //declared outside this pseudocode
|
||||
|| declaredIn.lexicalScopeForContainingDeclaration != instruction.lexicalScope.lexicalScopeForContainingDeclaration
|
||||
return VariableControlFlowState.create(/*initState=*/declaredOutsideThisDeclaration)
|
||||
}
|
||||
|
||||
private fun mergeIncomingEdgesDataForInitializers(
|
||||
incomingEdgesData: Collection<MutableMap<VariableDescriptor, VariableControlFlowState>>
|
||||
): MutableMap<VariableDescriptor, VariableControlFlowState> {
|
||||
incomingEdgesData: Collection<InitControlFlowInfo>
|
||||
): InitControlFlowInfo {
|
||||
val variablesInScope = Sets.newHashSet<VariableDescriptor>()
|
||||
for (edgeData in incomingEdgesData) {
|
||||
variablesInScope.addAll(edgeData.keys)
|
||||
}
|
||||
|
||||
val enterInstructionData = Maps.newHashMap<VariableDescriptor, VariableControlFlowState>()
|
||||
val enterInstructionData = InitControlFlowInfo()
|
||||
for (variable in variablesInScope) {
|
||||
var initState: InitState? = null
|
||||
var isDeclared = true
|
||||
for (edgeData in incomingEdgesData) {
|
||||
val varControlFlowState = edgeData[variable]
|
||||
if (varControlFlowState != null) {
|
||||
initState = if (initState != null) initState.merge(varControlFlowState.initState) else varControlFlowState.initState
|
||||
initState = initState?.merge(varControlFlowState.initState) ?: varControlFlowState.initState
|
||||
if (!varControlFlowState.isDeclared) {
|
||||
isDeclared = false
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
||||
@NotNull BindingContext bindingContext
|
||||
) {
|
||||
PseudocodeVariablesData pseudocodeVariablesData = new PseudocodeVariablesData(pseudocode.getRootPseudocode(), bindingContext);
|
||||
final Map<Instruction, Edges<Map<VariableDescriptor, VariableControlFlowState>>> variableInitializers =
|
||||
final Map<Instruction, Edges<InitControlFlowInfo>> variableInitializers =
|
||||
pseudocodeVariablesData.getVariableInitializers();
|
||||
final Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> useStatusData =
|
||||
final Map<Instruction, Edges<UseControlFlowInfo>> useStatusData =
|
||||
pseudocodeVariablesData.getVariableUseStatusData();
|
||||
final String initPrefix = " INIT:";
|
||||
final String usePrefix = " USE:";
|
||||
@@ -51,16 +51,16 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
||||
@Override
|
||||
public String invoke(Instruction instruction, Instruction next, Instruction prev) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
Edges<Map<VariableDescriptor, VariableControlFlowState>> initializersEdges = variableInitializers.get(instruction);
|
||||
Edges<Map<VariableDescriptor, VariableControlFlowState>> previousInitializersEdges = variableInitializers.get(prev);
|
||||
Edges<InitControlFlowInfo> initializersEdges = variableInitializers.get(instruction);
|
||||
Edges<InitControlFlowInfo> previousInitializersEdges = variableInitializers.get(prev);
|
||||
String initializersData = "";
|
||||
if (initializersEdges != null && !initializersEdges.equals(previousInitializersEdges)) {
|
||||
initializersData = dumpEdgesData(initPrefix, initializersEdges);
|
||||
}
|
||||
result.append(String.format("%1$-" + initializersColumnWidth + "s", initializersData));
|
||||
|
||||
Edges<Map<VariableDescriptor, VariableUseState>> useStatusEdges = useStatusData.get(instruction);
|
||||
Edges<Map<VariableDescriptor, VariableUseState>> nextUseStatusEdges = useStatusData.get(next);
|
||||
Edges<UseControlFlowInfo> useStatusEdges = useStatusData.get(instruction);
|
||||
Edges<UseControlFlowInfo> nextUseStatusEdges = useStatusData.get(next);
|
||||
if (useStatusEdges != null && !useStatusEdges.equals(nextUseStatusEdges)) {
|
||||
result.append(dumpEdgesData(usePrefix, useStatusEdges));
|
||||
}
|
||||
@@ -72,11 +72,11 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
||||
private static int countDataColumnWidth(
|
||||
@NotNull String prefix,
|
||||
@NotNull List<Instruction> instructions,
|
||||
@NotNull Map<Instruction, Edges<Map<VariableDescriptor, VariableControlFlowState>>> data
|
||||
@NotNull Map<Instruction, Edges<InitControlFlowInfo>> data
|
||||
) {
|
||||
int maxWidth = 0;
|
||||
for (Instruction instruction : instructions) {
|
||||
Edges<Map<VariableDescriptor, VariableControlFlowState>> edges = data.get(instruction);
|
||||
Edges<InitControlFlowInfo> edges = data.get(instruction);
|
||||
if (edges == null) continue;
|
||||
int length = dumpEdgesData(prefix, edges).length();
|
||||
if (maxWidth < length) {
|
||||
@@ -87,18 +87,18 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <D> String dumpEdgesData(String prefix, @NotNull Edges<Map<VariableDescriptor, D>> edges) {
|
||||
private static <S, I extends ControlFlowInfo<S>> String dumpEdgesData(String prefix, @NotNull Edges<I> edges) {
|
||||
return prefix +
|
||||
" in: " + renderVariableMap(edges.getIncoming()) +
|
||||
" out: " + renderVariableMap(edges.getOutgoing());
|
||||
}
|
||||
|
||||
private static <D> String renderVariableMap(Map<VariableDescriptor, D> map) {
|
||||
private static <S> String renderVariableMap(Map<VariableDescriptor, S> map) {
|
||||
List<String> result = Lists.newArrayList();
|
||||
for (Map.Entry<VariableDescriptor, D> entry : map.entrySet()) {
|
||||
for (Map.Entry<VariableDescriptor, S> entry : map.entrySet()) {
|
||||
VariableDescriptor variable = entry.getKey();
|
||||
D data = entry.getValue();
|
||||
result.add(variable.getName() + "=" + data);
|
||||
S state = entry.getValue();
|
||||
result.add(variable.getName() + "=" + state);
|
||||
}
|
||||
Collections.sort(result);
|
||||
return "{" + StringUtil.join(result, ", ") + "}";
|
||||
|
||||
Reference in New Issue
Block a user