From 34323be30455895a5555033abd910ac009e3fb2e Mon Sep 17 00:00:00 2001 From: Sergey Bogolepov Date: Thu, 12 Dec 2019 12:23:06 +0700 Subject: [PATCH] [StubIr][Metadata] Add support for classes and constructors --- .../native/interop/gen/StubIrExtensions.kt | 5 +- .../interop/gen/StubIrMetadataEmitter.kt | 66 +++++++++++++++++-- 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrExtensions.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrExtensions.kt index 18c35bc621d..1cb672a110b 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrExtensions.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrExtensions.kt @@ -67,4 +67,7 @@ val StubContainer.defaultMemberModality: MemberStubModality * Returns constructor that should be rendered in class header. */ val ClassStub.explicitPrimaryConstructor: ConstructorStub? - get() = functions.filterIsInstance().firstOrNull(ConstructorStub::isPrimary) \ No newline at end of file + get() = functions.filterIsInstance().firstOrNull(ConstructorStub::isPrimary) + +fun ClassStub.nestedName(): String = + classifier.relativeFqName.substringAfterLast('.') \ No newline at end of file diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrMetadataEmitter.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrMetadataEmitter.kt index 36d8224e962..b649974f4a0 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrMetadataEmitter.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrMetadataEmitter.kt @@ -76,8 +76,34 @@ internal class ModuleMetadataEmitter( private val visitor = object : StubIrVisitor { - override fun visitClass(element: ClassStub, data: VisitingContext) { - // TODO("not implemented") + override fun visitClass(element: ClassStub, data: VisitingContext): List { + val classVisitingContext = VisitingContext( + container = element, + uniqIds = data.uniqIds.createChild(element.nestedName()), + typeParametersInterner = Interner(data.typeParametersInterner) + ) + val children = element.children + if (element is ClassStub.Companion) { + listOf(ConstructorStub(isPrimary = true, visibility = VisibilityModifier.PRIVATE, origin = StubOrigin.SyntheticDefaultConstructor)) + } else emptyList() + val elements = KmElements(children.map { it.accept(this, classVisitingContext) }) + val kmClass = with (MappingExtensions(data.typeParametersInterner)) { + KmClass().also { km -> + element.annotations.mapTo(km.annotations) { it.map() } + km.flags = element.flags + km.name = element.classifier.fqNameSerialized + element.superClassInit?.let { km.supertypes += it.type.map() } + element.interfaces.mapTo(km.supertypes) { it.map() } + element.classes.mapTo(km.nestedClasses) { it.nestedName() } + km.typeAliases += elements.typeAliases.toList() + km.properties += elements.properties.toList() + km.functions += elements.functions.toList() + km.constructors += elements.constructors.toList() + km.companionObject = element.companion?.nestedName() + km.uniqId = data.uniqIds.uniqIdForClass(element) + } + } + // Metadata stores classes as flat list. + return listOf(kmClass) + elements.classes } override fun visitTypealias(element: TypealiasStub, data: VisitingContext): KmTypeAlias = @@ -123,9 +149,14 @@ internal class ModuleMetadataEmitter( } } - override fun visitConstructor(constructorStub: ConstructorStub, data: VisitingContext) { - // TODO("not implemented") - } + override fun visitConstructor(constructorStub: ConstructorStub, data: VisitingContext) = + with (MappingExtensions(data.typeParametersInterner)) { + KmConstructor(constructorStub.flags).apply { + constructorStub.parameters.mapTo(valueParameters, { it.map() }) + constructorStub.annotations.mapTo(annotations, { it.map() }) + uniqId = data.uniqIds.uniqIdForConstructor(constructorStub) + } + } override fun visitPropertyAccessor(propertyAccessor: PropertyAccessor, data: VisitingContext) { // TODO("not implemented") @@ -247,6 +278,31 @@ private class MappingExtensions( Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() } ) + val ClassStub.flags: Flags + get() = flagsOfNotNull( + Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() }, + Flag.IS_PUBLIC, + Flag.IS_OPEN.takeIf { this is ClassStub.Simple && this.modality == ClassStubModality.OPEN }, + Flag.IS_FINAL.takeIf { this is ClassStub.Simple && this.modality == ClassStubModality.NONE }, + Flag.Class.IS_COMPANION_OBJECT.takeIf { this is ClassStub.Companion }, + Flag.Class.IS_CLASS.takeIf { this is ClassStub.Simple }, + Flag.Class.IS_ENUM_CLASS.takeIf { this is ClassStub.Enum } + ) + + // TODO: Looks like [Flag.Constructor.IS_PRIMARY] flag is incorrect. + // Upstream fix to kotlinx-metadata. + private val isSecondaryConstructorFlag = Flag( + org.jetbrains.kotlin.metadata.deserialization.Flags.IS_SECONDARY.offset, + org.jetbrains.kotlin.metadata.deserialization.Flags.IS_SECONDARY.bitWidth, + value = 1 + ) + + val ConstructorStub.flags: Flags + get() = flagsOfNotNull( + isSecondaryConstructorFlag.takeIf { !isPrimary }, + Flag.HAS_ANNOTATIONS.takeIf { annotations.isNotEmpty() } + ) or visibility.flags + fun AnnotationStub.map(): KmAnnotation { fun Pair.asAnnotationArgument() = (first to KmAnnotationArgument.StringValue(second)).takeIf { second.isNotEmpty() }