ControlFlowInfo introduced to store variable states, related refactoring

This commit is contained in:
Mikhail Glukhikh
2015-12-25 13:57:58 +03:00
committed by Mikhail Glukhikh
parent 0f3997c6ca
commit 52c3fb03a2
6 changed files with 144 additions and 134 deletions
@@ -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, ", ") + "}";