all traverse pseudocode methods made static

This commit is contained in:
Svetlana Isakova
2012-05-26 14:58:38 +04:00
parent d1d0722b5a
commit cdcedbe6ed
6 changed files with 206 additions and 161 deletions
@@ -38,6 +38,7 @@ import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.JetMainDetector; import org.jetbrains.jet.plugin.JetMainDetector;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -62,7 +63,7 @@ public class JetFlowInformationProvider {
subroutine = declaration; subroutine = declaration;
this.trace = trace; this.trace = trace;
pseudocode = new JetControlFlowProcessor(trace).generatePseudocode(declaration); pseudocode = new JetControlFlowProcessor(trace).generatePseudocode(declaration);
pseudocodeData = new PseudocodeData(pseudocode, trace); pseudocodeData = new PseudocodeData(pseudocode, trace.getBindingContext());
} }
private void collectReturnExpressions(@NotNull final Collection<JetElement> returnedExpressions) { private void collectReturnExpressions(@NotNull final Collection<JetElement> returnedExpressions) {
@@ -195,7 +196,7 @@ public class JetFlowInformationProvider {
VariableDescriptor variableDescriptor = pseudocodeData.extractVariableDescriptorIfAny(instruction, true); VariableDescriptor variableDescriptor = pseudocodeData.extractVariableDescriptorIfAny(instruction, true);
if (variableDescriptor == null) return; if (variableDescriptor == null) return;
if (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction)) return; if (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction)) return;
InstructionData.EdgesData<VariableInitializers> variableInitializers = instructionData.getInitializersMap().get( Edges<VariableInitializers> variableInitializers = instructionData.getInitializersMap().get(
variableDescriptor); variableDescriptor);
if (variableInitializers == null) return; if (variableInitializers == null) return;
if (instruction instanceof ReadValueInstruction) { if (instruction instanceof ReadValueInstruction) {
@@ -394,7 +395,7 @@ public class JetFlowInformationProvider {
private void recordInitializedVariables(DeclarationData declarationData, InstructionData instructionData) { private void recordInitializedVariables(DeclarationData declarationData, InstructionData instructionData) {
for (VariableDescriptor variable : declarationData.usedVariables) { for (VariableDescriptor variable : declarationData.usedVariables) {
if (variable instanceof PropertyDescriptor && declarationData.declaredVariables.contains(variable)) { if (variable instanceof PropertyDescriptor && declarationData.declaredVariables.contains(variable)) {
InstructionData.EdgesData<VariableInitializers> variableInitializers = instructionData.getInitializersMap().get(variable); Edges<VariableInitializers> variableInitializers = instructionData.getInitializersMap().get(variable);
if (variableInitializers == null) return; if (variableInitializers == null) return;
trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, variableInitializers.getIn().isInitialized()); trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, variableInitializers.getIn().isInitialized());
} }
@@ -411,7 +412,7 @@ public class JetFlowInformationProvider {
VariableDescriptor variableDescriptor = pseudocodeData.extractVariableDescriptorIfAny(instruction, false); VariableDescriptor variableDescriptor = pseudocodeData.extractVariableDescriptorIfAny(instruction, false);
if (variableDescriptor == null || !declarationData.declaredVariables.contains(variableDescriptor) || if (variableDescriptor == null || !declarationData.declaredVariables.contains(variableDescriptor) ||
!DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return; !DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return;
InstructionData.EdgesData<VariableUseStatus> statusEdgesData = instructionData.getUseStatusMap().get(variableDescriptor); Edges<VariableUseStatus> statusEdgesData = instructionData.getUseStatusMap().get(variableDescriptor);
VariableUseStatus variableUseStatus = statusEdgesData != null ? statusEdgesData.getIn() : null; VariableUseStatus variableUseStatus = statusEdgesData != null ? statusEdgesData.getIn() : null;
if (instruction instanceof WriteValueInstruction) { if (instruction instanceof WriteValueInstruction) {
if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor)) return; if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor)) return;
@@ -487,10 +488,9 @@ public class JetFlowInformationProvider {
public void markUnusedLiteralsInBlock() { public void markUnusedLiteralsInBlock() {
assert pseudocode != null; assert pseudocode != null;
JetControlFlowGraphTraverser<Void> traverser = JetControlFlowGraphTraverser.create(pseudocode, true, true); PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, true, new PseudocodeTraverser.SimpleInstructionDataAnalyzeStrategy() {
traverser.traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
@Override @Override
public void execute(@NotNull Instruction instruction, @Nullable Void enterData, @Nullable Void exitData) { public void execute(@NotNull Instruction instruction) {
if (!(instruction instanceof ReadValueInstruction)) return; if (!(instruction instanceof ReadValueInstruction)) return;
JetElement element = ((ReadValueInstruction) instruction).getElement(); JetElement element = ((ReadValueInstruction) instruction).getElement();
if (!(element instanceof JetFunctionLiteralExpression if (!(element instanceof JetFunctionLiteralExpression
@@ -19,79 +19,71 @@ package org.jetbrains.jet.lang.cfg;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
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 com.intellij.openapi.util.Pair;
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.data.Edges;
import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.cfg.pseudocode.*;
import java.util.*; import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/** /**
* @author svtk * @author svtk
*/ */
public class JetControlFlowGraphTraverser<D> { public class PseudocodeTraverser {
private final Pseudocode pseudocode;
private final boolean lookInside;
private final boolean directOrder;
private final Map<Instruction, Pair<D, D>> dataMap = Maps.newLinkedHashMap();
public static <D> JetControlFlowGraphTraverser<D> create(@NotNull Pseudocode pseudocode, boolean lookInside, boolean straightDirection) {
return new JetControlFlowGraphTraverser<D>(pseudocode, lookInside, straightDirection);
}
private JetControlFlowGraphTraverser(@NotNull Pseudocode pseudocode, boolean lookInside, boolean directOrder) {
this.pseudocode = pseudocode;
this.lookInside = lookInside;
this.directOrder = directOrder;
}
@NotNull @NotNull
private Instruction getStartInstruction(@NotNull Pseudocode pseudocode) { private static Instruction getStartInstruction(@NotNull Pseudocode pseudocode, boolean directOrder) {
return directOrder ? pseudocode.getEnterInstruction() : pseudocode.getSinkInstruction(); return directOrder ? pseudocode.getEnterInstruction() : pseudocode.getSinkInstruction();
} }
@NotNull public static <D> Map<Instruction, Edges<D>> collectInformationFromInstructionGraph(
public Map<Instruction, Pair<D, D>> getDataMap() { boolean lookInside,
return dataMap; boolean directOrder,
} @NotNull Pseudocode pseudocode,
public void collectInformationFromInstructionGraph(
@NotNull D initialDataValue, @NotNull D initialDataValue,
@NotNull D initialDataValueForEnterInstruction, @NotNull D initialDataValueForEnterInstruction,
@NotNull InstructionDataMergeStrategy<D> instructionDataMergeStrategy) { @NotNull InstructionDataMergeStrategy<D> instructionDataMergeStrategy) {
initializeDataMap(pseudocode, initialDataValue); Map<Instruction, Edges<D>> dataMap = Maps.newLinkedHashMap();
dataMap.put(getStartInstruction(pseudocode), initializeDataMap(lookInside, dataMap, pseudocode, initialDataValue);
Pair.create(initialDataValueForEnterInstruction, initialDataValueForEnterInstruction)); dataMap.put(getStartInstruction(pseudocode, directOrder),
Edges.create(initialDataValueForEnterInstruction, initialDataValueForEnterInstruction));
boolean[] changed = new boolean[1]; boolean[] changed = new boolean[1];
changed[0] = true; changed[0] = true;
while (changed[0]) { while (changed[0]) {
changed[0] = false; changed[0] = false;
traverseSubGraph(pseudocode, instructionDataMergeStrategy, Collections.<Instruction>emptyList(), changed, false); traverseSubGraph(lookInside, pseudocode, dataMap, instructionDataMergeStrategy, Collections.<Instruction>emptyList(), directOrder, changed, false);
} }
return dataMap;
} }
private void initializeDataMap( private static <D> void initializeDataMap(
@NotNull Pseudocode pseudocode, boolean lookInside,
@NotNull Map<Instruction, Edges<D>> dataMap, @NotNull Pseudocode pseudocode,
@NotNull D initialDataValue) { @NotNull D initialDataValue) {
List<Instruction> instructions = pseudocode.getInstructions(); List<Instruction> instructions = pseudocode.getInstructions();
Pair<D, D> initialPair = Pair.create(initialDataValue, initialDataValue); Edges<D> initialEdge = Edges.create(initialDataValue, initialDataValue);
for (Instruction instruction : instructions) { for (Instruction instruction : instructions) {
dataMap.put(instruction, initialPair); dataMap.put(instruction, initialEdge);
if (lookInside && instruction instanceof LocalDeclarationInstruction) { if (lookInside && instruction instanceof LocalDeclarationInstruction) {
initializeDataMap(((LocalDeclarationInstruction) instruction).getBody(), initialDataValue); initializeDataMap(lookInside, dataMap, ((LocalDeclarationInstruction) instruction).getBody(), initialDataValue);
} }
} }
} }
private void traverseSubGraph( private static <D> void traverseSubGraph(
boolean lookInside,
@NotNull Pseudocode pseudocode, @NotNull Pseudocode pseudocode,
@NotNull Map<Instruction, Edges<D>> dataMap,
@NotNull InstructionDataMergeStrategy<D> instructionDataMergeStrategy, @NotNull InstructionDataMergeStrategy<D> instructionDataMergeStrategy,
@NotNull Collection<Instruction> previousSubGraphInstructions, @NotNull Collection<Instruction> previousSubGraphInstructions,
boolean directOrder,
boolean[] changed, boolean[] changed,
boolean isLocal) { boolean isLocal) {
List<Instruction> instructions = directOrder ? pseudocode.getInstructions() : pseudocode.getReversedInstructions(); List<Instruction> instructions = directOrder ? pseudocode.getInstructions() : pseudocode.getReversedInstructions();
Instruction startInstruction = getStartInstruction(pseudocode); Instruction startInstruction = getStartInstruction(pseudocode, directOrder);
for (Instruction instruction : instructions) { for (Instruction instruction : instructions) {
boolean isStart = directOrder ? instruction instanceof SubroutineEnterInstruction : instruction instanceof SubroutineSinkInstruction; boolean isStart = directOrder ? instruction instanceof SubroutineEnterInstruction : instruction instanceof SubroutineSinkInstruction;
@@ -110,27 +102,27 @@ public class JetControlFlowGraphTraverser<D> {
if (lookInside && instruction instanceof LocalDeclarationInstruction) { if (lookInside && instruction instanceof LocalDeclarationInstruction) {
Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody(); Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody();
traverseSubGraph(subroutinePseudocode, instructionDataMergeStrategy, previousInstructions, changed, true); traverseSubGraph(lookInside, subroutinePseudocode, dataMap ,instructionDataMergeStrategy, previousInstructions, directOrder, changed, true);
Instruction lastInstruction = directOrder ? subroutinePseudocode.getSinkInstruction() : subroutinePseudocode.getEnterInstruction(); Instruction lastInstruction = directOrder ? subroutinePseudocode.getSinkInstruction() : subroutinePseudocode.getEnterInstruction();
Pair<D, D> previousValue = dataMap.get(instruction); Edges<D> previousValue = dataMap.get(instruction);
Pair<D, D> newValue = dataMap.get(lastInstruction); Edges<D> newValue = dataMap.get(lastInstruction);
if (!previousValue.equals(newValue)) { if (!previousValue.equals(newValue)) {
changed[0] = true; changed[0] = true;
dataMap.put(instruction, newValue); dataMap.put(instruction, newValue);
} }
continue; continue;
} }
Pair<D, D> previousDataValue = dataMap.get(instruction); Edges<D> previousDataValue = dataMap.get(instruction);
Collection<D> incomingEdgesData = Sets.newHashSet(); Collection<D> incomingEdgesData = Sets.newHashSet();
for (Instruction previousInstruction : allPreviousInstructions) { for (Instruction previousInstruction : allPreviousInstructions) {
Pair<D, D> previousData = dataMap.get(previousInstruction); Edges<D> previousData = dataMap.get(previousInstruction);
if (previousData != null) { if (previousData != null) {
incomingEdgesData.add(previousData.getSecond()); incomingEdgesData.add(previousData.out);
} }
} }
Pair<D, D> mergedData = instructionDataMergeStrategy.execute(instruction, incomingEdgesData); Edges<D> mergedData = instructionDataMergeStrategy.execute(instruction, incomingEdgesData);
if (!mergedData.equals(previousDataValue)) { if (!mergedData.equals(previousDataValue)) {
changed[0] = true; changed[0] = true;
dataMap.put(instruction, mergedData); dataMap.put(instruction, mergedData);
@@ -138,13 +130,28 @@ public class JetControlFlowGraphTraverser<D> {
} }
} }
public void traverseAndAnalyzeInstructionGraph( public static void traverseAndAnalyzeInstructionGraph(
@NotNull InstructionDataAnalyzeStrategy<D> instructionDataAnalyzeStrategy) { @NotNull Pseudocode pseudocode,
traverseAndAnalyzeInstructionGraph(pseudocode, instructionDataAnalyzeStrategy); boolean directOrder,
SimpleInstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) {
List<Instruction> instructions = pseudocode.getInstructions();
if (!directOrder) {
instructions = Lists.newArrayList(instructions);
Collections.reverse(instructions);
}
for (Instruction instruction : instructions) {
if (instruction instanceof LocalDeclarationInstruction) {
traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody(), directOrder, instructionDataAnalyzeStrategy);
}
instructionDataAnalyzeStrategy.execute(instruction);
}
} }
private void traverseAndAnalyzeInstructionGraph( public static <D> void traverseAndAnalyzeInstructionGraph(
boolean lookInside,
@NotNull Pseudocode pseudocode, @NotNull Pseudocode pseudocode,
@NotNull Map<Instruction, Edges<D>> dataMap,
boolean directOrder,
@NotNull InstructionDataAnalyzeStrategy<D> instructionDataAnalyzeStrategy) { @NotNull InstructionDataAnalyzeStrategy<D> instructionDataAnalyzeStrategy) {
List<Instruction> instructions = pseudocode.getInstructions(); List<Instruction> instructions = pseudocode.getInstructions();
if (!directOrder) { if (!directOrder) {
@@ -153,24 +160,22 @@ public class JetControlFlowGraphTraverser<D> {
} }
for (Instruction instruction : instructions) { for (Instruction instruction : instructions) {
if (lookInside && instruction instanceof LocalDeclarationInstruction) { if (lookInside && instruction instanceof LocalDeclarationInstruction) {
traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody(), instructionDataAnalyzeStrategy); traverseAndAnalyzeInstructionGraph(lookInside, ((LocalDeclarationInstruction) instruction).getBody(), dataMap, directOrder, instructionDataAnalyzeStrategy);
} }
Pair<D, D> pair = dataMap.get(instruction); Edges<D> edges = dataMap.get(instruction);
instructionDataAnalyzeStrategy.execute(instruction, instructionDataAnalyzeStrategy.execute(instruction, edges != null ? edges.in : null, edges != null ? edges.out : null);
pair != null ? pair.getFirst() : null,
pair != null ? pair.getSecond() : null);
} }
} }
public D getResultInfo() {
return dataMap.get(pseudocode.getExitInstruction()).getFirst();
}
public interface InstructionDataMergeStrategy<D> { public interface InstructionDataMergeStrategy<D> {
Pair<D, D> execute(@NotNull Instruction instruction, @NotNull Collection<D> incomingEdgesData); Edges<D> execute(@NotNull Instruction instruction, @NotNull Collection<D> incomingEdgesData);
} }
public interface InstructionDataAnalyzeStrategy<D> { public interface InstructionDataAnalyzeStrategy<D> {
void execute(@NotNull Instruction instruction, @Nullable D enterData, @Nullable D exitData); void execute(@NotNull Instruction instruction, @Nullable D enterData, @Nullable D exitData);
} }
public interface SimpleInstructionDataAnalyzeStrategy {
void execute(@NotNull Instruction instruction);
}
} }
@@ -0,0 +1,66 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.cfg.data;
import org.jetbrains.annotations.NotNull;
/**
* @author svtk
*/
public class Edges<T> {
public final T in;
public final T out;
Edges(@NotNull T in, @NotNull T out) {
this.in = in;
this.out = out;
}
public static <T> Edges<T> create(@NotNull T in, @NotNull T out) {
return new Edges<T>(in, out);
}
@NotNull
public T getIn() {
return in;
}
@NotNull
public T getOut() {
return 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;
}
}
@@ -31,62 +31,38 @@ public class InstructionData {
public final Instruction instruction; public final Instruction instruction;
public final PseudocodeData pseudocodeData; public final PseudocodeData pseudocodeData;
private final Map<VariableDescriptor, EdgesData<VariableInitializers>> initializersMap = Maps.newHashMap(); private final Map<VariableDescriptor, Edges<VariableInitializers>> initializersMap = Maps.newHashMap();
private final Map<VariableDescriptor, EdgesData<VariableUseStatus>> useStatusMap = Maps.newHashMap(); private final Map<VariableDescriptor, Edges<VariableUseStatus>> useStatusMap = Maps.newHashMap();
public InstructionData(@NotNull PseudocodeData data, @NotNull Instruction instruction, public InstructionData(@NotNull PseudocodeData data, @NotNull Instruction instruction,
@NotNull Pair<Map<VariableDescriptor, VariableInitializers>, Map<VariableDescriptor, VariableInitializers>> pairOfVariableInitializersMap, @NotNull Edges<Map<VariableDescriptor, VariableInitializers>> pairOfVariableInitializersMap,
@NotNull Pair<Map<VariableDescriptor, VariableUseStatus>, Map<VariableDescriptor, VariableUseStatus>> pairOfVariableStatusMap) { @NotNull Edges<Map<VariableDescriptor, VariableUseStatus>> pairOfVariableStatusMap) {
pseudocodeData = data; pseudocodeData = data;
this.instruction = instruction; this.instruction = instruction;
for (Map.Entry<VariableDescriptor, VariableInitializers> entry : pairOfVariableInitializersMap.second.entrySet()) { for (Map.Entry<VariableDescriptor, VariableInitializers> entry : pairOfVariableInitializersMap.out.entrySet()) {
VariableDescriptor variableDescriptor = entry.getKey(); VariableDescriptor variableDescriptor = entry.getKey();
VariableInitializers in = pairOfVariableInitializersMap.first.get(variableDescriptor); VariableInitializers in = pairOfVariableInitializersMap.in.get(variableDescriptor);
VariableInitializers out = entry.getValue(); VariableInitializers out = entry.getValue();
initializersMap.put(variableDescriptor, EdgesData.create(in, out)); initializersMap.put(variableDescriptor, Edges.create(in, out));
} }
for (Map.Entry<VariableDescriptor, VariableUseStatus> entry : pairOfVariableStatusMap.second.entrySet()) { for (Map.Entry<VariableDescriptor, VariableUseStatus> entry : pairOfVariableStatusMap.out.entrySet()) {
VariableDescriptor variableDescriptor = entry.getKey(); VariableDescriptor variableDescriptor = entry.getKey();
VariableUseStatus in = pairOfVariableStatusMap.first.get(variableDescriptor); VariableUseStatus in = pairOfVariableStatusMap.in.get(variableDescriptor);
VariableUseStatus out = entry.getValue(); VariableUseStatus out = entry.getValue();
if (in == null || out == null) continue; if (in == null || out == null) continue;
useStatusMap.put(variableDescriptor, EdgesData.create(in, out)); useStatusMap.put(variableDescriptor, Edges.create(in, out));
} }
} }
@NotNull @NotNull
public Map<VariableDescriptor, EdgesData<VariableInitializers>> getInitializersMap() { public Map<VariableDescriptor, Edges<VariableInitializers>> getInitializersMap() {
return initializersMap; return initializersMap;
} }
@NotNull @NotNull
public Map<VariableDescriptor, EdgesData<VariableUseStatus>> getUseStatusMap() { public Map<VariableDescriptor, Edges<VariableUseStatus>> getUseStatusMap() {
return useStatusMap; return useStatusMap;
} }
public static class EdgesData<T> {
private final T in;
private final T out;
private EdgesData(@NotNull T in, @NotNull T out) {
this.in = in;
this.out = out;
}
private static <T> EdgesData<T> create(@NotNull T in, @NotNull T out) {
return new EdgesData<T>(in, out);
}
@NotNull
public T getIn() {
return in;
}
@NotNull
public T getOut() {
return out;
}
}
} }
@@ -19,10 +19,9 @@ package org.jetbrains.jet.lang.cfg.data;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
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 com.intellij.openapi.util.Pair;
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.JetControlFlowGraphTraverser; import org.jetbrains.jet.lang.cfg.PseudocodeTraverser;
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;
@@ -31,7 +30,6 @@ import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetProperty; import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import java.util.*; import java.util.*;
@@ -42,29 +40,38 @@ public class PseudocodeData {
private final Pseudocode pseudocode; private final Pseudocode pseudocode;
private final Map<Instruction, InstructionData> instructionDataMap = Maps.newLinkedHashMap(); private final Map<Instruction, InstructionData> instructionDataMap = Maps.newLinkedHashMap();
private final Map<Pseudocode, DeclarationData> declarationDataMap = Maps.newLinkedHashMap(); private final Map<Pseudocode, DeclarationData> declarationDataMap = Maps.newLinkedHashMap();
private final BindingTrace trace;
public PseudocodeData(@NotNull Pseudocode pseudocode, @NotNull BindingTrace trace) { //private final Map<Pseudocode, Set<VariableDescriptor>> declaredVariablesInEachDeclaration;
//private final Map<Pseudocode, Set<VariableDescriptor>> usedVariablesInEachDeclaration;
private final BindingContext bindingContext;
public PseudocodeData(@NotNull Pseudocode pseudocode, @NotNull BindingContext bindingContext) {
this.pseudocode = pseudocode; this.pseudocode = pseudocode;
this.trace = trace; this.bindingContext = bindingContext;
collectDeclarationData(pseudocode); collectDeclarationData(pseudocode);
DeclarationData declarationData = declarationDataMap.get(pseudocode); DeclarationData declarationData = declarationDataMap.get(pseudocode);
final Map<Instruction, Pair<Map<VariableDescriptor, VariableInitializers>, Map<VariableDescriptor, VariableInitializers>>> variableInitializersMap = final Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> variableInitializersMap =
collectVariableInitializers(pseudocode, declarationData); collectVariableInitializers(pseudocode, declarationData);
final Map<Instruction, Pair<Map<VariableDescriptor, VariableUseStatus>, Map<VariableDescriptor, VariableUseStatus>>> variableStatusMap = final Map<Instruction, Edges<Map<VariableDescriptor, VariableUseStatus>>> variableStatusMap =
collectVariableStatusData(); collectVariableStatusData();
JetControlFlowGraphTraverser.<Void>create(pseudocode, true, true).traverseAndAnalyzeInstructionGraph(
new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() { PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, true,
@Override new PseudocodeTraverser.SimpleInstructionDataAnalyzeStrategy() {
public void execute(@NotNull Instruction instruction, Void enterData, Void exitData) { @Override
instructionDataMap.put(instruction, public void execute(@NotNull Instruction instruction) {
new InstructionData(PseudocodeData.this, instruction, variableInitializersMap.get(instruction), instructionDataMap.put(instruction,
variableStatusMap.get(instruction))); new InstructionData(PseudocodeData.this,
} instruction,
}); variableInitializersMap
.get(instruction),
variableStatusMap
.get(instruction)));
}
});
} }
@NotNull @NotNull
@@ -126,64 +133,59 @@ public class PseudocodeData {
private Set<VariableDescriptor> collectUsedVariables(@NotNull Pseudocode pseudocode) { private Set<VariableDescriptor> collectUsedVariables(@NotNull Pseudocode pseudocode) {
final Set<VariableDescriptor> usedVariables = Sets.newHashSet(); final Set<VariableDescriptor> usedVariables = Sets.newHashSet();
JetControlFlowGraphTraverser.<Void>create(pseudocode, true, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() { PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, true,
@Override new PseudocodeTraverser.SimpleInstructionDataAnalyzeStrategy() {
public void execute(@NotNull Instruction instruction, @Nullable Void enterData, @Nullable Void exitData) { @Override
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false); public void execute(@NotNull Instruction instruction) {
if (variableDescriptor != null) { VariableDescriptor variableDescriptor =
usedVariables.add(variableDescriptor); extractVariableDescriptorIfAny(instruction, false);
} if (variableDescriptor != null) {
} usedVariables.add(variableDescriptor);
}); }
}
});
return usedVariables; return usedVariables;
} }
private Set<VariableDescriptor> collectDeclaredVariables(@NotNull Pseudocode pseudocode) { private Set<VariableDescriptor> collectDeclaredVariables(@NotNull Pseudocode pseudocode) {
final Set<VariableDescriptor> declaredVariables = Sets.newHashSet(); final Set<VariableDescriptor> declaredVariables = Sets.newHashSet();
JetControlFlowGraphTraverser.<Void>create(pseudocode, false, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() { for (Instruction instruction : pseudocode.getInstructions()) {
@Override if (instruction instanceof VariableDeclarationInstruction) {
public void execute(@NotNull Instruction instruction, @Nullable Void enterData, @Nullable Void exitData) { JetDeclaration variableDeclarationElement = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
if (instruction instanceof VariableDeclarationInstruction) { DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement);
JetDeclaration variableDeclarationElement = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); if (descriptor != null) {
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement); assert descriptor instanceof VariableDescriptor;
if (descriptor != null) { declaredVariables.add((VariableDescriptor) descriptor);
assert descriptor instanceof VariableDescriptor;
declaredVariables.add((VariableDescriptor) descriptor);
}
} }
} }
}); }
return declaredVariables; return declaredVariables;
} }
// variable initializers // variable initializers
private Map<Instruction, Pair<Map<VariableDescriptor, VariableInitializers>, Map<VariableDescriptor, VariableInitializers>>> collectVariableInitializers( private Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> collectVariableInitializers(
Pseudocode pseudocode, DeclarationData data) { Pseudocode pseudocode, DeclarationData data) {
JetControlFlowGraphTraverser<Map<VariableDescriptor, VariableInitializers>> traverser = JetControlFlowGraphTraverser.create(pseudocode, false, true);
final Map<VariableDescriptor, VariableInitializers> initialMapForStartInstruction = prepareInitialMapForStartInstruction(data.usedVariables, data.declaredVariables); final Map<VariableDescriptor, VariableInitializers> initialMapForStartInstruction = prepareInitialMapForStartInstruction(data.usedVariables, data.declaredVariables);
traverser.collectInformationFromInstructionGraph(Collections.<VariableDescriptor, VariableInitializers>emptyMap(), initialMapForStartInstruction, Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> result =
new JetControlFlowGraphTraverser.InstructionDataMergeStrategy<Map<VariableDescriptor, VariableInitializers>>() { PseudocodeTraverser.collectInformationFromInstructionGraph(false, true, pseudocode, Collections.<VariableDescriptor, VariableInitializers>emptyMap(), initialMapForStartInstruction,
new PseudocodeTraverser.InstructionDataMergeStrategy<Map<VariableDescriptor, VariableInitializers>>() {
@Override @Override
public Pair<Map<VariableDescriptor, VariableInitializers>, Map<VariableDescriptor, VariableInitializers>> execute( public Edges<Map<VariableDescriptor, VariableInitializers>> execute(
@NotNull Instruction instruction, @NotNull Instruction instruction,
@NotNull Collection<Map<VariableDescriptor, VariableInitializers>> incomingEdgesData) { @NotNull Collection<Map<VariableDescriptor, VariableInitializers>> incomingEdgesData) {
Map<VariableDescriptor, VariableInitializers> enterInstructionData = mergeIncomingEdgesData(incomingEdgesData); Map<VariableDescriptor, VariableInitializers> enterInstructionData = mergeIncomingEdgesData(incomingEdgesData);
Map<VariableDescriptor, VariableInitializers> exitInstructionData = addVariableInitializerFromCurrentInstructionIfAny(instruction, enterInstructionData); Map<VariableDescriptor, VariableInitializers> exitInstructionData = addVariableInitializerFromCurrentInstructionIfAny(instruction, enterInstructionData);
return Pair.create(enterInstructionData, exitInstructionData); return Edges.create(enterInstructionData, exitInstructionData);
} }
}); });
Map<Instruction, Pair<Map<VariableDescriptor, VariableInitializers>, Map<VariableDescriptor, VariableInitializers>>> result =
traverser.getDataMap();
for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) { for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) {
Pseudocode localPseudocode = localDeclarationInstruction.getBody(); Pseudocode localPseudocode = localDeclarationInstruction.getBody();
Map<Instruction, Pair<Map<VariableDescriptor, VariableInitializers>, Map<VariableDescriptor, VariableInitializers>>> initializersForLocalDeclaration = Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> initializersForLocalDeclaration =
collectVariableInitializers(localPseudocode, declarationDataMap.get(localPseudocode)); collectVariableInitializers(localPseudocode, declarationDataMap.get(localPseudocode));
for (Instruction instruction : initializersForLocalDeclaration.keySet()) { for (Instruction instruction : initializersForLocalDeclaration.keySet()) {
@@ -267,17 +269,15 @@ public class PseudocodeData {
// variable use // variable use
private Map<Instruction, Pair<Map<VariableDescriptor, VariableUseStatus>, Map<VariableDescriptor, VariableUseStatus>>> collectVariableStatusData() { private Map<Instruction, Edges<Map<VariableDescriptor, VariableUseStatus>>> collectVariableStatusData() {
JetControlFlowGraphTraverser<Map<VariableDescriptor, VariableUseStatus>> traverser =
JetControlFlowGraphTraverser.create(pseudocode, true, false);
Map<VariableDescriptor, VariableUseStatus> sinkInstructionData = Maps.newHashMap(); Map<VariableDescriptor, VariableUseStatus> sinkInstructionData = Maps.newHashMap();
for (VariableDescriptor usedVariable : declarationDataMap.get(pseudocode).usedVariables) { for (VariableDescriptor usedVariable : declarationDataMap.get(pseudocode).usedVariables) {
sinkInstructionData.put(usedVariable, VariableUseStatus.UNUSED); sinkInstructionData.put(usedVariable, VariableUseStatus.UNUSED);
} }
traverser.collectInformationFromInstructionGraph(Collections.<VariableDescriptor, VariableUseStatus>emptyMap(), sinkInstructionData, return PseudocodeTraverser.collectInformationFromInstructionGraph(true, false, pseudocode, Collections.<VariableDescriptor, VariableUseStatus>emptyMap(), sinkInstructionData,
new JetControlFlowGraphTraverser.InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseStatus>>() { new PseudocodeTraverser.InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseStatus>>() {
@Override @Override
public Pair<Map<VariableDescriptor, VariableUseStatus>, Map<VariableDescriptor, VariableUseStatus>> execute(@NotNull Instruction instruction, @NotNull Collection<Map<VariableDescriptor, VariableUseStatus>> incomingEdgesData) { public Edges<Map<VariableDescriptor, VariableUseStatus>> execute(@NotNull Instruction instruction, @NotNull Collection<Map<VariableDescriptor, VariableUseStatus>> incomingEdgesData) {
Map<VariableDescriptor, VariableUseStatus> enterResult = Maps.newHashMap(); Map<VariableDescriptor, VariableUseStatus> enterResult = Maps.newHashMap();
for (Map<VariableDescriptor, VariableUseStatus> edgeData : incomingEdgesData) { for (Map<VariableDescriptor, VariableUseStatus> edgeData : incomingEdgesData) {
for (Map.Entry<VariableDescriptor, VariableUseStatus> entry : edgeData.entrySet()) { for (Map.Entry<VariableDescriptor, VariableUseStatus> entry : edgeData.entrySet()) {
@@ -288,7 +288,7 @@ public class PseudocodeData {
} }
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true); VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true);
if (variableDescriptor == null || (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction))) { if (variableDescriptor == null || (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction))) {
return Pair.create(enterResult, enterResult); return Edges.create(enterResult, enterResult);
} }
Map<VariableDescriptor, VariableUseStatus> exitResult = Maps.newHashMap(enterResult); Map<VariableDescriptor, VariableUseStatus> exitResult = Maps.newHashMap(enterResult);
if (instruction instanceof ReadValueInstruction) { if (instruction instanceof ReadValueInstruction) {
@@ -307,10 +307,9 @@ public class PseudocodeData {
exitResult.put(variableDescriptor, VariableUseStatus.LAST_WRITTEN); exitResult.put(variableDescriptor, VariableUseStatus.LAST_WRITTEN);
} }
} }
return Pair.create(enterResult, exitResult); return Edges.create(enterResult, exitResult);
} }
}); });
return traverser.getDataMap();
} }
// Util methods // Util methods
@@ -327,7 +326,7 @@ public class PseudocodeData {
else if (instruction instanceof VariableDeclarationInstruction) { else if (instruction instanceof VariableDeclarationInstruction) {
element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
} }
return BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), element, onlyReference); return BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, element, onlyReference);
} }
} }
@@ -65,5 +65,4 @@ public class PseudocodeUtil {
return new JetControlFlowProcessor(mockTrace).generatePseudocode(declaration); return new JetControlFlowProcessor(mockTrace).generatePseudocode(declaration);
} }
} }