Skip to content

Commit ebafe29

Browse files
dimonchik0036Space Team
authored and
Space Team
committed
[PSI] KotlinClassStubImpl: add info about value class representation for cli
This information is required during deserialization of FIR from stubs as the provider cannot have recursive access to the cache. Alternative solution would be lazy calculated `valueClassRepresentation`, but the compiler prefers having right away calculations to reduce the number of implicit calculations. New information will be available only for stubs from compiled code. ^KT-69398
1 parent 9a79cb2 commit ebafe29

File tree

14 files changed

+87
-27
lines changed

14 files changed

+87
-27
lines changed

analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/MultiFieldValueClassWithTypeAlias/MultiFieldValueClassWithTypeAlias.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ PsiJetFileStubImpl[package=pack]
22
KotlinStub$PACKAGE_DIRECTIVE
33
KotlinStub$REFERENCE_EXPRESSION[referencedName=pack]
44
KotlinStub$IMPORT_LIST
5-
KotlinStub$CLASS[classId=pack/MultiFieldValueClassWithTypeAlias, fqName=pack.MultiFieldValueClassWithTypeAlias, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=MultiFieldValueClassWithTypeAlias, superNames=[]]
5+
KotlinStub$CLASS[classId=pack/MultiFieldValueClassWithTypeAlias, fqName=pack.MultiFieldValueClassWithTypeAlias, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=MultiFieldValueClassWithTypeAlias, superNames=[]] valueClassRepresentation: MULTI_FIELD_VALUE_CLASS
66
KotlinStub$MODIFIER_LIST[public final value]
77
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=JvmInline]
88
valueArguments: ()

analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/NestedMultiFieldValueClass/NestedMultiFieldValueClass.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ PsiJetFileStubImpl[package=test]
22
KotlinStub$PACKAGE_DIRECTIVE
33
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
44
KotlinStub$IMPORT_LIST
5-
KotlinStub$CLASS[classId=test/NestedMultiFieldValueClass, fqName=test.NestedMultiFieldValueClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=NestedMultiFieldValueClass, superNames=[]]
5+
KotlinStub$CLASS[classId=test/NestedMultiFieldValueClass, fqName=test.NestedMultiFieldValueClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=NestedMultiFieldValueClass, superNames=[]] valueClassRepresentation: MULTI_FIELD_VALUE_CLASS
66
KotlinStub$MODIFIER_LIST[public final value]
77
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=JvmInline]
88
valueArguments: ()

analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/ValueClassWithAnotherValueClass/ValueClassWithAnotherValueClass.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ PsiJetFileStubImpl[package=pack]
22
KotlinStub$PACKAGE_DIRECTIVE
33
KotlinStub$REFERENCE_EXPRESSION[referencedName=pack]
44
KotlinStub$IMPORT_LIST
5-
KotlinStub$CLASS[classId=pack/ValueClassWithAnotherValueClass, fqName=pack.ValueClassWithAnotherValueClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=ValueClassWithAnotherValueClass, superNames=[]]
5+
KotlinStub$CLASS[classId=pack/ValueClassWithAnotherValueClass, fqName=pack.ValueClassWithAnotherValueClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=ValueClassWithAnotherValueClass, superNames=[]] valueClassRepresentation: INLINE_CLASS
66
KotlinStub$MODIFIER_LIST[public final value]
77
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=JvmInline]
88
valueArguments: ()

analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/ValueClassWithMultiFieldValueClass/ValueClassWithMultiFieldValueClass.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ PsiJetFileStubImpl[package=test]
22
KotlinStub$PACKAGE_DIRECTIVE
33
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
44
KotlinStub$IMPORT_LIST
5-
KotlinStub$CLASS[classId=test/ValueClassWithMultiFieldValueClass, fqName=test.ValueClassWithMultiFieldValueClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=ValueClassWithMultiFieldValueClass, superNames=[]]
5+
KotlinStub$CLASS[classId=test/ValueClassWithMultiFieldValueClass, fqName=test.ValueClassWithMultiFieldValueClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=ValueClassWithMultiFieldValueClass, superNames=[]] valueClassRepresentation: MULTI_FIELD_VALUE_CLASS
66
KotlinStub$MODIFIER_LIST[public final value]
77
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=JvmInline]
88
valueArguments: ()

analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/ValueClassWithNestedClass/ValueClassWithNestedClass.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ PsiJetFileStubImpl[package=test]
22
KotlinStub$PACKAGE_DIRECTIVE
33
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
44
KotlinStub$IMPORT_LIST
5-
KotlinStub$CLASS[classId=test/ValueClassWithNestedClass, fqName=test.ValueClassWithNestedClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=ValueClassWithNestedClass, superNames=[]]
5+
KotlinStub$CLASS[classId=test/ValueClassWithNestedClass, fqName=test.ValueClassWithNestedClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=ValueClassWithNestedClass, superNames=[]] valueClassRepresentation: INLINE_CLASS
66
KotlinStub$MODIFIER_LIST[public final value]
77
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=JvmInline]
88
valueArguments: ()

analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/ValueClassWithNullableMultiFieldValueClass/ValueClassWithNullableMultiFieldValueClass.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ PsiJetFileStubImpl[package=test]
22
KotlinStub$PACKAGE_DIRECTIVE
33
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
44
KotlinStub$IMPORT_LIST
5-
KotlinStub$CLASS[classId=test/ValueClassWithNullableMultiFieldValueClass, fqName=test.ValueClassWithNullableMultiFieldValueClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=ValueClassWithNullableMultiFieldValueClass, superNames=[]]
5+
KotlinStub$CLASS[classId=test/ValueClassWithNullableMultiFieldValueClass, fqName=test.ValueClassWithNullableMultiFieldValueClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=ValueClassWithNullableMultiFieldValueClass, superNames=[]] valueClassRepresentation: INLINE_CLASS
66
KotlinStub$MODIFIER_LIST[public final value]
77
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=JvmInline]
88
valueArguments: ()

analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/ValueClassWithTypeAliasOnAnotherValueClass/ValueClassWithTypeAliasOnAnotherValueClass.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ PsiJetFileStubImpl[package=pack]
22
KotlinStub$PACKAGE_DIRECTIVE
33
KotlinStub$REFERENCE_EXPRESSION[referencedName=pack]
44
KotlinStub$IMPORT_LIST
5-
KotlinStub$CLASS[classId=pack/ValueClassWithTypeAliasOnAnotherValueClass, fqName=pack.ValueClassWithTypeAliasOnAnotherValueClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=ValueClassWithTypeAliasOnAnotherValueClass, superNames=[]]
5+
KotlinStub$CLASS[classId=pack/ValueClassWithTypeAliasOnAnotherValueClass, fqName=pack.ValueClassWithTypeAliasOnAnotherValueClass, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=ValueClassWithTypeAliasOnAnotherValueClass, superNames=[]] valueClassRepresentation: INLINE_CLASS
66
KotlinStub$MODIFIER_LIST[public final value]
77
KotlinStub$ANNOTATION_ENTRY[hasValueArguments=false, shortName=JvmInline]
88
valueArguments: ()

analysis/decompiled/decompiler-to-file-stubs/tests/org/jetbrains/kotlin/analysis/decompiler/stub/files/AdditionalStubInfoExtraction.kt

+3
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ private fun extractAdditionInfo(stub: StubElement<*>, builder: StringBuilder, le
6767
is KotlinParameterStubImpl -> {
6868
stub.functionTypeParameterName?.let { builder.append(" paramNameByAnnotation: ").append(it) }
6969
}
70+
is KotlinClassStubImpl -> {
71+
stub.valueClassRepresentation?.let { builder.append(" valueClassRepresentation: ").append(it) }
72+
}
7073
}
7174
for (child in stub.childrenStubs) {
7275
builder.append("\n").append(" ".repeat(level))

analysis/decompiled/decompiler-to-stubs/src/org/jetbrains/kotlin/analysis/decompiler/stub/ClassClsStubBuilder.kt

+17-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
25

36
package org.jetbrains.kotlin.analysis.decompiler.stub
47

@@ -17,6 +20,7 @@ import org.jetbrains.kotlin.name.ClassId
1720
import org.jetbrains.kotlin.psi.KtClassBody
1821
import org.jetbrains.kotlin.psi.KtSuperTypeEntry
1922
import org.jetbrains.kotlin.psi.KtSuperTypeList
23+
import org.jetbrains.kotlin.psi.stubs.elements.KotlinValueClassRepresentation
2024
import org.jetbrains.kotlin.psi.stubs.elements.KtClassElementType
2125
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
2226
import org.jetbrains.kotlin.psi.stubs.impl.KotlinClassStubImpl
@@ -33,7 +37,7 @@ fun createClassStub(
3337
nameResolver: NameResolver,
3438
classId: ClassId,
3539
source: SourceElement?,
36-
context: ClsStubBuilderContext
40+
context: ClsStubBuilderContext,
3741
) {
3842
ClassClsStubBuilder(parent, classProto, nameResolver, classId, source, context).build()
3943
}
@@ -44,7 +48,7 @@ private class ClassClsStubBuilder(
4448
nameResolver: NameResolver,
4549
private val classId: ClassId,
4650
source: SourceElement?,
47-
outerContext: ClsStubBuilderContext
51+
outerContext: ClsStubBuilderContext,
4852
) {
4953
private val thisAsProtoContainer = ProtoContainer.Class(
5054
classProto, nameResolver, TypeTable(classProto.typeTable), source, outerContext.protoContainer
@@ -147,11 +151,18 @@ private class ClassClsStubBuilder(
147151
isEnumEntry = classKind == ProtoBuf.Class.Kind.ENUM_ENTRY,
148152
isLocal = false,
149153
isTopLevel = !this.classId.isNestedClass,
154+
valueClassRepresentation = valueClassRepresentation(),
150155
)
151156
}
152157
}
153158
}
154159

160+
private fun valueClassRepresentation(): KotlinValueClassRepresentation? = when {
161+
classProto.multiFieldValueClassUnderlyingNameCount > 0 -> KotlinValueClassRepresentation.MULTI_FIELD_VALUE_CLASS
162+
classProto.hasInlineClassUnderlyingPropertyName() -> KotlinValueClassRepresentation.INLINE_CLASS
163+
else -> null
164+
}
165+
155166
private fun createConstructorStub() {
156167
if (!isClass()) return
157168

@@ -208,8 +219,10 @@ private class ClassClsStubBuilder(
208219
isInterface = false,
209220
isEnumEntry = true,
210221
isLocal = false,
211-
isTopLevel = false
222+
isTopLevel = false,
223+
valueClassRepresentation = null,
212224
)
225+
213226
if (annotations.isNotEmpty()) {
214227
createAnnotationStubs(annotations, createEmptyModifierListStub(enumEntryStub))
215228
}

compiler/psi/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
33
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
44
*/
55

@@ -12,12 +12,12 @@ object KotlinStubVersions {
1212
// Though only kotlin declarations (no code in the bodies) are stubbed, please do increase this version
1313
// if you are not 100% sure it can be avoided.
1414
// Increasing this version will lead to reindexing of all kotlin source files on the first IDE startup with the new version.
15-
const val SOURCE_STUB_VERSION = 165
15+
const val SOURCE_STUB_VERSION = 166
1616

1717
// Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed
1818
// or changes are made to the core stub building code (org.jetbrains.kotlin.idea.decompiler.stubBuilder).
1919
// Increasing this version will lead to reindexing of all binary files that are potentially kotlin binaries (including all class files).
20-
private const val BINARY_STUB_VERSION = 106
20+
private const val BINARY_STUB_VERSION = 107
2121

2222
// Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile)
2323
// Increasing this version will lead to reindexing of all classfiles.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package org.jetbrains.kotlin.psi.stubs.elements
7+
8+
/**
9+
* This class is intended to provide all necessary information via stubs to
10+
* create [org.jetbrains.kotlin.descriptors.ValueClassRepresentation] during stub -> FIR
11+
* conversion.
12+
*/
13+
enum class KotlinValueClassRepresentation {
14+
// The order of entries is important, as an entry's ordinal is used to serialize/deserialize it
15+
INLINE_CLASS,
16+
MULTI_FIELD_VALUE_CLASS,
17+
;
18+
}

compiler/psi/src/org/jetbrains/kotlin/psi/stubs/elements/KtClassElementType.java

+18-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
33
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
44
*/
55

@@ -11,6 +11,7 @@
1111
import com.intellij.psi.stubs.StubInputStream;
1212
import com.intellij.psi.stubs.StubOutputStream;
1313
import com.intellij.util.io.StringRef;
14+
import kotlin.collections.CollectionsKt;
1415
import org.jetbrains.annotations.NonNls;
1516
import org.jetbrains.annotations.NotNull;
1617
import org.jetbrains.kotlin.name.ClassId;
@@ -55,7 +56,8 @@ public KotlinClassStub createStub(@NotNull KtClass psi, StubElement parentStub)
5556
StringRef.fromString(fqName != null ? fqName.asString() : null), classId,
5657
StringRef.fromString(psi.getName()),
5758
Utils.INSTANCE.wrapStrings(superNames),
58-
psi.isInterface(), isEnumEntry, psi.isLocal(), psi.isTopLevel()
59+
psi.isInterface(), isEnumEntry, psi.isLocal(), psi.isTopLevel(),
60+
null
5961
);
6062
}
6163

@@ -78,6 +80,12 @@ public void serialize(@NotNull KotlinClassStub stub, @NotNull StubOutputStream d
7880
for (String name : superNames) {
7981
dataStream.writeName(name);
8082
}
83+
84+
if (stub instanceof KotlinClassStubImpl) {
85+
KotlinClassStubImpl stubImpl = (KotlinClassStubImpl) stub;
86+
KotlinValueClassRepresentation representation = stubImpl.getValueClassRepresentation();
87+
dataStream.writeVarInt(representation == null ? -1 : representation.ordinal());
88+
}
8189
}
8290

8391
@NotNull
@@ -99,9 +107,16 @@ public KotlinClassStub deserialize(@NotNull StubInputStream dataStream, StubElem
99107
superNames[i] = dataStream.readName();
100108
}
101109

110+
int representationOrdinal = dataStream.readVarInt();
111+
KotlinValueClassRepresentation representation = CollectionsKt.getOrNull(
112+
KotlinValueClassRepresentation.getEntries(),
113+
representationOrdinal
114+
);
115+
102116
return new KotlinClassStubImpl(
103117
getStubType(isEnumEntry), (StubElement<?>) parentStub, qualifiedName,classId, name, superNames,
104-
isTrait, isEnumEntry, isLocal, isTopLevel
118+
isTrait, isEnumEntry, isLocal, isTopLevel,
119+
representation
105120
);
106121
}
107122

compiler/psi/src/org/jetbrains/kotlin/psi/stubs/impl/KotlinClassStubImpl.kt

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.name.ClassId
1212
import org.jetbrains.kotlin.name.FqName
1313
import org.jetbrains.kotlin.psi.KtClass
1414
import org.jetbrains.kotlin.psi.stubs.KotlinClassStub
15+
import org.jetbrains.kotlin.psi.stubs.elements.KotlinValueClassRepresentation
1516
import org.jetbrains.kotlin.psi.stubs.elements.KtClassElementType
1617

1718
class KotlinClassStubImpl(
@@ -25,6 +26,7 @@ class KotlinClassStubImpl(
2526
private val isEnumEntry: Boolean,
2627
private val isLocal: Boolean,
2728
private val isTopLevel: Boolean,
29+
val valueClassRepresentation: KotlinValueClassRepresentation?,
2830
) : KotlinStubBaseImpl<KtClass>(parent, type), KotlinClassStub {
2931

3032
override fun getFqName(): FqName? {

core/deserialization.common/src/org/jetbrains/kotlin/serialization/deserialization/ValueClassUtil.kt

+19-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
33
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
44
*/
55

@@ -22,15 +22,8 @@ fun <T : RigidTypeMarker> ProtoBuf.Class.loadValueClassRepresentation(
2222
typeOfPublicProperty: (Name) -> T?,
2323
): ValueClassRepresentation<T>? {
2424
if (multiFieldValueClassUnderlyingNameCount > 0) {
25-
val names = multiFieldValueClassUnderlyingNameList.map { nameResolver.getName(it) }
26-
val typeIdCount = multiFieldValueClassUnderlyingTypeIdCount
27-
val typeCount = multiFieldValueClassUnderlyingTypeCount
28-
val types = when (typeIdCount to typeCount) {
29-
names.size to 0 -> multiFieldValueClassUnderlyingTypeIdList.map { typeTable[it] }
30-
0 to names.size -> multiFieldValueClassUnderlyingTypeList
31-
else -> error("class ${nameResolver.getName(fqName)} has illegal multi-field value class representation")
32-
}.map(typeDeserializer)
33-
return MultiFieldValueClassRepresentation(names zip types)
25+
val (names, types) = loadMultiFieldValueClassRepresentation(nameResolver, typeTable)
26+
return MultiFieldValueClassRepresentation(names zip types.map(typeDeserializer))
3427
}
3528

3629
if (hasInlineClassUnderlyingPropertyName()) {
@@ -43,3 +36,19 @@ fun <T : RigidTypeMarker> ProtoBuf.Class.loadValueClassRepresentation(
4336

4437
return null
4538
}
39+
40+
fun ProtoBuf.Class.loadMultiFieldValueClassRepresentation(
41+
nameResolver: NameResolver,
42+
typeTable: TypeTable,
43+
): Pair<List<Name>, List<ProtoBuf.Type>> {
44+
val names = multiFieldValueClassUnderlyingNameList.map { nameResolver.getName(it) }
45+
val typeIdCount = multiFieldValueClassUnderlyingTypeIdCount
46+
val typeCount = multiFieldValueClassUnderlyingTypeCount
47+
val types = when (typeIdCount to typeCount) {
48+
names.size to 0 -> multiFieldValueClassUnderlyingTypeIdList.map { typeTable[it] }
49+
0 to names.size -> multiFieldValueClassUnderlyingTypeList
50+
else -> error("class ${nameResolver.getName(fqName)} has illegal multi-field value class representation")
51+
}
52+
53+
return names to types
54+
}

0 commit comments

Comments
 (0)