rewrote PseudocodeTraverser to kotlin

This commit is contained in:
Svetlana Isakova
2014-03-06 14:15:59 +04:00
parent 18eaf483d3
commit eed3dec539
7 changed files with 196 additions and 234 deletions
@@ -22,14 +22,17 @@ import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import kotlin.Function1;
import kotlin.Unit;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.Edges; import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.Edges;
import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.InstructionAnalyzeStrategy; import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.InstructionDataAnalyzeStrategy;
import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.InstructionDataAnalyzeStrategy; import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.PseudocodeTraverserPackage;
import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableInitState; import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableInitState;
import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState; import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState;
import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.cfg.pseudocode.*;
import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory; import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory;
@@ -51,9 +54,8 @@ import org.jetbrains.jet.plugin.MainFunctionDetector;
import java.util.*; import java.util.*;
import static org.jetbrains.jet.lang.cfg.PseudocodeTraverser.TraversalOrder.BACKWARD;
import static org.jetbrains.jet.lang.cfg.PseudocodeTraverser.TraversalOrder.FORWARD;
import static org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState.*; import static org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState.*;
import static org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder.FORWARD;
import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.calls.TailRecursionKind.*; import static org.jetbrains.jet.lang.resolve.calls.TailRecursionKind.*;
@@ -262,7 +264,9 @@ public class JetFlowInformationProvider {
final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap(); final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap();
PseudocodeTraverser.traverse(pseudocode, FORWARD, initializers, new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, PseudocodeVariablesData.VariableInitState>>() { PseudocodeTraverserPackage.traverse(
pseudocode, FORWARD, initializers,
new InstructionDataAnalyzeStrategyJ<Map<VariableDescriptor, PseudocodeVariablesData.VariableInitState>>() {
@Override @Override
public void execute(@NotNull Instruction instruction, public void execute(@NotNull Instruction instruction,
@Nullable Map<VariableDescriptor, VariableInitState> in, @Nullable Map<VariableDescriptor, VariableInitState> in,
@@ -497,7 +501,7 @@ public class JetFlowInformationProvider {
Set<VariableDescriptor> declaredVariables = getPseudocodeVariablesData().getDeclaredVariables(pseudocode, false); Set<VariableDescriptor> declaredVariables = getPseudocodeVariablesData().getDeclaredVariables(pseudocode, false);
for (VariableDescriptor variable : declaredVariables) { for (VariableDescriptor variable : declaredVariables) {
if (variable instanceof PropertyDescriptor) { if (variable instanceof PropertyDescriptor) {
PseudocodeVariablesData.VariableInitState variableInitState = initializers.in.get(variable); PseudocodeVariablesData.VariableInitState variableInitState = initializers.getIn().get(variable);
if (variableInitState == null) return; if (variableInitState == null) return;
trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, variableInitState.isInitialized); trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, variableInitState.isInitialized);
} }
@@ -512,7 +516,7 @@ public class JetFlowInformationProvider {
Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> variableStatusData = pseudocodeVariablesData.getVariableUseStatusData(); Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> variableStatusData = pseudocodeVariablesData.getVariableUseStatusData();
final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap(); final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap();
InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseState>> variableStatusAnalyzeStrategy = InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseState>> variableStatusAnalyzeStrategy =
new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, PseudocodeVariablesData.VariableUseState>>() { new InstructionDataAnalyzeStrategyJ<Map<VariableDescriptor, PseudocodeVariablesData.VariableUseState>>() {
@Override @Override
public void execute(@NotNull Instruction instruction, public void execute(@NotNull Instruction instruction,
@Nullable Map<VariableDescriptor, VariableUseState> in, @Nullable Map<VariableDescriptor, VariableUseState> in,
@@ -586,7 +590,7 @@ public class JetFlowInformationProvider {
} }
} }
}; };
PseudocodeTraverser.traverse(pseudocode, BACKWARD, variableStatusData, variableStatusAnalyzeStrategy); PseudocodeTraverserPackage.traverse(pseudocode, TraversalOrder.BACKWARD, variableStatusData, variableStatusAnalyzeStrategy);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -594,8 +598,8 @@ public class JetFlowInformationProvider {
public void markUnusedLiteralsInBlock() { public void markUnusedLiteralsInBlock() {
final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap(); final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap();
PseudocodeTraverser.traverse( PseudocodeTraverserPackage.traverse(
pseudocode, FORWARD, new InstructionAnalyzeStrategy() { pseudocode, FORWARD, new FunctionVoid1<Instruction>() {
@Override @Override
public void execute(@NotNull Instruction instruction) { public void execute(@NotNull Instruction instruction) {
if (!(instruction instanceof ReadValueInstruction)) return; if (!(instruction instanceof ReadValueInstruction)) return;
@@ -642,11 +646,10 @@ public class JetFlowInformationProvider {
} }
} }
final Map<JetElement, KindAndCall> calls = new HashMap<JetElement, KindAndCall>(); final Map<JetElement, KindAndCall> calls = new HashMap<JetElement, KindAndCall>();
PseudocodeTraverser.traverse( PseudocodeTraverserPackage.traverse(
pseudocode, pseudocode,
FORWARD, FORWARD,
new InstructionAnalyzeStrategy() { new FunctionVoid1<Instruction>() {
@Override
public void execute(@NotNull Instruction instruction) { public void execute(@NotNull Instruction instruction) {
if (!(instruction instanceof CallInstruction)) return; if (!(instruction instanceof CallInstruction)) return;
CallInstruction callInstruction = (CallInstruction) instruction; CallInstruction callInstruction = (CallInstruction) instruction;
@@ -672,7 +675,7 @@ public class JetFlowInformationProvider {
return; return;
} }
boolean isTail = PseudocodeTraverser.traverseFollowingInstructions( boolean isTail = PseudocodeTraverserPackage.traverseFollowingInstructions(
callInstruction, callInstruction,
new HashSet<Instruction>(), new HashSet<Instruction>(),
FORWARD, FORWARD,
@@ -879,4 +882,25 @@ public class JetFlowInformationProvider {
exitUseState = variableDescriptor != null ? out.get(variableDescriptor) : null; exitUseState = variableDescriptor != null ? out.get(variableDescriptor) : null;
} }
} }
//TODO after KT-4621 rewrite to Kotlin
public abstract static class InstructionDataAnalyzeStrategyJ<D> implements InstructionDataAnalyzeStrategy<D> {
@Override
public Unit invoke(Instruction instruction, D enterData, D exitData) {
execute(instruction, enterData, exitData);
return Unit.VALUE;
}
public abstract void execute(Instruction instruction, D enterData, D exitData);
}
public abstract static class FunctionVoid1<P> implements Function1<P, Unit> {
@Override
public Unit invoke(P p) {
execute(p);
return Unit.VALUE;
}
public abstract void execute(P p);
}
} }
@@ -14,172 +14,107 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.jet.lang.cfg; package org.jetbrains.jet.lang.cfg.pseudocodeTraverser
import com.google.common.collect.Lists; import org.jetbrains.jet.lang.cfg.pseudocode.*
import com.google.common.collect.Maps; import java.util.*
import com.google.common.collect.Queues; import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder.FORWARD
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.pseudocode.*;
import java.util.*;
import static org.jetbrains.jet.lang.cfg.PseudocodeTraverser.TraversalOrder.FORWARD;
public class PseudocodeTraverser {
public static enum TraversalOrder {
FORWARD,
BACKWARD
}
@NotNull
/*package*/ static Instruction getStartInstruction(@NotNull Pseudocode pseudocode, @NotNull TraversalOrder traversalOrder) {
return traversalOrder == FORWARD ? pseudocode.getEnterInstruction() : pseudocode.getSinkInstruction();
}
@NotNull
/*package*/ static Instruction getLastInstruction(@NotNull Pseudocode pseudocode, @NotNull TraversalOrder traversalOrder) {
return traversalOrder == FORWARD ? pseudocode.getSinkInstruction() : pseudocode.getEnterInstruction();
}
@NotNull
/*package*/ static List<Instruction> getInstructions(@NotNull Pseudocode pseudocode, @NotNull TraversalOrder traversalOrder) {
return traversalOrder == FORWARD ? pseudocode.getInstructions() : pseudocode.getReversedInstructions();
}
@NotNull
/*packge*/ static Collection<Instruction> getPreviousInstruction(@NotNull Instruction instruction, @NotNull TraversalOrder traversalOrder) {
return traversalOrder == FORWARD ? instruction.getPreviousInstructions() : instruction.getNextInstructions();
}
/*package*/ static boolean isStartInstruction(@NotNull Instruction instruction, @NotNull TraversalOrder traversalOrder) {
return traversalOrder == FORWARD ? instruction instanceof SubroutineEnterInstruction
: instruction instanceof SubroutineSinkInstruction;
}
public static enum LookInsideStrategy {
ANALYSE_LOCAL_DECLARATIONS,
SKIP_LOCAL_DECLARATIONS
}
public static boolean shouldLookInside(Instruction instruction, LookInsideStrategy lookInside) {
return lookInside == LookInsideStrategy.ANALYSE_LOCAL_DECLARATIONS && instruction instanceof LocalFunctionDeclarationInstruction;
}
public static void traverse( enum class TraversalOrder {
@NotNull Pseudocode pseudocode, FORWARD
@NotNull TraversalOrder traversalOrder, BACKWARD
@NotNull InstructionAnalyzeStrategy instructionAnalyzeStrategy }
) {
List<Instruction> instructions = getInstructions(pseudocode, traversalOrder); fun Pseudocode.getStartInstruction(traversalOrder: TraversalOrder): Instruction =
for (Instruction instruction : instructions) { if (traversalOrder == FORWARD) getEnterInstruction() else getSinkInstruction()
if (instruction instanceof LocalFunctionDeclarationInstruction) {
traverse(((LocalFunctionDeclarationInstruction) instruction).getBody(), traversalOrder, instructionAnalyzeStrategy); fun Pseudocode.getLastInstruction(traversalOrder: TraversalOrder): Instruction =
} if (traversalOrder == FORWARD) getSinkInstruction() else getEnterInstruction()
instructionAnalyzeStrategy.execute(instruction);
} fun Pseudocode.getInstructions(traversalOrder: TraversalOrder): MutableList<Instruction> =
} if (traversalOrder == FORWARD) getInstructions() else getReversedInstructions()
public static <D> void traverse( fun Instruction.getNextInstructions(traversalOrder: TraversalOrder): Collection<Instruction> =
@NotNull Pseudocode pseudocode, TraversalOrder traversalOrder, if (traversalOrder == FORWARD) getNextInstructions() else getPreviousInstructions()
@NotNull Map<Instruction, Edges<D>> edgesMap,
@NotNull InstructionDataAnalyzeStrategy<D> instructionDataAnalyzeStrategy) { fun Instruction.getPreviousInstructions(traversalOrder: TraversalOrder): Collection<Instruction> =
if (traversalOrder == FORWARD) getPreviousInstructions() else getNextInstructions()
List<Instruction> instructions = getInstructions(pseudocode, traversalOrder);
for (Instruction instruction : instructions) { fun Instruction.isStartInstruction(traversalOrder: TraversalOrder): Boolean =
if (instruction instanceof LocalFunctionDeclarationInstruction) { if (traversalOrder == FORWARD) this is SubroutineEnterInstruction else this is SubroutineSinkInstruction
traverse(((LocalFunctionDeclarationInstruction) instruction).getBody(), traversalOrder, edgesMap,
instructionDataAnalyzeStrategy); enum class LookInsideStrategy {
} ANALYSE_LOCAL_DECLARATIONS
Edges<D> edges = edgesMap.get(instruction); SKIP_LOCAL_DECLARATIONS
instructionDataAnalyzeStrategy.execute(instruction, edges != null ? edges.in : null, edges != null ? edges.out : null); }
}
} fun Instruction.shouldLookInside(lookInside: LookInsideStrategy): Boolean =
lookInside == LookInsideStrategy.ANALYSE_LOCAL_DECLARATIONS && this is LocalFunctionDeclarationInstruction
public interface InstructionDataMergeStrategy<D> {
@NotNull
Edges<D> execute(@NotNull Instruction instruction, @NotNull Collection<D> incomingEdgesData); fun Pseudocode.traverse(
} traversalOrder: TraversalOrder,
analyzeInstruction: (Instruction) -> Unit
public interface InstructionDataAnalyzeStrategy<D> { ) {
void execute(@NotNull Instruction instruction, @Nullable D enterData, @Nullable D exitData); val instructions = getInstructions(traversalOrder)
} for (instruction in instructions) {
if (instruction is LocalFunctionDeclarationInstruction) {
public interface InstructionAnalyzeStrategy { instruction.getBody().traverse(traversalOrder, analyzeInstruction)
void execute(@NotNull Instruction instruction); }
} analyzeInstruction(instruction)
}
public static class Edges<T> { }
@NotNull
public final T in; fun <D> Pseudocode.traverse(
@NotNull traversalOrder: TraversalOrder,
public final T out; edgesMap: Map<Instruction, Edges<D>>,
instructionDataAnalyzeStrategy: InstructionDataAnalyzeStrategy<D>
Edges(@NotNull T in, @NotNull T out) { ) {
this.in = in; val instructions = getInstructions(traversalOrder)
this.out = out; for (instruction in instructions) {
} if (instruction is LocalFunctionDeclarationInstruction) {
instruction.getBody().traverse(traversalOrder, edgesMap, instructionDataAnalyzeStrategy)
@NotNull }
public static <T> Edges<T> create(@NotNull T in, @NotNull T out) { val edges = edgesMap.get(instruction)
return new Edges<T>(in, out); if (edges != null) {
} instructionDataAnalyzeStrategy(instruction, edges.`in`, edges.out)
}
@Override }
public boolean equals(Object o) { }
if (this == o) return true;
if (!(o instanceof Edges)) return false; trait InstructionDataMergeStrategy<D> : (Instruction, Collection<D>) -> Edges<D>
trait InstructionDataAnalyzeStrategy<D> : (Instruction, D, D) -> Unit
Edges edges = (Edges) o;
data class Edges<T>(val `in`: T, val out: T)
if (in != null ? !in.equals(edges.in) : edges.in != null) return false; fun <T> createEdges(`in`: T, out: T) = Edges(`in`, out)
if (out != null ? !out.equals(edges.out) : edges.out != null) return false;
return true; // returns false when interrupted by handler
} fun traverseFollowingInstructions(
rootInstruction: Instruction,
@Override visited: MutableSet<Instruction>,
public int hashCode() { order: TraversalOrder,
int result = in != null ? in.hashCode() : 0; // true to continue traversal
result = 31 * result + (out != null ? out.hashCode() : 0); handler: ((Instruction)->Boolean)?
return result; ): Boolean {
} val stack = ArrayDeque<Instruction>()
} stack.push(rootInstruction)
public interface InstructionHandler { while (!stack.isEmpty()) {
// true to continue traversal val instruction = stack.pop()
boolean handle(@NotNull Instruction instruction); visited.add(instruction)
}
val followingInstructions = instruction.getNextInstructions(order)
// returns false when interrupted by handler
public static boolean traverseFollowingInstructions( for (followingInstruction in followingInstructions) {
@NotNull Instruction rootInstruction, if (!visited.contains(followingInstruction)) {
@NotNull Set<Instruction> visited, if (handler != null && !handler(instruction)) {
@NotNull TraversalOrder order, return false
@Nullable InstructionHandler handler }
) { stack.push(followingInstruction)
Deque<Instruction> stack = Queues.newArrayDeque(); }
stack.push(rootInstruction); }
}
while (!stack.isEmpty()) { return true
Instruction instruction = stack.pop();
visited.add(instruction);
Collection<Instruction> followingInstructions =
order == FORWARD ? instruction.getNextInstructions() : instruction.getPreviousInstructions();
for (Instruction followingInstruction : followingInstructions) {
if (followingInstruction != null && !visited.contains(followingInstruction)) {
if (handler != null && !handler.handle(instruction)) return false;
stack.push(followingInstruction);
}
}
}
return true;
}
} }
@@ -21,7 +21,7 @@ import org.jetbrains.jet.lang.cfg.pseudocode.LocalFunctionDeclarationInstruction
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode
import org.jetbrains.jet.lang.descriptors.VariableDescriptor import org.jetbrains.jet.lang.descriptors.VariableDescriptor
import org.jetbrains.jet.lang.resolve.BindingContext import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.* import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.*
import org.jetbrains.jet.lang.cfg.pseudocode.LexicalScope import org.jetbrains.jet.lang.cfg.pseudocode.LexicalScope
import org.jetbrains.jet.lang.cfg.pseudocode.VariableDeclarationInstruction import org.jetbrains.jet.lang.cfg.pseudocode.VariableDeclarationInstruction
import org.jetbrains.jet.utils.addToStdlib.* import org.jetbrains.jet.utils.addToStdlib.*
@@ -54,8 +54,7 @@ public class PseudocodeVariableDataCollector(
val initialDataValue : Map<VariableDescriptor, D> = Collections.emptyMap<VariableDescriptor, D>() val initialDataValue : Map<VariableDescriptor, D> = Collections.emptyMap<VariableDescriptor, D>()
val edgesMap = LinkedHashMap<Instruction, Edges<Map<VariableDescriptor, D>>>() val edgesMap = LinkedHashMap<Instruction, Edges<Map<VariableDescriptor, D>>>()
initializeEdgesMap(pseudocode, edgesMap, initialDataValue) initializeEdgesMap(pseudocode, edgesMap, initialDataValue)
edgesMap.put(getStartInstruction(pseudocode, traversalOrder), edgesMap.put(pseudocode.getStartInstruction(traversalOrder), Edges(initialDataValue, initialDataValue))
Edges.create(initialDataValue, initialDataValue))
val changed = BooleanArray(1) val changed = BooleanArray(1)
changed[0] = true changed[0] = true
@@ -74,11 +73,11 @@ public class PseudocodeVariableDataCollector(
initialDataValue: M initialDataValue: M
) { ) {
val instructions = pseudocode.getInstructions() val instructions = pseudocode.getInstructions()
val initialEdge = Edges.create(initialDataValue, initialDataValue) val initialEdge = Edges(initialDataValue, initialDataValue)
for (instruction in instructions) { for (instruction in instructions) {
edgesMap.put(instruction, initialEdge) edgesMap.put(instruction, initialEdge)
if (PseudocodeTraverser.shouldLookInside(instruction, LookInsideStrategy.ANALYSE_LOCAL_DECLARATIONS)) { if (instruction.shouldLookInside(LookInsideStrategy.ANALYSE_LOCAL_DECLARATIONS)) {
initializeEdgesMap(((instruction as LocalFunctionDeclarationInstruction)).getBody(), edgesMap, initialDataValue) initializeEdgesMap((instruction as LocalFunctionDeclarationInstruction).getBody(), edgesMap, initialDataValue)
} }
} }
} }
@@ -93,24 +92,24 @@ public class PseudocodeVariableDataCollector(
changed: BooleanArray, changed: BooleanArray,
isLocal: Boolean isLocal: Boolean
) { ) {
val instructions = getInstructions(pseudocode, traversalOrder) val instructions = pseudocode.getInstructions(traversalOrder)
val startInstruction = getStartInstruction(pseudocode, traversalOrder) val startInstruction = pseudocode.getStartInstruction(traversalOrder)
for (instruction in instructions) { for (instruction in instructions) {
val isStart = isStartInstruction(instruction, traversalOrder) val isStart = instruction.isStartInstruction(traversalOrder)
if (!isLocal && isStart) if (!isLocal && isStart)
continue continue
val allPreviousInstructions: MutableCollection<Instruction> fun getPreviousIncludingSubGraphInstructions(): Collection<Instruction> {
val previousInstructions = getPreviousInstruction(instruction, traversalOrder) val previous = instruction.getPreviousInstructions(traversalOrder)
if (instruction != startInstruction || previousSubGraphInstructions.isEmpty()) {
if (instruction == startInstruction && !previousSubGraphInstructions.isEmpty()) { return previous
allPreviousInstructions = ArrayList(previousInstructions) }
allPreviousInstructions.addAll(previousSubGraphInstructions) val result = ArrayList(previous)
} result.addAll(previousSubGraphInstructions)
else { return result
allPreviousInstructions = previousInstructions
} }
val previousInstructions = getPreviousIncludingSubGraphInstructions()
fun updateEdgeDataForInstruction( fun updateEdgeDataForInstruction(
previousValue: Edges<Map<VariableDescriptor, D>>?, previousValue: Edges<Map<VariableDescriptor, D>>?,
@@ -122,19 +121,18 @@ public class PseudocodeVariableDataCollector(
} }
} }
if (shouldLookInside(instruction, lookInside)) { if (instruction.shouldLookInside(lookInside)) {
val functionInstruction = (instruction as LocalFunctionDeclarationInstruction) val functionInstruction = (instruction as LocalFunctionDeclarationInstruction)
val subroutinePseudocode = functionInstruction.getBody() val subroutinePseudocode = functionInstruction.getBody()
collectDataFromSubgraph( collectDataFromSubgraph(
subroutinePseudocode, traversalOrder, lookInside, edgesMap, instructionDataMergeStrategy, subroutinePseudocode, traversalOrder, lookInside, edgesMap, instructionDataMergeStrategy,
previousInstructions, changed, true) previousInstructions, changed, true)
val lastInstruction = getLastInstruction(subroutinePseudocode, traversalOrder) val lastInstruction = subroutinePseudocode.getLastInstruction(traversalOrder)
val previousValue = edgesMap.get(instruction) val previousValue = edgesMap.get(instruction)
val newValue = edgesMap.get(lastInstruction) val newValue = edgesMap.get(lastInstruction)
val updatedValue = if (newValue == null) null else val updatedValue = if (newValue == null) null else
Edges.create( Edges(filterOutVariablesOutOfScope(lastInstruction, instruction, newValue.`in`),
filterOutVariablesOutOfScope(lastInstruction, instruction, newValue.`in`), filterOutVariablesOutOfScope(lastInstruction, instruction, newValue.out))
filterOutVariablesOutOfScope(lastInstruction, instruction, newValue.out))
updateEdgeDataForInstruction(previousValue, updatedValue) updateEdgeDataForInstruction(previousValue, updatedValue)
continue continue
} }
@@ -142,14 +140,14 @@ public class PseudocodeVariableDataCollector(
val incomingEdgesData = HashSet<Map<VariableDescriptor, D>>() val incomingEdgesData = HashSet<Map<VariableDescriptor, D>>()
for (previousInstruction in allPreviousInstructions) { for (previousInstruction in previousInstructions) {
val previousData = edgesMap.get(previousInstruction) val previousData = edgesMap.get(previousInstruction)
if (previousData != null) { if (previousData != null) {
incomingEdgesData.add(filterOutVariablesOutOfScope( incomingEdgesData.add(filterOutVariablesOutOfScope(
previousInstruction, instruction, previousData.out)) previousInstruction, instruction, previousData.out))
} }
} }
val mergedData = instructionDataMergeStrategy.execute(instruction, incomingEdgesData) val mergedData = instructionDataMergeStrategy(instruction, incomingEdgesData)
updateEdgeDataForInstruction(previousDataValue, mergedData) updateEdgeDataForInstruction(previousDataValue, mergedData)
} }
} }
@@ -175,7 +173,7 @@ public class PseudocodeVariableDataCollector(
fun computeLexicalScopeVariableInfo(pseudocode: Pseudocode): LexicalScopeVariableInfo { fun computeLexicalScopeVariableInfo(pseudocode: Pseudocode): LexicalScopeVariableInfo {
val lexicalScopeVariableInfo = LexicalScopeVariableInfoImpl() val lexicalScopeVariableInfo = LexicalScopeVariableInfoImpl()
PseudocodeTraverser.traverse(pseudocode, TraversalOrder.FORWARD, { instruction -> pseudocode.traverse(TraversalOrder.FORWARD, { instruction ->
if (instruction is VariableDeclarationInstruction) { if (instruction is VariableDeclarationInstruction) {
val variableDeclarationElement = instruction.getVariableDeclarationElement() val variableDeclarationElement = instruction.getVariableDeclarationElement()
val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement) val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement)
@@ -18,11 +18,13 @@ package org.jetbrains.jet.lang.cfg;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import kotlin.Function1;
import kotlin.Unit;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.Edges; import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.Edges;
import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.InstructionAnalyzeStrategy; import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.InstructionDataMergeStrategy;
import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.InstructionDataMergeStrategy; import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.PseudocodeTraverserPackage;
import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.cfg.pseudocode.*;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
@@ -35,8 +37,9 @@ import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.jetbrains.jet.lang.cfg.PseudocodeTraverser.TraversalOrder.BACKWARD; import static org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder.BACKWARD;
import static org.jetbrains.jet.lang.cfg.PseudocodeTraverser.TraversalOrder.FORWARD; import static org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder.FORWARD;
import static org.jetbrains.jet.lang.cfg.pseudocodeTraverser.PseudocodeTraverserPackage.createEdges;
public class PseudocodeVariablesData { public class PseudocodeVariablesData {
private final Pseudocode pseudocode; private final Pseudocode pseudocode;
@@ -64,14 +67,15 @@ public class PseudocodeVariablesData {
Set<VariableDescriptor> usedVariables = usedVariablesForDeclaration.get(pseudocode); Set<VariableDescriptor> usedVariables = usedVariablesForDeclaration.get(pseudocode);
if (usedVariables == null) { if (usedVariables == null) {
final Set<VariableDescriptor> result = Sets.newHashSet(); final Set<VariableDescriptor> result = Sets.newHashSet();
PseudocodeTraverser.traverse(pseudocode, FORWARD, new InstructionAnalyzeStrategy() { PseudocodeTraverserPackage.traverse(pseudocode, FORWARD, new Function1<Instruction, Unit>() {
@Override @Override
public void execute(@NotNull Instruction instruction) { public Unit invoke(@NotNull Instruction instruction) {
VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(
bindingContext); instruction, false, bindingContext);
if (variableDescriptor != null) { if (variableDescriptor != null) {
result.add(variableDescriptor); result.add(variableDescriptor);
} }
return Unit.VALUE;
} }
}); });
usedVariables = Collections.unmodifiableSet(result); usedVariables = Collections.unmodifiableSet(result);
@@ -142,16 +146,16 @@ public class PseudocodeVariablesData {
new InstructionDataMergeStrategy<Map<VariableDescriptor, VariableInitState>>() { new InstructionDataMergeStrategy<Map<VariableDescriptor, VariableInitState>>() {
@NotNull @NotNull
@Override @Override
public Edges<Map<VariableDescriptor, VariableInitState>> execute( public Edges<Map<VariableDescriptor, VariableInitState>> invoke(
@NotNull Instruction instruction, @NotNull Instruction instruction,
@NotNull Collection<Map<VariableDescriptor, VariableInitState>> incomingEdgesData @NotNull Collection<? extends Map<VariableDescriptor, VariableInitState>> incomingEdgesData
) { ) {
Map<VariableDescriptor, VariableInitState> enterInstructionData = Map<VariableDescriptor, VariableInitState> enterInstructionData =
mergeIncomingEdgesDataForInitializers(incomingEdgesData); mergeIncomingEdgesDataForInitializers(incomingEdgesData);
Map<VariableDescriptor, VariableInitState> exitInstructionData = Map<VariableDescriptor, VariableInitState> exitInstructionData =
addVariableInitStateFromCurrentInstructionIfAny(instruction, enterInstructionData, declaredVariables); addVariableInitStateFromCurrentInstructionIfAny(instruction, enterInstructionData, declaredVariables);
return Edges.create(enterInstructionData, exitInstructionData); return createEdges(enterInstructionData, exitInstructionData);
} }
} }
); );
@@ -168,7 +172,7 @@ public class PseudocodeVariablesData {
@NotNull @NotNull
private static Map<VariableDescriptor, VariableInitState> mergeIncomingEdgesDataForInitializers( private static Map<VariableDescriptor, VariableInitState> mergeIncomingEdgesDataForInitializers(
@NotNull Collection<Map<VariableDescriptor, VariableInitState>> incomingEdgesData @NotNull Collection<? extends Map<VariableDescriptor, VariableInitState>> incomingEdgesData
) { ) {
Set<VariableDescriptor> variablesInScope = Sets.newHashSet(); Set<VariableDescriptor> variablesInScope = Sets.newHashSet();
for (Map<VariableDescriptor, VariableInitState> edgeData : incomingEdgesData) { for (Map<VariableDescriptor, VariableInitState> edgeData : incomingEdgesData) {
@@ -238,9 +242,9 @@ public class PseudocodeVariablesData {
new InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseState>>() { new InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseState>>() {
@NotNull @NotNull
@Override @Override
public Edges<Map<VariableDescriptor, VariableUseState>> execute( public Edges<Map<VariableDescriptor, VariableUseState>> invoke(
@NotNull Instruction instruction, @NotNull Instruction instruction,
@NotNull Collection<Map<VariableDescriptor, VariableUseState>> incomingEdgesData @NotNull Collection<? extends Map<VariableDescriptor, VariableUseState>> incomingEdgesData
) { ) {
Map<VariableDescriptor, VariableUseState> enterResult = Maps.newHashMap(); Map<VariableDescriptor, VariableUseState> enterResult = Maps.newHashMap();
@@ -255,7 +259,7 @@ public class PseudocodeVariablesData {
instruction, true, bindingContext); instruction, true, bindingContext);
if (variableDescriptor == null || if (variableDescriptor == null ||
(!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction))) { (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction))) {
return Edges.create(enterResult, enterResult); return createEdges(enterResult, enterResult);
} }
Map<VariableDescriptor, VariableUseState> exitResult = Maps.newHashMap(enterResult); Map<VariableDescriptor, VariableUseState> exitResult = Maps.newHashMap(enterResult);
if (instruction instanceof ReadValueInstruction) { if (instruction instanceof ReadValueInstruction) {
@@ -276,7 +280,7 @@ public class PseudocodeVariablesData {
exitResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ); exitResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ);
} }
} }
return Edges.create(enterResult, exitResult); return createEdges(enterResult, exitResult);
} }
} }
); );
@@ -16,11 +16,12 @@
package org.jetbrains.jet.lang.cfg; package org.jetbrains.jet.lang.cfg;
import kotlin.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.cfg.pseudocode.*;
import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetElement;
public class TailRecursionDetector extends InstructionVisitorWithResult<Boolean> implements PseudocodeTraverser.InstructionHandler { public class TailRecursionDetector extends InstructionVisitorWithResult<Boolean> implements Function1<Instruction, Boolean> {
private final JetElement subroutine; private final JetElement subroutine;
private final Instruction start; private final Instruction start;
@@ -30,7 +31,7 @@ public class TailRecursionDetector extends InstructionVisitorWithResult<Boolean>
} }
@Override @Override
public boolean handle(@NotNull Instruction instruction) { public Boolean invoke(@NotNull Instruction instruction) {
return instruction == start || instruction.accept(this); return instruction == start || instruction.accept(this);
} }
@@ -21,14 +21,14 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.Label; import org.jetbrains.jet.lang.cfg.Label;
import org.jetbrains.jet.lang.cfg.LoopInfo; import org.jetbrains.jet.lang.cfg.LoopInfo;
import org.jetbrains.jet.lang.cfg.PseudocodeTraverser; import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.PseudocodeTraverserPackage;
import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import java.util.*; import java.util.*;
import static org.jetbrains.jet.lang.cfg.PseudocodeTraverser.TraversalOrder.BACKWARD; import static org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder.BACKWARD;
import static org.jetbrains.jet.lang.cfg.PseudocodeTraverser.TraversalOrder.FORWARD; import static org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder.FORWARD;
public class PseudocodeImpl implements Pseudocode { public class PseudocodeImpl implements Pseudocode {
@@ -159,13 +159,13 @@ public class PseudocodeImpl implements Pseudocode {
@Override @Override
public List<Instruction> getReversedInstructions() { public List<Instruction> getReversedInstructions() {
LinkedHashSet<Instruction> traversedInstructions = Sets.newLinkedHashSet(); LinkedHashSet<Instruction> traversedInstructions = Sets.newLinkedHashSet();
PseudocodeTraverser.traverseFollowingInstructions(sinkInstruction, traversedInstructions, BACKWARD, null); PseudocodeTraverserPackage.traverseFollowingInstructions(sinkInstruction, traversedInstructions, BACKWARD, null);
if (traversedInstructions.size() < instructions.size()) { if (traversedInstructions.size() < instructions.size()) {
List<Instruction> simplyReversedInstructions = Lists.newArrayList(instructions); List<Instruction> simplyReversedInstructions = Lists.newArrayList(instructions);
Collections.reverse(simplyReversedInstructions); Collections.reverse(simplyReversedInstructions);
for (Instruction instruction : simplyReversedInstructions) { for (Instruction instruction : simplyReversedInstructions) {
if (!traversedInstructions.contains(instruction)) { if (!traversedInstructions.contains(instruction)) {
PseudocodeTraverser.traverseFollowingInstructions(instruction, traversedInstructions, BACKWARD, null); PseudocodeTraverserPackage.traverseFollowingInstructions(instruction, traversedInstructions, BACKWARD, null);
} }
} }
} }
@@ -338,7 +338,7 @@ public class PseudocodeImpl implements Pseudocode {
private Set<Instruction> collectReachableInstructions() { private Set<Instruction> collectReachableInstructions() {
Set<Instruction> visited = Sets.newHashSet(); Set<Instruction> visited = Sets.newHashSet();
PseudocodeTraverser.traverseFollowingInstructions(getEnterInstruction(), visited, FORWARD, null); PseudocodeTraverserPackage.traverseFollowingInstructions(getEnterInstruction(), visited, FORWARD, null);
if (!visited.contains(getExitInstruction())) { if (!visited.contains(getExitInstruction())) {
visited.add(getExitInstruction()); visited.add(getExitInstruction());
} }
@@ -30,7 +30,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static org.jetbrains.jet.lang.cfg.PseudocodeTraverser.Edges; import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.Edges;
import static org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableInitState; import static org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableInitState;
import static org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState; import static org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState;
@@ -93,8 +93,8 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
@NotNull @NotNull
private <D> String dumpEdgesData(String prefix, @NotNull Edges<Map<VariableDescriptor, D>> edges) { private <D> String dumpEdgesData(String prefix, @NotNull Edges<Map<VariableDescriptor, D>> edges) {
return prefix + return prefix +
" in: " + renderVariableMap(edges.in) + " in: " + renderVariableMap(edges.getIn()) +
" out: " + renderVariableMap(edges.out); " out: " + renderVariableMap(edges.getOut());
} }
private <D> String renderVariableMap(Map<VariableDescriptor, D> map) { private <D> String renderVariableMap(Map<VariableDescriptor, D> map) {