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