Test framework for instructions
This commit is contained in:
-7
@@ -1,7 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<settings>
|
|
||||||
<option name="PROJECT_PROFILE" value="Project Default" />
|
|
||||||
<option name="USE_PROJECT_PROFILE" value="true" />
|
|
||||||
<version value="1.0" />
|
|
||||||
</settings>
|
|
||||||
</component>
|
|
||||||
@@ -1,30 +1,24 @@
|
|||||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetElement;
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class JetControlFlowDataTrace {
|
public interface JetControlFlowDataTrace {
|
||||||
|
|
||||||
private Map<JetElement, Pseudocode> data = new LinkedHashMap<JetElement, Pseudocode>();
|
JetControlFlowDataTrace EMPTY = new JetControlFlowDataTrace() {
|
||||||
|
@Override
|
||||||
|
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||||
|
}
|
||||||
|
|
||||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
@Override
|
||||||
data.put(element, pseudocode);
|
public void close() {
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Nullable
|
void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode);
|
||||||
public Pseudocode getControlFlowData(@NotNull JetElement element) {
|
void close();
|
||||||
return data.get(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<Pseudocode> getAllData() {
|
|
||||||
return data.values();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
+6
-6
@@ -28,8 +28,8 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
this.trace = trace;
|
this.trace = trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pushBuilder(JetElement subroutine) {
|
private void pushBuilder(JetElement scopingElement, JetElement subroutine) {
|
||||||
JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(subroutine);
|
JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(scopingElement, subroutine);
|
||||||
builders.push(worker);
|
builders.push(worker);
|
||||||
builder = worker;
|
builder = worker;
|
||||||
}
|
}
|
||||||
@@ -46,10 +46,10 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
@Override
|
@Override
|
||||||
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
|
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
|
||||||
if (isFunctionLiteral) {
|
if (isFunctionLiteral) {
|
||||||
pushBuilder(builder.getCurrentSubroutine());
|
pushBuilder(subroutine, builder.getCurrentSubroutine());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pushBuilder(subroutine);
|
pushBuilder(subroutine, subroutine);
|
||||||
}
|
}
|
||||||
builder.enterSubroutine(subroutine, false);
|
builder.enterSubroutine(subroutine, false);
|
||||||
}
|
}
|
||||||
@@ -71,8 +71,8 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
private final Pseudocode pseudocode;
|
private final Pseudocode pseudocode;
|
||||||
private final JetElement currentSubroutine;
|
private final JetElement currentSubroutine;
|
||||||
|
|
||||||
private JetControlFlowInstructionsGeneratorWorker(JetElement currentSubroutine) {
|
private JetControlFlowInstructionsGeneratorWorker(@NotNull JetElement scopingElement, @NotNull JetElement currentSubroutine) {
|
||||||
this.pseudocode = new Pseudocode();
|
this.pseudocode = new Pseudocode(scopingElement);
|
||||||
this.currentSubroutine = currentSubroutine;
|
this.currentSubroutine = currentSubroutine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.cfg.pseudocode;
|
|||||||
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.Label;
|
import org.jetbrains.jet.lang.cfg.Label;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
|
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -50,6 +51,16 @@ public class Pseudocode {
|
|||||||
private final List<Instruction> instructions = new ArrayList<Instruction>();
|
private final List<Instruction> instructions = new ArrayList<Instruction>();
|
||||||
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
|
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
|
||||||
|
|
||||||
|
private final JetElement correspondingElement;
|
||||||
|
|
||||||
|
public Pseudocode(JetElement correspondingElement) {
|
||||||
|
this.correspondingElement = correspondingElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JetElement getCorrespondingElement() {
|
||||||
|
return correspondingElement;
|
||||||
|
}
|
||||||
|
|
||||||
public PseudocodeLabel createLabel(String name) {
|
public PseudocodeLabel createLabel(String name) {
|
||||||
PseudocodeLabel label = new PseudocodeLabel(name);
|
PseudocodeLabel label = new PseudocodeLabel(name);
|
||||||
labels.add(label);
|
labels.add(label);
|
||||||
@@ -146,7 +157,23 @@ public class Pseudocode {
|
|||||||
return getTargetInstruction(instructions.subList(targetPosition, instructions.size()));
|
return getTargetInstruction(instructions.subList(targetPosition, instructions.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dumpInstructions(@NotNull PrintStream out) {
|
public void dfsDump(StringBuilder nodes, StringBuilder edges, Map<Instruction, String> nodeNames) {
|
||||||
|
dfsDump(nodes, edges, instructions.get(0), nodeNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dfsDump(StringBuilder nodes, StringBuilder edges, Instruction instruction, Map<Instruction, String> 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<Pseudocode> locals = new ArrayList<Pseudocode>();
|
List<Pseudocode> locals = new ArrayList<Pseudocode>();
|
||||||
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
|
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
|
||||||
Instruction instruction = instructions.get(i);
|
Instruction instruction = instructions.get(i);
|
||||||
@@ -156,10 +183,10 @@ public class Pseudocode {
|
|||||||
}
|
}
|
||||||
for (PseudocodeLabel label: labels) {
|
for (PseudocodeLabel label: labels) {
|
||||||
if (label.getTargetInstructionIndex() == i) {
|
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) {
|
for (Pseudocode local : locals) {
|
||||||
local.dumpInstructions(out);
|
local.dumpInstructions(out);
|
||||||
|
|||||||
@@ -9,4 +9,8 @@ public interface JetDeclarationWithBody {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
JetExpression getBodyExpression();
|
JetExpression getBodyExpression();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
String getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.intellij.openapi.project.Project;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.ErrorHandler;
|
import org.jetbrains.jet.lang.ErrorHandler;
|
||||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
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.JetFile;
|
||||||
import org.jetbrains.jet.lang.psi.JetNamespace;
|
import org.jetbrains.jet.lang.psi.JetNamespace;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JavaPackageScope;
|
import org.jetbrains.jet.lang.resolve.java.JavaPackageScope;
|
||||||
@@ -16,10 +17,14 @@ import org.jetbrains.jet.lang.types.ModuleDescriptor;
|
|||||||
public class AnalyzingUtils {
|
public class AnalyzingUtils {
|
||||||
public static BindingContext analyzeFile(@NotNull JetFile file, @NotNull ErrorHandler errorHandler) {
|
public static BindingContext analyzeFile(@NotNull JetFile file, @NotNull ErrorHandler errorHandler) {
|
||||||
JetNamespace rootNamespace = file.getRootNamespace();
|
JetNamespace rootNamespace = file.getRootNamespace();
|
||||||
return analyzeNamespace(rootNamespace, errorHandler);
|
return analyzeNamespace(rootNamespace, errorHandler, JetControlFlowDataTraceFactory.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BindingContext analyzeNamespace(@NotNull JetNamespace namespace, @NotNull ErrorHandler errorHandler) {
|
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();
|
Project project = namespace.getProject();
|
||||||
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project, errorHandler);
|
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project, errorHandler);
|
||||||
|
|
||||||
@@ -33,7 +38,7 @@ public class AnalyzingUtils {
|
|||||||
scope.importScope(new JavaPackageScope("", null, javaSemanticServices));
|
scope.importScope(new JavaPackageScope("", null, javaSemanticServices));
|
||||||
scope.importScope(new JavaPackageScope("java.lang", 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;
|
return bindingTraceContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,7 @@ import com.intellij.openapi.application.ApplicationManager;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||||
import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor;
|
import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.Instruction;
|
import org.jetbrains.jet.lang.cfg.pseudocode.*;
|
||||||
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.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
|
|
||||||
@@ -30,12 +27,22 @@ public class TopDownAnalyzer {
|
|||||||
private final ClassDescriptorResolver classDescriptorResolver;
|
private final ClassDescriptorResolver classDescriptorResolver;
|
||||||
private final BindingTrace trace;
|
private final BindingTrace trace;
|
||||||
private final JetTypeInferrer typeInferrer;
|
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) {
|
public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTrace bindingTrace) {
|
||||||
this.semanticServices = semanticServices;
|
this.semanticServices = semanticServices;
|
||||||
this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, bindingTrace);
|
this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, bindingTrace);
|
||||||
this.trace = bindingTrace;
|
this.trace = bindingTrace;
|
||||||
this.typeInferrer = semanticServices.getTypeInferrer(trace);
|
this.typeInferrer = semanticServices.getTypeInferrer(trace);
|
||||||
|
this.flowDataTraceFactory = JetControlFlowDataTraceFactory.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void process(@NotNull JetScope outerScope, @NotNull JetDeclaration declaration) {
|
public void process(@NotNull JetScope outerScope, @NotNull JetDeclaration declaration) {
|
||||||
@@ -233,47 +240,6 @@ public class TopDownAnalyzer {
|
|||||||
FunctionDescriptor descriptor = classDescriptorResolver.resolveFunctionDescriptor(declaringScope.getContainingDeclaration(), declaringScope, function);
|
FunctionDescriptor descriptor = classDescriptorResolver.resolveFunctionDescriptor(declaringScope.getContainingDeclaration(), declaringScope, function);
|
||||||
declaringScope.addFunctionDescriptor(descriptor);
|
declaringScope.addFunctionDescriptor(descriptor);
|
||||||
functions.put(function, 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<Pseudocode> pseudocodes = controlFlowDataTrace.getAllData();
|
|
||||||
int[] count = new int[1];
|
|
||||||
Map<Instruction, String> nodeToName = new HashMap<Instruction, String>();
|
|
||||||
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) {
|
private void processProperty(WritableScope declaringScope, JetProperty property) {
|
||||||
@@ -290,10 +256,10 @@ public class TopDownAnalyzer {
|
|||||||
|
|
||||||
private void resolveBehaviorDeclarationBodies() {
|
private void resolveBehaviorDeclarationBodies() {
|
||||||
for (Map.Entry<JetDeclaration, FunctionDescriptor> entry : functions.entrySet()) {
|
for (Map.Entry<JetDeclaration, FunctionDescriptor> entry : functions.entrySet()) {
|
||||||
JetDeclaration declarations = entry.getKey();
|
JetDeclaration declaration = entry.getKey();
|
||||||
FunctionDescriptor descriptor = entry.getValue();
|
FunctionDescriptor descriptor = entry.getValue();
|
||||||
|
|
||||||
WritableScope declaringScope = declaringScopes.get(declarations);
|
WritableScope declaringScope = declaringScopes.get(declaration);
|
||||||
assert declaringScope != null;
|
assert declaringScope != null;
|
||||||
|
|
||||||
WritableScope parameterScope = semanticServices.createWritableScope(declaringScope, descriptor);
|
WritableScope parameterScope = semanticServices.createWritableScope(declaringScope, descriptor);
|
||||||
@@ -304,15 +270,28 @@ public class TopDownAnalyzer {
|
|||||||
parameterScope.addPropertyDescriptor(valueParameterDescriptor);
|
parameterScope.addPropertyDescriptor(valueParameterDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert declarations instanceof JetFunction || declarations instanceof JetConstructor;
|
assert declaration instanceof JetFunction || declaration instanceof JetConstructor;
|
||||||
JetExpression bodyExpression = ((JetDeclarationWithBody) declarations).getBodyExpression();
|
JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) declaration;
|
||||||
|
JetExpression bodyExpression = declarationWithBody.getBodyExpression();
|
||||||
|
|
||||||
if (bodyExpression != null) {
|
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);
|
typeInferrer.getType(scope, expression, preferBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
l0:
|
||||||
|
<START>
|
||||||
|
r(a)
|
||||||
|
l1:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun f(a : Boolean) {
|
||||||
|
a
|
||||||
|
}
|
||||||
@@ -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<File> subdirs = Arrays.asList(files);
|
||||||
|
Collections.sort(subdirs);
|
||||||
|
for (File subdir : subdirs) {
|
||||||
|
suite.addTest(suiteForDirectory(baseDataDir, dataPath + "/" + subdir.getName(), recursive, factory));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<File> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<JetElement, Pseudocode> data = new LinkedHashMap<JetElement, Pseudocode>();
|
||||||
|
|
||||||
|
@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<Pseudocode> 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<Pseudocode> 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<Instruction, String> nodeToName = new HashMap<Instruction, String>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,38 +1,28 @@
|
|||||||
package org.jetbrains.jet.checkers;
|
package org.jetbrains.jet.checkers;
|
||||||
|
|
||||||
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
|
import junit.framework.Test;
|
||||||
import com.intellij.openapi.application.PathManager;
|
import junit.framework.TestSuite;
|
||||||
import org.jetbrains.jet.parsing.JetParsingTest;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.JetTestCaseBase;
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class JetPsiCheckerTest extends LightDaemonAnalyzerTestCase {
|
public class JetPsiCheckerTest extends JetTestCaseBase {
|
||||||
|
|
||||||
@Override
|
public JetPsiCheckerTest(String dataPath, String name) {
|
||||||
protected String getTestDataPath() {
|
super(dataPath, name);
|
||||||
return getHomeDirectory() + "/idea/testData";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getHomeDirectory() {
|
public static Test suite() {
|
||||||
return new File(PathManager.getResourceRoot(JetParsingTest.class, "/org/jetbrains/jet/parsing/JetParsingTest.class")).getParentFile().getParentFile().getParent();
|
TestSuite suite = new TestSuite();
|
||||||
}
|
suite.addTest(JetTestCaseBase.suiteForDirectory(getTestDataPathBase(), "/checker/", true, new JetTestCaseBase.NamedTestFactory() {
|
||||||
|
@NotNull
|
||||||
public void testProperties() throws Exception {
|
@Override
|
||||||
doTest("/checker/Properties.jet", true, true);
|
public Test createTest(@NotNull String dataPath, @NotNull String name) {
|
||||||
}
|
return new JetPsiCheckerTest(dataPath, name);
|
||||||
|
}
|
||||||
public void testBinaryCallsOnNullableValues() throws Exception {
|
}));
|
||||||
doTest("/checker/BinaryCallsOnNullableValues.jet", true, true);
|
return suite;
|
||||||
}
|
|
||||||
|
|
||||||
public void testQualifiedThis() throws Exception {
|
|
||||||
doTest("/checker/QualifiedThis.jet", true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testBreakContinue() throws Exception {
|
|
||||||
doTest("/checker/BreakContinue.jet", true, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,20 +9,18 @@ import com.intellij.psi.PsiErrorElement;
|
|||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import com.intellij.testFramework.ParsingTestCase;
|
import com.intellij.testFramework.ParsingTestCase;
|
||||||
|
import junit.framework.Test;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
import org.jetbrains.annotations.NonNls;
|
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.JetElement;
|
||||||
import org.jetbrains.jet.lang.psi.JetVisitor;
|
import org.jetbrains.jet.lang.psi.JetVisitor;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
|
||||||
import java.io.FilenameFilter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class JetParsingTest extends ParsingTestCase {
|
public class JetParsingTest extends ParsingTestCase {
|
||||||
static {
|
static {
|
||||||
@@ -101,40 +99,16 @@ public class JetParsingTest extends ParsingTestCase {
|
|||||||
|
|
||||||
public static TestSuite suite() {
|
public static TestSuite suite() {
|
||||||
TestSuite suite = new TestSuite();
|
TestSuite suite = new TestSuite();
|
||||||
suite.addTest(suiteForDirectory("/", false));
|
JetTestCaseBase.NamedTestFactory factory = new JetTestCaseBase.NamedTestFactory() {
|
||||||
suite.addTest(suiteForDirectory("examples", true));
|
@NotNull
|
||||||
return suite;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TestSuite suiteForDirectory(final String dataPath, boolean recursive) {
|
|
||||||
TestSuite suite = new TestSuite(dataPath);
|
|
||||||
final String extension = ".jet";
|
|
||||||
FilenameFilter extensionFilter = new FilenameFilter() {
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File dir, String name) {
|
public Test createTest(@NotNull String dataPath, @NotNull String name) {
|
||||||
return name.endsWith(extension);
|
return new JetParsingTest(dataPath, name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
File dir = new File(getTestDataDir() + "/psi/" + dataPath);
|
String prefix = JetParsingTest.getTestDataDir() + "/psi/";
|
||||||
FileFilter dirFilter = new FileFilter() {
|
suite.addTest(JetTestCaseBase.suiteForDirectory(prefix, "/", false, factory));
|
||||||
@Override
|
suite.addTest(JetTestCaseBase.suiteForDirectory(prefix, "examples", true, factory));
|
||||||
public boolean accept(File pathname) {
|
|
||||||
return pathname.isDirectory();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (recursive) {
|
|
||||||
List<File> subdirs = Arrays.asList(dir.listFiles(dirFilter));
|
|
||||||
Collections.sort(subdirs);
|
|
||||||
for (File subdir : subdirs) {
|
|
||||||
suite.addTest(suiteForDirectory(dataPath + "/" + subdir.getName(), recursive));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<File> 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())));
|
|
||||||
}
|
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user