diff --git a/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java b/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java index 937243c1eb3..00b5e641aee 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java +++ b/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.cfg; import com.google.common.collect.Sets; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,9 +30,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.lazy.KotlinTestWithEnvironment; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.PrintStream; import java.util.*; public abstract class AbstractControlFlowTest extends KotlinTestWithEnvironment { @@ -75,7 +72,7 @@ public abstract class AbstractControlFlowTest extends KotlinTestWithEnvironment } finally { if ("true".equals(System.getProperty("jet.control.flow.test.dump.graphs"))) { - dumpDot(file, data.values()); + CFGraphToDotFilePrinter.dumpDot(file, data.values()); } } } @@ -270,149 +267,4 @@ public abstract class AbstractControlFlowTest extends KotlinTestWithEnvironment } return Collections.singleton(natural).equals(new HashSet(actual)); } - - public void dumpEdges(List instructions, final PrintStream out, final int[] count, final Map nodeToName) { - for (Instruction fromInst : instructions) { - fromInst.accept(new InstructionVisitor() { - @Override - public void visitLocalFunctionDeclarationInstruction(LocalFunctionDeclarationInstruction instruction) { - int index = count[0]; -// instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";", nodeToName); - printEdge(out, nodeToName.get(instruction), nodeToName.get(((PseudocodeImpl)instruction.getBody()).getAllInstructions().get(0)), null); - visitInstructionWithNext(instruction); - } - - @Override - public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) { - printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getResolvedTarget()), null); - } - - @Override - public void visitJump(AbstractJumpInstruction instruction) { - printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getResolvedTarget()), null); - } - - @Override - public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) { - for (Instruction nextInstruction : instruction.getNextInstructions()) { - printEdge(out, nodeToName.get(instruction), nodeToName.get(nextInstruction), null); - } - } - - @Override - public void visitReturnValue(ReturnValueInstruction instruction) { - super.visitReturnValue(instruction); - } - - @Override - public void visitReturnNoValue(ReturnNoValueInstruction instruction) { - super.visitReturnNoValue(instruction); - } - - @Override - public void visitConditionalJump(ConditionalJumpInstruction instruction) { - String from = nodeToName.get(instruction); - printEdge(out, from, nodeToName.get(instruction.getNextOnFalse()), "no"); - printEdge(out, from, nodeToName.get(instruction.getNextOnTrue()), "yes"); - } - - @Override - public void visitInstructionWithNext(InstructionWithNext instruction) { - printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null); - } - - @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 - } - - @Override - public void visitInstruction(Instruction instruction) { - throw new UnsupportedOperationException(instruction.toString()); - } - }); - } - } - - public void dumpNodes(List instructions, PrintStream out, int[] count, Map nodeToName, Set remainedAfterPostProcessInstructions) { - for (Instruction node : instructions) { - String name = "n" + count[0]++; - nodeToName.put(node, name); - String text = node.toString(); - int newline = text.indexOf("\n"); - if (newline >= 0) { - text = text.substring(0, newline); - } - String shape = "box"; - if (node instanceof ConditionalJumpInstruction || node instanceof UnconditionalJumpInstruction) { - shape = "diamond"; - } - else if (node instanceof NondeterministicJumpInstruction) { - shape = "Mdiamond"; - } - else if (node instanceof UnsupportedElementInstruction) { - shape = "box, fillcolor=red, style=filled"; - } - else if (node instanceof LocalFunctionDeclarationInstruction) { - shape = "Mcircle"; - } - else if (node instanceof SubroutineEnterInstruction || node instanceof SubroutineExitInstruction) { - shape = "roundrect, style=rounded"; - } - if (!remainedAfterPostProcessInstructions.contains(node)) { - shape += "box, fillcolor=grey, style=filled"; - } - out.println(name + "[label=\"" + text + "\", shape=" + shape + "];"); - } - } - - private void printEdge(PrintStream out, String from, String to, String label) { - if (label != null) { - label = "[label=\"" + label + "\"]"; - } - else { - label = ""; - } - out.println(from + " -> " + to + label + ";"); - } - - private void dumpDot(File file, Collection pseudocodes) throws FileNotFoundException { - File target = JetTestUtils.replaceExtension(file, "dot"); - - PrintStream out = new PrintStream(target); - - out.println("digraph " + FileUtil.getNameWithoutExtension(file) + " {"); - int[] count = new int[1]; - Map nodeToName = new HashMap(); - for (Pseudocode pseudocode : pseudocodes) { - dumpNodes(((PseudocodeImpl)pseudocode).getAllInstructions(), out, count, nodeToName, Sets.newHashSet(pseudocode.getInstructions())); - } - int i = 0; - for (Pseudocode pseudocode : pseudocodes) { - String label; - JetElement correspondingElement = pseudocode.getCorrespondingElement(); - if (correspondingElement instanceof JetNamedDeclaration) { - JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) correspondingElement; - label = namedDeclaration.getName(); - } - else { - label = "anonymous_" + i; - } - out.println("subgraph cluster_" + i + " {\n" + - "label=\"" + label + "\";\n" + - "color=blue;\n"); - dumpEdges(((PseudocodeImpl)pseudocode).getAllInstructions(), out, count, nodeToName); - out.println("}"); - i++; - } - out.println("}"); - out.close(); - } } diff --git a/compiler/tests/org/jetbrains/jet/cfg/CFGraphToDotFilePrinter.java b/compiler/tests/org/jetbrains/jet/cfg/CFGraphToDotFilePrinter.java new file mode 100644 index 00000000000..2b04195b309 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/cfg/CFGraphToDotFilePrinter.java @@ -0,0 +1,177 @@ +/* + * Copyright 2010-2014 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.cfg; + +import com.google.common.collect.Sets; +import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.lang.cfg.pseudocode.*; +import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.psi.JetNamedDeclaration; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.util.*; + +public class CFGraphToDotFilePrinter { + public static void dumpDot(File file, Collection pseudocodes) throws FileNotFoundException { + File target = JetTestUtils.replaceExtension(file, "dot"); + + PrintStream out = new PrintStream(target); + + out.println("digraph " + FileUtil.getNameWithoutExtension(file) + " {"); + int[] count = new int[1]; + Map nodeToName = new HashMap(); + for (Pseudocode pseudocode : pseudocodes) { + dumpNodes(((PseudocodeImpl)pseudocode).getAllInstructions(), out, count, nodeToName, Sets + .newHashSet(pseudocode.getInstructions())); + } + int i = 0; + for (Pseudocode pseudocode : pseudocodes) { + String label; + JetElement correspondingElement = pseudocode.getCorrespondingElement(); + if (correspondingElement instanceof JetNamedDeclaration) { + JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) correspondingElement; + label = namedDeclaration.getName(); + } + else { + label = "anonymous_" + i; + } + out.println("subgraph cluster_" + i + " {\n" + + "label=\"" + label + "\";\n" + + "color=blue;\n"); + dumpEdges(((PseudocodeImpl)pseudocode).getAllInstructions(), out, count, nodeToName); + out.println("}"); + i++; + } + out.println("}"); + out.close(); + } + + private static void dumpEdges(List instructions, final PrintStream out, final int[] count, final Map nodeToName) { + for (Instruction fromInst : instructions) { + fromInst.accept(new InstructionVisitor() { + @Override + public void visitLocalFunctionDeclarationInstruction(LocalFunctionDeclarationInstruction instruction) { + int index = count[0]; +// instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";", nodeToName); + printEdge(out, nodeToName.get(instruction), nodeToName.get(((PseudocodeImpl)instruction.getBody()).getAllInstructions().get(0)), null); + visitInstructionWithNext(instruction); + } + + @Override + public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) { + printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getResolvedTarget()), null); + } + + @Override + public void visitJump(AbstractJumpInstruction instruction) { + printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getResolvedTarget()), null); + } + + @Override + public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) { + for (Instruction nextInstruction : instruction.getNextInstructions()) { + printEdge(out, nodeToName.get(instruction), nodeToName.get(nextInstruction), null); + } + } + + @Override + public void visitReturnValue(ReturnValueInstruction instruction) { + super.visitReturnValue(instruction); + } + + @Override + public void visitReturnNoValue(ReturnNoValueInstruction instruction) { + super.visitReturnNoValue(instruction); + } + + @Override + public void visitConditionalJump(ConditionalJumpInstruction instruction) { + String from = nodeToName.get(instruction); + printEdge(out, from, nodeToName.get(instruction.getNextOnFalse()), "no"); + printEdge(out, from, nodeToName.get(instruction.getNextOnTrue()), "yes"); + } + + @Override + public void visitInstructionWithNext(InstructionWithNext instruction) { + printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null); + } + + @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 + } + + @Override + public void visitInstruction(Instruction instruction) { + throw new UnsupportedOperationException(instruction.toString()); + } + }); + } + } + + private static void dumpNodes(List instructions, PrintStream out, int[] count, Map nodeToName, Set remainedAfterPostProcessInstructions) { + for (Instruction node : instructions) { + String name = "n" + count[0]++; + nodeToName.put(node, name); + String text = node.toString(); + int newline = text.indexOf("\n"); + if (newline >= 0) { + text = text.substring(0, newline); + } + String shape = "box"; + if (node instanceof ConditionalJumpInstruction || node instanceof UnconditionalJumpInstruction) { + shape = "diamond"; + } + else if (node instanceof NondeterministicJumpInstruction) { + shape = "Mdiamond"; + } + else if (node instanceof UnsupportedElementInstruction) { + shape = "box, fillcolor=red, style=filled"; + } + else if (node instanceof LocalFunctionDeclarationInstruction) { + shape = "Mcircle"; + } + else if (node instanceof SubroutineEnterInstruction || node instanceof SubroutineExitInstruction) { + shape = "roundrect, style=rounded"; + } + if (!remainedAfterPostProcessInstructions.contains(node)) { + shape += "box, fillcolor=grey, style=filled"; + } + out.println(name + "[label=\"" + text + "\", shape=" + shape + "];"); + } + } + + private static void printEdge(PrintStream out, String from, String to, String label) { + if (label != null) { + label = "[label=\"" + label + "\"]"; + } + else { + label = ""; + } + out.println(from + " -> " + to + label + ";"); + } +}