diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt index 37c3c31d5b5..377e170c11f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt @@ -14,508 +14,420 @@ * limitations under the License. */ -package org.jetbrains.kotlin.cfg; +package org.jetbrains.kotlin.cfg -import com.google.common.collect.Lists; -import com.intellij.psi.PsiElement; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.SmartFMap; -import com.intellij.util.containers.ContainerUtil; -import kotlin.collections.ArraysKt; -import kotlin.collections.CollectionsKt; -import kotlin.jvm.functions.Function0; -import kotlin.jvm.functions.Function1; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.builtins.KotlinBuiltIns; -import org.jetbrains.kotlin.cfg.pseudocode.ControlFlowInstructionsGenerator; -import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue; -import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode; -import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeImpl; -import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget; -import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue; -import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind; -import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor; -import org.jetbrains.kotlin.lexer.KtToken; -import org.jetbrains.kotlin.lexer.KtTokens; -import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt; -import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.BindingContextUtils; -import org.jetbrains.kotlin.resolve.BindingTrace; -import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils; -import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; -import org.jetbrains.kotlin.resolve.calls.model.*; -import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind; -import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; -import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; -import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; -import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver; -import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver; -import org.jetbrains.kotlin.types.KotlinType; -import org.jetbrains.kotlin.types.expressions.OperatorConventions; +import com.google.common.collect.Lists +import com.intellij.psi.tree.IElementType +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.SmartFMap +import com.intellij.util.containers.ContainerUtil +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.cfg.pseudocode.ControlFlowInstructionsGenerator +import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue +import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode +import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeImpl +import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget +import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue +import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor +import org.jetbrains.kotlin.lexer.KtToken +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.BindingContextUtils +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils +import org.jetbrains.kotlin.resolve.calls.callUtil.* +import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver +import org.jetbrains.kotlin.types.expressions.OperatorConventions -import java.util.*; +import java.util.* -import static org.jetbrains.kotlin.cfg.ControlFlowBuilder.PredefinedOperation.*; -import static org.jetbrains.kotlin.diagnostics.Errors.*; -import static org.jetbrains.kotlin.lexer.KtTokens.*; +import org.jetbrains.kotlin.cfg.ControlFlowBuilder.PredefinedOperation.* +import org.jetbrains.kotlin.diagnostics.Errors.* +import org.jetbrains.kotlin.lexer.KtTokens.* -public class ControlFlowProcessor { +class ControlFlowProcessor(private val trace: BindingTrace) { - private final ControlFlowBuilder builder; - private final BindingTrace trace; + private val builder: ControlFlowBuilder = ControlFlowInstructionsGenerator() - public ControlFlowProcessor(BindingTrace trace) { - this.builder = new ControlFlowInstructionsGenerator(); - this.trace = trace; + fun generatePseudocode(subroutine: KtElement): Pseudocode { + val pseudocode = generate(subroutine) + (pseudocode as PseudocodeImpl).postProcess() + return pseudocode } - @NotNull - public Pseudocode generatePseudocode(@NotNull KtElement subroutine) { - Pseudocode pseudocode = generate(subroutine); - ((PseudocodeImpl) pseudocode).postProcess(); - return pseudocode; - } - - @NotNull - private Pseudocode generate(@NotNull KtElement subroutine) { - builder.enterSubroutine(subroutine); - CFPVisitor cfpVisitor = new CFPVisitor(builder); - if (subroutine instanceof KtDeclarationWithBody && !(subroutine instanceof KtSecondaryConstructor)) { - KtDeclarationWithBody declarationWithBody = (KtDeclarationWithBody) subroutine; - List valueParameters = declarationWithBody.getValueParameters(); - for (KtParameter valueParameter : valueParameters) { - cfpVisitor.generateInstructions(valueParameter); + private fun generate(subroutine: KtElement): Pseudocode { + builder.enterSubroutine(subroutine) + val cfpVisitor = CFPVisitor(builder) + if (subroutine is KtDeclarationWithBody && subroutine !is KtSecondaryConstructor) { + val valueParameters = subroutine.valueParameters + for (valueParameter in valueParameters) { + cfpVisitor.generateInstructions(valueParameter) } - KtExpression bodyExpression = declarationWithBody.getBodyExpression(); + val bodyExpression = subroutine.bodyExpression if (bodyExpression != null) { - cfpVisitor.generateInstructions(bodyExpression); - if (!declarationWithBody.hasBlockBody()) { - generateImplicitReturnValue(bodyExpression, subroutine); + cfpVisitor.generateInstructions(bodyExpression) + if (!subroutine.hasBlockBody()) { + generateImplicitReturnValue(bodyExpression, subroutine) } } - } else { - cfpVisitor.generateInstructions(subroutine); } - return builder.exitSubroutine(subroutine); + else { + cfpVisitor.generateInstructions(subroutine) + } + return builder.exitSubroutine(subroutine) } - private void generateImplicitReturnValue(@NotNull KtExpression bodyExpression, @NotNull KtElement subroutine) { - CallableDescriptor subroutineDescriptor = (CallableDescriptor) trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, subroutine); - if (subroutineDescriptor == null) return; + private fun generateImplicitReturnValue(bodyExpression: KtExpression, subroutine: KtElement) { + val subroutineDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, subroutine) as CallableDescriptor? ?: return - KotlinType returnType = subroutineDescriptor.getReturnType(); - if (returnType != null && KotlinBuiltIns.isUnit(returnType) && subroutineDescriptor instanceof AnonymousFunctionDescriptor) return; + val returnType = subroutineDescriptor.returnType + if (returnType != null && KotlinBuiltIns.isUnit(returnType) && subroutineDescriptor is AnonymousFunctionDescriptor) return - PseudoValue returnValue = builder.getBoundValue(bodyExpression); - if (returnValue == null) return; + val returnValue = builder.getBoundValue(bodyExpression) ?: return - builder.returnValue(bodyExpression, returnValue, subroutine); + builder.returnValue(bodyExpression, returnValue, subroutine) } - private void processLocalDeclaration(@NotNull KtDeclaration subroutine) { - Label afterDeclaration = builder.createUnboundLabel("after local declaration"); + private fun processLocalDeclaration(subroutine: KtDeclaration) { + val afterDeclaration = builder.createUnboundLabel("after local declaration") - builder.nondeterministicJump(afterDeclaration, subroutine, null); - generate(subroutine); - builder.bindLabel(afterDeclaration); + builder.nondeterministicJump(afterDeclaration, subroutine, null) + generate(subroutine) + builder.bindLabel(afterDeclaration) } - private class CFPVisitor extends KtVisitorVoid { - private final ControlFlowBuilder builder; + private inner class CFPVisitor(private val builder: ControlFlowBuilder) : KtVisitorVoid() { - private final KtVisitorVoid conditionVisitor = new KtVisitorVoid() { + private val conditionVisitor = object : KtVisitorVoid() { - private KtExpression getSubjectExpression(KtWhenCondition condition) { - KtWhenExpression whenExpression = PsiTreeUtil.getParentOfType(condition, KtWhenExpression.class); - return whenExpression != null ? whenExpression.getSubjectExpression() : null; + private fun getSubjectExpression(condition: KtWhenCondition): KtExpression? { + return condition.getStrictParentOfType()?.subjectExpression } - @Override - public void visitWhenConditionInRange(@NotNull KtWhenConditionInRange condition) { - if (!generateCall(condition.getOperationReference())) { - KtExpression rangeExpression = condition.getRangeExpression(); - generateInstructions(rangeExpression); - createNonSyntheticValue(condition, MagicKind.UNRESOLVED_CALL, rangeExpression); + override fun visitWhenConditionInRange(condition: KtWhenConditionInRange) { + if (!generateCall(condition.operationReference)) { + val rangeExpression = condition.rangeExpression + generateInstructions(rangeExpression) + createNonSyntheticValue(condition, MagicKind.UNRESOLVED_CALL, rangeExpression) } } - @Override - public void visitWhenConditionIsPattern(@NotNull KtWhenConditionIsPattern condition) { - mark(condition); - createNonSyntheticValue(condition, MagicKind.IS, getSubjectExpression(condition)); + override fun visitWhenConditionIsPattern(condition: KtWhenConditionIsPattern) { + mark(condition) + createNonSyntheticValue(condition, MagicKind.IS, getSubjectExpression(condition)) } - @Override - public void visitWhenConditionWithExpression(@NotNull KtWhenConditionWithExpression condition) { - mark(condition); + override fun visitWhenConditionWithExpression(condition: KtWhenConditionWithExpression) { + mark(condition) - KtExpression expression = condition.getExpression(); - generateInstructions(expression); + val expression = condition.expression + generateInstructions(expression) - KtExpression subjectExpression = getSubjectExpression(condition); + val subjectExpression = getSubjectExpression(condition) if (subjectExpression != null) { // todo: this can be replaced by equals() invocation (when corresponding resolved call is recorded) - createNonSyntheticValue(condition, MagicKind.EQUALS_IN_WHEN_CONDITION, subjectExpression, expression); + createNonSyntheticValue(condition, MagicKind.EQUALS_IN_WHEN_CONDITION, subjectExpression, expression) } else { - copyValue(expression, condition); + copyValue(expression, condition) } } - @Override - public void visitKtElement(@NotNull KtElement element) { - throw new UnsupportedOperationException("[ControlFlowProcessor] " + element.toString()); + override fun visitKtElement(element: KtElement) { + throw UnsupportedOperationException("[ControlFlowProcessor] " + element.toString()) } - }; - - private CFPVisitor(@NotNull ControlFlowBuilder builder) { - this.builder = builder; } - private void mark(KtElement element) { - builder.mark(element); + private fun mark(element: KtElement) { + builder.mark(element) } - public void generateInstructions(@Nullable KtElement element) { - if (element == null) return; - element.accept(this); - checkNothingType(element); + fun generateInstructions(element: KtElement?) { + if (element == null) return + element.accept(this) + checkNothingType(element) } - private void checkNothingType(KtElement element) { - if (!(element instanceof KtExpression)) return; + private fun checkNothingType(element: KtElement) { + if (element !is KtExpression) return - KtExpression expression = KtPsiUtil.deparenthesize((KtExpression) element); - if (expression == null) return; + val expression = KtPsiUtil.deparenthesize(element) ?: return - if (expression instanceof KtStatementExpression || expression instanceof KtTryExpression - || expression instanceof KtIfExpression || expression instanceof KtWhenExpression) { - return; + if (expression is KtStatementExpression || expression is KtTryExpression + || expression is KtIfExpression || expression is KtWhenExpression) { + return } - KotlinType type = trace.getBindingContext().getType(expression); + val type = trace.bindingContext.getType(expression) if (type != null && KotlinBuiltIns.isNothing(type)) { - builder.jumpToError(expression); + builder.jumpToError(expression) } } - @NotNull - private PseudoValue createSyntheticValue(@NotNull KtElement instructionElement, @NotNull MagicKind kind, KtElement... from) { - List values = elementsToValues(from.length > 0 ? Arrays.asList(from) : Collections.emptyList()); - return builder.magic(instructionElement, null, values, kind).getOutputValue(); + private fun createSyntheticValue(instructionElement: KtElement, kind: MagicKind, vararg from: KtElement): PseudoValue { + return builder.magic(instructionElement, null, elementsToValues(from.asList()), kind).outputValue } - @NotNull - private PseudoValue createNonSyntheticValue( - @NotNull KtElement to, @NotNull List from, @NotNull MagicKind kind - ) { - List values = elementsToValues(from); - return builder.magic(to, to, values, kind).getOutputValue(); + private fun createNonSyntheticValue(to: KtElement, from: List, kind: MagicKind): PseudoValue { + return builder.magic(to, to, elementsToValues(from), kind).outputValue } - @NotNull - private PseudoValue createNonSyntheticValue(@NotNull KtElement to, @NotNull MagicKind kind, KtElement... from) { - return createNonSyntheticValue(to, Arrays.asList(from), kind); + private fun createNonSyntheticValue(to: KtElement, kind: MagicKind, vararg from: KtElement?): PseudoValue { + return createNonSyntheticValue(to, from.asList(), kind) } - private void mergeValues(@NotNull List from, @NotNull KtExpression to) { - builder.merge(to, elementsToValues(from)); + private fun mergeValues(from: List, to: KtExpression) { + builder.merge(to, elementsToValues(from)) } - private void copyValue(@Nullable KtElement from, @NotNull KtElement to) { - PseudoValue value = getBoundOrUnreachableValue(from); - if (value != null) { - builder.bindValue(value, to); - } + private fun copyValue(from: KtElement?, to: KtElement) { + getBoundOrUnreachableValue(from)?.let { builder.bindValue(it, to) } } - @Nullable - private PseudoValue getBoundOrUnreachableValue(@Nullable KtElement element) { - if (element == null) return null; + private fun getBoundOrUnreachableValue(element: KtElement?): PseudoValue? { + if (element == null) return null - PseudoValue value = builder.getBoundValue(element); - return value != null || element instanceof KtDeclaration ? value : builder.newValue(element); + val value = builder.getBoundValue(element) + return if (value != null || element is KtDeclaration) value else builder.newValue(element) } - private List elementsToValues(List from) { - if (from.isEmpty()) return Collections.emptyList(); - return CollectionsKt.filterNotNull( - CollectionsKt.map( - from, - new Function1() { - @Override - public PseudoValue invoke(KtElement element) { - return getBoundOrUnreachableValue(element); - } - } - ) - ); + private fun elementsToValues(from: List): List { + return from.map { element -> getBoundOrUnreachableValue(element) }.filterNotNull() } - private void generateInitializer(@NotNull KtDeclaration declaration, @NotNull PseudoValue initValue) { - builder.write( - declaration, - declaration, - initValue, - getDeclarationAccessTarget(declaration), - Collections.emptyMap() - ); + private fun generateInitializer(declaration: KtDeclaration, initValue: PseudoValue) { + builder.write(declaration, declaration, initValue, getDeclarationAccessTarget(declaration), emptyMap()) } - @NotNull - private AccessTarget getResolvedCallAccessTarget(KtElement element) { - ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(element, trace.getBindingContext()); - return resolvedCall != null ? new AccessTarget.Call(resolvedCall) : AccessTarget.BlackBox.INSTANCE; + private fun getResolvedCallAccessTarget(element: KtElement?): AccessTarget { + return element.getResolvedCall(trace.bindingContext)?.let { AccessTarget.Call(it) } + ?: AccessTarget.BlackBox } - @NotNull - private AccessTarget getDeclarationAccessTarget(KtElement element) { - DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); - return descriptor instanceof VariableDescriptor - ? new AccessTarget.Declaration((VariableDescriptor) descriptor) - : AccessTarget.BlackBox.INSTANCE; + private fun getDeclarationAccessTarget(element: KtElement): AccessTarget { + val descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element) + return if (descriptor is VariableDescriptor) + AccessTarget.Declaration(descriptor) + else + AccessTarget.BlackBox } - @Override - public void visitParenthesizedExpression(@NotNull KtParenthesizedExpression expression) { - mark(expression); - KtExpression innerExpression = expression.getExpression(); + override fun visitParenthesizedExpression(expression: KtParenthesizedExpression) { + mark(expression) + val innerExpression = expression.expression if (innerExpression != null) { - generateInstructions(innerExpression); - copyValue(innerExpression, expression); + generateInstructions(innerExpression) + copyValue(innerExpression, expression) } } - @Override - public void visitAnnotatedExpression(@NotNull KtAnnotatedExpression expression) { - KtExpression baseExpression = expression.getBaseExpression(); + override fun visitAnnotatedExpression(expression: KtAnnotatedExpression) { + val baseExpression = expression.baseExpression if (baseExpression != null) { - generateInstructions(baseExpression); - copyValue(baseExpression, expression); + generateInstructions(baseExpression) + copyValue(baseExpression, expression) } } - @Override - public void visitThisExpression(@NotNull KtThisExpression expression) { - ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, trace.getBindingContext()); + override fun visitThisExpression(expression: KtThisExpression) { + val resolvedCall = expression.getResolvedCall(trace.bindingContext) if (resolvedCall == null) { - createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL); - return; + createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL) + return } - CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); - if (resultingDescriptor instanceof ReceiverParameterDescriptor) { - builder.readVariable(expression, resolvedCall, getReceiverValues(resolvedCall)); + val resultingDescriptor = resolvedCall.resultingDescriptor + if (resultingDescriptor is ReceiverParameterDescriptor) { + builder.readVariable(expression, resolvedCall, getReceiverValues(resolvedCall)) } - copyValue(expression, expression.getInstanceReference()); + copyValue(expression, expression.instanceReference) } - @Override - public void visitConstantExpression(@NotNull KtConstantExpression expression) { - CompileTimeConstant constant = ConstantExpressionEvaluator.getConstant(expression, trace.getBindingContext()); - builder.loadConstant(expression, constant); + override fun visitConstantExpression(expression: KtConstantExpression) { + val constant = ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext) + builder.loadConstant(expression, constant) } - @Override - public void visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression) { - ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, trace.getBindingContext()); - if (resolvedCall instanceof VariableAsFunctionResolvedCall) { - VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; - generateCall(variableAsFunctionResolvedCall.getVariableCall()); + override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { + val resolvedCall = expression.getResolvedCall(trace.bindingContext) + if (resolvedCall is VariableAsFunctionResolvedCall) { + generateCall(resolvedCall.variableCall) } - else if (!generateCall(expression) && !(expression.getParent() instanceof KtCallExpression)) { - createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, generateAndGetReceiverIfAny(expression)); + else if (!generateCall(expression) && expression.parent !is KtCallExpression) { + createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, generateAndGetReceiverIfAny(expression)) } } - @Override - public void visitLabeledExpression(@NotNull KtLabeledExpression expression) { - mark(expression); - KtExpression baseExpression = expression.getBaseExpression(); + override fun visitLabeledExpression(expression: KtLabeledExpression) { + mark(expression) + val baseExpression = expression.baseExpression if (baseExpression != null) { - generateInstructions(baseExpression); - copyValue(baseExpression, expression); + generateInstructions(baseExpression) + copyValue(baseExpression, expression) } } - @SuppressWarnings("SuspiciousMethodCalls") - @Override - public void visitBinaryExpression(@NotNull KtBinaryExpression expression) { - KtSimpleNameExpression operationReference = expression.getOperationReference(); - IElementType operationType = operationReference.getReferencedNameElementType(); + override fun visitBinaryExpression(expression: KtBinaryExpression) { + val operationReference = expression.operationReference + val operationType = operationReference.getReferencedNameElementType() - KtExpression left = expression.getLeft(); - KtExpression right = expression.getRight(); - if (operationType == ANDAND || operationType == OROR) { - generateBooleanOperation(expression); + val left = expression.left + val right = expression.right + if (operationType === ANDAND || operationType === OROR) { + generateBooleanOperation(expression) } - else if (operationType == EQ) { - visitAssignment(left, getDeferredValue(right), expression); + else if (operationType === EQ) { + visitAssignment(left, getDeferredValue(right), expression) } else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) { - ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, trace.getBindingContext()); + val resolvedCall = expression.getResolvedCall(trace.bindingContext) if (resolvedCall != null) { - PseudoValue rhsValue = generateCall(resolvedCall).getOutputValue(); - Name assignMethodName = OperatorConventions.getNameForOperationSymbol((KtToken) expression.getOperationToken()); - if (!resolvedCall.getResultingDescriptor().getName().equals(assignMethodName)) { + val rhsValue = generateCall(resolvedCall).outputValue + val assignMethodName = OperatorConventions.getNameForOperationSymbol(expression.operationToken as KtToken) + if (resolvedCall.resultingDescriptor.name != assignMethodName) { /* At this point assignment of the form a += b actually means a = a + b * So we first generate call of "+" operation and then use its output pseudo-value * as a right-hand side when generating assignment call */ - visitAssignment(left, getValueAsFunction(rhsValue), expression); + visitAssignment(left, getValueAsFunction(rhsValue), expression) } } else { - generateBothArgumentsAndMark(expression); + generateBothArgumentsAndMark(expression) } } - else if (operationType == ELVIS) { - generateInstructions(left); - mark(expression); - Label afterElvis = builder.createUnboundLabel("after elvis operator"); - builder.jumpOnTrue(afterElvis, expression, builder.getBoundValue(left)); - if (right != null) { - generateInstructions(right); - } - builder.bindLabel(afterElvis); - mergeValues(Arrays.asList(left, right), expression); + else if (operationType === ELVIS) { + generateInstructions(left) + mark(expression) + val afterElvis = builder.createUnboundLabel("after elvis operator") + builder.jumpOnTrue(afterElvis, expression, builder.getBoundValue(left)) + generateInstructions(right) + builder.bindLabel(afterElvis) + mergeValues(listOf(left, right).filterNotNull(), expression) } else { if (!generateCall(expression)) { - generateBothArgumentsAndMark(expression); + generateBothArgumentsAndMark(expression) } } } - private void generateBooleanOperation(KtBinaryExpression expression) { - IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); - KtExpression left = expression.getLeft(); - KtExpression right = expression.getRight(); + private fun generateBooleanOperation(expression: KtBinaryExpression) { + val operationType = expression.operationReference.getReferencedNameElementType() + val left = expression.left + val right = expression.right - Label resultLabel = builder.createUnboundLabel("result of boolean operation"); - generateInstructions(left); - if (operationType == ANDAND) { - builder.jumpOnFalse(resultLabel, expression, builder.getBoundValue(left)); + val resultLabel = builder.createUnboundLabel("result of boolean operation") + generateInstructions(left) + if (operationType === ANDAND) { + builder.jumpOnFalse(resultLabel, expression, builder.getBoundValue(left)) } else { - builder.jumpOnTrue(resultLabel, expression, builder.getBoundValue(left)); + builder.jumpOnTrue(resultLabel, expression, builder.getBoundValue(left)) } - if (right != null) { - generateInstructions(right); - } - builder.bindLabel(resultLabel); - ControlFlowBuilder.PredefinedOperation operation = operationType == ANDAND ? AND : OR; - builder.predefinedOperation(expression, operation, elementsToValues(Arrays.asList(left, right))); + generateInstructions(right) + builder.bindLabel(resultLabel) + val operation = if (operationType === ANDAND) AND else OR + builder.predefinedOperation(expression, operation, elementsToValues(listOf(left, right).filterNotNull())) } - private Function0 getValueAsFunction(final PseudoValue value) { - return new Function0() { - @Override - public PseudoValue invoke() { - return value; - } - }; + private fun getValueAsFunction(value: PseudoValue?) = { value } + + private fun getDeferredValue(expression: KtExpression?) = { + generateInstructions(expression) + getBoundOrUnreachableValue(expression) } - private Function0 getDeferredValue(final KtExpression expression) { - return new Function0() { - @Override - public PseudoValue invoke() { - generateInstructions(expression); - return getBoundOrUnreachableValue(expression); - } - }; - } - - private void generateBothArgumentsAndMark(KtBinaryExpression expression) { - KtExpression left = KtPsiUtil.deparenthesize(expression.getLeft()); + private fun generateBothArgumentsAndMark(expression: KtBinaryExpression) { + val left = KtPsiUtil.deparenthesize(expression.left) if (left != null) { - generateInstructions(left); + generateInstructions(left) } - KtExpression right = expression.getRight(); + val right = expression.right if (right != null) { - generateInstructions(right); + generateInstructions(right) } - mark(expression); - createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, left, right); + mark(expression) + createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, left, right) } - private void visitAssignment( - KtExpression lhs, - @NotNull Function0 rhsDeferredValue, - KtExpression parentExpression + private fun visitAssignment( + lhs: KtExpression?, + rhsDeferredValue: () -> PseudoValue?, + parentExpression: KtExpression ) { - KtExpression left = KtPsiUtil.deparenthesize(lhs); + val left = KtPsiUtil.deparenthesize(lhs) if (left == null) { - List arguments = Collections.singletonList(rhsDeferredValue.invoke()); - builder.magic(parentExpression, parentExpression, arguments, MagicKind.UNSUPPORTED_ELEMENT); - return; + val arguments = rhsDeferredValue()?.let { listOf(it) } ?: emptyList() + builder.magic(parentExpression, parentExpression, arguments, MagicKind.UNSUPPORTED_ELEMENT) + return } - if (left instanceof KtArrayAccessExpression) { - generateArrayAssignment((KtArrayAccessExpression) left, rhsDeferredValue, parentExpression); - return; + if (left is KtArrayAccessExpression) { + generateArrayAssignment(left, rhsDeferredValue, parentExpression) + return } - Map receiverValues = SmartFMap.emptyMap(); - AccessTarget accessTarget = AccessTarget.BlackBox.INSTANCE; - if (left instanceof KtSimpleNameExpression || left instanceof KtQualifiedExpression) { - accessTarget = getResolvedCallAccessTarget(KtPsiUtilKt.getQualifiedElementSelector(left)); - if (accessTarget instanceof AccessTarget.Call) { - receiverValues = getReceiverValues(((AccessTarget.Call) accessTarget).getResolvedCall()); + var receiverValues: Map = SmartFMap.emptyMap() + var accessTarget: AccessTarget = AccessTarget.BlackBox + if (left is KtSimpleNameExpression || left is KtQualifiedExpression) { + accessTarget = getResolvedCallAccessTarget(left.getQualifiedElementSelector()) + if (accessTarget is AccessTarget.Call) { + receiverValues = getReceiverValues(accessTarget.resolvedCall) } } - else if (left instanceof KtProperty) { - accessTarget = getDeclarationAccessTarget(left); + else if (left is KtProperty) { + accessTarget = getDeclarationAccessTarget(left) } - if (accessTarget == AccessTarget.BlackBox.INSTANCE && !(left instanceof KtProperty)) { - generateInstructions(left); - createSyntheticValue(left, MagicKind.VALUE_CONSUMER, left); + if (accessTarget === AccessTarget.BlackBox && left !is KtProperty) { + generateInstructions(left) + createSyntheticValue(left, MagicKind.VALUE_CONSUMER, left) } - PseudoValue rightValue = rhsDeferredValue.invoke(); - PseudoValue rValue = - rightValue != null ? rightValue : createSyntheticValue(parentExpression, MagicKind.UNRECOGNIZED_WRITE_RHS); - builder.write(parentExpression, left, rValue, accessTarget, receiverValues); + val rightValue = rhsDeferredValue.invoke() + val rValue = rightValue ?: createSyntheticValue(parentExpression, MagicKind.UNRECOGNIZED_WRITE_RHS) + builder.write(parentExpression, left, rValue, accessTarget, receiverValues) } - private void generateArrayAssignment( - KtArrayAccessExpression lhs, - @NotNull Function0 rhsDeferredValue, - @NotNull KtExpression parentExpression + private fun generateArrayAssignment( + lhs: KtArrayAccessExpression, + rhsDeferredValue: () -> PseudoValue?, + parentExpression: KtExpression ) { - ResolvedCall setResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_SET, lhs); + val setResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_SET, lhs) if (setResolvedCall == null) { - generateArrayAccess(lhs, null); + generateArrayAccess(lhs, null) - List arguments = CollectionsKt.filterNotNull( - Arrays.asList(getBoundOrUnreachableValue(lhs), rhsDeferredValue.invoke()) - ); - builder.magic(parentExpression, parentExpression, arguments, MagicKind.UNRESOLVED_CALL); + val arguments = listOf(getBoundOrUnreachableValue(lhs), rhsDeferredValue.invoke()).filterNotNull() + builder.magic(parentExpression, parentExpression, arguments, MagicKind.UNRESOLVED_CALL) - return; + return } // In case of simple ('=') array assignment mark instruction is not generated yet, so we put it before generating "set" call - if (((KtOperationExpression) parentExpression).getOperationReference().getReferencedNameElementType() == EQ) { - mark(lhs); + if ((parentExpression as KtOperationExpression).operationReference.getReferencedNameElementType() === EQ) { + mark(lhs) } - generateInstructions(lhs.getArrayExpression()); + generateInstructions(lhs.arrayExpression) - Map receiverValues = getReceiverValues(setResolvedCall); - SmartFMap argumentValues = getArraySetterArguments(rhsDeferredValue, setResolvedCall); + val receiverValues = getReceiverValues(setResolvedCall) + val argumentValues = getArraySetterArguments(rhsDeferredValue, setResolvedCall) - builder.call(parentExpression, setResolvedCall, receiverValues, argumentValues); + builder.call(parentExpression, setResolvedCall, receiverValues, argumentValues) } /* We assume that assignment right-hand side corresponds to the last argument of the call @@ -524,1080 +436,986 @@ public class ControlFlowProcessor { * For example, assignment a[1, 2] += 3 means a.set(1, 2, a.get(1) + 3), so in order to generate "set" call * we first generate instructions for 1 and 2 whereas 3 is replaced by pseudo-value corresponding to "a.get(1) + 3" */ - private SmartFMap getArraySetterArguments( - Function0 rhsDeferredValue, - final ResolvedCall setResolvedCall - ) { - List valueArguments = CollectionsKt.flatMapTo( - setResolvedCall.getResultingDescriptor().getValueParameters(), - new ArrayList(), - new Function1>() { - @Override - public Iterable invoke(ValueParameterDescriptor descriptor) { - ResolvedValueArgument resolvedValueArgument = setResolvedCall.getValueArguments().get(descriptor); - return resolvedValueArgument != null - ? resolvedValueArgument.getArguments() - : Collections.emptyList(); - } - } - ); + private fun getArraySetterArguments( + rhsDeferredValue: () -> PseudoValue?, + setResolvedCall: ResolvedCall + ): SmartFMap { + val valueArguments = setResolvedCall.resultingDescriptor.valueParameters.flatMapTo( + ArrayList() + ) { descriptor -> setResolvedCall.valueArguments[descriptor]?.arguments ?: emptyList() } - ValueArgument rhsArgument = CollectionsKt.lastOrNull(valueArguments); - SmartFMap argumentValues = SmartFMap.emptyMap(); - for (ValueArgument valueArgument : valueArguments) { - ArgumentMapping argumentMapping = setResolvedCall.getArgumentMapping(valueArgument); - if (argumentMapping.isError() || (!(argumentMapping instanceof ArgumentMatch))) continue; + val rhsArgument = valueArguments.lastOrNull() + var argumentValues = SmartFMap.emptyMap() + for (valueArgument in valueArguments) { + val argumentMapping = setResolvedCall.getArgumentMapping(valueArgument) + if (argumentMapping.isError() || argumentMapping !is ArgumentMatch) continue - ValueParameterDescriptor parameterDescriptor = ((ArgumentMatch) argumentMapping).getValueParameter(); - if (valueArgument != rhsArgument) { - argumentValues = generateValueArgument(valueArgument, parameterDescriptor, argumentValues); + val parameterDescriptor = argumentMapping.valueParameter + if (valueArgument !== rhsArgument) { + argumentValues = generateValueArgument(valueArgument, parameterDescriptor, argumentValues) } else { - PseudoValue rhsValue = rhsDeferredValue.invoke(); + val rhsValue = rhsDeferredValue.invoke() if (rhsValue != null) { - argumentValues = argumentValues.plus(rhsValue, parameterDescriptor); + argumentValues = argumentValues.plus(rhsValue, parameterDescriptor) } } } - return argumentValues; + return argumentValues } - private void generateArrayAccess(KtArrayAccessExpression arrayAccessExpression, @Nullable ResolvedCall resolvedCall) { - if (builder.getBoundValue(arrayAccessExpression) != null) return; - mark(arrayAccessExpression); + private fun generateArrayAccess(arrayAccessExpression: KtArrayAccessExpression, resolvedCall: ResolvedCall<*>?) { + if (builder.getBoundValue(arrayAccessExpression) != null) return + mark(arrayAccessExpression) if (!checkAndGenerateCall(resolvedCall)) { - generateArrayAccessWithoutCall(arrayAccessExpression); + generateArrayAccessWithoutCall(arrayAccessExpression) } } - private void generateArrayAccessWithoutCall(KtArrayAccessExpression arrayAccessExpression) { - createNonSyntheticValue(arrayAccessExpression, generateArrayAccessArguments(arrayAccessExpression), MagicKind.UNRESOLVED_CALL); + private fun generateArrayAccessWithoutCall(arrayAccessExpression: KtArrayAccessExpression) { + createNonSyntheticValue(arrayAccessExpression, generateArrayAccessArguments(arrayAccessExpression), MagicKind.UNRESOLVED_CALL) } - private List generateArrayAccessArguments(KtArrayAccessExpression arrayAccessExpression) { - List inputExpressions = new ArrayList(); + private fun generateArrayAccessArguments(arrayAccessExpression: KtArrayAccessExpression): List { + val inputExpressions = ArrayList() - KtExpression arrayExpression = arrayAccessExpression.getArrayExpression(); - inputExpressions.add(arrayExpression); - generateInstructions(arrayExpression); + val arrayExpression = arrayAccessExpression.arrayExpression + if (arrayExpression != null) { + inputExpressions.add(arrayExpression) + } + generateInstructions(arrayExpression) - for (KtExpression index : arrayAccessExpression.getIndexExpressions()) { - generateInstructions(index); - inputExpressions.add(index); + for (index in arrayAccessExpression.indexExpressions) { + generateInstructions(index) + inputExpressions.add(index) } - return inputExpressions; + return inputExpressions } - @Override - public void visitUnaryExpression(@NotNull KtUnaryExpression expression) { - KtSimpleNameExpression operationSign = expression.getOperationReference(); - IElementType operationType = operationSign.getReferencedNameElementType(); - KtExpression baseExpression = expression.getBaseExpression(); - if (baseExpression == null) return; - if (KtTokens.EXCLEXCL == operationType) { - generateInstructions(baseExpression); - builder.predefinedOperation(expression, NOT_NULL_ASSERTION, elementsToValues(Collections.singletonList(baseExpression))); - return; + override fun visitUnaryExpression(expression: KtUnaryExpression) { + val operationSign = expression.operationReference + val operationType = operationSign.getReferencedNameElementType() + val baseExpression = expression.baseExpression ?: return + if (KtTokens.EXCLEXCL === operationType) { + generateInstructions(baseExpression) + builder.predefinedOperation(expression, NOT_NULL_ASSERTION, elementsToValues(listOf(baseExpression))) + return } - boolean incrementOrDecrement = isIncrementOrDecrement(operationType); - ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, trace.getBindingContext()); + val incrementOrDecrement = isIncrementOrDecrement(operationType) + val resolvedCall = expression.getResolvedCall(trace.bindingContext) - PseudoValue rhsValue; + val rhsValue: PseudoValue? if (resolvedCall != null) { - rhsValue = generateCall(resolvedCall).getOutputValue(); + rhsValue = generateCall(resolvedCall).outputValue } else { - generateInstructions(baseExpression); - rhsValue = createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, baseExpression); + generateInstructions(baseExpression) + rhsValue = createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, baseExpression) } if (incrementOrDecrement) { - visitAssignment(baseExpression, getValueAsFunction(rhsValue), expression); - if (expression instanceof KtPostfixExpression) { - copyValue(baseExpression, expression); + visitAssignment(baseExpression, getValueAsFunction(rhsValue), expression) + if (expression is KtPostfixExpression) { + copyValue(baseExpression, expression) } } } - private boolean isIncrementOrDecrement(IElementType operationType) { - return operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS; + private fun isIncrementOrDecrement(operationType: IElementType): Boolean { + return operationType === KtTokens.PLUSPLUS || operationType === KtTokens.MINUSMINUS } - @Override - public void visitIfExpression(@NotNull KtIfExpression expression) { - mark(expression); - List branches = new ArrayList(2); - KtExpression condition = expression.getCondition(); - if (condition != null) { - generateInstructions(condition); - } - Label elseLabel = builder.createUnboundLabel("else branch"); - builder.jumpOnFalse(elseLabel, expression, builder.getBoundValue(condition)); - KtExpression thenBranch = expression.getThen(); + override fun visitIfExpression(expression: KtIfExpression) { + mark(expression) + val branches = ArrayList(2) + val condition = expression.condition + generateInstructions(condition) + val elseLabel = builder.createUnboundLabel("else branch") + builder.jumpOnFalse(elseLabel, expression, builder.getBoundValue(condition)) + val thenBranch = expression.then if (thenBranch != null) { - branches.add(thenBranch); - generateInstructions(thenBranch); + branches.add(thenBranch) + generateInstructions(thenBranch) } else { - builder.loadUnit(expression); + builder.loadUnit(expression) } - Label resultLabel = builder.createUnboundLabel("'if' expression result"); - builder.jump(resultLabel, expression); - builder.bindLabel(elseLabel); - KtExpression elseBranch = expression.getElse(); + val resultLabel = builder.createUnboundLabel("'if' expression result") + builder.jump(resultLabel, expression) + builder.bindLabel(elseLabel) + val elseBranch = expression.`else` if (elseBranch != null) { - branches.add(elseBranch); - generateInstructions(elseBranch); + branches.add(elseBranch) + generateInstructions(elseBranch) } else { - builder.loadUnit(expression); + builder.loadUnit(expression) } - builder.bindLabel(resultLabel); - mergeValues(branches, expression); + builder.bindLabel(resultLabel) + mergeValues(branches, expression) } - private class FinallyBlockGenerator { - private final KtFinallySection finallyBlock; - private Label startFinally = null; - private Label finishFinally = null; + private inner class FinallyBlockGenerator(private val finallyBlock: KtFinallySection?) { + private var startFinally: Label? = null + private var finishFinally: Label? = null - private FinallyBlockGenerator(KtFinallySection block) { - finallyBlock = block; - } - - public void generate() { - KtBlockExpression finalExpression = finallyBlock.getFinalExpression(); - if (finalExpression == null) return; - if (startFinally != null) { - assert finishFinally != null; - builder.repeatPseudocode(startFinally, finishFinally); - return; + fun generate() { + val finalExpression = finallyBlock?.finalExpression ?: return + startFinally?.let { + assert(finishFinally != null) { "startFinally label is set to $startFinally but finishFinally label is not set" } + builder.repeatPseudocode(it, finishFinally!!) + return + } + builder.createUnboundLabel("start finally").let { + startFinally = it + builder.bindLabel(it) + } + generateInstructions(finalExpression) + builder.createUnboundLabel("finish finally").let { + finishFinally = it + builder.bindLabel(it) } - startFinally = builder.createUnboundLabel("start finally"); - builder.bindLabel(startFinally); - generateInstructions(finalExpression); - finishFinally = builder.createUnboundLabel("finish finally"); - builder.bindLabel(finishFinally); } } - @Override - public void visitTryExpression(@NotNull KtTryExpression expression) { - mark(expression); + override fun visitTryExpression(expression: KtTryExpression) { + mark(expression) - KtFinallySection finallyBlock = expression.getFinallyBlock(); - final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock); - boolean hasFinally = finallyBlock != null; + val finallyBlock = expression.finallyBlock + val finallyBlockGenerator = FinallyBlockGenerator(finallyBlock) + val hasFinally = finallyBlock != null if (hasFinally) { - builder.enterTryFinally(new GenerationTrigger() { - private boolean working = false; + builder.enterTryFinally(object : GenerationTrigger { + private var working = false - @Override - public void generate() { + override fun generate() { // This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}' - if (working) return; - working = true; - finallyBlockGenerator.generate(); - working = false; + if (working) return + working = true + finallyBlockGenerator.generate() + working = false } - }); + }) } - Label onExceptionToFinallyBlock = generateTryAndCatches(expression); + val onExceptionToFinallyBlock = generateTryAndCatches(expression) if (hasFinally) { - assert onExceptionToFinallyBlock != null : "No finally lable generated: " + expression.getText(); + assert(onExceptionToFinallyBlock != null) { "No finally label generated: " + expression.text } - builder.exitTryFinally(); + builder.exitTryFinally() - Label skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock"); - builder.jump(skipFinallyToErrorBlock, expression); - builder.bindLabel(onExceptionToFinallyBlock); - finallyBlockGenerator.generate(); - builder.jumpToError(expression); - builder.bindLabel(skipFinallyToErrorBlock); + val skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock") + builder.jump(skipFinallyToErrorBlock, expression) + builder.bindLabel(onExceptionToFinallyBlock!!) + finallyBlockGenerator.generate() + builder.jumpToError(expression) + builder.bindLabel(skipFinallyToErrorBlock) - finallyBlockGenerator.generate(); + finallyBlockGenerator.generate() } - List branches = new ArrayList(); - branches.add(expression.getTryBlock()); - for (KtCatchClause catchClause : expression.getCatchClauses()) { - branches.add(catchClause.getCatchBody()); + val branches = ArrayList() + branches.add(expression.tryBlock) + for (catchClause in expression.catchClauses) { + catchClause.catchBody?.let { branches.add(it) } } - mergeValues(branches, expression); + mergeValues(branches, expression) } // Returns label for 'finally' block - @Nullable - private Label generateTryAndCatches(@NotNull KtTryExpression expression) { - List catchClauses = expression.getCatchClauses(); - boolean hasCatches = !catchClauses.isEmpty(); + private fun generateTryAndCatches(expression: KtTryExpression): Label? { + val catchClauses = expression.catchClauses + val hasCatches = !catchClauses.isEmpty() - Label onException = null; + var onException: Label? = null if (hasCatches) { - onException = builder.createUnboundLabel("onException"); - builder.nondeterministicJump(onException, expression, null); + onException = builder.createUnboundLabel("onException") + builder.nondeterministicJump(onException, expression, null) } - Label onExceptionToFinallyBlock = null; - if (expression.getFinallyBlock() != null) { - onExceptionToFinallyBlock = builder.createUnboundLabel("onExceptionToFinallyBlock"); - builder.nondeterministicJump(onExceptionToFinallyBlock, expression, null); + var onExceptionToFinallyBlock: Label? = null + if (expression.finallyBlock != null) { + onExceptionToFinallyBlock = builder.createUnboundLabel("onExceptionToFinallyBlock") + builder.nondeterministicJump(onExceptionToFinallyBlock, expression, null) } - KtBlockExpression tryBlock = expression.getTryBlock(); - generateInstructions(tryBlock); + val tryBlock = expression.tryBlock + generateInstructions(tryBlock) - if (hasCatches) { - Label afterCatches = builder.createUnboundLabel("afterCatches"); - builder.jump(afterCatches, expression); + if (hasCatches && onException != null) { + val afterCatches = builder.createUnboundLabel("afterCatches") + builder.jump(afterCatches, expression) - builder.bindLabel(onException); - LinkedList