[FIR] Add contract renderer
This commit is contained in:
+7
-3
@@ -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) {
|
||||
|
||||
+76
@@ -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<Unit, Nothing?>() {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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 <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitBooleanValueParameterReference(this, data)
|
||||
}
|
||||
Reference in New Issue
Block a user