From 50627f2c83d160bfe92db84be8610bdf08ac0edb Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 8 Apr 2020 15:02:32 +0300 Subject: [PATCH] [FIR] Add contract renderer --- .../FirContractDeserializer.kt | 10 ++- .../description/ConeContractRenderer.kt | 76 +++++++++++++++++++ .../fir/contracts/description/ConeValues.kt | 4 +- 3 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractRenderer.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt index 271cb6e98a3..7f072eea6b5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt @@ -125,16 +125,20 @@ class FirContractDeserializer(private val c: FirDeserializationContext) { val valueParameterIndex = proto.valueParameterReference - 1 + val name: String val typeRef = if (valueParameterIndex < 0) { + name = "this" ownerFunction.receiverTypeRef } else { - ownerFunction.valueParameters.getOrNull(valueParameterIndex)?.returnTypeRef + val parameter = ownerFunction.valueParameters.getOrNull(valueParameterIndex) ?: return null + name = parameter.name.asString() + parameter.returnTypeRef } ?: return null return if (!typeRef.isBoolean) - ConeValueParameterReference(valueParameterIndex) + ConeValueParameterReference(valueParameterIndex, name) else - ConeBooleanValueParameterReference(valueParameterIndex) + ConeBooleanValueParameterReference(valueParameterIndex, name) } private fun ProtoBuf.Effect.InvocationKind.toDescriptorInvocationKind(): InvocationKind? = when (this) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractRenderer.kt new file mode 100644 index 00000000000..4654e0d4a08 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractRenderer.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.contracts.description + +import org.jetbrains.kotlin.contracts.description.expressions.* + +class ConeContractRenderer(private val builder: StringBuilder) : ConeContractDescriptionVisitor() { + override fun visitConditionalEffectDeclaration(conditionalEffect: ConeConditionalEffectDeclaration, data: Nothing?) { + conditionalEffect.effect.accept(this, data) + builder.append(" -> ") + conditionalEffect.condition.accept(this, data) + } + + override fun visitReturnsEffectDeclaration(returnsEffect: ConeReturnsEffectDeclaration, data: Nothing?) { + builder.append("Returns(") + returnsEffect.value.accept(this, data) + builder.append(")") + } + + override fun visitCallsEffectDeclaration(callsEffect: ConeCallsEffectDeclaration, data: Nothing?) { + builder.append("CallsInPlace(") + callsEffect.valueParameterReference.accept(this, data) + builder.append(", ${callsEffect.kind})") + } + + override fun visitLogicalBinaryOperationContractExpression(binaryLogicExpression: ConeBinaryLogicExpression, data: Nothing?) { + inBracketsIfNecessary(binaryLogicExpression, binaryLogicExpression.left) { binaryLogicExpression.left.accept(this, data) } + builder.append(" ${binaryLogicExpression.kind.token} ") + inBracketsIfNecessary(binaryLogicExpression, binaryLogicExpression.right) { binaryLogicExpression.right.accept(this, data) } + } + + override fun visitLogicalNot(logicalNot: ConeLogicalNot, data: Nothing?) { + inBracketsIfNecessary(logicalNot, logicalNot.arg) { builder.append("!") } + logicalNot.arg.accept(this, data) + } + + override fun visitIsInstancePredicate(isInstancePredicate: ConeIsInstancePredicate, data: Nothing?) { + isInstancePredicate.arg.accept(this, data) + builder.append(" ${if (isInstancePredicate.isNegated) "!" else ""}is ${isInstancePredicate.type}") + } + + override fun visitIsNullPredicate(isNullPredicate: ConeIsNullPredicate, data: Nothing?) { + isNullPredicate.arg.accept(this, data) + builder.append(" ${if (isNullPredicate.isNegated) "!=" else "=="} null") + } + + override fun visitConstantDescriptor(constantReference: ConeConstantReference, data: Nothing?) { + builder.append(constantReference.name) + } + + override fun visitValueParameterReference(valueParameterReference: ConeValueParameterReference, data: Nothing?) { + builder.append(valueParameterReference.name) + } + + private fun inBracketsIfNecessary(parent: ConeContractDescriptionElement, child: ConeContractDescriptionElement, block: () -> Unit) { + if (needsBrackets(parent, child)) { + builder.append("(") + block() + builder.append(")") + } else { + block() + } + } + + private fun ConeContractDescriptionElement.isAtom(): Boolean = + this is VariableReference || this is ConstantReference || this is ConeIsNullPredicate || this is ConeIsInstancePredicate + + private fun needsBrackets(parent: ConeContractDescriptionElement, child: ConeContractDescriptionElement): Boolean { + if (child.isAtom()) return false + if (parent is ConeLogicalNot) return true + return parent::class != child::class + } +} \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeValues.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeValues.kt index ffbf55be4c9..555332db0a0 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeValues.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeValues.kt @@ -35,7 +35,7 @@ class ConeBooleanConstantReference private constructor(name: String) : ConeConst * Index of value parameter of function * -1 means that it is reference to extension receiver */ -open class ConeValueParameterReference(val parameterIndex: Int) : ConeContractDescriptionValue { +open class ConeValueParameterReference(val parameterIndex: Int, val name: String) : ConeContractDescriptionValue { init { assert(parameterIndex >= -1) } @@ -44,7 +44,7 @@ open class ConeValueParameterReference(val parameterIndex: Int) : ConeContractDe contractDescriptionVisitor.visitValueParameterReference(this, data) } -class ConeBooleanValueParameterReference(parameterIndex: Int) : ConeValueParameterReference(parameterIndex), ConeBooleanExpression { +class ConeBooleanValueParameterReference(parameterIndex: Int, name: String) : ConeValueParameterReference(parameterIndex, name), ConeBooleanExpression { override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = contractDescriptionVisitor.visitBooleanValueParameterReference(this, data) } \ No newline at end of file