Extract descriptor-related behavior in StringTable to separate interface

Descriptor-related code is only needed to be able to compute
"replacement" names for local classes, which are different in JVM and JS
This commit is contained in:
Alexander Udalov
2018-03-09 17:29:06 +01:00
parent 043f4c3d01
commit acf357e9b5
12 changed files with 104 additions and 96 deletions
@@ -151,7 +151,7 @@ public class ClassFileFactory implements OutputFileCollection {
ProtoBuf.Annotation.Builder annotation = ProtoBuf.Annotation.newBuilder(); ProtoBuf.Annotation.Builder annotation = ProtoBuf.Annotation.newBuilder();
ClassId classId = DescriptorUtilsKt.getClassId(descriptor); ClassId classId = DescriptorUtilsKt.getClassId(descriptor);
if (classId != null) { if (classId != null) {
annotation.setId(stringTable.getClassIdIndex(classId)); annotation.setId(stringTable.getQualifiedClassNameIndex(classId.asString(), false));
builder.addAnnotation(annotation); builder.addAnnotation(annotation);
} }
} }
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.coroutines.COROUTINE_IMPL_ASM_TYPE import org.jetbrains.kotlin.codegen.coroutines.COROUTINE_IMPL_ASM_TYPE
import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable
import org.jetbrains.kotlin.codegen.serialization.JvmStringTable import org.jetbrains.kotlin.codegen.serialization.JvmStringTable
import org.jetbrains.kotlin.codegen.writeKotlinMetadata import org.jetbrains.kotlin.codegen.writeKotlinMetadata
import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.JvmAnnotationNames
@@ -202,7 +203,7 @@ class AnonymousObjectTransformer(
when (header.kind) { when (header.kind) {
KotlinClassHeader.Kind.CLASS -> { KotlinClassHeader.Kind.CLASS -> {
val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(data, strings) val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(data, strings)
val newStringTable = JvmStringTable(state.typeMapper, nameResolver) val newStringTable = JvmCodegenStringTable(state.typeMapper, nameResolver)
val newProto = classProto.toBuilder().apply { val newProto = classProto.toBuilder().apply {
setExtension(JvmProtoBuf.anonymousObjectOriginName, newStringTable.getStringIndex(oldObjectType.internalName)) setExtension(JvmProtoBuf.anonymousObjectOriginName, newStringTable.getStringIndex(oldObjectType.internalName))
}.build() }.build()
@@ -210,7 +211,7 @@ class AnonymousObjectTransformer(
} }
KotlinClassHeader.Kind.SYNTHETIC_CLASS -> { KotlinClassHeader.Kind.SYNTHETIC_CLASS -> {
val (nameResolver, functionProto) = JvmProtoBufUtil.readFunctionDataFrom(data, strings) val (nameResolver, functionProto) = JvmProtoBufUtil.readFunctionDataFrom(data, strings)
val newStringTable = JvmStringTable(state.typeMapper, nameResolver) val newStringTable = JvmCodegenStringTable(state.typeMapper, nameResolver)
val newProto = functionProto.toBuilder().apply { val newProto = functionProto.toBuilder().apply {
setExtension(JvmProtoBuf.lambdaClassOriginName, newStringTable.getStringIndex(oldObjectType.internalName)) setExtension(JvmProtoBuf.lambdaClassOriginName, newStringTable.getStringIndex(oldObjectType.internalName))
}.build() }.build()
@@ -0,0 +1,33 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. 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.codegen.serialization
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolver
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.DescriptorAwareStringTable
class JvmCodegenStringTable @JvmOverloads constructor(
private val typeMapper: KotlinTypeMapper,
nameResolver: JvmNameResolver? = null
) : JvmStringTable(nameResolver), DescriptorAwareStringTable {
override fun getLocalClassIdReplacement(descriptor: ClassifierDescriptorWithTypeParameters): ClassId {
val container = descriptor.containingDeclaration
return when (container) {
is ClassifierDescriptorWithTypeParameters -> getLocalClassIdReplacement(container).createNestedClassId(descriptor.name)
is PackageFragmentDescriptor -> {
throw IllegalStateException("getLocalClassIdReplacement should only be called for local classes: $descriptor")
}
else -> {
val fqName = FqName(typeMapper.mapClass(descriptor).internalName.replace('/', '.'))
ClassId(fqName.parent(), FqName.topLevel(fqName.shortName()), true)
}
}
}
}
@@ -43,7 +43,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.serialization.AnnotationSerializer; import org.jetbrains.kotlin.serialization.AnnotationSerializer;
import org.jetbrains.kotlin.serialization.DescriptorSerializer; import org.jetbrains.kotlin.serialization.DescriptorSerializer;
import org.jetbrains.kotlin.serialization.SerializerExtension; import org.jetbrains.kotlin.serialization.SerializerExtension;
import org.jetbrains.kotlin.serialization.StringTable;
import org.jetbrains.kotlin.types.FlexibleType; import org.jetbrains.kotlin.types.FlexibleType;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.Type;
@@ -57,7 +56,7 @@ public class JvmSerializerExtension extends SerializerExtension {
private final JvmSerializationBindings bindings; private final JvmSerializationBindings bindings;
private final BindingContext codegenBinding; private final BindingContext codegenBinding;
private final KotlinTypeMapper typeMapper; private final KotlinTypeMapper typeMapper;
private final StringTable stringTable; private final JvmCodegenStringTable stringTable;
private final AnnotationSerializer annotationSerializer; private final AnnotationSerializer annotationSerializer;
private final boolean useTypeTable; private final boolean useTypeTable;
private final String moduleName; private final String moduleName;
@@ -67,7 +66,7 @@ public class JvmSerializerExtension extends SerializerExtension {
this.bindings = bindings; this.bindings = bindings;
this.codegenBinding = state.getBindingContext(); this.codegenBinding = state.getBindingContext();
this.typeMapper = state.getTypeMapper(); this.typeMapper = state.getTypeMapper();
this.stringTable = new JvmStringTable(typeMapper); this.stringTable = new JvmCodegenStringTable(typeMapper);
this.annotationSerializer = new AnnotationSerializer(stringTable); this.annotationSerializer = new AnnotationSerializer(stringTable);
this.useTypeTable = state.getUseTypeTableInSerializer(); this.useTypeTable = state.getUseTypeTableInSerializer();
this.moduleName = state.getModuleName(); this.moduleName = state.getModuleName();
@@ -76,7 +75,7 @@ public class JvmSerializerExtension extends SerializerExtension {
@NotNull @NotNull
@Override @Override
public StringTable getStringTable() { public JvmCodegenStringTable getStringTable() {
return stringTable; return stringTable;
} }
@@ -16,33 +16,28 @@
package org.jetbrains.kotlin.codegen.serialization package org.jetbrains.kotlin.codegen.serialization
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolver import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolver
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.StringTable import org.jetbrains.kotlin.serialization.StringTable
import org.jetbrains.kotlin.types.ErrorUtils
import java.io.OutputStream import java.io.OutputStream
// TODO: optimize by reordering records to minimize storage of 'range' fields // TODO: optimize by reordering records to minimize storage of 'range' fields
class JvmStringTable(private val typeMapper: KotlinTypeMapper) : StringTable { open class JvmStringTable(nameResolver: JvmNameResolver? = null) : StringTable {
val strings = ArrayList<String>() val strings = ArrayList<String>()
private val records = ArrayList<Record.Builder>() private val records = ArrayList<Record.Builder>()
private val map = HashMap<String, Int>() private val map = HashMap<String, Int>()
private val localNames = LinkedHashSet<Int>() private val localNames = LinkedHashSet<Int>()
constructor(typeMapper: KotlinTypeMapper, nameResolver: JvmNameResolver) : this(typeMapper) { init {
strings.addAll(nameResolver.strings) if (nameResolver != null) {
nameResolver.records.mapTo(records, JvmProtoBuf.StringTableTypes.Record::toBuilder) strings.addAll(nameResolver.strings)
for (index in strings.indices) { nameResolver.records.mapTo(records, JvmProtoBuf.StringTableTypes.Record::toBuilder)
map[nameResolver.getString(index)] = index for (index in strings.indices) {
map[nameResolver.getString(index)] = index
}
localNames.addAll(nameResolver.types.localNameList)
} }
localNames.addAll(nameResolver.types.localNameList)
} }
override fun getStringIndex(string: String): Int = override fun getStringIndex(string: String): Int =
@@ -62,14 +57,6 @@ class JvmStringTable(private val typeMapper: KotlinTypeMapper) : StringTable {
return !hasPredefinedIndex() && !hasOperation() && substringIndexCount == 0 && replaceCharCount == 0 return !hasPredefinedIndex() && !hasOperation() && substringIndexCount == 0 && replaceCharCount == 0
} }
override fun getFqNameIndex(descriptor: ClassifierDescriptorWithTypeParameters): Int {
if (ErrorUtils.isError(descriptor)) {
throw IllegalStateException("Cannot get FQ name of error class: " + descriptor)
}
return getClassIdIndex(descriptor.classId)
}
// We use the following format to encode ClassId: "pkg/Outer.Inner". // We use the following format to encode ClassId: "pkg/Outer.Inner".
// It represents a unique name, but such names don't usually appear in the constant pool, so we're writing "Lpkg/Outer$Inner;" // It represents a unique name, but such names don't usually appear in the constant pool, so we're writing "Lpkg/Outer$Inner;"
// instead and an instruction to drop the first and the last character in this string and replace all '$' with '.'. // instead and an instruction to drop the first and the last character in this string and replace all '$' with '.'.
@@ -78,30 +65,28 @@ class JvmStringTable(private val typeMapper: KotlinTypeMapper) : StringTable {
// string literally: "pkg/Outer.Inner$with$dollars" // string literally: "pkg/Outer.Inner$with$dollars"
// - the class is local or nested in local. In this case we're also storing the literal string, and also storing the fact that // - the class is local or nested in local. In this case we're also storing the literal string, and also storing the fact that
// this name represents a local class in a separate list // this name represents a local class in a separate list
override fun getClassIdIndex(classId: ClassId): Int { override fun getQualifiedClassNameIndex(className: String, isLocal: Boolean): Int {
val string = classId.asString() map[className]?.let { recordedIndex ->
map[string]?.let { recordedIndex ->
// If we already recorded such string, we only return its index if it's local and our name is local // If we already recorded such string, we only return its index if it's local and our name is local
// OR it's not local and our name is not local as well // OR it's not local and our name is not local as well
if (classId.isLocal == (recordedIndex in localNames)) { if (isLocal == (recordedIndex in localNames)) {
return recordedIndex return recordedIndex
} }
} }
val index = strings.size val index = strings.size
if (classId.isLocal) { if (isLocal) {
localNames.add(index) localNames.add(index)
} }
val record = Record.newBuilder() val record = Record.newBuilder()
// If the class is local or any of its outer class names contains '$', store a literal string // If the class is local or any of its outer class names contains '$', store a literal string
if (classId.isLocal || '$' in string) { if (isLocal || '$' in className) {
strings.add(string) strings.add(className)
} }
else { else {
val predefinedIndex = JvmNameResolver.getPredefinedStringIndex(string) val predefinedIndex = JvmNameResolver.getPredefinedStringIndex(className)
if (predefinedIndex != null) { if (predefinedIndex != null) {
record.predefinedIndex = predefinedIndex record.predefinedIndex = predefinedIndex
// TODO: move all records with predefined names to the end and do not write associated strings for them (since they are ignored) // TODO: move all records with predefined names to the end and do not write associated strings for them (since they are ignored)
@@ -109,30 +94,17 @@ class JvmStringTable(private val typeMapper: KotlinTypeMapper) : StringTable {
} }
else { else {
record.operation = Record.Operation.DESC_TO_CLASS_ID record.operation = Record.Operation.DESC_TO_CLASS_ID
strings.add("L${string.replace('.', '$')};") strings.add("L${className.replace('.', '$')};")
} }
} }
records.add(record) records.add(record)
map[string] = index map[className] = index
return index return index
} }
private val ClassifierDescriptorWithTypeParameters.classId: ClassId
get() {
val container = containingDeclaration
return when (container) {
is ClassDescriptor -> container.classId.createNestedClassId(name)
is PackageFragmentDescriptor -> ClassId(container.fqName, name)
else -> {
val fqName = FqName(typeMapper.mapClass(this).internalName.replace('/', '.'))
ClassId(fqName.parent(), FqName.topLevel(fqName.shortName()), /* isLocal = */ true)
}
}
}
override fun serializeTo(output: OutputStream) { override fun serializeTo(output: OutputStream) {
with(JvmProtoBuf.StringTableTypes.newBuilder()) { with(JvmProtoBuf.StringTableTypes.newBuilder()) {
addAllRecord(records.map { it.build() }) addAllRecord(records.map { it.build() })
@@ -18,18 +18,16 @@ package org.jetbrains.kotlin.serialization.builtins
import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.UnresolvedType import org.jetbrains.kotlin.types.UnresolvedType
class BuiltInsSerializerExtension : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) { class BuiltInsSerializerExtension : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) {
private val shortNameToClassId = mapOf( private val shortNameToClassId = mapOf(
"IntRange" to "kotlin.ranges.IntRange", "IntRange" to "kotlin/ranges/IntRange",
"LongRange" to "kotlin.ranges.LongRange", "LongRange" to "kotlin/ranges/LongRange",
"CharRange" to "kotlin.ranges.CharRange" "CharRange" to "kotlin/ranges/CharRange"
).mapValues { (_, value) -> ClassId.topLevel(FqName(value)) } )
override fun shouldUseTypeTable(): Boolean = true override fun shouldUseTypeTable(): Boolean = true
@@ -39,9 +37,9 @@ class BuiltInsSerializerExtension : KotlinSerializerExtensionBase(BuiltInSeriali
throw UnsupportedOperationException("Error types which are not UnresolvedType instances are not supported here: $unwrapped") throw UnsupportedOperationException("Error types which are not UnresolvedType instances are not supported here: $unwrapped")
} }
val classId = shortNameToClassId[unwrapped.presentableName] val className = shortNameToClassId[unwrapped.presentableName]
?: throw UnsupportedOperationException("Unsupported unresolved type: $unwrapped") ?: throw UnsupportedOperationException("Unsupported unresolved type: $unwrapped")
builder.className = stringTable.getClassIdIndex(classId) builder.className = stringTable.getQualifiedClassNameIndex(className, false)
} }
} }
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
class AnnotationSerializer(private val stringTable: StringTable) { class AnnotationSerializer(private val stringTable: DescriptorAwareStringTable) {
fun serializeAnnotation(annotation: AnnotationDescriptor): ProtoBuf.Annotation = ProtoBuf.Annotation.newBuilder().apply { fun serializeAnnotation(annotation: AnnotationDescriptor): ProtoBuf.Annotation = ProtoBuf.Annotation.newBuilder().apply {
val annotationClass = annotation.annotationClass ?: error("Annotation type is not a class: ${annotation.type}") val annotationClass = annotation.annotationClass ?: error("Annotation type is not a class: ${annotation.type}")
if (ErrorUtils.isError(annotationClass)) { if (ErrorUtils.isError(annotationClass)) {
@@ -79,7 +79,7 @@ class AnnotationSerializer(private val stringTable: StringTable) {
override fun visitEnumValue(value: EnumValue, data: Unit) { override fun visitEnumValue(value: EnumValue, data: Unit) {
type = Type.ENUM type = Type.ENUM
classId = stringTable.getClassIdIndex(value.enumClassId) classId = stringTable.getQualifiedClassNameIndex(value.enumClassId.asString(), value.enumClassId.isLocal)
enumValueId = stringTable.getStringIndex(value.enumEntryName.asString()) enumValueId = stringTable.getStringIndex(value.enumEntryName.asString())
} }
@@ -48,7 +48,7 @@ class DescriptorSerializer private constructor(
DescriptorSerializer(descriptor, Interner(typeParameters), extension, typeTable, versionRequirementTable, DescriptorSerializer(descriptor, Interner(typeParameters), extension, typeTable, versionRequirementTable,
serializeTypeTableToFunction = false) serializeTypeTableToFunction = false)
val stringTable: StringTable val stringTable: DescriptorAwareStringTable
get() = extension.stringTable get() = extension.stringTable
private fun useTypeTable(): Boolean = extension.shouldUseTypeTable() private fun useTypeTable(): Boolean = extension.shouldUseTypeTable()
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.types.FlexibleType
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
abstract class SerializerExtension { abstract class SerializerExtension {
abstract val stringTable: StringTable abstract val stringTable: DescriptorAwareStringTable
val annotationSerializer by lazy { AnnotationSerializer(stringTable) } val annotationSerializer by lazy { AnnotationSerializer(stringTable) }
@@ -18,14 +18,33 @@ package org.jetbrains.kotlin.serialization
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.ErrorUtils
import java.io.OutputStream import java.io.OutputStream
interface StringTable { interface StringTable {
fun getStringIndex(string: String): Int fun getStringIndex(string: String): Int
fun getFqNameIndex(descriptor: ClassifierDescriptorWithTypeParameters): Int /**
* @param className the fully qualified name of some class in the format: `org/foo/bar/Test.Inner`
fun getClassIdIndex(classId: ClassId): Int */
fun getQualifiedClassNameIndex(className: String, isLocal: Boolean): Int
fun serializeTo(output: OutputStream) fun serializeTo(output: OutputStream)
} }
interface DescriptorAwareStringTable : StringTable {
fun getFqNameIndex(descriptor: ClassifierDescriptorWithTypeParameters): Int {
if (ErrorUtils.isError(descriptor)) {
throw IllegalStateException("Cannot get FQ name of error class: $descriptor")
}
val classId = descriptor.classId
?: getLocalClassIdReplacement(descriptor)
?: throw IllegalStateException("Cannot get FQ name of local class: $descriptor")
return getQualifiedClassNameIndex(classId.asString(), classId.isLocal)
}
fun getLocalClassIdReplacement(descriptor: ClassifierDescriptorWithTypeParameters): ClassId? = null
}
@@ -16,18 +16,14 @@
package org.jetbrains.kotlin.serialization package org.jetbrains.kotlin.serialization
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf.QualifiedNameTable.QualifiedName import org.jetbrains.kotlin.metadata.ProtoBuf.QualifiedNameTable.QualifiedName
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.utils.Interner import org.jetbrains.kotlin.utils.Interner
import java.io.OutputStream import java.io.OutputStream
open class StringTableImpl : StringTable { open class StringTableImpl : DescriptorAwareStringTable {
private class FqNameProto(val fqName: QualifiedName.Builder) { private class FqNameProto(val fqName: QualifiedName.Builder) {
override fun hashCode(): Int { override fun hashCode(): Int {
var result = 13 var result = 13
@@ -50,25 +46,17 @@ open class StringTableImpl : StringTable {
private val strings = Interner<String>() private val strings = Interner<String>()
private val qualifiedNames = Interner<FqNameProto>() private val qualifiedNames = Interner<FqNameProto>()
fun getSimpleNameIndex(name: Name): Int = getStringIndex(name.asString())
override fun getStringIndex(string: String): Int = strings.intern(string) override fun getStringIndex(string: String): Int = strings.intern(string)
override fun getFqNameIndex(descriptor: ClassifierDescriptorWithTypeParameters): Int { override fun getQualifiedClassNameIndex(className: String, isLocal: Boolean): Int =
if (ErrorUtils.isError(descriptor)) { getQualifiedClassNameIndex(ClassId.fromString(className, isLocal))
throw IllegalStateException("Cannot get FQ name of error class: $descriptor")
}
val classId = descriptor.classId ?: return getFqNameIndexOfLocalAnonymousClass(descriptor) private fun getQualifiedClassNameIndex(classId: ClassId): Int {
return getClassIdIndex(classId)
}
override fun getClassIdIndex(classId: ClassId): Int {
val builder = QualifiedName.newBuilder() val builder = QualifiedName.newBuilder()
builder.kind = QualifiedName.Kind.CLASS builder.kind = QualifiedName.Kind.CLASS
builder.parentQualifiedName = builder.parentQualifiedName =
classId.outerClassId?.let(this::getClassIdIndex) classId.outerClassId?.let(this::getQualifiedClassNameIndex)
?: getPackageFqNameIndex(classId.packageFqName) ?: getPackageFqNameIndex(classId.packageFqName)
builder.shortName = getStringIndex(classId.shortClassName.asString()) builder.shortName = getStringIndex(classId.shortClassName.asString())
@@ -76,15 +64,11 @@ open class StringTableImpl : StringTable {
return qualifiedNames.intern(FqNameProto(builder)) return qualifiedNames.intern(FqNameProto(builder))
} }
open fun getFqNameIndexOfLocalAnonymousClass(descriptor: ClassifierDescriptorWithTypeParameters): Int {
throw IllegalStateException("Cannot get FQ name of local class: " + descriptor)
}
fun getPackageFqNameIndex(fqName: FqName): Int { fun getPackageFqNameIndex(fqName: FqName): Int {
var result = -1 var result = -1
for (segment in fqName.pathSegments()) { for (segment in fqName.pathSegments()) {
val builder = QualifiedName.newBuilder() val builder = QualifiedName.newBuilder()
builder.shortName = getSimpleNameIndex(segment) builder.shortName = getStringIndex(segment.asString())
if (result != -1) { if (result != -1) {
builder.parentQualifiedName = result builder.parentQualifiedName = result
} }
@@ -16,30 +16,32 @@
package org.jetbrains.kotlin.serialization.js package org.jetbrains.kotlin.serialization.js
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.serialization.StringTableImpl import org.jetbrains.kotlin.serialization.StringTableImpl
class JavaScriptStringTable : StringTableImpl() { class JavaScriptStringTable : StringTableImpl() {
override fun getFqNameIndexOfLocalAnonymousClass(descriptor: ClassifierDescriptorWithTypeParameters): Int { override fun getLocalClassIdReplacement(descriptor: ClassifierDescriptorWithTypeParameters): ClassId? {
return if (descriptor.containingDeclaration is CallableMemberDescriptor) { return if (descriptor.containingDeclaration is CallableMemberDescriptor) {
val superClassifiers = descriptor.getAllSuperClassifiers() val superClassifiers = descriptor.getAllSuperClassifiers()
.mapNotNull { it as ClassifierDescriptorWithTypeParameters } .mapNotNull { it as ClassifierDescriptorWithTypeParameters }
.filter { it != descriptor } .filter { it != descriptor }
.toList() .toList()
if (superClassifiers.size == 1) { if (superClassifiers.size == 1) {
getFqNameIndex(superClassifiers[0]) superClassifiers[0].classId
} }
else { else {
val superClass = superClassifiers.find { !DescriptorUtils.isInterface(it) } val superClass = superClassifiers.find { !DescriptorUtils.isInterface(it) }
getFqNameIndex(superClass ?: descriptor.module.builtIns.any) superClass?.classId ?: ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.any.toSafe())
} }
} }
else { else {
super.getFqNameIndexOfLocalAnonymousClass(descriptor) super.getLocalClassIdReplacement(descriptor)
} }
} }
} }