Special instructions added for calls and other constructs

This commit is contained in:
Andrey Breslav
2013-12-02 17:28:38 +04:00
parent 0b575da5d3
commit 1e2eb6dfa1
20 changed files with 594 additions and 115 deletions
@@ -19,7 +19,11 @@ package org.jetbrains.jet.lang.cfg;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import java.util.List;
@@ -82,7 +86,24 @@ public interface JetControlFlowBuilder {
// Reading values
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);
// Other
@@ -19,7 +19,11 @@ package org.jetbrains.jet.lang.cfg;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import java.util.List;
@@ -27,13 +31,48 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
protected JetControlFlowBuilder builder;
@Override
public void read(@NotNull JetElement element) {
builder.read(element);
public void loadUnit(@NotNull JetExpression expression) {
builder.loadUnit(expression);
}
@Override
public void loadUnit(@NotNull JetExpression expression) {
builder.loadUnit(expression);
public void loadConstant(@NotNull JetExpression expression, @Nullable CompileTimeConstant<?> constant) {
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
@@ -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.Pseudocode;
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.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
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.CompileTimeConstant;
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.expressions.OperatorConventions;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import static org.jetbrains.jet.lang.cfg.JetControlFlowBuilder.PredefinedOperation.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
public class JetControlFlowProcessor {
@@ -153,8 +167,6 @@ public class JetControlFlowProcessor {
@Override
public void visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression) {
builder.read(expression);
JetExpression innerExpression = expression.getExpression();
if (innerExpression != null) {
generateInstructions(innerExpression, inCondition);
@@ -163,8 +175,6 @@ public class JetControlFlowProcessor {
@Override
public void visitAnnotatedExpression(@NotNull JetAnnotatedExpression expression) {
builder.read(expression);
JetExpression baseExpression = expression.getBaseExpression();
if (baseExpression != null) {
generateInstructions(baseExpression, inCondition);
@@ -173,17 +183,26 @@ public class JetControlFlowProcessor {
@Override
public void visitThisExpression(@NotNull JetThisExpression expression) {
builder.read(expression);
ResolvedCall<?> resolvedCall = getResolvedCall(expression);
builder.readThis(expression, resolvedCall == null ? null : (ReceiverParameterDescriptor) resolvedCall.getResultingDescriptor());
}
@Override
public void visitConstantExpression(@NotNull JetConstantExpression expression) {
builder.read(expression);
CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
builder.loadConstant(expression, constant);
}
@Override
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
@@ -204,7 +223,8 @@ public class JetControlFlowProcessor {
@SuppressWarnings("SuspiciousMethodCalls") @Override
public void visitBinaryExpression(@NotNull JetBinaryExpression expression) {
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
JetSimpleNameExpression operationReference = expression.getOperationReference();
IElementType operationType = operationReference.getReferencedNameElementType();
JetExpression right = expression.getRight();
if (operationType == JetTokens.ANDAND) {
generateInstructions(expression.getLeft(), true);
@@ -215,7 +235,7 @@ public class JetControlFlowProcessor {
}
builder.bindLabel(resultLabel);
if (!inCondition) {
builder.read(expression);
builder.predefinedOperation(expression, AND);
}
}
else if (operationType == JetTokens.OROR) {
@@ -227,51 +247,33 @@ public class JetControlFlowProcessor {
}
builder.bindLabel(resultLabel);
if (!inCondition) {
builder.read(expression);
builder.predefinedOperation(expression, OR);
}
}
else if (operationType == JetTokens.EQ) {
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
if (right != null) {
generateInstructions(right, false);
}
if (left instanceof JetSimpleNameExpression) {
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
}
visitAssignment(expression.getLeft(), expression);
}
else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
if (left != null) {
generateInstructions(left, false);
if (generateCall(operationReference)) {
ResolvedCall<?> resolvedCall = getResolvedCall(operationReference);
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) {
generateInstructions(right, false);
}
if (left instanceof JetSimpleNameExpression || left instanceof JetArrayAccessExpression) {
generateInstructions(expression.getOperationReference(), false);
builder.write(expression, left);
}
else if (left != null) {
builder.unsupported(expression); // TODO
else {
generateBothArguments(expression);
}
}
else if (operationType == JetTokens.ELVIS) {
builder.read(expression);
generateInstructions(expression.getLeft(), false);
generateInstructions(expression.getOperationReference(), false);
generateInstructions(operationReference, false);
Label afterElvis = builder.createUnboundLabel();
builder.jumpOnTrue(afterElvis);
if (right != null) {
@@ -280,22 +282,60 @@ public class JetControlFlowProcessor {
builder.bindLabel(afterElvis);
}
else {
generateInstructions(expression.getLeft(), false);
if (right != null) {
generateInstructions(right, false);
if (!generateCall(operationReference)) {
generateBothArguments(expression);
}
generateInstructions(expression.getOperationReference(), false);
builder.read(expression);
}
}
private void visitAssignToArrayAccess(JetBinaryExpression expression, JetArrayAccessExpression arrayAccessExpression) {
for (JetExpression index : arrayAccessExpression.getIndexExpressions()) {
generateInstructions(index, false);
private void generateBothArguments(JetBinaryExpression expression) {
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
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
@@ -308,16 +348,20 @@ public class JetControlFlowProcessor {
String referencedName = operationSign.getReferencedName();
visitLabeledExpression(referencedName.substring(1), baseExpression);
}
else {
else if (JetTokens.EXCLEXCL == operationType) {
generateInstructions(baseExpression, false);
generateInstructions(operationSign, false);
builder.predefinedOperation(expression, NOT_NULL_ASSERTION);
}
else {
if (!generateCall(expression.getOperationReference())) {
generateInstructions(baseExpression, false);
}
boolean incrementOrDecrement = isIncrementOrDecrement(operationType);
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);
}
private class FinallyBlockGenerator {
private final JetFinallySection finallyBlock;
private Label startFinally = null;
@@ -382,7 +426,6 @@ public class JetControlFlowProcessor {
@Override
public void visitTryExpression(@NotNull JetTryExpression expression) {
builder.read(expression);
JetFinallySection finallyBlock = expression.getFinallyBlock();
final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock);
if (finallyBlock != null) {
@@ -414,7 +457,6 @@ public class JetControlFlowProcessor {
}
generateInstructions(expression.getTryBlock(), inCondition);
Collection<Label> allowDeadLabels = Lists.newArrayList();
if (hasCatches) {
Label afterCatches = builder.createUnboundLabel("afterCatches");
builder.jump(afterCatches);
@@ -467,7 +509,6 @@ public class JetControlFlowProcessor {
@Override
public void visitWhileExpression(@NotNull JetWhileExpression expression) {
builder.read(expression);
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
builder.bindLabel(loopInfo.getConditionEntryPoint());
@@ -498,7 +539,6 @@ public class JetControlFlowProcessor {
@Override
public void visitDoWhileExpression(@NotNull JetDoWhileExpression expression) {
builder.read(expression);
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
builder.bindLabel(loopInfo.getBodyEntryPoint());
@@ -518,7 +558,6 @@ public class JetControlFlowProcessor {
@Override
public void visitForExpression(@NotNull JetForExpression expression) {
builder.read(expression);
JetExpression loopRange = expression.getLoopRange();
if (loopRange != null) {
generateInstructions(loopRange, false);
@@ -657,42 +696,32 @@ public class JetControlFlowProcessor {
public void visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression) {
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
processLocalDeclaration(functionLiteral);
builder.read(expression);
}
@Override
public void visitQualifiedExpression(@NotNull JetQualifiedExpression expression) {
generateInstructions(expression.getReceiverExpression(), false);
JetExpression selectorExpression = expression.getSelectorExpression();
if (selectorExpression != null) {
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
public void visitCallExpression(@NotNull JetCallExpression expression) {
for (JetTypeProjection typeArgument : expression.getTypeArguments()) {
generateInstructions(typeArgument, false);
if (!generateCall(expression.getCalleeExpression())) {
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
@@ -701,7 +730,7 @@ public class JetControlFlowProcessor {
JetExpression initializer = property.getInitializer();
if (initializer != null) {
generateInstructions(initializer, false);
builder.write(property, property);
visitAssignment(property, property);
}
JetExpression delegate = property.getDelegateExpression();
if (delegate != null) {
@@ -721,6 +750,10 @@ public class JetControlFlowProcessor {
List<JetMultiDeclarationEntry> entries = declaration.getEntries();
for (JetMultiDeclarationEntry entry : entries) {
builder.declareVariable(entry);
ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
if (resolvedCall != null) {
builder.call(entry, resolvedCall);
}
builder.write(entry, entry);
}
}
@@ -735,7 +768,6 @@ public class JetControlFlowProcessor {
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) {
generateInstructions(expression.getLeft(), false);
builder.read(expression);
}
else {
visitJetElement(expression);
@@ -753,20 +785,14 @@ public class JetControlFlowProcessor {
@Override
public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) {
for (JetExpression index : expression.getIndexExpressions()) {
generateInstructions(index, false);
if (!generateCall(expression)) {
generateArrayAccess(expression);
}
generateInstructions(expression.getArrayExpression(), false);
// TODO : read 'get' or 'set' function
builder.read(expression);
}
@Override
public void visitIsExpression(@NotNull JetIsExpression expression) {
generateInstructions(expression.getLeftHandSide(), inCondition);
// no CF for types
// TODO : builder.read(expression.getPattern());
builder.read(expression);
}
@Override
@@ -783,8 +809,6 @@ public class JetControlFlowProcessor {
for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
JetWhenEntry whenEntry = iterator.next();
builder.read(whenEntry);
boolean isElse = whenEntry.isElse();
if (isElse) {
hasElse = true;
@@ -837,7 +861,7 @@ public class JetControlFlowProcessor {
for (JetDeclaration function : functions) {
generateInstructions(function, inCondition);
}
builder.read(expression);
builder.createAnonymousObject(expression);
}
@Override
@@ -853,7 +877,7 @@ public class JetControlFlowProcessor {
generateInstructions(entryWithExpression.getExpression(), false);
}
}
builder.read(expression);
builder.loadStringTemplate(expression);
}
@Override
@@ -913,5 +937,79 @@ public class JetControlFlowProcessor {
public void visitJetElement(@NotNull JetElement 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);
}
}
}
}
}
@@ -80,11 +80,19 @@ public class InstructionVisitor {
visitInstructionWithNext(instruction);
}
public void visitWriteValue(WriteValueInstruction writeValueInstruction) {
visitInstructionWithNext(writeValueInstruction);
public void visitWriteValue(WriteValueInstruction instruction) {
visitInstructionWithNext(instruction);
}
public void visitLoadUnitValue(LoadUnitValueInstruction instruction) {
visitInstructionWithNext(instruction);
}
public void visitCallInstruction(CallInstruction instruction) {
visitInstructionWithNext(instruction);
}
public void visitCompilationErrorInstruction(CompilationErrorInstruction instruction) {
visitInstructionWithNext(instruction);
}
}
@@ -20,7 +20,11 @@ import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import java.util.ArrayList;
import java.util.HashMap;
@@ -251,11 +255,6 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
add(new LocalFunctionDeclarationInstruction(subroutine, pseudocode));
}
@Override
public void read(@NotNull JetElement element) {
add(new ReadValueInstruction(element));
}
@Override
public void loadUnit(@NotNull JetExpression expression) {
add(new LoadUnitValueInstruction(expression));
@@ -313,7 +312,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
handleJumpInsideTryFinally(error);
add(new ThrowExceptionInstruction(expression, error));
}
public void exitTryFinally() {
BlockInfo pop = allBlocks.pop();
assert pop instanceof TryFinallyBlockInfo;
@@ -328,6 +327,50 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
public void repeatPseudocode(@NotNull Label startLabel, @NotNull Label 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 {
@@ -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++
}
+18
View File
@@ -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>]
=====================
+3
View File
@@ -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 : Int)++
(a)++
<!UNUSED_CHANGED_VALUE!>(a)++<!>
}
fun testVariables1() {
@@ -46,11 +46,21 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
doTest("compiler/testData/cfg/ArrayAccess.kt");
}
@TestMetadata("arrayAccessExpression.kt")
public void testArrayAccessExpression() throws Exception {
doTest("compiler/testData/cfg/arrayAccessExpression.kt");
}
@TestMetadata("Assignments.kt")
public void testAssignments() throws Exception {
doTest("compiler/testData/cfg/Assignments.kt");
}
@TestMetadata("backingFieldAccess.kt")
public void testBackingFieldAccess() throws Exception {
doTest("compiler/testData/cfg/backingFieldAccess.kt");
}
@TestMetadata("Basic.kt")
public void testBasic() throws Exception {
doTest("compiler/testData/cfg/Basic.kt");
@@ -96,6 +106,16 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
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")
public void testLazyBooleans() throws Exception {
doTest("compiler/testData/cfg/LazyBooleans.kt");
@@ -111,6 +131,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
doTest("compiler/testData/cfg/MultiDecl.kt");
}
@TestMetadata("multiDeclarationWithError.kt")
public void testMultiDeclarationWithError() throws Exception {
doTest("compiler/testData/cfg/multiDeclarationWithError.kt");
}
@TestMetadata("ObjectExpression.kt")
public void testObjectExpression() throws Exception {
doTest("compiler/testData/cfg/ObjectExpression.kt");
@@ -121,6 +146,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
doTest("compiler/testData/cfg/OnlyWhileInFunctionBody.kt");
}
@TestMetadata("propertySafeCall.kt")
public void testPropertySafeCall() throws Exception {
doTest("compiler/testData/cfg/propertySafeCall.kt");
}
@TestMetadata("ReturnFromExpression.kt")
public void testReturnFromExpression() throws Exception {
doTest("compiler/testData/cfg/ReturnFromExpression.kt");