diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
deleted file mode 100644
index 3b312839bf2..00000000000
--- a/.idea/inspectionProfiles/profiles_settings.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowDataTrace.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowDataTrace.java
index 90e422bdab8..b16a3454c67 100644
--- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowDataTrace.java
+++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowDataTrace.java
@@ -1,30 +1,24 @@
package org.jetbrains.jet.lang.cfg.pseudocode;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetElement;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
/**
* @author abreslav
*/
-public class JetControlFlowDataTrace {
+public interface JetControlFlowDataTrace {
- private Map data = new LinkedHashMap();
+ JetControlFlowDataTrace EMPTY = new JetControlFlowDataTrace() {
+ @Override
+ public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
+ }
- public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
- data.put(element, pseudocode);
- }
+ @Override
+ public void close() {
+ }
+ };
- @Nullable
- public Pseudocode getControlFlowData(@NotNull JetElement element) {
- return data.get(element);
- }
+ void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode);
+ void close();
- public Collection getAllData() {
- return data.values();
- }
}
diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowDataTraceFactory.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowDataTraceFactory.java
new file mode 100644
index 00000000000..e1c946ac086
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowDataTraceFactory.java
@@ -0,0 +1,20 @@
+package org.jetbrains.jet.lang.cfg.pseudocode;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.lang.psi.JetElement;
+
+/**
+ * @author abreslav
+ */
+public interface JetControlFlowDataTraceFactory {
+ JetControlFlowDataTraceFactory EMPTY = new JetControlFlowDataTraceFactory() {
+ @NotNull
+ @Override
+ public JetControlFlowDataTrace createTrace(JetElement element) {
+ return JetControlFlowDataTrace.EMPTY;
+ }
+ };
+
+ @NotNull
+ JetControlFlowDataTrace createTrace(JetElement element);
+}
diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java
index dda6a393931..9fd6907e304 100644
--- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java
+++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java
@@ -28,8 +28,8 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
this.trace = trace;
}
- private void pushBuilder(JetElement subroutine) {
- JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(subroutine);
+ private void pushBuilder(JetElement scopingElement, JetElement subroutine) {
+ JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(scopingElement, subroutine);
builders.push(worker);
builder = worker;
}
@@ -46,10 +46,10 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
@Override
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
if (isFunctionLiteral) {
- pushBuilder(builder.getCurrentSubroutine());
+ pushBuilder(subroutine, builder.getCurrentSubroutine());
}
else {
- pushBuilder(subroutine);
+ pushBuilder(subroutine, subroutine);
}
builder.enterSubroutine(subroutine, false);
}
@@ -71,8 +71,8 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
private final Pseudocode pseudocode;
private final JetElement currentSubroutine;
- private JetControlFlowInstructionsGeneratorWorker(JetElement currentSubroutine) {
- this.pseudocode = new Pseudocode();
+ private JetControlFlowInstructionsGeneratorWorker(@NotNull JetElement scopingElement, @NotNull JetElement currentSubroutine) {
+ this.pseudocode = new Pseudocode(scopingElement);
this.currentSubroutine = currentSubroutine;
}
diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java
index 67e9899ebc5..b157a33e763 100644
--- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java
+++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java
@@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.cfg.pseudocode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.Label;
+import org.jetbrains.jet.lang.psi.JetElement;
import java.io.PrintStream;
import java.util.*;
@@ -50,6 +51,16 @@ public class Pseudocode {
private final List instructions = new ArrayList();
private final List labels = new ArrayList();
+ private final JetElement correspondingElement;
+
+ public Pseudocode(JetElement correspondingElement) {
+ this.correspondingElement = correspondingElement;
+ }
+
+ public JetElement getCorrespondingElement() {
+ return correspondingElement;
+ }
+
public PseudocodeLabel createLabel(String name) {
PseudocodeLabel label = new PseudocodeLabel(name);
labels.add(label);
@@ -146,7 +157,23 @@ public class Pseudocode {
return getTargetInstruction(instructions.subList(targetPosition, instructions.size()));
}
- public void dumpInstructions(@NotNull PrintStream out) {
+ public void dfsDump(StringBuilder nodes, StringBuilder edges, Map nodeNames) {
+ dfsDump(nodes, edges, instructions.get(0), nodeNames);
+ }
+
+ private void dfsDump(StringBuilder nodes, StringBuilder edges, Instruction instruction, Map nodeNames) {
+ if (nodeNames.containsKey(instruction)) return;
+ String name = "n" + nodeNames.size();
+ nodeNames.put(instruction, name);
+ nodes.append(name).append(" := ").append(renderName(instruction));
+
+ }
+
+ private String renderName(Instruction instruction) {
+ throw new UnsupportedOperationException(); // TODO
+ }
+
+ public void dumpInstructions(@NotNull StringBuilder out) {
List locals = new ArrayList();
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
Instruction instruction = instructions.get(i);
@@ -156,10 +183,10 @@ public class Pseudocode {
}
for (PseudocodeLabel label: labels) {
if (label.getTargetInstructionIndex() == i) {
- out.println(label.getName() + ":");
+ out.append(label.getName()).append(":\n");
}
}
- out.println(" " + instruction);
+ out.append(" ").append(instruction).append("\n");
}
for (Pseudocode local : locals) {
local.dumpInstructions(out);
diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetDeclarationWithBody.java b/idea/src/org/jetbrains/jet/lang/psi/JetDeclarationWithBody.java
index 072acf8ba84..df4f9c63776 100644
--- a/idea/src/org/jetbrains/jet/lang/psi/JetDeclarationWithBody.java
+++ b/idea/src/org/jetbrains/jet/lang/psi/JetDeclarationWithBody.java
@@ -9,4 +9,8 @@ public interface JetDeclarationWithBody {
@Nullable
JetExpression getBodyExpression();
+
+ @Nullable
+ String getName();
}
+
diff --git a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java
index 24064d58ce8..d20100828ad 100644
--- a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java
+++ b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java
@@ -4,6 +4,7 @@ import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.JetSemanticServices;
+import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.java.JavaPackageScope;
@@ -16,10 +17,14 @@ import org.jetbrains.jet.lang.types.ModuleDescriptor;
public class AnalyzingUtils {
public static BindingContext analyzeFile(@NotNull JetFile file, @NotNull ErrorHandler errorHandler) {
JetNamespace rootNamespace = file.getRootNamespace();
- return analyzeNamespace(rootNamespace, errorHandler);
+ return analyzeNamespace(rootNamespace, errorHandler, JetControlFlowDataTraceFactory.EMPTY);
}
public static BindingContext analyzeNamespace(@NotNull JetNamespace namespace, @NotNull ErrorHandler errorHandler) {
+ return analyzeNamespace(namespace, errorHandler, JetControlFlowDataTraceFactory.EMPTY);
+ }
+
+ public static BindingContext analyzeNamespace(@NotNull JetNamespace namespace, @NotNull ErrorHandler errorHandler, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
Project project = namespace.getProject();
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project, errorHandler);
@@ -33,7 +38,7 @@ public class AnalyzingUtils {
scope.importScope(new JavaPackageScope("", null, javaSemanticServices));
scope.importScope(new JavaPackageScope("java.lang", null, javaSemanticServices));
- new TopDownAnalyzer(semanticServices, bindingTraceContext).process(scope, namespace);
+ new TopDownAnalyzer(semanticServices, bindingTraceContext, flowDataTraceFactory).process(scope, namespace);
return bindingTraceContext;
}
}
diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java
index c7a595474d9..94803998f91 100644
--- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java
+++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java
@@ -4,10 +4,7 @@ import com.intellij.openapi.application.ApplicationManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor;
-import org.jetbrains.jet.lang.cfg.pseudocode.Instruction;
-import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTrace;
-import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator;
-import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
+import org.jetbrains.jet.lang.cfg.pseudocode.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*;
@@ -30,12 +27,22 @@ public class TopDownAnalyzer {
private final ClassDescriptorResolver classDescriptorResolver;
private final BindingTrace trace;
private final JetTypeInferrer typeInferrer;
+ private final JetControlFlowDataTraceFactory flowDataTraceFactory;
+
+ public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTrace bindingTrace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
+ this.semanticServices = semanticServices;
+ this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, bindingTrace);
+ this.trace = bindingTrace;
+ this.typeInferrer = semanticServices.getTypeInferrer(trace);
+ this.flowDataTraceFactory = flowDataTraceFactory;
+ }
public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTrace bindingTrace) {
this.semanticServices = semanticServices;
this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, bindingTrace);
this.trace = bindingTrace;
this.typeInferrer = semanticServices.getTypeInferrer(trace);
+ this.flowDataTraceFactory = JetControlFlowDataTraceFactory.EMPTY;
}
public void process(@NotNull JetScope outerScope, @NotNull JetDeclaration declaration) {
@@ -233,47 +240,6 @@ public class TopDownAnalyzer {
FunctionDescriptor descriptor = classDescriptorResolver.resolveFunctionDescriptor(declaringScope.getContainingDeclaration(), declaringScope, function);
declaringScope.addFunctionDescriptor(descriptor);
functions.put(function, descriptor);
-
- JetExpression bodyExpression = function.getBodyExpression();
- if (bodyExpression != null) {
- JetControlFlowDataTrace controlFlowDataTrace = new JetControlFlowDataTrace();
- JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(controlFlowDataTrace);
- new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(function, bodyExpression);
- if (!ApplicationManager.getApplication().isUnitTestMode()) {
- try {
- File workDirectory = new File(System.getProperty("user.home") + "/work/");
- workDirectory.mkdirs();
- File target = new File(workDirectory, "cfg.dot");
-
- PrintStream out = new PrintStream(target);
- out.println("digraph " + function.getName() + " {");
- Collection pseudocodes = controlFlowDataTrace.getAllData();
- int[] count = new int[1];
- Map nodeToName = new HashMap();
- for (Pseudocode pseudocode : pseudocodes) {
- pseudocode.postProcess();
- System.out.println("-------------");
- pseudocode.dumpInstructions(System.out);
- System.out.println("-------------");
- pseudocode.dumpNodes(out, count, nodeToName);
- }
- int i = 0;
- for (Pseudocode pseudocode : pseudocodes) {
- out.println("subgraph cluster_" + i + " {\n" +
- "label=\"f" + i + "\";\n" +
- "color=blue;\n");
- pseudocode.dumpEdges(out, count, nodeToName);
- out.println("}");
- i++;
- }
- out.println("}");
- out.close();
- } catch (FileNotFoundException e) {
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
- }
-
- }
- }
}
private void processProperty(WritableScope declaringScope, JetProperty property) {
@@ -290,10 +256,10 @@ public class TopDownAnalyzer {
private void resolveBehaviorDeclarationBodies() {
for (Map.Entry entry : functions.entrySet()) {
- JetDeclaration declarations = entry.getKey();
+ JetDeclaration declaration = entry.getKey();
FunctionDescriptor descriptor = entry.getValue();
- WritableScope declaringScope = declaringScopes.get(declarations);
+ WritableScope declaringScope = declaringScopes.get(declaration);
assert declaringScope != null;
WritableScope parameterScope = semanticServices.createWritableScope(declaringScope, descriptor);
@@ -304,15 +270,28 @@ public class TopDownAnalyzer {
parameterScope.addPropertyDescriptor(valueParameterDescriptor);
}
- assert declarations instanceof JetFunction || declarations instanceof JetConstructor;
- JetExpression bodyExpression = ((JetDeclarationWithBody) declarations).getBodyExpression();
+ assert declaration instanceof JetFunction || declaration instanceof JetConstructor;
+ JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) declaration;
+ JetExpression bodyExpression = declarationWithBody.getBodyExpression();
+
if (bodyExpression != null) {
- resolveExpression(parameterScope, bodyExpression, true);
+ JetControlFlowDataTrace controlFlowDataTrace = flowDataTraceFactory.createTrace(declaration);
+ JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(controlFlowDataTrace);
+ new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(declaration, bodyExpression);
+ controlFlowDataTrace.close();
+
+ boolean preferBlock = true;
+ if (declaration instanceof JetFunction) {
+ JetFunction jetFunction = (JetFunction) declaration;
+ preferBlock = jetFunction.hasBlockBody();
+ }
+
+ resolveExpression(parameterScope, bodyExpression, preferBlock, controlFlowDataTrace);
}
}
}
- private void resolveExpression(@NotNull JetScope scope, JetExpression expression, boolean preferBlock) {
+ private void resolveExpression(@NotNull JetScope scope, JetExpression expression, boolean preferBlock, JetControlFlowDataTrace controlFlowDataTrace) {
typeInferrer.getType(scope, expression, preferBlock);
}
diff --git a/idea/testData/cfg/Basic.instructions b/idea/testData/cfg/Basic.instructions
new file mode 100644
index 00000000000..457dca2839b
--- /dev/null
+++ b/idea/testData/cfg/Basic.instructions
@@ -0,0 +1,6 @@
+l0:
+
+ r(a)
+l1:
+
+=====================
diff --git a/idea/testData/cfg/Basic.jet b/idea/testData/cfg/Basic.jet
new file mode 100644
index 00000000000..60009e6397b
--- /dev/null
+++ b/idea/testData/cfg/Basic.jet
@@ -0,0 +1,3 @@
+fun f(a : Boolean) {
+ a
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/jet/JetTestCaseBase.java b/idea/tests/org/jetbrains/jet/JetTestCaseBase.java
new file mode 100644
index 00000000000..c086a793366
--- /dev/null
+++ b/idea/tests/org/jetbrains/jet/JetTestCaseBase.java
@@ -0,0 +1,96 @@
+package org.jetbrains.jet;
+
+import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
+import com.intellij.openapi.application.PathManager;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author abreslav
+ */
+public abstract class JetTestCaseBase extends LightDaemonAnalyzerTestCase {
+
+ private String dataPath;
+ protected final String name;
+
+ public JetTestCaseBase(String dataPath, String name) {
+ this.dataPath = dataPath;
+ this.name = name;
+ }
+
+ @Override
+ protected String getTestDataPath() {
+ return getTestDataPathBase();
+ }
+
+ protected static String getTestDataPathBase() {
+ return getHomeDirectory() + "/idea/testData";
+ }
+
+ private static String getHomeDirectory() {
+ return new File(PathManager.getResourceRoot(JetTestCaseBase.class, "/org/jetbrains/jet/JetTestCaseBase.class")).getParentFile().getParentFile().getParent();
+ }
+
+ @Override
+ public String getName() {
+ return "test" + name;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ doTest(getTestFilePath(), false, false);
+ }
+
+ @NotNull
+ protected String getTestFilePath() {
+ return dataPath + name + ".jet";
+ }
+
+ public interface NamedTestFactory {
+ @NotNull Test createTest(@NotNull String dataPath, @NotNull String name);
+ }
+
+ @NotNull
+ public static TestSuite suiteForDirectory(String baseDataDir, @NotNull final String dataPath, boolean recursive, @NotNull NamedTestFactory factory) {
+ TestSuite suite = new TestSuite(dataPath);
+ final String extension = ".jet";
+ FilenameFilter extensionFilter = new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(extension);
+ }
+ };
+ File dir = new File(baseDataDir + dataPath);
+ FileFilter dirFilter = new FileFilter() {
+ @Override
+ public boolean accept(File pathname) {
+ return pathname.isDirectory();
+ }
+ };
+ if (recursive) {
+ File[] files = dir.listFiles(dirFilter);
+ assert files != null : dir;
+ List subdirs = Arrays.asList(files);
+ Collections.sort(subdirs);
+ for (File subdir : subdirs) {
+ suite.addTest(suiteForDirectory(baseDataDir, dataPath + "/" + subdir.getName(), recursive, factory));
+ }
+ }
+ List files = Arrays.asList(dir.listFiles(extensionFilter));
+ Collections.sort(files);
+ for (File file : files) {
+ String fileName = file.getName();
+ assert fileName != null;
+ suite.addTest(factory.createTest(dataPath, fileName.substring(0, fileName.length() - extension.length())));
+ }
+ return suite;
+ }
+}
diff --git a/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java b/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java
new file mode 100644
index 00000000000..82c43840605
--- /dev/null
+++ b/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java
@@ -0,0 +1,149 @@
+/*
+ * @author max
+ */
+package org.jetbrains.jet.cfg;
+
+import com.intellij.openapi.util.io.FileUtil;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.JetTestCaseBase;
+import org.jetbrains.jet.lang.ErrorHandler;
+import org.jetbrains.jet.lang.cfg.pseudocode.Instruction;
+import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTrace;
+import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
+import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
+import org.jetbrains.jet.lang.psi.JetElement;
+import org.jetbrains.jet.lang.psi.JetFile;
+import org.jetbrains.jet.lang.psi.JetNamedDeclaration;
+import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class JetControlFlowTest extends JetTestCaseBase {
+ static {
+ System.setProperty("idea.platform.prefix", "Idea");
+ }
+
+ public JetControlFlowTest(String dataPath, String name) {
+ super(dataPath, name);
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ configureByFile(getTestFilePath());
+ JetFile file = (JetFile) getFile();
+
+ AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), ErrorHandler.THROW_EXCEPTION, new JetControlFlowDataTraceFactory() {
+ @NotNull
+ @Override
+ public JetControlFlowDataTrace createTrace(JetElement element) {
+ return new JetControlFlowDataTrace() {
+ private final Map data = new LinkedHashMap();
+
+ @Override
+ public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
+ data.put(element, pseudocode);
+ }
+
+ @Override
+ public void close() {
+ try {
+ try {
+ processCFData(name);
+ } catch (AssertionFailedError e) {
+ dumpDot(name, data.values());
+ throw e;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void processCFData(String name) throws IOException {
+ Collection pseudocodes = data.values();
+ for (Pseudocode pseudocode : pseudocodes) {
+ pseudocode.postProcess();
+ }
+
+ StringBuilder instructionDump = new StringBuilder();
+ for (Pseudocode pseudocode : pseudocodes) {
+ pseudocode.dumpInstructions(instructionDump);
+ instructionDump.append("=====================\n");
+ }
+
+ String expectedInstructionsFileName = getTestDataPath() + "/" + getTestFilePath().replace(".jet", ".instructions");
+ File expectedInstructionsFile = new File(expectedInstructionsFileName);
+ if (!expectedInstructionsFile.exists()) {
+ FileUtil.writeToFile(expectedInstructionsFile, instructionDump.toString());
+ fail("No expected instructions for " + name + " generated result is written into " + expectedInstructionsFileName);
+ }
+ String expectedInstructions = FileUtil.loadFile(expectedInstructionsFile);
+
+ assertEquals(expectedInstructions, instructionDump.toString());
+
+// StringBuilder graphDump = new StringBuilder();
+// for (Pseudocode pseudocode : pseudocodes) {
+// topOrderDump(pseudocode.)
+// }
+ }
+ };
+ }
+ });
+ }
+
+ private void dumpDot(String name, Collection pseudocodes) throws FileNotFoundException {
+ String graphFileName = getTestDataPath() + "/" + getTestFilePath().replace(".jet", ".dot");
+ File target = new File(graphFileName);
+
+ PrintStream out = new PrintStream(target);
+
+ out.println("digraph " + name + " {");
+ int[] count = new int[1];
+ Map nodeToName = new HashMap();
+ for (Pseudocode pseudocode : pseudocodes) {
+ pseudocode.dumpNodes(out, count, nodeToName);
+ }
+ 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");
+ pseudocode.dumpEdges(out, count, nodeToName);
+ out.println("}");
+ i++;
+ }
+ out.println("}");
+ out.close();
+ }
+
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite();
+ suite.addTest(JetTestCaseBase.suiteForDirectory(getTestDataPathBase(), "/cfg/", true, new JetTestCaseBase.NamedTestFactory() {
+ @NotNull
+ @Override
+ public Test createTest(@NotNull String dataPath, @NotNull String name) {
+ return new JetControlFlowTest(dataPath, name);
+ }
+ }));
+ return suite;
+ }
+
+}
diff --git a/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java b/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java
index d59db8f7704..349989c7fed 100644
--- a/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java
+++ b/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java
@@ -1,38 +1,28 @@
package org.jetbrains.jet.checkers;
-import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
-import com.intellij.openapi.application.PathManager;
-import org.jetbrains.jet.parsing.JetParsingTest;
-
-import java.io.File;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.JetTestCaseBase;
/**
* @author abreslav
*/
-public class JetPsiCheckerTest extends LightDaemonAnalyzerTestCase {
+public class JetPsiCheckerTest extends JetTestCaseBase {
- @Override
- protected String getTestDataPath() {
- return getHomeDirectory() + "/idea/testData";
+ public JetPsiCheckerTest(String dataPath, String name) {
+ super(dataPath, name);
}
- private static String getHomeDirectory() {
- return new File(PathManager.getResourceRoot(JetParsingTest.class, "/org/jetbrains/jet/parsing/JetParsingTest.class")).getParentFile().getParentFile().getParent();
- }
-
- public void testProperties() throws Exception {
- doTest("/checker/Properties.jet", true, true);
- }
-
- public void testBinaryCallsOnNullableValues() throws Exception {
- doTest("/checker/BinaryCallsOnNullableValues.jet", true, true);
- }
-
- public void testQualifiedThis() throws Exception {
- doTest("/checker/QualifiedThis.jet", true, true);
- }
-
- public void testBreakContinue() throws Exception {
- doTest("/checker/BreakContinue.jet", true, true);
+ public static Test suite() {
+ TestSuite suite = new TestSuite();
+ suite.addTest(JetTestCaseBase.suiteForDirectory(getTestDataPathBase(), "/checker/", true, new JetTestCaseBase.NamedTestFactory() {
+ @NotNull
+ @Override
+ public Test createTest(@NotNull String dataPath, @NotNull String name) {
+ return new JetPsiCheckerTest(dataPath, name);
+ }
+ }));
+ return suite;
}
}
diff --git a/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java b/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java
index 6706c6bf2a9..9a117cc015b 100644
--- a/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java
+++ b/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java
@@ -9,20 +9,18 @@ import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.ParsingTestCase;
+import junit.framework.Test;
import junit.framework.TestSuite;
import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.JetTestCaseBase;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetVisitor;
import java.io.File;
-import java.io.FileFilter;
-import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
public class JetParsingTest extends ParsingTestCase {
static {
@@ -101,40 +99,16 @@ public class JetParsingTest extends ParsingTestCase {
public static TestSuite suite() {
TestSuite suite = new TestSuite();
- suite.addTest(suiteForDirectory("/", false));
- suite.addTest(suiteForDirectory("examples", true));
- return suite;
- }
-
- private static TestSuite suiteForDirectory(final String dataPath, boolean recursive) {
- TestSuite suite = new TestSuite(dataPath);
- final String extension = ".jet";
- FilenameFilter extensionFilter = new FilenameFilter() {
+ JetTestCaseBase.NamedTestFactory factory = new JetTestCaseBase.NamedTestFactory() {
+ @NotNull
@Override
- public boolean accept(File dir, String name) {
- return name.endsWith(extension);
+ public Test createTest(@NotNull String dataPath, @NotNull String name) {
+ return new JetParsingTest(dataPath, name);
}
};
- File dir = new File(getTestDataDir() + "/psi/" + dataPath);
- FileFilter dirFilter = new FileFilter() {
- @Override
- public boolean accept(File pathname) {
- return pathname.isDirectory();
- }
- };
- if (recursive) {
- List subdirs = Arrays.asList(dir.listFiles(dirFilter));
- Collections.sort(subdirs);
- for (File subdir : subdirs) {
- suite.addTest(suiteForDirectory(dataPath + "/" + subdir.getName(), recursive));
- }
- }
- List files = Arrays.asList(dir.listFiles(extensionFilter));
- Collections.sort(files);
- for (File file : files) {
- String fileName = file.getName();
- suite.addTest(new JetParsingTest(dataPath, fileName.substring(0, fileName.length() - extension.length())));
- }
+ String prefix = JetParsingTest.getTestDataDir() + "/psi/";
+ suite.addTest(JetTestCaseBase.suiteForDirectory(prefix, "/", false, factory));
+ suite.addTest(JetTestCaseBase.suiteForDirectory(prefix, "examples", true, factory));
return suite;
}