cfg analyzing enhancement
This commit is contained in:
@@ -18,14 +18,16 @@ import java.util.Map;
|
||||
*/
|
||||
public class JetControlFlowGraphTraverser<D> {
|
||||
private final Pseudocode pseudocode;
|
||||
private final boolean lookInside;
|
||||
private final Map<Instruction, Pair<D, D>> dataMap = Maps.newLinkedHashMap();
|
||||
|
||||
public static <D> JetControlFlowGraphTraverser<D> create(Pseudocode pseudocode) {
|
||||
return new JetControlFlowGraphTraverser<D>(pseudocode);
|
||||
public static <D> JetControlFlowGraphTraverser<D> create(Pseudocode pseudocode, boolean lookInside) {
|
||||
return new JetControlFlowGraphTraverser<D>(pseudocode, lookInside);
|
||||
}
|
||||
|
||||
private JetControlFlowGraphTraverser(Pseudocode pseudocode) {
|
||||
private JetControlFlowGraphTraverser(Pseudocode pseudocode, boolean lookInside) {
|
||||
this.pseudocode = pseudocode;
|
||||
this.lookInside = lookInside;
|
||||
}
|
||||
|
||||
public void collectInformationFromInstructionGraph(
|
||||
@@ -51,7 +53,7 @@ public class JetControlFlowGraphTraverser<D> {
|
||||
Pair<D, D> initialPair = Pair.create(initialDataValue, initialDataValue);
|
||||
for (Instruction instruction : instructions) {
|
||||
dataMap.put(instruction, initialPair);
|
||||
if (instruction instanceof LocalDeclarationInstruction) {
|
||||
if (lookInside && instruction instanceof LocalDeclarationInstruction) {
|
||||
initializeDataMap(((LocalDeclarationInstruction) instruction).getBody(), initialDataValue);
|
||||
}
|
||||
}
|
||||
@@ -82,7 +84,7 @@ public class JetControlFlowGraphTraverser<D> {
|
||||
allPreviousInstructions = previousInstructions;
|
||||
}
|
||||
|
||||
if (instruction instanceof LocalDeclarationInstruction) {
|
||||
if (lookInside && instruction instanceof LocalDeclarationInstruction) {
|
||||
Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody();
|
||||
traverseSubGraph(subroutinePseudocode, instructionsMergeStrategy, previousInstructions, straightDirection, changed, true);
|
||||
}
|
||||
@@ -111,11 +113,11 @@ public class JetControlFlowGraphTraverser<D> {
|
||||
InstructionDataAnalyzeStrategy<D> instructionDataAnalyzeStrategy) {
|
||||
List<Instruction> instructions = pseudocode.getInstructions();
|
||||
for (Instruction instruction : instructions) {
|
||||
if (((InstructionImpl)instruction).isDead()) continue;
|
||||
if (instruction instanceof LocalDeclarationInstruction) {
|
||||
if (instruction.isDead()) continue;
|
||||
Pair<D, D> pair = dataMap.get(instruction);
|
||||
if (lookInside && instruction instanceof LocalDeclarationInstruction) {
|
||||
traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody(), instructionDataAnalyzeStrategy);
|
||||
}
|
||||
Pair<D, D> pair = dataMap.get(instruction);
|
||||
instructionDataAnalyzeStrategy.execute(instruction,
|
||||
pair != null ? pair.getFirst() : null,
|
||||
pair != null ? pair.getSecond() : null);
|
||||
@@ -123,7 +125,7 @@ public class JetControlFlowGraphTraverser<D> {
|
||||
}
|
||||
|
||||
public D getResultInfo() {
|
||||
return dataMap.get(pseudocode.getExitInstruction()).getFirst();
|
||||
return dataMap.get(pseudocode.getSinkInstruction()).getFirst();
|
||||
}
|
||||
|
||||
interface InstructionsMergeStrategy<D> {
|
||||
|
||||
@@ -733,36 +733,47 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
|
||||
value(expression.getObjectDeclaration(), inCondition);
|
||||
JetObjectDeclaration declaration = expression.getObjectDeclaration();
|
||||
value(declaration, inCondition);
|
||||
|
||||
List<JetDeclaration> declarations = declaration.getDeclarations();
|
||||
List<JetDeclaration> functions = Lists.newArrayList();
|
||||
for (JetDeclaration localDeclaration : declarations) {
|
||||
if (!(localDeclaration instanceof JetProperty) && !(localDeclaration instanceof JetClassInitializer)) {
|
||||
functions.add(localDeclaration);
|
||||
}
|
||||
}
|
||||
Queue<Label> declarationLabels = new LinkedList<Label>();
|
||||
for (JetDeclaration function : functions) {
|
||||
declarationLabels.add(builder.createUnboundLabel());
|
||||
}
|
||||
builder.nondeterministicJump(Lists.newArrayList(declarationLabels));
|
||||
|
||||
for (JetDeclaration function : functions) {
|
||||
if (function instanceof JetNamedDeclaration) {
|
||||
if (function instanceof JetDeclarationWithBody) {
|
||||
JetExpression bodyExpression = ((JetDeclarationWithBody) function).getBodyExpression();
|
||||
generate(function, bodyExpression != null ? bodyExpression : function);
|
||||
}
|
||||
else {
|
||||
generate(function, function);
|
||||
}
|
||||
}
|
||||
else {
|
||||
generate(declaration, function);
|
||||
}
|
||||
builder.bindLabel(declarationLabels.remove());
|
||||
}
|
||||
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitObjectDeclaration(JetObjectDeclaration declaration) {
|
||||
// for (JetDelegationSpecifier delegationSpecifier : declaration.getDelegationSpecifiers()) {
|
||||
public void visitObjectDeclaration(JetObjectDeclaration objectDeclaration) {
|
||||
// for (JetDelegationSpecifier delegationSpecifier : objectDeclaration.getDelegationSpecifiers()) {
|
||||
// value(delegationSpecifier, inCondition);
|
||||
// }
|
||||
Queue<Label> declarationLabels = new LinkedList<Label>();
|
||||
List<JetDeclaration> declarations = declaration.getDeclarations();
|
||||
for (JetDeclaration localDeclaration : declarations) {
|
||||
declarationLabels.add(builder.createUnboundLabel());
|
||||
}
|
||||
builder.nondeterministicJump(Lists.newArrayList(declarationLabels));
|
||||
for (JetDeclaration localDeclaration : declarations) {
|
||||
if (localDeclaration instanceof JetNamedDeclaration) {
|
||||
if (localDeclaration instanceof JetDeclarationWithBody) {
|
||||
JetExpression bodyExpression = ((JetDeclarationWithBody) localDeclaration).getBodyExpression();
|
||||
generate(localDeclaration, bodyExpression != null ? bodyExpression : localDeclaration);
|
||||
}
|
||||
else {
|
||||
generate(localDeclaration, localDeclaration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
generate(declaration, localDeclaration);
|
||||
}
|
||||
builder.bindLabel(declarationLabels.remove());
|
||||
}
|
||||
visitClassOrObject(objectDeclaration);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -783,17 +794,22 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitAnonymousInitializer(JetClassInitializer classInitializer) {
|
||||
classInitializer.getBody().accept(this);
|
||||
value(classInitializer.getBody(), inCondition);
|
||||
}
|
||||
|
||||
private void visitClassOrObject(JetClassOrObject classOrObject) {
|
||||
List<JetDeclaration> declarations = classOrObject.getDeclarations();
|
||||
for (JetDeclaration declaration : declarations) {
|
||||
if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) {
|
||||
//declaration.accept(this);
|
||||
value(declaration, inCondition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(JetClass klass) {
|
||||
List<JetDeclaration> declarations = klass.getDeclarations();
|
||||
for (JetDeclaration declaration : declarations) {
|
||||
if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) {
|
||||
declaration.accept(this);
|
||||
}
|
||||
}
|
||||
visitClassOrObject(klass);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.*;
|
||||
@@ -122,11 +123,11 @@ public class JetFlowInformationProvider {
|
||||
}
|
||||
}
|
||||
|
||||
public void markUninitializedVariables(@NotNull JetElement subroutine, final boolean inAnonymousInitializers) {
|
||||
public void markUninitializedVariables(@NotNull JetElement subroutine, final boolean inAnonymousInitializers, final boolean declaredLocally) {
|
||||
final Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
JetControlFlowGraphTraverser<Map<VariableDescriptor, InitializationPoints>> traverser = JetControlFlowGraphTraverser.create(pseudocode);
|
||||
JetControlFlowGraphTraverser<Map<VariableDescriptor, InitializationPoints>> traverser = JetControlFlowGraphTraverser.create(pseudocode, true);
|
||||
|
||||
JetControlFlowGraphTraverser.InstructionsMergeStrategy<Map<VariableDescriptor, InitializationPoints>> instructionsMergeStrategy =
|
||||
new JetControlFlowGraphTraverser.InstructionsMergeStrategy<Map<VariableDescriptor, InitializationPoints>>() {
|
||||
@@ -163,7 +164,9 @@ public class JetFlowInformationProvider {
|
||||
}
|
||||
};
|
||||
|
||||
Map<VariableDescriptor, InitializationPoints> initialMapForStartInstruction = prepareInitialMapForStartInstruction(subroutine, pseudocode);
|
||||
Collection<VariableDescriptor> usedVariables = collectUsedVariables(pseudocode);
|
||||
Collection<VariableDescriptor> declaredVariables = collectDeclaredVariables(subroutine);
|
||||
Map<VariableDescriptor, InitializationPoints> initialMapForStartInstruction = prepareInitialMapForStartInstruction(usedVariables, declaredVariables);
|
||||
|
||||
traverser.collectInformationFromInstructionGraph(instructionsMergeStrategy,
|
||||
Collections.<VariableDescriptor, InitializationPoints>emptyMap(),
|
||||
@@ -189,7 +192,7 @@ public class JetFlowInformationProvider {
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
if (!isInitialized) {
|
||||
if (!declaredLocally && !isInitialized) {
|
||||
trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor));
|
||||
}
|
||||
}
|
||||
@@ -211,10 +214,12 @@ public class JetFlowInformationProvider {
|
||||
}
|
||||
}
|
||||
JetSimpleNameExpression expression = (JetSimpleNameExpression) element;
|
||||
if (hasInitializer && !variableDescriptor.isVar()) {
|
||||
trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor));
|
||||
if (!declaredLocally && hasInitializer && !variableDescriptor.isVar()) {
|
||||
PsiElement psiElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor);
|
||||
JetProperty property = psiElement instanceof JetProperty ? (JetProperty) psiElement : null;
|
||||
trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor, property == null ? new JetProperty[0] : new JetProperty[] { property }));
|
||||
}
|
||||
if (inAnonymousInitializers && variableDescriptor instanceof PropertyDescriptor &&
|
||||
if (!declaredLocally && inAnonymousInitializers && variableDescriptor instanceof PropertyDescriptor &&
|
||||
!enterInitializationPoints.isInitialized() && exitInitializationPoints.isInitialized()) {
|
||||
if (expression.getReferencedNameElementType() != JetTokens.FIELD_IDENTIFIER) {
|
||||
trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD.on(expression, variableDescriptor));
|
||||
@@ -225,22 +230,17 @@ public class JetFlowInformationProvider {
|
||||
}
|
||||
});
|
||||
|
||||
if (inAnonymousInitializers) {
|
||||
Map<VariableDescriptor, InitializationPoints> lastInfo = traverser.getResultInfo();
|
||||
for (Map.Entry<VariableDescriptor, InitializationPoints> entry : lastInfo.entrySet()) {
|
||||
VariableDescriptor variable = entry.getKey();
|
||||
if (variable instanceof PropertyDescriptor) {
|
||||
InitializationPoints initializationPoints = entry.getValue();
|
||||
trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, initializationPoints.isInitialized());
|
||||
}
|
||||
Map<VariableDescriptor, InitializationPoints> lastInfo = traverser.getResultInfo();
|
||||
for (Map.Entry<VariableDescriptor, InitializationPoints> entry : lastInfo.entrySet()) {
|
||||
VariableDescriptor variable = entry.getKey();
|
||||
if (variable instanceof PropertyDescriptor && declaredVariables.contains(variable)) {
|
||||
InitializationPoints initializationPoints = entry.getValue();
|
||||
trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, initializationPoints.isInitialized());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<VariableDescriptor, InitializationPoints> prepareInitialMapForStartInstruction(JetElement subroutine, Pseudocode pseudocode) {
|
||||
Collection<VariableDescriptor> usedVariables = collectUsedVariables(pseudocode);
|
||||
Collection<VariableDescriptor> declaredVariables = collectDeclaredVariables(subroutine);
|
||||
|
||||
private Map<VariableDescriptor, InitializationPoints> prepareInitialMapForStartInstruction(Collection<VariableDescriptor> usedVariables, Collection<VariableDescriptor> declaredVariables) {
|
||||
Map<VariableDescriptor, InitializationPoints> initialMapForStartInstruction = Maps.newHashMap();
|
||||
InitializationPoints initialPointsForDeclaredVariable = new InitializationPoints(false);
|
||||
InitializationPoints initialPointsForExternalVariable = new InitializationPoints(true);
|
||||
@@ -267,7 +267,7 @@ public class JetFlowInformationProvider {
|
||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
JetControlFlowGraphTraverser.<Void>create(pseudocode).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
|
||||
JetControlFlowGraphTraverser.<Void>create(pseudocode, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
|
||||
@Override
|
||||
public void execute(Instruction instruction, Void enterData, Void exitData) {
|
||||
if (instruction instanceof ReadValueInstruction) {
|
||||
@@ -314,7 +314,7 @@ public class JetFlowInformationProvider {
|
||||
|
||||
private Collection<VariableDescriptor> collectUsedVariables(Pseudocode pseudocode) {
|
||||
final Set<VariableDescriptor> usedVariables = Sets.newHashSet();
|
||||
JetControlFlowGraphTraverser.<Void>create(pseudocode).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
|
||||
JetControlFlowGraphTraverser.<Void>create(pseudocode, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
|
||||
@Override
|
||||
public void execute(Instruction instruction, Void enterData, Void exitData) {
|
||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
|
||||
@@ -336,7 +336,7 @@ public class JetFlowInformationProvider {
|
||||
assert descriptor instanceof VariableDescriptor;
|
||||
declaredVariables.add((VariableDescriptor) descriptor);
|
||||
}
|
||||
return null;
|
||||
return super.visitProperty(property, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -349,7 +349,7 @@ public class JetFlowInformationProvider {
|
||||
declaredVariables.add((VariableDescriptor) descriptor);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return super.visitForExpression(expression, data);
|
||||
}
|
||||
}, null);
|
||||
return declaredVariables;
|
||||
|
||||
+6
-3
@@ -30,9 +30,12 @@ public class LocalDeclarationInstruction extends InstructionWithNext {
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Instruction> getNextInstructions() {
|
||||
ArrayList<Instruction> instructions = Lists.newArrayList(sink);
|
||||
instructions.addAll(super.getNextInstructions());
|
||||
return instructions;
|
||||
if (sink != null) {
|
||||
ArrayList<Instruction> instructions = Lists.newArrayList(sink);
|
||||
instructions.addAll(super.getNextInstructions());
|
||||
return instructions;
|
||||
}
|
||||
return super.getNextInstructions();
|
||||
}
|
||||
|
||||
public void setSink(SubroutineSinkInstruction sink) {
|
||||
|
||||
@@ -12,7 +12,6 @@ import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -27,13 +26,13 @@ public class ControlFlowAnalyzer {
|
||||
private TopDownAnalysisContext context;
|
||||
private ExpressionTypingServices typeInferrerServices;
|
||||
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
|
||||
private final boolean declaredLocally;
|
||||
private final boolean isDeclaredLocally;
|
||||
|
||||
public ControlFlowAnalyzer(TopDownAnalysisContext context, JetControlFlowDataTraceFactory flowDataTraceFactory, boolean declaredLocally) {
|
||||
this.context = context;
|
||||
this.flowDataTraceFactory = flowDataTraceFactory;
|
||||
isDeclaredLocally = declaredLocally;
|
||||
this.typeInferrerServices = context.getSemanticServices().getTypeInferrerServices(context.getTrace());
|
||||
this.declaredLocally = declaredLocally;
|
||||
}
|
||||
|
||||
public void process() {
|
||||
@@ -43,8 +42,18 @@ public class ControlFlowAnalyzer {
|
||||
|
||||
if (!context.completeAnalysisNeeded(aClass)) continue;
|
||||
|
||||
checkClass(aClass, classDescriptor);
|
||||
checkClassOrObject(aClass, classDescriptor);
|
||||
}
|
||||
|
||||
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
|
||||
JetObjectDeclaration objectDeclaration = entry.getKey();
|
||||
MutableClassDescriptor objectDescriptor = entry.getValue();
|
||||
|
||||
if (!context.completeAnalysisNeeded(objectDeclaration)) continue;
|
||||
|
||||
checkClassOrObject(objectDeclaration, objectDescriptor);
|
||||
}
|
||||
|
||||
for (Map.Entry<JetNamedFunction, FunctionDescriptorImpl> entry : context.getFunctions().entrySet()) {
|
||||
JetNamedFunction function = entry.getKey();
|
||||
FunctionDescriptorImpl functionDescriptor = entry.getValue();
|
||||
@@ -73,9 +82,9 @@ public class ControlFlowAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkClass(JetClass klass, MutableClassDescriptor classDescriptor) {
|
||||
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider(klass, klass, flowDataTraceFactory, context.getTrace());
|
||||
flowInformationProvider.markUninitializedVariables(klass, true);
|
||||
private void checkClassOrObject(JetClassOrObject klass, MutableClassDescriptor classDescriptor) {
|
||||
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) klass, (JetExpression) klass, flowDataTraceFactory, context.getTrace());
|
||||
flowInformationProvider.markUninitializedVariables((JetElement) klass, true, isDeclaredLocally);
|
||||
}
|
||||
|
||||
private void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, final @NotNull JetType expectedReturnType) {
|
||||
@@ -129,12 +138,10 @@ public class ControlFlowAnalyzer {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!declaredLocally) {
|
||||
flowInformationProvider.markUninitializedVariables(function.asElement(), false);
|
||||
if (((JetDeclaration) function).hasModifier(JetTokens.INLINE_KEYWORD)) {
|
||||
//inline functions after M1
|
||||
flowInformationProvider.markUninitializedVariables(function.asElement(), false, isDeclaredLocally);
|
||||
if (((JetDeclaration) function).hasModifier(JetTokens.INLINE_KEYWORD)) {
|
||||
//inline functions after M1
|
||||
// flowInformationProvider.markNotOnlyInvokedFunctionVariables(function.asElement(), functionDescriptor.getValueParameters());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -247,4 +247,62 @@ class ForwardAccessToBackingField() { //kt-147
|
||||
val a = <!UNRESOLVED_REFERENCE, UNINITIALIZED_VARIABLE!>$a<!> // error
|
||||
val b = <!UNINITIALIZED_VARIABLE!>$c<!> // error
|
||||
val c = 1
|
||||
}
|
||||
|
||||
class ClassObject() {
|
||||
class object {
|
||||
val x : Int
|
||||
|
||||
{
|
||||
$x = 1
|
||||
}
|
||||
|
||||
|
||||
fun foo() {
|
||||
val a : Int
|
||||
doSmth(<!UNINITIALIZED_VARIABLE!>a<!>)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
val a = object {
|
||||
val x : Int
|
||||
val <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>y<!> : Int
|
||||
{
|
||||
$x = 1
|
||||
}
|
||||
//todo
|
||||
/* fun foo() {
|
||||
<VAL_REASSIGNMENT>y<> = 10
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
object O {
|
||||
val x : Int
|
||||
val <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>y<!> : Int
|
||||
{
|
||||
$x = 1
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
<!VAL_REASSIGNMENT!>y<!> = 10
|
||||
val i: Int
|
||||
if (1 < 3) {
|
||||
i = 10
|
||||
}
|
||||
doSmth(<!UNINITIALIZED_VARIABLE!>i<!>)
|
||||
}
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
val b = 1
|
||||
val a = object {
|
||||
val x = b
|
||||
{
|
||||
<!VAL_REASSIGNMENT!>b<!> = 4
|
||||
<!UNRESOLVED_REFERENCE!>$b<!> = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,8 +285,9 @@ public class JetControlFlowTest extends JetLiteFixture {
|
||||
|
||||
@Override
|
||||
public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
|
||||
//todo print edges
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null);
|
||||
for (Instruction nextInstruction : instruction.getNextInstructions()) {
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(nextInstruction), null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -313,6 +314,13 @@ public class JetControlFlowTest extends JetLiteFixture {
|
||||
|
||||
@Override
|
||||
public void visitSubroutineExit(SubroutineExitInstruction instruction) {
|
||||
if (!instruction.getNextInstructions().isEmpty()) {
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNextInstructions().iterator().next()), null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubroutineSink(SubroutineSinkInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@@ -367,7 +375,7 @@ public class JetControlFlowTest extends JetLiteFixture {
|
||||
}
|
||||
|
||||
private void dumpDot(String name, Collection<Pseudocode> pseudocodes) throws FileNotFoundException {
|
||||
String graphFileName = getTestDataPath() + "/" + getTestFilePath() + ".dot";
|
||||
String graphFileName = getTestFilePath() + ".dot";
|
||||
File target = new File(graphFileName);
|
||||
|
||||
PrintStream out = new PrintStream(target);
|
||||
|
||||
Reference in New Issue
Block a user