Serialize native klib extensions to pass most ObjCExport and CInterop tests.

Merge-request: KT-MR-8398
Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt
index ef4d95a..932a6b5 100644
--- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt
+++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt
@@ -58,6 +58,8 @@
 import org.jetbrains.kotlin.fir.pipeline.runResolution
 import org.jetbrains.kotlin.fir.resolve.providers.firProvider
 import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
+import org.jetbrains.kotlin.fir.serialization.FirElementAwareSerializableStringTable
+import org.jetbrains.kotlin.fir.serialization.FirKLibSerializerExtension
 import org.jetbrains.kotlin.fir.serialization.serializeSingleFirFile
 import org.jetbrains.kotlin.fir.session.FirJsSessionFactory
 import org.jetbrains.kotlin.fir.session.FirSessionConfigurator
@@ -631,7 +633,12 @@
                 jsOutputName = null
             ) { file ->
                 val firFile = firFilesBySourceFile[file] ?: error("cannot find FIR file by source file ${file.name} (${file.path})")
-                serializeSingleFirFile(firFile, session, scopeSession, metadataVersion)
+                serializeSingleFirFile(
+                    firFile,
+                    session,
+                    scopeSession,
+                    FirKLibSerializerExtension(session, metadataVersion, FirElementAwareSerializableStringTable())
+                )
             }
         }
 
diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/firKlibSerialization.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/firKlibSerialization.kt
index 561c12b..e3f2232 100644
--- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/firKlibSerialization.kt
+++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/firKlibSerialization.kt
@@ -17,8 +17,7 @@
 import org.jetbrains.kotlin.name.ClassId
 import org.jetbrains.kotlin.serialization.SerializableStringTable
 
-fun serializeSingleFirFile(file: FirFile, session: FirSession, scopeSession: ScopeSession, metadataVersion: BinaryVersion): ProtoBuf.PackageFragment {
-    val serializerExtension = FirKLibSerializerExtension(session, metadataVersion, FirElementAwareSerializableStringTable())
+fun serializeSingleFirFile(file: FirFile, session: FirSession, scopeSession: ScopeSession, serializerExtension: FirKLibSerializerExtension): ProtoBuf.PackageFragment {
     val approximator = TypeApproximatorForMetadataSerializer(session)
     val packageSerializer = FirElementSerializer.createTopLevel(session, scopeSession, serializerExtension, approximator)
 
@@ -51,7 +50,7 @@
     )
 }
 
-class FirKLibSerializerExtension(
+open class FirKLibSerializerExtension(
     override val session: FirSession,
     override val metadataVersion: BinaryVersion,
     override val stringTable: FirElementAwareSerializableStringTable
diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt
index 7eed65a..c26845a 100644
--- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt
+++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt
@@ -29,6 +29,8 @@
 import org.jetbrains.kotlin.fir.moduleData
 import org.jetbrains.kotlin.fir.resolve.providers.firProvider
 import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
+import org.jetbrains.kotlin.fir.serialization.FirElementAwareSerializableStringTable
+import org.jetbrains.kotlin.fir.serialization.FirKLibSerializerExtension
 import org.jetbrains.kotlin.fir.serialization.serializeSingleFirFile
 import org.jetbrains.kotlin.incremental.components.LookupTracker
 import org.jetbrains.kotlin.ir.backend.js.JsFactories
@@ -90,7 +92,12 @@
             hasErrors,
         ) { file ->
             val firFile = firFilesBySourceFile[file] ?: error("cannot find FIR file by source file ${file.name} (${file.path})")
-            serializeSingleFirFile(firFile, components.session, components.scopeSession, metadataVersion)
+            serializeSingleFirFile(
+                firFile,
+                components.session,
+                components.scopeSession,
+                FirKLibSerializerExtension(components.session, metadataVersion, FirElementAwareSerializableStringTable())
+            )
         }
     }
 }
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirSerializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirSerializer.kt
index 5edf3a2..dda7310 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirSerializer.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirSerializer.kt
@@ -12,15 +12,22 @@
 import org.jetbrains.kotlin.config.CompilerConfiguration
 import org.jetbrains.kotlin.config.languageVersionSettings
 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.fir.serialization.serializeSingleFirFile
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.declarations.*
+import org.jetbrains.kotlin.fir.expressions.FirAnnotation
+import org.jetbrains.kotlin.fir.serialization.*
 import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
 import org.jetbrains.kotlin.ir.symbols.IrSymbol
 import org.jetbrains.kotlin.ir.util.IrMessageLogger
 import org.jetbrains.kotlin.konan.library.KonanLibrary
 import org.jetbrains.kotlin.library.SerializedIrFile
+import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
 import org.jetbrains.kotlin.library.metadata.resolver.TopologicalLibraryOrder
 import org.jetbrains.kotlin.metadata.ProtoBuf
 import org.jetbrains.kotlin.utils.toMetadataVersion
+import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
+import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
+import org.jetbrains.kotlin.psi
 
 internal fun PhaseContext.firSerializer(
         input: Fir2IrOutput
@@ -42,7 +49,11 @@
             expectDescriptorToSymbol = mutableMapOf() // TODO: expect -> actual mapping
     ) { file ->
         val firFile = firFilesBySourceFile[file] ?: error("cannot find FIR file by source file ${file.name} (${file.path})")
-        serializeSingleFirFile(firFile, input.session, input.scopeSession, metadataVersion)
+        serializeSingleFirFile(
+                firFile,
+                input.session,
+                input.scopeSession,
+                FirNativeKLibSerializerExtension(input.session, metadataVersion, FirElementAwareSerializableStringTable()))
     }
 }
 
@@ -102,3 +113,101 @@
 
     return SerializerOutput(serializedMetadata, serializedIr, null, dependencies)
 }
+
+class FirNativeKLibSerializerExtension(
+        override val session: FirSession,
+        override val metadataVersion: BinaryVersion,
+        override val stringTable: FirElementAwareSerializableStringTable
+) : FirKLibSerializerExtension(session, metadataVersion, stringTable) {
+    private fun declarationFileId(declaration: FirMemberDeclaration): Int? {
+        val fileName = declaration.source.psi?.containingFile?.name ?: return null
+        return stringTable.getStringIndex(fileName)
+    }
+
+    override fun serializeFunction(
+            function: FirFunction,
+            proto: ProtoBuf.Function.Builder,
+            versionRequirementTable: MutableVersionRequirementTable?,
+            childSerializer: FirElementSerializer
+    ) {
+        // inspired by KlibMetadataSerializerExtension.serializeFunction
+        declarationFileId(function)?.let { proto.setExtension(KlibMetadataProtoBuf.functionFile, it) }
+        function.annotations.forEach {
+            proto.addExtension(KlibMetadataProtoBuf.functionAnnotation, annotationSerializer.serializeAnnotation(it))
+        }
+        function.receiverParameter?.annotations?.forEach {
+            proto.addExtension(KlibMetadataProtoBuf.functionExtensionReceiverAnnotation, annotationSerializer.serializeAnnotation(it))
+        }
+        // TODO KT-56090 Serialize KDocString
+        super.serializeFunction(function, proto, versionRequirementTable, childSerializer)
+    }
+
+    override fun serializeValueParameter(parameter: FirValueParameter, proto: ProtoBuf.ValueParameter.Builder) {
+        parameter.annotations.forEach {
+            proto.addExtension(KlibMetadataProtoBuf.parameterAnnotation, annotationSerializer.serializeAnnotation(it))
+        }
+        super.serializeValueParameter(parameter, proto)
+    }
+
+    override fun serializeProperty(
+            property: FirProperty,
+            proto: ProtoBuf.Property.Builder,
+            versionRequirementTable: MutableVersionRequirementTable?,
+            childSerializer: FirElementSerializer
+    ) {
+        // inspired by KlibMetadataSerializerExtension.serializeProperty
+        declarationFileId(property)?.let { proto.setExtension(KlibMetadataProtoBuf.propertyFile, it) }
+        property.annotations.forEach {
+            proto.addExtension(KlibMetadataProtoBuf.propertyAnnotation, annotationSerializer.serializeAnnotation(it))
+        }
+        // TODO KT-56090 Serialize KDocString
+        super.serializeProperty(property, proto, versionRequirementTable, childSerializer)
+    }
+
+    override fun serializeClass(
+            klass: FirClass,
+            proto: ProtoBuf.Class.Builder,
+            versionRequirementTable: MutableVersionRequirementTable,
+            childSerializer: FirElementSerializer
+    ) {
+        klass.annotations.forEach {
+            proto.addExtension(KlibMetadataProtoBuf.classAnnotation, annotationSerializer.serializeAnnotation(it))
+        }
+        // TODO KT-56090 Serialize KDocString
+        super.serializeClass(klass, proto, versionRequirementTable, childSerializer)
+    }
+
+    override fun serializeConstructor(
+            constructor: FirConstructor,
+            proto: ProtoBuf.Constructor.Builder,
+            childSerializer: FirElementSerializer
+    ) {
+        constructor.annotations.forEach {
+            proto.addExtension(KlibMetadataProtoBuf.constructorAnnotation, annotationSerializer.serializeAnnotation(it))
+        }
+        // TODO KT-56090 Serialize KDocString
+        super.serializeConstructor(constructor, proto, childSerializer)
+    }
+
+    override fun serializeEnumEntry(enumEntry: FirEnumEntry, proto: ProtoBuf.EnumEntry.Builder) {
+        enumEntry.annotations.forEach {
+            proto.addExtension(KlibMetadataProtoBuf.enumEntryAnnotation, annotationSerializer.serializeAnnotation(it))
+        }
+        super.serializeEnumEntry(enumEntry, proto)
+    }
+
+    override fun serializeTypeAnnotation(annotation: FirAnnotation, proto: ProtoBuf.Type.Builder) {
+        annotation.annotations.forEach {
+            proto.addExtension(KlibMetadataProtoBuf.typeAnnotation, annotationSerializer.serializeAnnotation(it))
+        }
+        super.serializeTypeAnnotation(annotation, proto)
+    }
+
+    override fun serializeTypeParameter(typeParameter: FirTypeParameter, proto: ProtoBuf.TypeParameter.Builder) {
+        typeParameter.annotations.forEach {
+            proto.addExtension(KlibMetadataProtoBuf.typeParameterAnnotation, annotationSerializer.serializeAnnotation(it))
+        }
+        super.serializeTypeParameter(typeParameter, proto)
+    }
+
+}
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/DynamicCompilerDriver.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/DynamicCompilerDriver.kt
index a09a9ad..8687a3e 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/DynamicCompilerDriver.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/DynamicCompilerDriver.kt
@@ -95,7 +95,7 @@
         require(frontendOutput is FirOutput.Full)
 
         val fir2IrOutput = engine.runFir2Ir(frontendOutput)
-        engine.runK2SpecialBackendChecks(fir2IrOutput)
+//        engine.runK2SpecialBackendChecks(fir2IrOutput)  // TODO After fix of KT-56018 try uncommenting this line
         return engine.runFirSerializer(fir2IrOutput)
     }