[cls] write contracts information to cls stubs

^ KTIJ-24665
this information would be used to create resolved FirElements from stubs,
so no ProtoBuf would be kept in memory
This commit is contained in:
Anna Kozlova
2023-04-05 17:12:30 +02:00
committed by Space Team
parent 9d4db72d72
commit 4fe239375f
44 changed files with 1182 additions and 534 deletions
@@ -23,12 +23,12 @@ object KotlinStubVersions {
// Though only kotlin declarations (no code in the bodies) are stubbed, please do increase this version
// if you are not 100% sure it can be avoided.
// Increasing this version will lead to reindexing of all kotlin source files on the first IDE startup with the new version.
const val SOURCE_STUB_VERSION = 149
const val SOURCE_STUB_VERSION = 150
// Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed
// or changes are made to the core stub building code (org.jetbrains.kotlin.idea.decompiler.stubBuilder).
// Increasing this version will lead to reindexing of all binary files that are potentially kotlin binaries (including all class files).
private const val BINARY_STUB_VERSION = 85
private const val BINARY_STUB_VERSION = 86
// Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile)
// Increasing this version will lead to reindexing of all classfiles.
@@ -51,7 +51,8 @@ public class KtFunctionElementType extends KtStubElementType<KotlinFunctionStub,
return new KotlinFunctionStubImpl(
(StubElement<?>) parentStub, StringRef.fromString(psi.getName()), isTopLevel, fqName,
isExtension, hasBlockBody, hasBody, psi.hasTypeParameterListBeforeFunctionName(),
psi.mayHaveContract()
psi.mayHaveContract(),
null
);
}
@@ -67,7 +68,11 @@ public class KtFunctionElementType extends KtStubElementType<KotlinFunctionStub,
dataStream.writeBoolean(stub.hasBlockBody());
dataStream.writeBoolean(stub.hasBody());
dataStream.writeBoolean(stub.hasTypeParameterListBeforeFunctionName());
dataStream.writeBoolean(stub.mayHaveContract());
boolean haveContract = stub.mayHaveContract();
dataStream.writeBoolean(haveContract);
if (haveContract && stub instanceof KotlinFunctionStubImpl) {
((KotlinFunctionStubImpl) stub).serializeContract(dataStream);
}
}
@NotNull
@@ -84,10 +89,9 @@ public class KtFunctionElementType extends KtStubElementType<KotlinFunctionStub,
boolean hasBody = dataStream.readBoolean();
boolean hasTypeParameterListBeforeFunctionName = dataStream.readBoolean();
boolean mayHaveContract = dataStream.readBoolean();
return new KotlinFunctionStubImpl(
(StubElement<?>) parentStub, name, isTopLevel, fqName, isExtension, hasBlockBody, hasBody,
hasTypeParameterListBeforeFunctionName, mayHaveContract
hasTypeParameterListBeforeFunctionName, mayHaveContract, mayHaveContract ? KotlinFunctionStubImpl.Companion.deserializeContract(dataStream) : null
);
}
@@ -61,7 +61,7 @@ public class KtUserTypeElementType extends KtStubElementType<KotlinUserTypeStub,
}
}
private static void serializeType(@NotNull StubOutputStream dataStream, @Nullable KotlinTypeBean type) throws IOException {
public static void serializeType(@NotNull StubOutputStream dataStream, @Nullable KotlinTypeBean type) throws IOException {
dataStream.writeInt(KotlinTypeBeanKind.fromBean(type).ordinal());
if (type instanceof KotlinClassTypeBean) {
StubUtils.serializeClassId(dataStream, ((KotlinClassTypeBean) type).getClassId());
@@ -94,7 +94,7 @@ public class KtUserTypeElementType extends KtStubElementType<KotlinUserTypeStub,
}
@Nullable
private static KotlinTypeBean deserializeType(@NotNull StubInputStream dataStream) throws IOException {
public static KotlinTypeBean deserializeType(@NotNull StubInputStream dataStream) throws IOException {
KotlinTypeBeanKind typeKind = KotlinTypeBeanKind.values()[dataStream.readInt()];
switch (typeKind) {
case CLASS: {
@@ -7,12 +7,165 @@ package org.jetbrains.kotlin.psi.stubs.impl
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import com.intellij.psi.stubs.StubInputStream
import com.intellij.psi.stubs.StubOutputStream
import org.jetbrains.kotlin.contracts.description.*
import org.jetbrains.kotlin.psi.KtContractEffect
import org.jetbrains.kotlin.psi.stubs.KotlinContractEffectStub
import org.jetbrains.kotlin.psi.stubs.elements.KtContractEffectElementType
import org.jetbrains.kotlin.psi.stubs.elements.KtUserTypeElementType.deserializeType
import org.jetbrains.kotlin.psi.stubs.elements.KtUserTypeElementType.serializeType
class KotlinContractEffectStubImpl(
parent: StubElement<out PsiElement>?,
elementType: KtContractEffectElementType
) : KotlinPlaceHolderStubImpl<KtContractEffect>(parent, elementType), KotlinContractEffectStub {
) : KotlinPlaceHolderStubImpl<KtContractEffect>(parent, elementType), KotlinContractEffectStub
enum class KotlinContractEffectType {
CALLS {
override fun deserialize(dataStream: StubInputStream): KtCallsEffectDeclaration<KotlinTypeBean, Nothing?> {
val declaration = PARAMETER_REFERENCE.deserialize(dataStream)
val range = EventOccurrencesRange.values()[dataStream.readInt()]
return KtCallsEffectDeclaration(declaration as KtValueParameterReference, range)
}
},
RETURNS {
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
return KtReturnsEffectDeclaration(CONSTANT.deserialize(dataStream) as KtConstantReference)
}
},
CONDITIONAL {
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
val descriptionElement = values()[dataStream.readInt()].deserialize(dataStream)
val condition = values()[dataStream.readInt()].deserialize(dataStream)
return KtConditionalEffectDeclaration(
descriptionElement as KtEffectDeclaration,
condition as KtBooleanExpression
)
}
},
IS_NULL {
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
return KtIsNullPredicate(
PARAMETER_REFERENCE.deserialize(dataStream) as KtValueParameterReference,
dataStream.readBoolean()
)
}
},
IS_INSTANCE {
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
return KtIsInstancePredicate(
PARAMETER_REFERENCE.deserialize(dataStream) as KtValueParameterReference,
deserializeType(dataStream)!!,
dataStream.readBoolean()
)
}
},
NOT {
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
return KtLogicalNot(values()[dataStream.readInt()].deserialize(dataStream) as KtBooleanExpression)
}
},
BOOLEAN_LOGIC {
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
val kind = if (dataStream.readBoolean()) LogicOperationKind.AND else LogicOperationKind.OR
val left = values()[dataStream.readInt()].deserialize(dataStream) as KtBooleanExpression
val right = values()[dataStream.readInt()].deserialize(dataStream) as KtBooleanExpression
return KtBinaryLogicExpression(left, right, kind)
}
},
PARAMETER_REFERENCE {
override fun deserialize(dataStream: StubInputStream): KtValueParameterReference<KotlinTypeBean, Nothing?> {
return KtValueParameterReference(dataStream.readInt(), IGNORE_REFERENCE_PARAMETER_NAME)
}
},
CONSTANT {
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
return when (val str = dataStream.readNameString()!!) {
"TRUE" -> KotlinContractConstantValues.TRUE
"FALSE" -> KotlinContractConstantValues.FALSE
"NULL" -> KotlinContractConstantValues.NULL
"NOT_NULL" -> KotlinContractConstantValues.NOT_NULL
"WILDCARD" -> KotlinContractConstantValues.WILDCARD
else -> error("Unexpected $str")
}
}
};
abstract fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?>
companion object {
const val IGNORE_REFERENCE_PARAMETER_NAME = "<ignore>"
}
}
class KotlinContractSerializationVisitor(val dataStream: StubOutputStream) :
KtContractDescriptionVisitor<Unit, Nothing?, KotlinTypeBean, Nothing?>() {
override fun visitConditionalEffectDeclaration(
conditionalEffect: KtConditionalEffectDeclaration<KotlinTypeBean, Nothing?>,
data: Nothing?
) {
dataStream.writeInt(KotlinContractEffectType.CONDITIONAL.ordinal)
conditionalEffect.effect.accept(this, data)
conditionalEffect.condition.accept(this, data)
}
override fun visitReturnsEffectDeclaration(returnsEffect: KtReturnsEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
dataStream.writeInt(KotlinContractEffectType.RETURNS.ordinal)
returnsEffect.value.accept(this, data)
}
override fun visitCallsEffectDeclaration(callsEffect: KtCallsEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
dataStream.writeInt(KotlinContractEffectType.CALLS.ordinal)
callsEffect.valueParameterReference.accept(this, data)
dataStream.writeInt(callsEffect.kind.ordinal)
}
override fun visitLogicalBinaryOperationContractExpression(
binaryLogicExpression: KtBinaryLogicExpression<KotlinTypeBean, Nothing?>,
data: Nothing?
) {
dataStream.writeInt(KotlinContractEffectType.BOOLEAN_LOGIC.ordinal)
dataStream.writeBoolean(binaryLogicExpression.kind == LogicOperationKind.AND)
binaryLogicExpression.left.accept(this, data)
binaryLogicExpression.right.accept(this, data)
}
override fun visitLogicalNot(logicalNot: KtLogicalNot<KotlinTypeBean, Nothing?>, data: Nothing?) {
dataStream.writeInt(KotlinContractEffectType.NOT.ordinal)
logicalNot.arg.accept(this, data)
}
override fun visitIsInstancePredicate(isInstancePredicate: KtIsInstancePredicate<KotlinTypeBean, Nothing?>, data: Nothing?) {
dataStream.writeInt(KotlinContractEffectType.IS_INSTANCE.ordinal)
isInstancePredicate.arg.accept(this, data)
serializeType(dataStream, isInstancePredicate.type)
dataStream.writeBoolean(isInstancePredicate.isNegated)
}
override fun visitIsNullPredicate(isNullPredicate: KtIsNullPredicate<KotlinTypeBean, Nothing?>, data: Nothing?) {
dataStream.writeInt(KotlinContractEffectType.IS_NULL.ordinal)
isNullPredicate.arg.accept(this, data)
dataStream.writeBoolean(isNullPredicate.isNegated)
}
override fun visitConstantDescriptor(constantReference: KtConstantReference<KotlinTypeBean, Nothing?>, data: Nothing?) {
dataStream.writeInt(KotlinContractEffectType.CONSTANT.ordinal)
dataStream.writeName(constantReference.name)
}
override fun visitValueParameterReference(valueParameterReference: KtValueParameterReference<KotlinTypeBean, Nothing?>, data: Nothing?) {
dataStream.writeInt(KotlinContractEffectType.PARAMETER_REFERENCE.ordinal)
dataStream.writeInt(valueParameterReference.parameterIndex)
}
}
object KotlinContractConstantValues {
val NULL = KtConstantReference<KotlinTypeBean, Nothing?>("NULL")
val WILDCARD = KtConstantReference<KotlinTypeBean, Nothing?>("WILDCARD")
val NOT_NULL = KtConstantReference<KotlinTypeBean, Nothing?>("NOT_NULL")
val TRUE = KtBooleanConstantReference<KotlinTypeBean, Nothing?>("TRUE")
val FALSE = KtBooleanConstantReference<KotlinTypeBean, Nothing?>("FALSE")
}
@@ -16,13 +16,17 @@
package org.jetbrains.kotlin.psi.stubs.impl
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import com.intellij.psi.stubs.StubInputStream
import com.intellij.psi.stubs.StubOutputStream
import com.intellij.util.io.StringRef
import org.jetbrains.kotlin.contracts.description.KtContractDescriptionElement
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.stubs.KotlinFunctionStub
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
import org.jetbrains.kotlin.name.FqName
import com.intellij.psi.PsiElement
import java.io.IOException
class KotlinFunctionStubImpl(
parent: StubElement<out PsiElement>?,
@@ -33,7 +37,8 @@ class KotlinFunctionStubImpl(
private val hasBlockBody: Boolean,
private val hasBody: Boolean,
private val hasTypeParameterListBeforeFunctionName: Boolean,
private val mayHaveContract: Boolean
private val mayHaveContract: Boolean,
val contract: List<KtContractDescriptionElement<KotlinTypeBean, Nothing?>>?
) : KotlinStubBaseImpl<KtNamedFunction>(parent, KtStubElementTypes.FUNCTION), KotlinFunctionStub {
init {
if (isTopLevel && fqName == null) {
@@ -50,4 +55,24 @@ class KotlinFunctionStubImpl(
override fun hasBody() = hasBody
override fun hasTypeParameterListBeforeFunctionName() = hasTypeParameterListBeforeFunctionName
override fun mayHaveContract(): Boolean = mayHaveContract
@Throws(IOException::class)
fun serializeContract(dataStream: StubOutputStream) {
val effects: List<KtContractDescriptionElement<KotlinTypeBean, Nothing?>>? = contract
dataStream.writeInt(effects?.size ?: 0)
val visitor = KotlinContractSerializationVisitor(dataStream)
effects?.forEach { it.accept(visitor, null) }
}
companion object {
fun deserializeContract(dataStream: StubInputStream): List<KtContractDescriptionElement<KotlinTypeBean, Nothing?>> {
val effects = mutableListOf<KtContractDescriptionElement<KotlinTypeBean, Nothing?>>()
val count: Int = dataStream.readInt()
for (i in 0 until count) {
val effectType: KotlinContractEffectType = KotlinContractEffectType.values()[dataStream.readInt()]
effects.add(effectType.deserialize(dataStream))
}
return effects
}
}
}