Special instructions added for calls and other constructs
This commit is contained in:
@@ -19,7 +19,11 @@ package org.jetbrains.jet.lang.cfg;
|
|||||||
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.pseudocode.Pseudocode;
|
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||||
|
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -82,7 +86,24 @@ public interface JetControlFlowBuilder {
|
|||||||
|
|
||||||
// Reading values
|
// Reading values
|
||||||
void loadUnit(@NotNull JetExpression expression);
|
void loadUnit(@NotNull JetExpression expression);
|
||||||
void read(@NotNull JetElement element);
|
void loadConstant(@NotNull JetExpression expression, @Nullable CompileTimeConstant<?> constant);
|
||||||
|
void createAnonymousObject(@NotNull JetObjectLiteralExpression expression);
|
||||||
|
void loadStringTemplate(@NotNull JetStringTemplateExpression expression);
|
||||||
|
|
||||||
|
void readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor);
|
||||||
|
void readVariable(@NotNull JetExpression expression, @Nullable VariableDescriptor variableDescriptor);
|
||||||
|
|
||||||
|
void call(@NotNull JetExpression expression, @NotNull ResolvedCall<?> resolvedCall);
|
||||||
|
|
||||||
|
enum PredefinedOperation {
|
||||||
|
AND,
|
||||||
|
OR,
|
||||||
|
NOT_NULL_ASSERTION
|
||||||
|
}
|
||||||
|
void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation);
|
||||||
|
|
||||||
|
void compilationError(@NotNull JetElement element, @NotNull String message);
|
||||||
|
|
||||||
void write(@NotNull JetElement assignment, @NotNull JetElement lValue);
|
void write(@NotNull JetElement assignment, @NotNull JetElement lValue);
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
|
|||||||
@@ -19,7 +19,11 @@ package org.jetbrains.jet.lang.cfg;
|
|||||||
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.pseudocode.Pseudocode;
|
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||||
|
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -27,13 +31,48 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
|||||||
protected JetControlFlowBuilder builder;
|
protected JetControlFlowBuilder builder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(@NotNull JetElement element) {
|
public void loadUnit(@NotNull JetExpression expression) {
|
||||||
builder.read(element);
|
builder.loadUnit(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadUnit(@NotNull JetExpression expression) {
|
public void loadConstant(@NotNull JetExpression expression, @Nullable CompileTimeConstant<?> constant) {
|
||||||
builder.loadUnit(expression);
|
builder.loadConstant(expression, constant);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createAnonymousObject(@NotNull JetObjectLiteralExpression expression) {
|
||||||
|
builder.createAnonymousObject(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadStringTemplate(@NotNull JetStringTemplateExpression expression) {
|
||||||
|
builder.loadStringTemplate(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
|
||||||
|
builder.readThis(expression, parameterDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readVariable(@NotNull JetExpression expression, @Nullable VariableDescriptor variableDescriptor) {
|
||||||
|
builder.readVariable(expression, variableDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void call(@NotNull JetExpression expression, @NotNull ResolvedCall<?> resolvedCall) {
|
||||||
|
builder.call(expression, resolvedCall);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation) {
|
||||||
|
builder.predefinedOperation(expression, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void compilationError(@NotNull JetElement element, @NotNull String message) {
|
||||||
|
builder.compilationError(element, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -26,21 +26,35 @@ import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator
|
|||||||
import org.jetbrains.jet.lang.cfg.pseudocode.LocalFunctionDeclarationInstruction;
|
import org.jetbrains.jet.lang.cfg.pseudocode.LocalFunctionDeclarationInstruction;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl;
|
import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
|
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastReceiver;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.BooleanValue;
|
import org.jetbrains.jet.lang.resolve.constants.BooleanValue;
|
||||||
|
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
|
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
|
||||||
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||||
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver;
|
||||||
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
|
import org.jetbrains.jet.lexer.JetToken;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lang.cfg.JetControlFlowBuilder.PredefinedOperation.*;
|
||||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||||
|
|
||||||
public class JetControlFlowProcessor {
|
public class JetControlFlowProcessor {
|
||||||
@@ -153,8 +167,6 @@ public class JetControlFlowProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression) {
|
public void visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression) {
|
||||||
builder.read(expression);
|
|
||||||
|
|
||||||
JetExpression innerExpression = expression.getExpression();
|
JetExpression innerExpression = expression.getExpression();
|
||||||
if (innerExpression != null) {
|
if (innerExpression != null) {
|
||||||
generateInstructions(innerExpression, inCondition);
|
generateInstructions(innerExpression, inCondition);
|
||||||
@@ -163,8 +175,6 @@ public class JetControlFlowProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitAnnotatedExpression(@NotNull JetAnnotatedExpression expression) {
|
public void visitAnnotatedExpression(@NotNull JetAnnotatedExpression expression) {
|
||||||
builder.read(expression);
|
|
||||||
|
|
||||||
JetExpression baseExpression = expression.getBaseExpression();
|
JetExpression baseExpression = expression.getBaseExpression();
|
||||||
if (baseExpression != null) {
|
if (baseExpression != null) {
|
||||||
generateInstructions(baseExpression, inCondition);
|
generateInstructions(baseExpression, inCondition);
|
||||||
@@ -173,17 +183,26 @@ public class JetControlFlowProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitThisExpression(@NotNull JetThisExpression expression) {
|
public void visitThisExpression(@NotNull JetThisExpression expression) {
|
||||||
builder.read(expression);
|
ResolvedCall<?> resolvedCall = getResolvedCall(expression);
|
||||||
|
builder.readThis(expression, resolvedCall == null ? null : (ReceiverParameterDescriptor) resolvedCall.getResultingDescriptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitConstantExpression(@NotNull JetConstantExpression expression) {
|
public void visitConstantExpression(@NotNull JetConstantExpression expression) {
|
||||||
builder.read(expression);
|
CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
|
||||||
|
builder.loadConstant(expression, constant);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) {
|
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) {
|
||||||
builder.read(expression);
|
ResolvedCall<?> resolvedCall = getResolvedCall(expression);
|
||||||
|
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||||
|
VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
|
||||||
|
generateCall(expression, variableAsFunctionResolvedCall.getVariableCall());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
generateCall(expression);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -204,7 +223,8 @@ public class JetControlFlowProcessor {
|
|||||||
|
|
||||||
@SuppressWarnings("SuspiciousMethodCalls") @Override
|
@SuppressWarnings("SuspiciousMethodCalls") @Override
|
||||||
public void visitBinaryExpression(@NotNull JetBinaryExpression expression) {
|
public void visitBinaryExpression(@NotNull JetBinaryExpression expression) {
|
||||||
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
|
JetSimpleNameExpression operationReference = expression.getOperationReference();
|
||||||
|
IElementType operationType = operationReference.getReferencedNameElementType();
|
||||||
JetExpression right = expression.getRight();
|
JetExpression right = expression.getRight();
|
||||||
if (operationType == JetTokens.ANDAND) {
|
if (operationType == JetTokens.ANDAND) {
|
||||||
generateInstructions(expression.getLeft(), true);
|
generateInstructions(expression.getLeft(), true);
|
||||||
@@ -215,7 +235,7 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
builder.bindLabel(resultLabel);
|
builder.bindLabel(resultLabel);
|
||||||
if (!inCondition) {
|
if (!inCondition) {
|
||||||
builder.read(expression);
|
builder.predefinedOperation(expression, AND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (operationType == JetTokens.OROR) {
|
else if (operationType == JetTokens.OROR) {
|
||||||
@@ -227,51 +247,33 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
builder.bindLabel(resultLabel);
|
builder.bindLabel(resultLabel);
|
||||||
if (!inCondition) {
|
if (!inCondition) {
|
||||||
builder.read(expression);
|
builder.predefinedOperation(expression, OR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (operationType == JetTokens.EQ) {
|
else if (operationType == JetTokens.EQ) {
|
||||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
|
||||||
if (right != null) {
|
if (right != null) {
|
||||||
generateInstructions(right, false);
|
generateInstructions(right, false);
|
||||||
}
|
}
|
||||||
if (left instanceof JetSimpleNameExpression) {
|
visitAssignment(expression.getLeft(), expression);
|
||||||
builder.write(expression, left);
|
|
||||||
}
|
|
||||||
else if (left instanceof JetArrayAccessExpression) {
|
|
||||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
|
||||||
visitAssignToArrayAccess(expression, arrayAccessExpression);
|
|
||||||
}
|
|
||||||
else if (left instanceof JetQualifiedExpression) {
|
|
||||||
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) left;
|
|
||||||
generateInstructions(qualifiedExpression.getReceiverExpression(), false);
|
|
||||||
generateInstructions(expression.getOperationReference(), false);
|
|
||||||
builder.write(expression, left);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
builder.unsupported(expression); // TODO
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
|
else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
|
||||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
if (generateCall(operationReference)) {
|
||||||
if (left != null) {
|
ResolvedCall<?> resolvedCall = getResolvedCall(operationReference);
|
||||||
generateInstructions(left, false);
|
assert resolvedCall != null : "Generation succeeded, but no call is found: " + expression.getText();
|
||||||
|
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||||
|
Name assignMethodName = OperatorConventions.getNameForOperationSymbol((JetToken) expression.getOperationToken());
|
||||||
|
if (!descriptor.getName().equals(assignMethodName)) {
|
||||||
|
// plus() called, assignment needed
|
||||||
|
visitAssignment(expression.getLeft(), expression);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (right != null) {
|
else {
|
||||||
generateInstructions(right, false);
|
generateBothArguments(expression);
|
||||||
}
|
|
||||||
if (left instanceof JetSimpleNameExpression || left instanceof JetArrayAccessExpression) {
|
|
||||||
generateInstructions(expression.getOperationReference(), false);
|
|
||||||
builder.write(expression, left);
|
|
||||||
}
|
|
||||||
else if (left != null) {
|
|
||||||
builder.unsupported(expression); // TODO
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (operationType == JetTokens.ELVIS) {
|
else if (operationType == JetTokens.ELVIS) {
|
||||||
builder.read(expression);
|
|
||||||
generateInstructions(expression.getLeft(), false);
|
generateInstructions(expression.getLeft(), false);
|
||||||
generateInstructions(expression.getOperationReference(), false);
|
generateInstructions(operationReference, false);
|
||||||
Label afterElvis = builder.createUnboundLabel();
|
Label afterElvis = builder.createUnboundLabel();
|
||||||
builder.jumpOnTrue(afterElvis);
|
builder.jumpOnTrue(afterElvis);
|
||||||
if (right != null) {
|
if (right != null) {
|
||||||
@@ -280,22 +282,60 @@ public class JetControlFlowProcessor {
|
|||||||
builder.bindLabel(afterElvis);
|
builder.bindLabel(afterElvis);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
generateInstructions(expression.getLeft(), false);
|
if (!generateCall(operationReference)) {
|
||||||
if (right != null) {
|
generateBothArguments(expression);
|
||||||
generateInstructions(right, false);
|
|
||||||
}
|
}
|
||||||
generateInstructions(expression.getOperationReference(), false);
|
|
||||||
builder.read(expression);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void visitAssignToArrayAccess(JetBinaryExpression expression, JetArrayAccessExpression arrayAccessExpression) {
|
private void generateBothArguments(JetBinaryExpression expression) {
|
||||||
for (JetExpression index : arrayAccessExpression.getIndexExpressions()) {
|
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||||
generateInstructions(index, false);
|
if (left != null) {
|
||||||
|
generateInstructions(left, false);
|
||||||
|
}
|
||||||
|
JetExpression right = expression.getRight();
|
||||||
|
if (right != null) {
|
||||||
|
generateInstructions(right, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visitAssignment(JetExpression lhs, JetExpression parentExpression) {
|
||||||
|
JetExpression left = JetPsiUtil.deparenthesize(lhs);
|
||||||
|
if (left == null) {
|
||||||
|
builder.compilationError(lhs, "No lValue in assignment");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (left instanceof JetSimpleNameExpression) {
|
||||||
|
// Do nothing, only record write below
|
||||||
|
}
|
||||||
|
else if (left instanceof JetArrayAccessExpression) {
|
||||||
|
generateArrayAccess((JetArrayAccessExpression) left);
|
||||||
|
}
|
||||||
|
else if (left instanceof JetQualifiedExpression) {
|
||||||
|
// read the receiver
|
||||||
|
generateInstructions(((JetQualifiedExpression) left).getReceiverExpression(), false);
|
||||||
|
}
|
||||||
|
else if (left instanceof JetProperty) {
|
||||||
|
// do nothing, just write below
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
builder.unsupported(parentExpression); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableDescriptor descriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), left, false);
|
||||||
|
if (descriptor != null) {
|
||||||
|
builder.write(parentExpression, left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateArrayAccess(JetArrayAccessExpression arrayAccessExpression) {
|
||||||
|
if (!generateCall(arrayAccessExpression)) {
|
||||||
|
for (JetExpression index : arrayAccessExpression.getIndexExpressions()) {
|
||||||
|
generateInstructions(index, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateInstructions(arrayAccessExpression.getArrayExpression(), false);
|
||||||
}
|
}
|
||||||
generateInstructions(arrayAccessExpression.getArrayExpression(), false);
|
|
||||||
generateInstructions(expression.getOperationReference(), false);
|
|
||||||
builder.write(expression, arrayAccessExpression); // TODO : ???
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -308,16 +348,20 @@ public class JetControlFlowProcessor {
|
|||||||
String referencedName = operationSign.getReferencedName();
|
String referencedName = operationSign.getReferencedName();
|
||||||
visitLabeledExpression(referencedName.substring(1), baseExpression);
|
visitLabeledExpression(referencedName.substring(1), baseExpression);
|
||||||
}
|
}
|
||||||
else {
|
else if (JetTokens.EXCLEXCL == operationType) {
|
||||||
generateInstructions(baseExpression, false);
|
generateInstructions(baseExpression, false);
|
||||||
generateInstructions(operationSign, false);
|
builder.predefinedOperation(expression, NOT_NULL_ASSERTION);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!generateCall(expression.getOperationReference())) {
|
||||||
|
generateInstructions(baseExpression, false);
|
||||||
|
}
|
||||||
|
|
||||||
boolean incrementOrDecrement = isIncrementOrDecrement(operationType);
|
boolean incrementOrDecrement = isIncrementOrDecrement(operationType);
|
||||||
if (incrementOrDecrement) {
|
if (incrementOrDecrement) {
|
||||||
builder.write(expression, baseExpression);
|
// We skip dup's and other subtleties here
|
||||||
|
visitAssignment(baseExpression, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.read(expression);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +397,7 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
builder.bindLabel(resultLabel);
|
builder.bindLabel(resultLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FinallyBlockGenerator {
|
private class FinallyBlockGenerator {
|
||||||
private final JetFinallySection finallyBlock;
|
private final JetFinallySection finallyBlock;
|
||||||
private Label startFinally = null;
|
private Label startFinally = null;
|
||||||
@@ -382,7 +426,6 @@ public class JetControlFlowProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitTryExpression(@NotNull JetTryExpression expression) {
|
public void visitTryExpression(@NotNull JetTryExpression expression) {
|
||||||
builder.read(expression);
|
|
||||||
JetFinallySection finallyBlock = expression.getFinallyBlock();
|
JetFinallySection finallyBlock = expression.getFinallyBlock();
|
||||||
final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock);
|
final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock);
|
||||||
if (finallyBlock != null) {
|
if (finallyBlock != null) {
|
||||||
@@ -414,7 +457,6 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
generateInstructions(expression.getTryBlock(), inCondition);
|
generateInstructions(expression.getTryBlock(), inCondition);
|
||||||
|
|
||||||
Collection<Label> allowDeadLabels = Lists.newArrayList();
|
|
||||||
if (hasCatches) {
|
if (hasCatches) {
|
||||||
Label afterCatches = builder.createUnboundLabel("afterCatches");
|
Label afterCatches = builder.createUnboundLabel("afterCatches");
|
||||||
builder.jump(afterCatches);
|
builder.jump(afterCatches);
|
||||||
@@ -467,7 +509,6 @@ public class JetControlFlowProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitWhileExpression(@NotNull JetWhileExpression expression) {
|
public void visitWhileExpression(@NotNull JetWhileExpression expression) {
|
||||||
builder.read(expression);
|
|
||||||
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
|
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
|
||||||
|
|
||||||
builder.bindLabel(loopInfo.getConditionEntryPoint());
|
builder.bindLabel(loopInfo.getConditionEntryPoint());
|
||||||
@@ -498,7 +539,6 @@ public class JetControlFlowProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitDoWhileExpression(@NotNull JetDoWhileExpression expression) {
|
public void visitDoWhileExpression(@NotNull JetDoWhileExpression expression) {
|
||||||
builder.read(expression);
|
|
||||||
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
|
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
|
||||||
|
|
||||||
builder.bindLabel(loopInfo.getBodyEntryPoint());
|
builder.bindLabel(loopInfo.getBodyEntryPoint());
|
||||||
@@ -518,7 +558,6 @@ public class JetControlFlowProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitForExpression(@NotNull JetForExpression expression) {
|
public void visitForExpression(@NotNull JetForExpression expression) {
|
||||||
builder.read(expression);
|
|
||||||
JetExpression loopRange = expression.getLoopRange();
|
JetExpression loopRange = expression.getLoopRange();
|
||||||
if (loopRange != null) {
|
if (loopRange != null) {
|
||||||
generateInstructions(loopRange, false);
|
generateInstructions(loopRange, false);
|
||||||
@@ -657,42 +696,32 @@ public class JetControlFlowProcessor {
|
|||||||
public void visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression) {
|
public void visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression) {
|
||||||
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
||||||
processLocalDeclaration(functionLiteral);
|
processLocalDeclaration(functionLiteral);
|
||||||
builder.read(expression);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitQualifiedExpression(@NotNull JetQualifiedExpression expression) {
|
public void visitQualifiedExpression(@NotNull JetQualifiedExpression expression) {
|
||||||
generateInstructions(expression.getReceiverExpression(), false);
|
|
||||||
JetExpression selectorExpression = expression.getSelectorExpression();
|
JetExpression selectorExpression = expression.getSelectorExpression();
|
||||||
if (selectorExpression != null) {
|
if (selectorExpression != null) {
|
||||||
generateInstructions(selectorExpression, false);
|
generateInstructions(selectorExpression, false);
|
||||||
}
|
}
|
||||||
builder.read(expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void visitCall(JetCallElement call) {
|
|
||||||
for (ValueArgument argument : call.getValueArguments()) {
|
|
||||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
|
||||||
if (argumentExpression != null) {
|
|
||||||
generateInstructions(argumentExpression, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (JetExpression functionLiteral : call.getFunctionLiteralArguments()) {
|
|
||||||
generateInstructions(functionLiteral, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitCallExpression(@NotNull JetCallExpression expression) {
|
public void visitCallExpression(@NotNull JetCallExpression expression) {
|
||||||
for (JetTypeProjection typeArgument : expression.getTypeArguments()) {
|
if (!generateCall(expression.getCalleeExpression())) {
|
||||||
generateInstructions(typeArgument, false);
|
for (ValueArgument argument : expression.getValueArguments()) {
|
||||||
|
JetExpression argumentExpression = argument.getArgumentExpression();
|
||||||
|
if (argumentExpression != null) {
|
||||||
|
generateInstructions(argumentExpression, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (JetExpression functionLiteral : expression.getFunctionLiteralArguments()) {
|
||||||
|
generateInstructions(functionLiteral, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateInstructions(expression.getCalleeExpression(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitCall(expression);
|
|
||||||
|
|
||||||
generateInstructions(expression.getCalleeExpression(), false);
|
|
||||||
builder.read(expression);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -701,7 +730,7 @@ public class JetControlFlowProcessor {
|
|||||||
JetExpression initializer = property.getInitializer();
|
JetExpression initializer = property.getInitializer();
|
||||||
if (initializer != null) {
|
if (initializer != null) {
|
||||||
generateInstructions(initializer, false);
|
generateInstructions(initializer, false);
|
||||||
builder.write(property, property);
|
visitAssignment(property, property);
|
||||||
}
|
}
|
||||||
JetExpression delegate = property.getDelegateExpression();
|
JetExpression delegate = property.getDelegateExpression();
|
||||||
if (delegate != null) {
|
if (delegate != null) {
|
||||||
@@ -721,6 +750,10 @@ public class JetControlFlowProcessor {
|
|||||||
List<JetMultiDeclarationEntry> entries = declaration.getEntries();
|
List<JetMultiDeclarationEntry> entries = declaration.getEntries();
|
||||||
for (JetMultiDeclarationEntry entry : entries) {
|
for (JetMultiDeclarationEntry entry : entries) {
|
||||||
builder.declareVariable(entry);
|
builder.declareVariable(entry);
|
||||||
|
ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
|
||||||
|
if (resolvedCall != null) {
|
||||||
|
builder.call(entry, resolvedCall);
|
||||||
|
}
|
||||||
builder.write(entry, entry);
|
builder.write(entry, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -735,7 +768,6 @@ public class JetControlFlowProcessor {
|
|||||||
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
|
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
|
||||||
if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) {
|
if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) {
|
||||||
generateInstructions(expression.getLeft(), false);
|
generateInstructions(expression.getLeft(), false);
|
||||||
builder.read(expression);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
visitJetElement(expression);
|
visitJetElement(expression);
|
||||||
@@ -753,20 +785,14 @@ public class JetControlFlowProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) {
|
public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) {
|
||||||
for (JetExpression index : expression.getIndexExpressions()) {
|
if (!generateCall(expression)) {
|
||||||
generateInstructions(index, false);
|
generateArrayAccess(expression);
|
||||||
}
|
}
|
||||||
generateInstructions(expression.getArrayExpression(), false);
|
|
||||||
// TODO : read 'get' or 'set' function
|
|
||||||
builder.read(expression);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitIsExpression(@NotNull JetIsExpression expression) {
|
public void visitIsExpression(@NotNull JetIsExpression expression) {
|
||||||
generateInstructions(expression.getLeftHandSide(), inCondition);
|
generateInstructions(expression.getLeftHandSide(), inCondition);
|
||||||
// no CF for types
|
|
||||||
// TODO : builder.read(expression.getPattern());
|
|
||||||
builder.read(expression);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -783,8 +809,6 @@ public class JetControlFlowProcessor {
|
|||||||
for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
|
for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
|
||||||
JetWhenEntry whenEntry = iterator.next();
|
JetWhenEntry whenEntry = iterator.next();
|
||||||
|
|
||||||
builder.read(whenEntry);
|
|
||||||
|
|
||||||
boolean isElse = whenEntry.isElse();
|
boolean isElse = whenEntry.isElse();
|
||||||
if (isElse) {
|
if (isElse) {
|
||||||
hasElse = true;
|
hasElse = true;
|
||||||
@@ -837,7 +861,7 @@ public class JetControlFlowProcessor {
|
|||||||
for (JetDeclaration function : functions) {
|
for (JetDeclaration function : functions) {
|
||||||
generateInstructions(function, inCondition);
|
generateInstructions(function, inCondition);
|
||||||
}
|
}
|
||||||
builder.read(expression);
|
builder.createAnonymousObject(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -853,7 +877,7 @@ public class JetControlFlowProcessor {
|
|||||||
generateInstructions(entryWithExpression.getExpression(), false);
|
generateInstructions(entryWithExpression.getExpression(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.read(expression);
|
builder.loadStringTemplate(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -913,5 +937,79 @@ public class JetControlFlowProcessor {
|
|||||||
public void visitJetElement(@NotNull JetElement element) {
|
public void visitJetElement(@NotNull JetElement element) {
|
||||||
builder.unsupported(element);
|
builder.unsupported(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private ResolvedCall<?> getResolvedCall(@NotNull JetElement expression) {
|
||||||
|
return trace.get(BindingContext.RESOLVED_CALL, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean generateCall(JetExpression calleeExpression) {
|
||||||
|
ResolvedCall<?> resolvedCall = getResolvedCall(calleeExpression);
|
||||||
|
if (resolvedCall == null) {
|
||||||
|
builder.compilationError(calleeExpression, "No resolved call");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
generateCall(calleeExpression, resolvedCall);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateCall(JetExpression calleeExpression, ResolvedCall<?> resolvedCall) {
|
||||||
|
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||||
|
VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
|
||||||
|
generateCall(calleeExpression, variableAsFunctionResolvedCall.getFunctionCall());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
|
||||||
|
if (resultingDescriptor instanceof ExpressionAsFunctionDescriptor) {
|
||||||
|
generateInstructions(((ExpressionAsFunctionDescriptor) resultingDescriptor).getExpression(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateReceiver(resolvedCall.getThisObject());
|
||||||
|
generateReceiver(resolvedCall.getReceiverArgument());
|
||||||
|
|
||||||
|
for (ValueParameterDescriptor parameterDescriptor : resultingDescriptor.getValueParameters()) {
|
||||||
|
ResolvedValueArgument argument = resolvedCall.getValueArguments().get(parameterDescriptor);
|
||||||
|
if (argument == null) continue;
|
||||||
|
|
||||||
|
generateValueArgument(argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultingDescriptor instanceof VariableDescriptor) {
|
||||||
|
builder.readVariable(calleeExpression, (VariableDescriptor) resultingDescriptor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
builder.call(calleeExpression, resolvedCall);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateReceiver(ReceiverValue receiver) {
|
||||||
|
if (!receiver.exists()) return;
|
||||||
|
if (receiver instanceof ThisReceiver) {
|
||||||
|
// TODO: Receiver is passed implicitly: no expression to tie the read to
|
||||||
|
}
|
||||||
|
else if (receiver instanceof ExpressionReceiver) {
|
||||||
|
generateInstructions(((ExpressionReceiver) receiver).getExpression(), false);
|
||||||
|
}
|
||||||
|
else if (receiver instanceof TransientReceiver) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
else if (receiver instanceof AutoCastReceiver) {
|
||||||
|
// No cast instruction in our CFG
|
||||||
|
generateReceiver(((AutoCastReceiver) receiver).getOriginal());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException("Unknown receiver kind: " + receiver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateValueArgument(ResolvedValueArgument argument) {
|
||||||
|
for (ValueArgument valueArgument : argument.getArguments()) {
|
||||||
|
JetExpression expression = valueArgument.getArgumentExpression();
|
||||||
|
if (expression != null) {
|
||||||
|
generateInstructions(expression, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -80,11 +80,19 @@ public class InstructionVisitor {
|
|||||||
visitInstructionWithNext(instruction);
|
visitInstructionWithNext(instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitWriteValue(WriteValueInstruction writeValueInstruction) {
|
public void visitWriteValue(WriteValueInstruction instruction) {
|
||||||
visitInstructionWithNext(writeValueInstruction);
|
visitInstructionWithNext(instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitLoadUnitValue(LoadUnitValueInstruction instruction) {
|
public void visitLoadUnitValue(LoadUnitValueInstruction instruction) {
|
||||||
visitInstructionWithNext(instruction);
|
visitInstructionWithNext(instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void visitCallInstruction(CallInstruction instruction) {
|
||||||
|
visitInstructionWithNext(instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitCompilationErrorInstruction(CompilationErrorInstruction instruction) {
|
||||||
|
visitInstructionWithNext(instruction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-6
@@ -20,7 +20,11 @@ import com.intellij.util.containers.Stack;
|
|||||||
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.*;
|
import org.jetbrains.jet.lang.cfg.*;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||||
|
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -251,11 +255,6 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
add(new LocalFunctionDeclarationInstruction(subroutine, pseudocode));
|
add(new LocalFunctionDeclarationInstruction(subroutine, pseudocode));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void read(@NotNull JetElement element) {
|
|
||||||
add(new ReadValueInstruction(element));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadUnit(@NotNull JetExpression expression) {
|
public void loadUnit(@NotNull JetExpression expression) {
|
||||||
add(new LoadUnitValueInstruction(expression));
|
add(new LoadUnitValueInstruction(expression));
|
||||||
@@ -313,7 +312,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
handleJumpInsideTryFinally(error);
|
handleJumpInsideTryFinally(error);
|
||||||
add(new ThrowExceptionInstruction(expression, error));
|
add(new ThrowExceptionInstruction(expression, error));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void exitTryFinally() {
|
public void exitTryFinally() {
|
||||||
BlockInfo pop = allBlocks.pop();
|
BlockInfo pop = allBlocks.pop();
|
||||||
assert pop instanceof TryFinallyBlockInfo;
|
assert pop instanceof TryFinallyBlockInfo;
|
||||||
@@ -328,6 +327,50 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
public void repeatPseudocode(@NotNull Label startLabel, @NotNull Label finishLabel) {
|
public void repeatPseudocode(@NotNull Label startLabel, @NotNull Label finishLabel) {
|
||||||
pseudocode.repeatPart(startLabel, finishLabel);
|
pseudocode.repeatPart(startLabel, finishLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadConstant(@NotNull JetExpression expression, @Nullable CompileTimeConstant<?> constant) {
|
||||||
|
read(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createAnonymousObject(@NotNull JetObjectLiteralExpression expression) {
|
||||||
|
read(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadStringTemplate(@NotNull JetStringTemplateExpression expression) {
|
||||||
|
read(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
|
||||||
|
read(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readVariable(@NotNull JetExpression expression, @Nullable VariableDescriptor variableDescriptor) {
|
||||||
|
read(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void call(@NotNull JetExpression expression, @NotNull ResolvedCall<?> resolvedCall) {
|
||||||
|
add(new CallInstruction(expression, resolvedCall));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation) {
|
||||||
|
read(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void compilationError(@NotNull JetElement element, @NotNull String message) {
|
||||||
|
add(new CompilationErrorInstruction(element, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void read(@NotNull JetElement element) {
|
||||||
|
add(new ReadValueInstruction(element));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TryFinallyBlockInfo extends BlockInfo {
|
public static class TryFinallyBlockInfo extends BlockInfo {
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.lang.cfg.pseudocode
|
||||||
|
|
||||||
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor
|
||||||
|
import org.jetbrains.jet.lang.psi.JetElement
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
|
||||||
|
|
||||||
|
class CallInstruction(
|
||||||
|
element: JetElement,
|
||||||
|
val resolvedCall: ResolvedCall<*>
|
||||||
|
) : InstructionWithNext(element) {
|
||||||
|
|
||||||
|
override fun accept(visitor: InstructionVisitor) {
|
||||||
|
visitor.visitCallInstruction(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createCopy() = CallInstruction(element, resolvedCall)
|
||||||
|
|
||||||
|
override fun toString() = "call(${element.getText()}, ${resolvedCall.getResultingDescriptor()!!.getName()})"
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompilationErrorInstruction(
|
||||||
|
element: JetElement,
|
||||||
|
val message: String
|
||||||
|
) : InstructionWithNext(element) {
|
||||||
|
|
||||||
|
override fun accept(visitor: InstructionVisitor) {
|
||||||
|
visitor.visitCompilationErrorInstruction(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createCopy() = CompilationErrorInstruction(element, message)
|
||||||
|
|
||||||
|
override fun toString() = "error(${element.getText()}, $message)"
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
== Ab ==
|
||||||
|
abstract class Ab {
|
||||||
|
abstract fun getArray() : Array<Int>
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
<START> NEXT:[<END>] PREV:[]
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>] PREV:[<START>]
|
||||||
|
error:
|
||||||
|
<ERROR> NEXT:[<SINK>] PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> NEXT:[] PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
|
== test ==
|
||||||
|
fun test(ab: Ab) {
|
||||||
|
ab.getArray()[1]
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
<START> NEXT:[v(ab: Ab)] PREV:[]
|
||||||
|
v(ab: Ab) NEXT:[w(ab)] PREV:[<START>]
|
||||||
|
w(ab) NEXT:[r(ab)] PREV:[v(ab: Ab)]
|
||||||
|
r(ab) NEXT:[call(getArray, getArray)] PREV:[w(ab)]
|
||||||
|
call(getArray, getArray) NEXT:[r(1)] PREV:[r(ab)]
|
||||||
|
r(1) NEXT:[call(ab.getArray()[1], get)] PREV:[call(getArray, getArray)]
|
||||||
|
call(ab.getArray()[1], get) NEXT:[<END>] PREV:[r(1)]
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>] PREV:[call(ab.getArray()[1], get)]
|
||||||
|
error:
|
||||||
|
<ERROR> NEXT:[<SINK>] PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> NEXT:[] PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
abstract class Ab {
|
||||||
|
abstract fun getArray() : Array<Int>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test(ab: Ab) {
|
||||||
|
ab.getArray()[1]
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
== C ==
|
||||||
|
class C {
|
||||||
|
val a: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
{
|
||||||
|
$a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
<START> NEXT:[v(val a: Int get() = 1) ] PREV:[]
|
||||||
|
v(val a: Int
|
||||||
|
get() = 1) NEXT:[jmp?(L2)] PREV:[<START>]
|
||||||
|
jmp?(L2) NEXT:[r($a), d(get() = 1)] PREV:[v(val a: Int get() = 1) ]
|
||||||
|
d(get() = 1) NEXT:[<SINK>] PREV:[jmp?(L2)]
|
||||||
|
L2:
|
||||||
|
r($a) NEXT:[<END>] PREV:[jmp?(L2)]
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>] PREV:[r($a)]
|
||||||
|
error:
|
||||||
|
<ERROR> NEXT:[<SINK>] PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> NEXT:[] PREV:[<ERROR>, <END>, d(get() = 1)]
|
||||||
|
L3:
|
||||||
|
<START> NEXT:[r(1)] PREV:[]
|
||||||
|
r(1) NEXT:[<END>] PREV:[<START>]
|
||||||
|
L4:
|
||||||
|
<END> NEXT:[<SINK>] PREV:[r(1)]
|
||||||
|
error:
|
||||||
|
<ERROR> NEXT:[<SINK>] PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> NEXT:[] PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
|
== get_a ==
|
||||||
|
get() = 1
|
||||||
|
---------------------
|
||||||
|
L3:
|
||||||
|
<START> NEXT:[r(1)] PREV:[]
|
||||||
|
r(1) NEXT:[<END>] PREV:[<START>]
|
||||||
|
L4:
|
||||||
|
<END> NEXT:[<SINK>] PREV:[r(1)]
|
||||||
|
error:
|
||||||
|
<ERROR> NEXT:[<SINK>] PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> NEXT:[] PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
class C {
|
||||||
|
val a: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
{
|
||||||
|
$a
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
== foo ==
|
||||||
|
fun foo() {
|
||||||
|
var i = 1
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
<START> NEXT:[v(var i = 1)] PREV:[]
|
||||||
|
v(var i = 1) NEXT:[r(1)] PREV:[<START>]
|
||||||
|
r(1) NEXT:[w(i)] PREV:[v(var i = 1)]
|
||||||
|
w(i) NEXT:[r(i)] PREV:[r(1)]
|
||||||
|
r(i) NEXT:[call(++, inc)] PREV:[w(i)]
|
||||||
|
call(++, inc) NEXT:[w(i)] PREV:[r(i)]
|
||||||
|
w(i) NEXT:[<END>] PREV:[call(++, inc)]
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>] PREV:[w(i)]
|
||||||
|
error:
|
||||||
|
<ERROR> NEXT:[<SINK>] PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> NEXT:[] PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo() {
|
||||||
|
var i = 1
|
||||||
|
i++
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
== foo ==
|
||||||
|
fun foo(f: () -> Unit) {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
<START> NEXT:[v(f: () -> Unit)] PREV:[]
|
||||||
|
v(f: () -> Unit) NEXT:[w(f)] PREV:[<START>]
|
||||||
|
w(f) NEXT:[r(f)] PREV:[v(f: () -> Unit)]
|
||||||
|
r(f) NEXT:[call(f, invoke)] PREV:[w(f)]
|
||||||
|
call(f, invoke) NEXT:[<END>] PREV:[r(f)]
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>] PREV:[call(f, invoke)]
|
||||||
|
error:
|
||||||
|
<ERROR> NEXT:[<SINK>] PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> NEXT:[] PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo(f: () -> Unit) {
|
||||||
|
f()
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
== foo ==
|
||||||
|
fun foo(x: Int) {
|
||||||
|
val (a, b) = x
|
||||||
|
a
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
<START> NEXT:[v(x: Int)] PREV:[]
|
||||||
|
v(x: Int) NEXT:[w(x)] PREV:[<START>]
|
||||||
|
w(x) NEXT:[r(x)] PREV:[v(x: Int)]
|
||||||
|
r(x) NEXT:[v(a)] PREV:[w(x)]
|
||||||
|
v(a) NEXT:[w(a)] PREV:[r(x)]
|
||||||
|
w(a) NEXT:[v(b)] PREV:[v(a)]
|
||||||
|
v(b) NEXT:[w(b)] PREV:[w(a)]
|
||||||
|
w(b) NEXT:[r(a)] PREV:[v(b)]
|
||||||
|
r(a) NEXT:[<END>] PREV:[w(b)]
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>] PREV:[r(a)]
|
||||||
|
error:
|
||||||
|
<ERROR> NEXT:[<SINK>] PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> NEXT:[] PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo(x: Int) {
|
||||||
|
val (a, b) = x
|
||||||
|
a
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
== test ==
|
||||||
|
fun test(s: String?) {
|
||||||
|
s?.length
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
<START> NEXT:[v(s: String?)] PREV:[]
|
||||||
|
v(s: String?) NEXT:[w(s)] PREV:[<START>]
|
||||||
|
w(s) NEXT:[r(s)] PREV:[v(s: String?)]
|
||||||
|
r(s) NEXT:[call(length, length)] PREV:[w(s)]
|
||||||
|
call(length, length) NEXT:[<END>] PREV:[r(s)]
|
||||||
|
L1:
|
||||||
|
<END> NEXT:[<SINK>] PREV:[call(length, length)]
|
||||||
|
error:
|
||||||
|
<ERROR> NEXT:[<SINK>] PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> NEXT:[] PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun test(s: String?) {
|
||||||
|
s?.length
|
||||||
|
}
|
||||||
@@ -110,7 +110,7 @@ class Test() {
|
|||||||
a++
|
a++
|
||||||
(@ a)++
|
(@ a)++
|
||||||
(a : Int)++
|
(a : Int)++
|
||||||
(a)++
|
<!UNUSED_CHANGED_VALUE!>(a)++<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testVariables1() {
|
fun testVariables1() {
|
||||||
|
|||||||
@@ -46,11 +46,21 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
|
|||||||
doTest("compiler/testData/cfg/ArrayAccess.kt");
|
doTest("compiler/testData/cfg/ArrayAccess.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("arrayAccessExpression.kt")
|
||||||
|
public void testArrayAccessExpression() throws Exception {
|
||||||
|
doTest("compiler/testData/cfg/arrayAccessExpression.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Assignments.kt")
|
@TestMetadata("Assignments.kt")
|
||||||
public void testAssignments() throws Exception {
|
public void testAssignments() throws Exception {
|
||||||
doTest("compiler/testData/cfg/Assignments.kt");
|
doTest("compiler/testData/cfg/Assignments.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("backingFieldAccess.kt")
|
||||||
|
public void testBackingFieldAccess() throws Exception {
|
||||||
|
doTest("compiler/testData/cfg/backingFieldAccess.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Basic.kt")
|
@TestMetadata("Basic.kt")
|
||||||
public void testBasic() throws Exception {
|
public void testBasic() throws Exception {
|
||||||
doTest("compiler/testData/cfg/Basic.kt");
|
doTest("compiler/testData/cfg/Basic.kt");
|
||||||
@@ -96,6 +106,16 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
|
|||||||
doTest("compiler/testData/cfg/If.kt");
|
doTest("compiler/testData/cfg/If.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("incrementAtTheEnd.kt")
|
||||||
|
public void testIncrementAtTheEnd() throws Exception {
|
||||||
|
doTest("compiler/testData/cfg/incrementAtTheEnd.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("invoke.kt")
|
||||||
|
public void testInvoke() throws Exception {
|
||||||
|
doTest("compiler/testData/cfg/invoke.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("LazyBooleans.kt")
|
@TestMetadata("LazyBooleans.kt")
|
||||||
public void testLazyBooleans() throws Exception {
|
public void testLazyBooleans() throws Exception {
|
||||||
doTest("compiler/testData/cfg/LazyBooleans.kt");
|
doTest("compiler/testData/cfg/LazyBooleans.kt");
|
||||||
@@ -111,6 +131,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
|
|||||||
doTest("compiler/testData/cfg/MultiDecl.kt");
|
doTest("compiler/testData/cfg/MultiDecl.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("multiDeclarationWithError.kt")
|
||||||
|
public void testMultiDeclarationWithError() throws Exception {
|
||||||
|
doTest("compiler/testData/cfg/multiDeclarationWithError.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ObjectExpression.kt")
|
@TestMetadata("ObjectExpression.kt")
|
||||||
public void testObjectExpression() throws Exception {
|
public void testObjectExpression() throws Exception {
|
||||||
doTest("compiler/testData/cfg/ObjectExpression.kt");
|
doTest("compiler/testData/cfg/ObjectExpression.kt");
|
||||||
@@ -121,6 +146,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
|
|||||||
doTest("compiler/testData/cfg/OnlyWhileInFunctionBody.kt");
|
doTest("compiler/testData/cfg/OnlyWhileInFunctionBody.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertySafeCall.kt")
|
||||||
|
public void testPropertySafeCall() throws Exception {
|
||||||
|
doTest("compiler/testData/cfg/propertySafeCall.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ReturnFromExpression.kt")
|
@TestMetadata("ReturnFromExpression.kt")
|
||||||
public void testReturnFromExpression() throws Exception {
|
public void testReturnFromExpression() throws Exception {
|
||||||
doTest("compiler/testData/cfg/ReturnFromExpression.kt");
|
doTest("compiler/testData/cfg/ReturnFromExpression.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user