[klib] Add an option to write out header klibs

The header klib is supposed to only contain the public abi of the module
similar to jvm-abi-gen. It is intended to be used as a dependency for other
klib compilations instead of the full klib for compilation avoidance.

^KT-60807
This commit is contained in:
Johan Bay
2023-05-09 14:29:21 +02:00
committed by Space Team
parent 829e0675f4
commit 0a612e4268
90 changed files with 1374 additions and 76 deletions
@@ -45,6 +45,7 @@ fun copyK2NativeCompilerArguments(from: K2NativeCompilerArguments, to: K2NativeC
to.generateNoExitTestRunner = from.generateNoExitTestRunner to.generateNoExitTestRunner = from.generateNoExitTestRunner
to.generateTestRunner = from.generateTestRunner to.generateTestRunner = from.generateTestRunner
to.generateWorkerTestRunner = from.generateWorkerTestRunner to.generateWorkerTestRunner = from.generateWorkerTestRunner
to.headerKlibPath = from.headerKlibPath
to.includeBinaries = from.includeBinaries?.copyOf() to.includeBinaries = from.includeBinaries?.copyOf()
to.includes = from.includes?.copyOf() to.includes = from.includes?.copyOf()
to.incrementalCacheDir = from.incrementalCacheDir to.incrementalCacheDir = from.incrementalCacheDir
@@ -372,6 +372,12 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-Xmetadata-klib", description = "Produce a klib that only contains the declarations metadata") @Argument(value = "-Xmetadata-klib", description = "Produce a klib that only contains the declarations metadata")
var metadataKlib: Boolean = false var metadataKlib: Boolean = false
@Argument(
value = "-Xheader-klib-path",
description = "Save a klib that only contains the public abi to the given path"
)
var headerKlibPath: String? = null
@Argument(value = "-Xdebug-prefix-map", valueDescription = "<old1=new1,old2=new2,...>", description = "Remap file source directory paths in debug info") @Argument(value = "-Xdebug-prefix-map", valueDescription = "<old1=new1,old2=new2,...>", description = "Remap file source directory paths in debug info")
var debugPrefixMap: Array<String>? = null var debugPrefixMap: Array<String>? = null
@@ -58,7 +58,8 @@ internal class K2MetadataKlibSerializer(
project, project,
exportKDoc = false, exportKDoc = false,
skipExpects = false, skipExpects = false,
includeOnlyModuleContent = true includeOnlyModuleContent = true,
produceHeaderKlib = false,
).serializeModule(module) ).serializeModule(module)
buildKotlinMetadataLibrary(configuration, serializedMetadata, destDir) buildKotlinMetadataLibrary(configuration, serializedMetadata, destDir)
@@ -74,6 +74,7 @@ class FirElementSerializer private constructor(
private val serializeTypeTableToFunction: Boolean, private val serializeTypeTableToFunction: Boolean,
private val typeApproximator: AbstractTypeApproximator, private val typeApproximator: AbstractTypeApproximator,
private val languageVersionSettings: LanguageVersionSettings, private val languageVersionSettings: LanguageVersionSettings,
private val produceHeaderKlib: Boolean,
) { ) {
private val contractSerializer = FirContractSerializer() private val contractSerializer = FirContractSerializer()
private val providedDeclarationsService = session.providedDeclarationsForMetadataService private val providedDeclarationsService = session.providedDeclarationsForMetadataService
@@ -89,7 +90,8 @@ class FirElementSerializer private constructor(
fun addDeclaration(declaration: FirDeclaration, onUnsupportedDeclaration: (FirDeclaration) -> Unit) { fun addDeclaration(declaration: FirDeclaration, onUnsupportedDeclaration: (FirDeclaration) -> Unit) {
if (declaration is FirMemberDeclaration) { if (declaration is FirMemberDeclaration) {
if (!declaration.shouldBeSerialized(actualizedExpectDeclarations)) return if (!declaration.isNotExpectOrShouldBeSerialized(actualizedExpectDeclarations)) return
if (!declaration.isNotPrivateOrShouldBeSerialized(produceHeaderKlib)) return
when (declaration) { when (declaration) {
is FirProperty -> propertyProto(declaration)?.let { builder.addProperty(it) } is FirProperty -> propertyProto(declaration)?.let { builder.addProperty(it) }
is FirSimpleFunction -> functionProto(declaration)?.let { builder.addFunction(it) } is FirSimpleFunction -> functionProto(declaration)?.let { builder.addFunction(it) }
@@ -178,6 +180,7 @@ class FirElementSerializer private constructor(
*/ */
if (regularClass != null && regularClass.classKind != ClassKind.ENUM_ENTRY) { if (regularClass != null && regularClass.classKind != ClassKind.ENUM_ENTRY) {
for (constructor in regularClass.constructors()) { for (constructor in regularClass.constructors()) {
if (!constructor.isNotPrivateOrShouldBeSerialized(produceHeaderKlib)) continue
builder.addConstructor(constructorProto(constructor)) builder.addConstructor(constructorProto(constructor))
} }
@@ -203,6 +206,7 @@ class FirElementSerializer private constructor(
for (declaration in callableMembers) { for (declaration in callableMembers) {
if (declaration !is FirEnumEntry && declaration.isStatic) continue // ??? Miss values() & valueOf() if (declaration !is FirEnumEntry && declaration.isStatic) continue // ??? Miss values() & valueOf()
if (!declaration.isNotPrivateOrShouldBeSerialized(produceHeaderKlib)) continue
when (declaration) { when (declaration) {
is FirProperty -> propertyProto(declaration)?.let { builder.addProperty(it) } is FirProperty -> propertyProto(declaration)?.let { builder.addProperty(it) }
is FirSimpleFunction -> functionProto(declaration)?.let { builder.addFunction(it) } is FirSimpleFunction -> functionProto(declaration)?.let { builder.addFunction(it) }
@@ -1042,7 +1046,7 @@ class FirElementSerializer private constructor(
FirElementSerializer( FirElementSerializer(
session, scopeSession, declaration, Interner(typeParameters), extension, session, scopeSession, declaration, Interner(typeParameters), extension,
typeTable, versionRequirementTable, serializeTypeTableToFunction = false, typeTable, versionRequirementTable, serializeTypeTableToFunction = false,
typeApproximator, languageVersionSettings typeApproximator, languageVersionSettings, produceHeaderKlib
) )
val stringTable: FirElementAwareStringTable val stringTable: FirElementAwareStringTable
@@ -1148,6 +1152,7 @@ class FirElementSerializer private constructor(
extension: FirSerializerExtension, extension: FirSerializerExtension,
typeApproximator: AbstractTypeApproximator, typeApproximator: AbstractTypeApproximator,
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
produceHeaderKlib: Boolean = false,
): FirElementSerializer = ): FirElementSerializer =
FirElementSerializer( FirElementSerializer(
session, scopeSession, null, session, scopeSession, null,
@@ -1155,6 +1160,7 @@ class FirElementSerializer private constructor(
serializeTypeTableToFunction = false, serializeTypeTableToFunction = false,
typeApproximator, typeApproximator,
languageVersionSettings, languageVersionSettings,
produceHeaderKlib,
) )
@JvmStatic @JvmStatic
@@ -1171,6 +1177,7 @@ class FirElementSerializer private constructor(
versionRequirementTable = null, serializeTypeTableToFunction = true, versionRequirementTable = null, serializeTypeTableToFunction = true,
typeApproximator, typeApproximator,
languageVersionSettings, languageVersionSettings,
produceHeaderKlib = false,
) )
@JvmStatic @JvmStatic
@@ -1182,16 +1189,17 @@ class FirElementSerializer private constructor(
parentSerializer: FirElementSerializer?, parentSerializer: FirElementSerializer?,
typeApproximator: AbstractTypeApproximator, typeApproximator: AbstractTypeApproximator,
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
produceHeaderKlib: Boolean = false,
): FirElementSerializer { ): FirElementSerializer {
val parentClassId = klass.symbol.classId.outerClassId val parentClassId = klass.symbol.classId.outerClassId
val parent = if (parentClassId != null && !parentClassId.isLocal) { val parent = if (parentClassId != null && !parentClassId.isLocal) {
val parentClass = session.symbolProvider.getClassLikeSymbolByClassId(parentClassId)!!.fir as FirRegularClass val parentClass = session.symbolProvider.getClassLikeSymbolByClassId(parentClassId)!!.fir as FirRegularClass
parentSerializer ?: create( parentSerializer ?: create(
session, scopeSession, parentClass, extension, null, typeApproximator, session, scopeSession, parentClass, extension, null, typeApproximator,
languageVersionSettings, languageVersionSettings, produceHeaderKlib
) )
} else { } else {
createTopLevel(session, scopeSession, extension, typeApproximator, languageVersionSettings) createTopLevel(session, scopeSession, extension, typeApproximator, languageVersionSettings, produceHeaderKlib)
} }
// Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always // Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always
@@ -1212,6 +1220,7 @@ class FirElementSerializer private constructor(
serializeTypeTableToFunction = false, serializeTypeTableToFunction = false,
typeApproximator, typeApproximator,
languageVersionSettings, languageVersionSettings,
produceHeaderKlib,
) )
for (typeParameter in klass.typeParameters) { for (typeParameter in klass.typeParameters) {
if (typeParameter !is FirTypeParameter) continue if (typeParameter !is FirTypeParameter) continue
@@ -22,12 +22,14 @@ fun serializeSingleFirFile(
actualizedExpectDeclarations: Set<FirDeclaration>?, actualizedExpectDeclarations: Set<FirDeclaration>?,
serializerExtension: FirKLibSerializerExtension, serializerExtension: FirKLibSerializerExtension,
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
produceHeaderKlib: Boolean = false,
): ProtoBuf.PackageFragment { ): ProtoBuf.PackageFragment {
val approximator = TypeApproximatorForMetadataSerializer(session) val approximator = TypeApproximatorForMetadataSerializer(session)
val packageSerializer = FirElementSerializer.createTopLevel( val packageSerializer = FirElementSerializer.createTopLevel(
session, scopeSession, serializerExtension, session, scopeSession, serializerExtension,
approximator, approximator,
languageVersionSettings languageVersionSettings,
produceHeaderKlib
) )
// TODO: typealiases (see klib serializer) // TODO: typealiases (see klib serializer)
@@ -40,13 +42,16 @@ fun serializeSingleFirFile(
fun List<FirClassSymbol<*>>.makeClassesProtoWithNested() { fun List<FirClassSymbol<*>>.makeClassesProtoWithNested() {
val classSymbols = this val classSymbols = this
.filter { it.fir.shouldBeSerialized(actualizedExpectDeclarations) } .filter {
it.fir.isNotExpectOrShouldBeSerialized(actualizedExpectDeclarations) &&
it.fir.isNotPrivateOrShouldBeSerialized(produceHeaderKlib)
}
.sortedBy { it.classId.asFqNameString() } .sortedBy { it.classId.asFqNameString() }
for (symbol in classSymbols) { for (symbol in classSymbols) {
val klass = symbol.fir val klass = symbol.fir
val classSerializer = FirElementSerializer.create( val classSerializer = FirElementSerializer.create(
session, scopeSession, klass, serializerExtension, null, session, scopeSession, klass, serializerExtension, null,
approximator, languageVersionSettings approximator, languageVersionSettings, produceHeaderKlib
) )
val index = classSerializer.stringTable.getFqNameIndex(klass) val index = classSerializer.stringTable.getFqNameIndex(klass)
@@ -60,7 +65,8 @@ fun serializeSingleFirFile(
} }
val hasTopLevelDeclarations = file.declarations.any { val hasTopLevelDeclarations = file.declarations.any {
it is FirMemberDeclaration && it.shouldBeSerialized(actualizedExpectDeclarations) && it is FirMemberDeclaration && it.isNotExpectOrShouldBeSerialized(actualizedExpectDeclarations) &&
it.isNotPrivateOrShouldBeSerialized(produceHeaderKlib) &&
(it is FirProperty || it is FirSimpleFunction || it is FirTypeAlias) (it is FirProperty || it is FirSimpleFunction || it is FirTypeAlias)
} }
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic
import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
@@ -47,6 +48,10 @@ fun ConeKotlinType.suspendFunctionTypeToFunctionTypeWithContinuation(session: Fi
) )
} }
fun FirMemberDeclaration.shouldBeSerialized(actualizedExpectDeclaration: Set<FirDeclaration>?): Boolean { fun FirMemberDeclaration.isNotExpectOrShouldBeSerialized(actualizedExpectDeclaration: Set<FirDeclaration>?): Boolean {
return !isExpect || actualizedExpectDeclaration == null || this !in actualizedExpectDeclaration return !isExpect || actualizedExpectDeclaration == null || this !in actualizedExpectDeclaration
} }
fun FirMemberDeclaration.isNotPrivateOrShouldBeSerialized(produceHeaderKlib: Boolean): Boolean {
return !produceHeaderKlib || visibility.isPublicAPI
}
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.library.impl.IrMemoryStringWriter
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.filterIsInstanceAnd import org.jetbrains.kotlin.utils.filterIsInstanceAnd
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
import java.io.File import java.io.File
import org.jetbrains.kotlin.backend.common.serialization.proto.AccessorIdSignature as ProtoAccessorIdSignature import org.jetbrains.kotlin.backend.common.serialization.proto.AccessorIdSignature as ProtoAccessorIdSignature
import org.jetbrains.kotlin.backend.common.serialization.proto.CommonIdSignature as ProtoCommonIdSignature import org.jetbrains.kotlin.backend.common.serialization.proto.CommonIdSignature as ProtoCommonIdSignature
@@ -118,6 +119,7 @@ open class IrFileSerializer(
private val languageVersionSettings: LanguageVersionSettings, private val languageVersionSettings: LanguageVersionSettings,
private val bodiesOnlyForInlines: Boolean = false, private val bodiesOnlyForInlines: Boolean = false,
private val normalizeAbsolutePaths: Boolean = false, private val normalizeAbsolutePaths: Boolean = false,
private val skipPrivateApi: Boolean = false,
private val sourceBaseDirs: Collection<String> private val sourceBaseDirs: Collection<String>
) { ) {
private val loopIndex = hashMapOf<IrLoop, Int>() private val loopIndex = hashMapOf<IrLoop, Int>()
@@ -183,7 +185,11 @@ open class IrFileSerializer(
private fun serializeIrStatementOrigin(origin: IrStatementOrigin): Int = private fun serializeIrStatementOrigin(origin: IrStatementOrigin): Int =
serializeString((origin as? IrStatementOriginImpl)?.debugName ?: error("Unable to serialize origin ${origin.javaClass.name}")) serializeString((origin as? IrStatementOriginImpl)?.debugName ?: error("Unable to serialize origin ${origin.javaClass.name}"))
private fun serializeCoordinates(start: Int, end: Int): Long = BinaryCoordinates.encode(start, end) private fun serializeCoordinates(start: Int, end: Int): Long = if (skipPrivateApi) {
0L
} else {
BinaryCoordinates.encode(start, end)
}
/* ------- Strings ---------------------------------------------------------- */ /* ------- Strings ---------------------------------------------------------- */
@@ -1340,9 +1346,9 @@ open class IrFileSerializer(
// ---------- Top level ------------------------------------------------------ // ---------- Top level ------------------------------------------------------
private fun serializeFileEntry(entry: IrFileEntry): ProtoFileEntry = ProtoFileEntry.newBuilder() private fun serializeFileEntry(entry: IrFileEntry, includeLineStartOffsets: Boolean = true): ProtoFileEntry = ProtoFileEntry.newBuilder()
.setName(entry.matchAndNormalizeFilePath()) .setName(entry.matchAndNormalizeFilePath())
.addAllLineStartOffset(entry.lineStartOffsets.asIterable()) .applyIf(includeLineStartOffsets) { addAllLineStartOffset(entry.lineStartOffsets.asIterable()) }
.build() .build()
open fun backendSpecificExplicitRoot(node: IrAnnotationContainer): Boolean = false open fun backendSpecificExplicitRoot(node: IrAnnotationContainer): Boolean = false
@@ -1351,12 +1357,18 @@ open class IrFileSerializer(
open fun backendSpecificSerializeAllMembers(irClass: IrClass) = false open fun backendSpecificSerializeAllMembers(irClass: IrClass) = false
open fun backendSpecificMetadata(irFile: IrFile): FileBackendSpecificMetadata? = null open fun backendSpecificMetadata(irFile: IrFile): FileBackendSpecificMetadata? = null
private fun skipIfPrivate(declaration: IrDeclaration) =
skipPrivateApi && (declaration as? IrDeclarationWithVisibility)?.visibility?.isPublicAPI != true
open fun memberNeedsSerialization(member: IrDeclaration): Boolean { open fun memberNeedsSerialization(member: IrDeclaration): Boolean {
val parent = member.parent val parent = member.parent
require(parent is IrClass) require(parent is IrClass)
if (backendSpecificSerializeAllMembers(parent)) return true if (backendSpecificSerializeAllMembers(parent)) return true
if (bodiesOnlyForInlines && member is IrAnonymousInitializer && parent.visibility != DescriptorVisibilities.LOCAL) if (bodiesOnlyForInlines && member is IrAnonymousInitializer && parent.visibility != DescriptorVisibilities.LOCAL)
return false return false
if (skipIfPrivate(member)) {
return false
}
return (!member.isFakeOverride) return (!member.isFakeOverride)
} }
@@ -1414,11 +1426,15 @@ open class IrFileSerializer(
val topLevelDeclarations = mutableListOf<SerializedDeclaration>() val topLevelDeclarations = mutableListOf<SerializedDeclaration>()
val proto = ProtoFile.newBuilder() val proto = ProtoFile.newBuilder()
.setFileEntry(serializeFileEntry(file.fileEntry)) .setFileEntry(serializeFileEntry(file.fileEntry, includeLineStartOffsets = !skipPrivateApi))
.addAllFqName(serializeFqName(file.packageFqName.asString())) .addAllFqName(serializeFqName(file.packageFqName.asString()))
.addAllAnnotation(serializeAnnotations(file.annotations)) .addAllAnnotation(serializeAnnotations(file.annotations))
file.declarations.forEach { file.declarations.forEach {
if (skipIfPrivate(it)) {
// Skip the declaration if producing header klib and the declaration is not public.
return@forEach
}
if (it.descriptor.isExpectMember && !it.descriptor.isSerializableExpectClass) { if (it.descriptor.isExpectMember && !it.descriptor.isSerializableExpectClass) {
// Skip the declaration unless it is `expect annotation class` marked with `OptionalExpectation` // Skip the declaration unless it is `expect annotation class` marked with `OptionalExpectation`
// without the corresponding `actual` counterpart for the current leaf target. // without the corresponding `actual` counterpart for the current leaf target.
@@ -1441,7 +1457,7 @@ open class IrFileSerializer(
// Make sure that all top level properties are initialized on library's load. // Make sure that all top level properties are initialized on library's load.
file.declarations file.declarations
.filterIsInstanceAnd<IrProperty> { it.backingField?.initializer != null && keepOrderOfProperties(it) } .filterIsInstanceAnd<IrProperty> { it.backingField?.initializer != null && keepOrderOfProperties(it) && !skipIfPrivate(it) }
.forEach { .forEach {
val fieldSymbol = it.backingField?.symbol ?: error("Not found ID ${it.render()}") val fieldSymbol = it.backingField?.symbol ?: error("Not found ID ${it.render()}")
proto.addExplicitlyExportedToCompiler(serializeIrSymbol(fieldSymbol)) proto.addExplicitlyExportedToCompiler(serializeIrSymbol(fieldSymbol))
@@ -27,8 +27,9 @@ class KlibMetadataMonolithicSerializer(
exportKDoc: Boolean, exportKDoc: Boolean,
skipExpects: Boolean, skipExpects: Boolean,
includeOnlyModuleContent: Boolean = false, includeOnlyModuleContent: Boolean = false,
allowErrorTypes: Boolean = false allowErrorTypes: Boolean = false,
) : KlibMetadataSerializer(languageVersionSettings, metadataVersion, project, exportKDoc, skipExpects, includeOnlyModuleContent, allowErrorTypes) { produceHeaderKlib: Boolean = false,
) : KlibMetadataSerializer(languageVersionSettings, metadataVersion, project, exportKDoc, skipExpects, includeOnlyModuleContent, allowErrorTypes, produceHeaderKlib) {
private fun serializePackageFragment(fqName: FqName, module: ModuleDescriptor): List<ProtoBuf.PackageFragment> { private fun serializePackageFragment(fqName: FqName, module: ModuleDescriptor): List<ProtoBuf.PackageFragment> {
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
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.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.serialization.ApproximatingStringTable import org.jetbrains.kotlin.serialization.ApproximatingStringTable
import org.jetbrains.kotlin.serialization.DescriptorSerializer import org.jetbrains.kotlin.serialization.DescriptorSerializer
@@ -36,7 +36,8 @@ abstract class KlibMetadataSerializer(
val exportKDoc: Boolean = false, val exportKDoc: Boolean = false,
val skipExpects: Boolean = false, val skipExpects: Boolean = false,
val includeOnlyModuleContent: Boolean = false, val includeOnlyModuleContent: Boolean = false,
private val allowErrorTypes: Boolean private val allowErrorTypes: Boolean,
val produceHeaderKlib: Boolean = false,
) { ) {
lateinit var serializerContext: SerializerContext lateinit var serializerContext: SerializerContext
@@ -54,7 +55,8 @@ abstract class KlibMetadataSerializer(
metadataVersion, metadataVersion,
ApproximatingStringTable(), ApproximatingStringTable(),
allowErrorTypes, allowErrorTypes,
exportKDoc exportKDoc,
produceHeaderKlib
) )
return SerializerContext( return SerializerContext(
extension, extension,
@@ -94,8 +96,8 @@ abstract class KlibMetadataSerializer(
// TODO: we filter out expects with present actuals. // TODO: we filter out expects with present actuals.
// This is done because deserialized member scope doesn't give us actuals // This is done because deserialized member scope doesn't give us actuals
// when it has a choice // when it has a choice
private fun List<DeclarationDescriptor>.filterOutExpectsWithActuals(): List<DeclarationDescriptor> { private fun Sequence<DeclarationDescriptor>.filterOutExpectsWithActuals(): Sequence<DeclarationDescriptor> {
val actualClassIds = this.filter{ !it.isExpectMember }.map { ClassId.topLevel(it.fqNameSafe) } val actualClassIds = this.filter { !it.isExpectMember }.map { ClassId.topLevel(it.fqNameSafe) }
return this.filterNot { return this.filterNot {
// TODO: this only filters classes for now. // TODO: this only filters classes for now.
// Need to do the same for functions etc // Need to do the same for functions etc
@@ -103,12 +105,20 @@ abstract class KlibMetadataSerializer(
} }
} }
protected fun List<DeclarationDescriptor>.filterOutExpects(): List<DeclarationDescriptor> = private fun Sequence<DeclarationDescriptor>.filterOutExpects(): Sequence<DeclarationDescriptor> =
if (skipExpects) if (skipExpects)
this.filterNot { it.isExpectMember && !it.isSerializableExpectClass } this.filterNot { it.isExpectMember && !it.isSerializableExpectClass }
else else
this.filterOutExpectsWithActuals() this.filterOutExpectsWithActuals()
private fun Sequence<DeclarationDescriptor>.filterPrivate(): Sequence<DeclarationDescriptor> =
if (produceHeaderKlib) {
// We keep all interfaces since publicly accessible classes can inherit from private interfaces.
this.filter {
it is ClassDescriptor && it.kind.isInterface || it is DeclarationDescriptorWithVisibility && it.effectiveVisibility().publicApi
}
} else this
private fun serializeClasses(packageName: FqName, private fun serializeClasses(packageName: FqName,
//builder: ProtoBuf.PackageFragment.Builder, //builder: ProtoBuf.PackageFragment.Builder,
descriptors: Collection<DeclarationDescriptor>): List<Pair<ProtoBuf.Class, Int>> { descriptors: Collection<DeclarationDescriptor>): List<Pair<ProtoBuf.Class, Int>> {
@@ -131,8 +141,8 @@ abstract class KlibMetadataSerializer(
allTopLevelDescriptors: List<DeclarationDescriptor> allTopLevelDescriptors: List<DeclarationDescriptor>
): List<ProtoBuf.PackageFragment> { ): List<ProtoBuf.PackageFragment> {
val classifierDescriptors = allClassifierDescriptors.filterOutExpects() val classifierDescriptors = allClassifierDescriptors.asSequence().filterOutExpects().filterPrivate().toList()
val topLevelDescriptors = allTopLevelDescriptors.filterOutExpects() val topLevelDescriptors = allTopLevelDescriptors.asSequence().filterOutExpects().filterPrivate().toList()
if (TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE == null && if (TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE == null &&
TOP_LEVEL_DECLARATION_COUNT_PER_FILE == null) { TOP_LEVEL_DECLARATION_COUNT_PER_FILE == null) {
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.backend.common.serialization.metadata package org.jetbrains.kotlin.backend.common.serialization.metadata
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
@@ -15,8 +14,10 @@ import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtPrimaryConstructor import org.jetbrains.kotlin.psi.KtPrimaryConstructor
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.serialization.DescriptorSerializer import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.serialization.DescriptorSerializer.Companion.sort
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
import org.jetbrains.kotlin.serialization.StringTableImpl import org.jetbrains.kotlin.serialization.StringTableImpl
import org.jetbrains.kotlin.serialization.deserialization.DYNAMIC_TYPE_DESERIALIZER_ID import org.jetbrains.kotlin.serialization.deserialization.DYNAMIC_TYPE_DESERIALIZER_ID
@@ -28,9 +29,22 @@ class KlibMetadataSerializerExtension(
override val metadataVersion: BinaryVersion, override val metadataVersion: BinaryVersion,
override val stringTable: StringTableImpl, override val stringTable: StringTableImpl,
private val allowErrorTypes: Boolean, private val allowErrorTypes: Boolean,
private val exportKDoc: Boolean private val exportKDoc: Boolean,
private val produceHeaderKlib: Boolean
) : KotlinSerializerExtensionBase(KlibMetadataSerializerProtocol) { ) : KotlinSerializerExtensionBase(KlibMetadataSerializerProtocol) {
override fun shouldUseTypeTable(): Boolean = true override fun shouldUseTypeTable(): Boolean = true
override val customClassMembersProducer: ClassMembersProducer?
get() = if (produceHeaderKlib)
object : ClassMembersProducer {
override fun getCallableMembers(classDescriptor: ClassDescriptor) =
sort(
DescriptorUtils.getAllDescriptors(classDescriptor.defaultType.memberScope)
.filterIsInstance<CallableMemberDescriptor>()
.filter { it.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
.filter { it.visibility.isPublicAPI }
)
}
else super.customClassMembersProducer
private fun descriptorFileId(descriptor: DeclarationDescriptorWithSource): Int? { private fun descriptorFileId(descriptor: DeclarationDescriptorWithSource): Int? {
val fileName = descriptor.source.containingFile.name ?: return null val fileName = descriptor.source.containingFile.name ?: return null
@@ -163,10 +163,15 @@ class DescriptorSerializer private constructor(
classDescriptor.inlineClassRepresentation?.let { inlineClassRepresentation -> classDescriptor.inlineClassRepresentation?.let { inlineClassRepresentation ->
builder.inlineClassUnderlyingPropertyName = getSimpleNameIndex(inlineClassRepresentation.underlyingPropertyName) builder.inlineClassUnderlyingPropertyName = getSimpleNameIndex(inlineClassRepresentation.underlyingPropertyName)
val property = callableMembers.single { // The underlying property might be missing from `callableMembers` if we are producing a header klib and
it is PropertyDescriptor && it.extensionReceiverParameter == null && it.name == inlineClassRepresentation.underlyingPropertyName // the inline class is a part of the public API but the underlying property is not.
} val property = callableMembers.singleOrNull { candidate ->
if (!property.visibility.isPublicAPI) { candidate is PropertyDescriptor
&& candidate.extensionReceiverParameter == null
&& candidate.name == inlineClassRepresentation.underlyingPropertyName
} ?: return@let
if (property.visibility.isPublicAPI) {
if (useTypeTable()) { if (useTypeTable()) {
builder.inlineClassUnderlyingTypeId = typeId(inlineClassRepresentation.underlyingType) builder.inlineClassUnderlyingTypeId = typeId(inlineClassRepresentation.underlyingType)
} else { } else {
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.backend.common.serialization.metadata.serializeKlibH
import org.jetbrains.kotlin.backend.konan.driver.PhaseContext import org.jetbrains.kotlin.backend.konan.driver.PhaseContext
import org.jetbrains.kotlin.backend.konan.driver.phases.Fir2IrOutput import org.jetbrains.kotlin.backend.konan.driver.phases.Fir2IrOutput
import org.jetbrains.kotlin.backend.konan.driver.phases.FirOutput import org.jetbrains.kotlin.backend.konan.driver.phases.FirOutput
import org.jetbrains.kotlin.backend.konan.driver.phases.FirSerializerInput
import org.jetbrains.kotlin.backend.konan.driver.phases.SerializerOutput import org.jetbrains.kotlin.backend.konan.driver.phases.SerializerOutput
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
@@ -34,11 +35,13 @@ internal fun PhaseContext.firSerializer(input: FirOutput): SerializerOutput? = w
else -> firSerializerBase(input.firResult, null) else -> firSerializerBase(input.firResult, null)
} }
internal fun PhaseContext.fir2IrSerializer(input: Fir2IrOutput) = firSerializerBase(input.firResult, input) internal fun PhaseContext.fir2IrSerializer(input: FirSerializerInput) =
firSerializerBase(input.firToIrOutput.firResult, input.firToIrOutput, produceHeaderKlib = input.produceHeaderKlib)
internal fun PhaseContext.firSerializerBase( internal fun PhaseContext.firSerializerBase(
firResult: FirResult, firResult: FirResult,
fir2IrInput: Fir2IrOutput?, fir2IrInput: Fir2IrOutput?,
produceHeaderKlib: Boolean = false,
): SerializerOutput { ): SerializerOutput {
val configuration = config.configuration val configuration = config.configuration
val sourceFiles = mutableListOf<KtSourceFile>() val sourceFiles = mutableListOf<KtSourceFile>()
@@ -71,6 +74,8 @@ internal fun PhaseContext.firSerializerBase(
moduleName = fir2IrInput?.irModuleFragment?.descriptor?.name?.asString() moduleName = fir2IrInput?.irModuleFragment?.descriptor?.name?.asString()
?: firResult.outputs.last().session.moduleData.name.asString(), ?: firResult.outputs.last().session.moduleData.name.asString(),
firFilesAndSessionsBySourceFile, firFilesAndSessionsBySourceFile,
bodiesOnlyForInlines = produceHeaderKlib,
skipPrivateApi = produceHeaderKlib,
) { firFile, session, scopeSession -> ) { firFile, session, scopeSession ->
serializeSingleFirFile( serializeSingleFirFile(
firFile, firFile,
@@ -87,6 +92,7 @@ internal fun PhaseContext.firSerializerBase(
additionalAnnotationsProvider = fir2IrInput?.components?.annotationsFromPluginRegistrar?.createMetadataAnnotationsProvider() additionalAnnotationsProvider = fir2IrInput?.components?.annotationsFromPluginRegistrar?.createMetadataAnnotationsProvider()
), ),
configuration.languageVersionSettings, configuration.languageVersionSettings,
produceHeaderKlib,
) )
} }
} }
@@ -102,14 +108,16 @@ class KotlinFileSerializedData(
} }
internal fun PhaseContext.serializeNativeModule( internal fun PhaseContext.serializeNativeModule(
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
messageLogger: IrMessageLogger, messageLogger: IrMessageLogger,
files: List<KtSourceFile>, files: List<KtSourceFile>,
dependencies: List<KonanLibrary>?, dependencies: List<KonanLibrary>?,
moduleFragment: IrModuleFragment?, moduleFragment: IrModuleFragment?,
moduleName: String, moduleName: String,
firFilesAndSessionsBySourceFile: Map<KtSourceFile, Triple<FirFile, FirSession, ScopeSession>>, firFilesAndSessionsBySourceFile: Map<KtSourceFile, Triple<FirFile, FirSession, ScopeSession>>,
serializeSingleFile: (FirFile, FirSession, ScopeSession) -> ProtoBuf.PackageFragment bodiesOnlyForInlines: Boolean = false,
skipPrivateApi: Boolean = false,
serializeSingleFile: (FirFile, FirSession, ScopeSession) -> ProtoBuf.PackageFragment
): SerializerOutput { ): SerializerOutput {
if (moduleFragment != null) { if (moduleFragment != null) {
assert(files.size == moduleFragment.files.size) assert(files.size == moduleFragment.files.size)
@@ -126,6 +134,8 @@ internal fun PhaseContext.serializeNativeModule(
normalizeAbsolutePaths = absolutePathNormalization, normalizeAbsolutePaths = absolutePathNormalization,
sourceBaseDirs = sourceBaseDirs, sourceBaseDirs = sourceBaseDirs,
languageVersionSettings = configuration.languageVersionSettings, languageVersionSettings = configuration.languageVersionSettings,
bodiesOnlyForInlines = bodiesOnlyForInlines,
skipPrivateApi = skipPrivateApi
).serializedIrModule(moduleFragment) ).serializedIrModule(moduleFragment)
} }
@@ -225,6 +225,8 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
internal val metadataKlib get() = configuration.get(KonanConfigKeys.METADATA_KLIB)!! internal val metadataKlib get() = configuration.get(KonanConfigKeys.METADATA_KLIB)!!
internal val headerKlibPath get() = configuration.get(KonanConfigKeys.HEADER_KLIB)
internal val produceStaticFramework get() = configuration.getBoolean(KonanConfigKeys.STATIC_FRAMEWORK) internal val produceStaticFramework get() = configuration.getBoolean(KonanConfigKeys.STATIC_FRAMEWORK)
internal val purgeUserLibs: Boolean internal val purgeUserLibs: Boolean
@@ -75,6 +75,8 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("provide manifest addend file") = CompilerConfigurationKey.create("provide manifest addend file")
val METADATA_KLIB: CompilerConfigurationKey<Boolean> val METADATA_KLIB: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("metadata klib") = CompilerConfigurationKey.create("metadata klib")
val HEADER_KLIB: CompilerConfigurationKey<String?>
= CompilerConfigurationKey.create("path to file where header klib should be produced")
val MODULE_NAME: CompilerConfigurationKey<String?> val MODULE_NAME: CompilerConfigurationKey<String?>
= CompilerConfigurationKey.create("module name") = CompilerConfigurationKey.create("module name")
val NATIVE_LIBRARY_FILES: CompilerConfigurationKey<List<String>> val NATIVE_LIBRARY_FILES: CompilerConfigurationKey<List<String>>
@@ -56,6 +56,7 @@ fun CompilerConfiguration.setupFromArguments(arguments: K2NativeCompilerArgument
(arguments.produce ?: "program").uppercase()) (arguments.produce ?: "program").uppercase())
put(PRODUCE, outputKind) put(PRODUCE, outputKind)
put(METADATA_KLIB, arguments.metadataKlib) put(METADATA_KLIB, arguments.metadataKlib)
putIfNotNull(HEADER_KLIB, arguments.headerKlibPath)
arguments.libraryVersion?.let { put(LIBRARY_VERSION, it) } arguments.libraryVersion?.let { put(LIBRARY_VERSION, it) }
@@ -108,8 +108,15 @@ internal class DynamicCompilerDriver : CompilerDriver() {
engine.runFirSerializer(frontendOutput) engine.runFirSerializer(frontendOutput)
} else { } else {
val fir2IrOutput = engine.runFir2Ir(frontendOutput) val fir2IrOutput = engine.runFir2Ir(frontendOutput)
val headerKlibPath = environment.configuration.get(KonanConfigKeys.HEADER_KLIB)
if (!headerKlibPath.isNullOrEmpty()) {
val headerKlib = engine.runFir2IrSerializer(FirSerializerInput(fir2IrOutput, produceHeaderKlib = true))
engine.writeKlib(headerKlib, headerKlibPath)
}
engine.runK2SpecialBackendChecks(fir2IrOutput) engine.runK2SpecialBackendChecks(fir2IrOutput)
engine.runFir2IrSerializer(fir2IrOutput) engine.runFir2IrSerializer(FirSerializerInput(fir2IrOutput))
} }
} }
@@ -124,6 +131,10 @@ internal class DynamicCompilerDriver : CompilerDriver() {
} else { } else {
engine.runPsiToIr(frontendOutput, isProducingLibrary = true) as PsiToIrOutput.ForKlib engine.runPsiToIr(frontendOutput, isProducingLibrary = true) as PsiToIrOutput.ForKlib
} }
if (!config.headerKlibPath.isNullOrEmpty()) {
val headerKlib = engine.runSerializer(frontendOutput.moduleDescriptor, psiToIrOutput, produceHeaderKlib = true)
engine.writeKlib(headerKlib, config.headerKlibPath)
}
return engine.runSerializer(frontendOutput.moduleDescriptor, psiToIrOutput) return engine.runSerializer(frontendOutput.moduleDescriptor, psiToIrOutput)
} }
@@ -10,6 +10,12 @@ import org.jetbrains.kotlin.backend.konan.driver.PhaseEngine
import org.jetbrains.kotlin.backend.konan.firSerializer import org.jetbrains.kotlin.backend.konan.firSerializer
import org.jetbrains.kotlin.backend.konan.fir2IrSerializer import org.jetbrains.kotlin.backend.konan.fir2IrSerializer
internal data class FirSerializerInput(
val firToIrOutput: Fir2IrOutput,
val produceHeaderKlib: Boolean = false,
)
internal val FirSerializerPhase = createSimpleNamedCompilerPhase<PhaseContext, FirOutput, SerializerOutput?>( internal val FirSerializerPhase = createSimpleNamedCompilerPhase<PhaseContext, FirOutput, SerializerOutput?>(
"FirSerializer", "Fir serializer", "FirSerializer", "Fir serializer",
outputIfNotEnabled = { _, _, _, _ -> SerializerOutput(null, null, null, listOf()) } outputIfNotEnabled = { _, _, _, _ -> SerializerOutput(null, null, null, listOf()) }
@@ -17,10 +23,10 @@ internal val FirSerializerPhase = createSimpleNamedCompilerPhase<PhaseContext, F
context.firSerializer(input) context.firSerializer(input)
} }
internal val Fir2IrSerializerPhase = createSimpleNamedCompilerPhase<PhaseContext, Fir2IrOutput, SerializerOutput>( internal val Fir2IrSerializerPhase = createSimpleNamedCompilerPhase<PhaseContext, FirSerializerInput, SerializerOutput>(
"Fir2IrSerializer", "Fir2Ir serializer", "Fir2IrSerializer", "Fir2Ir serializer",
outputIfNotEnabled = { _, _, _, _ -> SerializerOutput(null, null, null, listOf()) } outputIfNotEnabled = { _, _, _, _ -> SerializerOutput(null, null, null, listOf()) }
) { context: PhaseContext, input: Fir2IrOutput -> ) { context: PhaseContext, input: FirSerializerInput ->
context.fir2IrSerializer(input) context.fir2IrSerializer(input)
} }
@@ -31,7 +37,7 @@ internal fun <T : PhaseContext> PhaseEngine<T>.runFirSerializer(
} }
internal fun <T : PhaseContext> PhaseEngine<T>.runFir2IrSerializer( internal fun <T : PhaseContext> PhaseEngine<T>.runFir2IrSerializer(
fir2irOutput: Fir2IrOutput firSerializerInput: FirSerializerInput
): SerializerOutput { ): SerializerOutput {
return this.runPhase(Fir2IrSerializerPhase, fir2irOutput) return this.runPhase(Fir2IrSerializerPhase, firSerializerInput)
} }
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.library.SerializedMetadata
internal data class SerializerInput( internal data class SerializerInput(
val moduleDescriptor: ModuleDescriptor, val moduleDescriptor: ModuleDescriptor,
val psiToIrOutput: PsiToIrOutput.ForKlib?, val psiToIrOutput: PsiToIrOutput.ForKlib?,
val produceHeaderKlib: Boolean,
) )
data class SerializerOutput( data class SerializerOutput(
@@ -48,24 +49,27 @@ internal val SerializerPhase = createSimpleNamedCompilerPhase<PhaseContext, Seri
normalizeAbsolutePaths = normalizeAbsolutePaths, normalizeAbsolutePaths = normalizeAbsolutePaths,
sourceBaseDirs = relativePathBase, sourceBaseDirs = relativePathBase,
languageVersionSettings = config.languageVersionSettings, languageVersionSettings = config.languageVersionSettings,
bodiesOnlyForInlines = input.produceHeaderKlib,
skipPrivateApi = input.produceHeaderKlib,
).serializedIrModule(ir) ).serializedIrModule(ir)
} }
val serializer = KlibMetadataMonolithicSerializer( val serializer = KlibMetadataMonolithicSerializer(
config.configuration.languageVersionSettings, config.configuration.languageVersionSettings,
config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!, config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!,
config.project, config.project,
exportKDoc = context.shouldExportKDoc(), exportKDoc = context.shouldExportKDoc(),
!expectActualLinker, includeOnlyModuleContent = true) !expectActualLinker, includeOnlyModuleContent = true, produceHeaderKlib = input.produceHeaderKlib)
val serializedMetadata = serializer.serializeModule(input.moduleDescriptor) val serializedMetadata = serializer.serializeModule(input.moduleDescriptor)
val neededLibraries = config.librariesWithDependencies() val neededLibraries = config.librariesWithDependencies()
SerializerOutput(serializedMetadata, serializedIr, null, neededLibraries) SerializerOutput(serializedMetadata, serializedIr, null, neededLibraries)
} }
internal fun <T : PhaseContext> PhaseEngine<T>.runSerializer( internal fun <T : PhaseContext> PhaseEngine<T>.runSerializer(
moduleDescriptor: ModuleDescriptor, moduleDescriptor: ModuleDescriptor,
psiToIrResult: PsiToIrOutput.ForKlib?, psiToIrResult: PsiToIrOutput.ForKlib?,
produceHeaderKlib: Boolean = false,
): SerializerOutput { ): SerializerOutput {
val input = SerializerInput(moduleDescriptor, psiToIrResult) val input = SerializerInput(moduleDescriptor, psiToIrResult, produceHeaderKlib)
return this.runPhase(SerializerPhase, input) return this.runPhase(SerializerPhase, input)
} }
@@ -14,13 +14,19 @@ import org.jetbrains.kotlin.konan.library.impl.buildLibrary
import org.jetbrains.kotlin.library.KotlinAbiVersion import org.jetbrains.kotlin.library.KotlinAbiVersion
import org.jetbrains.kotlin.library.KotlinLibraryVersioning import org.jetbrains.kotlin.library.KotlinLibraryVersioning
import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion
import org.jetbrains.kotlin.util.removeSuffixIfPresent
internal val WriteKlibPhase = createSimpleNamedCompilerPhase<PhaseContext, SerializerOutput>( internal data class KlibWriterInput(
val serializerOutput: SerializerOutput,
val customOutputPath: String?
)
internal val WriteKlibPhase = createSimpleNamedCompilerPhase<PhaseContext, KlibWriterInput>(
"WriteKlib", "Write klib output", "WriteKlib", "Write klib output",
) { context, input -> ) { context, input ->
val config = context.config val config = context.config
val configuration = config.configuration val configuration = config.configuration
val outputFiles = OutputFiles(config.outputPath, config.target, config.produce) val outputFiles = OutputFiles(input.customOutputPath?.removeSuffixIfPresent(".klib")
?: config.outputPath, config.target, config.produce)
val nopack = configuration.getBoolean(KonanConfigKeys.NOPACK) val nopack = configuration.getBoolean(KonanConfigKeys.NOPACK)
val output = outputFiles.klibOutputFileName(!nopack) val output = outputFiles.klibOutputFileName(!nopack)
val libraryName = config.moduleId val libraryName = config.moduleId
@@ -51,14 +57,14 @@ internal val WriteKlibPhase = createSimpleNamedCompilerPhase<PhaseContext, Seria
(e.g. commonized cinterops, host vs client environment differences). (e.g. commonized cinterops, host vs client environment differences).
*/ */
val linkDependencies = if (context.config.metadataKlib) emptyList() val linkDependencies = if (context.config.metadataKlib) emptyList()
else input.neededLibraries else input.serializerOutput.neededLibraries
buildLibrary( buildLibrary(
natives = config.nativeLibraries, natives = config.nativeLibraries,
included = config.includeBinaries, included = config.includeBinaries,
linkDependencies = linkDependencies, linkDependencies = linkDependencies,
metadata = input.serializedMetadata!!, metadata = input.serializerOutput.serializedMetadata!!,
ir = input.serializedIr, ir = input.serializerOutput.serializedIr,
versions = versions, versions = versions,
target = target, target = target,
output = output, output = output,
@@ -66,12 +72,13 @@ internal val WriteKlibPhase = createSimpleNamedCompilerPhase<PhaseContext, Seria
nopack = nopack, nopack = nopack,
shortName = shortLibraryName, shortName = shortLibraryName,
manifestProperties = manifestProperties, manifestProperties = manifestProperties,
dataFlowGraph = input.dataFlowGraph dataFlowGraph = input.serializerOutput.dataFlowGraph
) )
} }
internal fun <T : PhaseContext> PhaseEngine<T>.writeKlib( internal fun <T : PhaseContext> PhaseEngine<T>.writeKlib(
serializationOutput: SerializerOutput, serializationOutput: SerializerOutput,
customOutputPath: String? = null,
) { ) {
this.runPhase(WriteKlibPhase, serializationOutput) this.runPhase(WriteKlibPhase, KlibWriterInput(serializationOutput, customOutputPath))
} }
@@ -12,21 +12,23 @@ import org.jetbrains.kotlin.ir.util.IrMessageLogger
import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.ir.util.hasAnnotation
class KonanIrFileSerializer( class KonanIrFileSerializer(
messageLogger: IrMessageLogger, messageLogger: IrMessageLogger,
declarationTable: DeclarationTable, declarationTable: DeclarationTable,
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
bodiesOnlyForInlines: Boolean = false, bodiesOnlyForInlines: Boolean = false,
compatibilityMode: CompatibilityMode, compatibilityMode: CompatibilityMode,
normalizeAbsolutePaths: Boolean, normalizeAbsolutePaths: Boolean,
sourceBaseDirs: Collection<String> sourceBaseDirs: Collection<String>,
skipPrivateApi: Boolean = false,
) : IrFileSerializer( ) : IrFileSerializer(
messageLogger = messageLogger, messageLogger,
declarationTable = declarationTable, declarationTable,
compatibilityMode = compatibilityMode, compatibilityMode,
languageVersionSettings = languageVersionSettings, languageVersionSettings,
bodiesOnlyForInlines = bodiesOnlyForInlines, skipPrivateApi = skipPrivateApi,
normalizeAbsolutePaths = normalizeAbsolutePaths, bodiesOnlyForInlines = bodiesOnlyForInlines,
sourceBaseDirs = sourceBaseDirs normalizeAbsolutePaths = normalizeAbsolutePaths,
sourceBaseDirs = sourceBaseDirs
) { ) {
override fun backendSpecificExplicitRoot(node: IrAnnotationContainer): Boolean { override fun backendSpecificExplicitRoot(node: IrAnnotationContainer): Boolean {
@@ -15,6 +15,8 @@ class KonanIrModuleSerializer(
normalizeAbsolutePaths: Boolean, normalizeAbsolutePaths: Boolean,
sourceBaseDirs: Collection<String>, sourceBaseDirs: Collection<String>,
private val languageVersionSettings: LanguageVersionSettings, private val languageVersionSettings: LanguageVersionSettings,
private val bodiesOnlyForInlines: Boolean = false,
private val skipPrivateApi: Boolean = false,
) : IrModuleSerializer<KonanIrFileSerializer>(messageLogger, compatibilityMode, normalizeAbsolutePaths, sourceBaseDirs) { ) : IrModuleSerializer<KonanIrFileSerializer>(messageLogger, compatibilityMode, normalizeAbsolutePaths, sourceBaseDirs) {
private val globalDeclarationTable = KonanGlobalDeclarationTable(irBuiltIns) private val globalDeclarationTable = KonanGlobalDeclarationTable(irBuiltIns)
@@ -33,5 +35,7 @@ class KonanIrModuleSerializer(
compatibilityMode = compatibilityMode, compatibilityMode = compatibilityMode,
normalizeAbsolutePaths = normalizeAbsolutePaths, normalizeAbsolutePaths = normalizeAbsolutePaths,
sourceBaseDirs = sourceBaseDirs, sourceBaseDirs = sourceBaseDirs,
languageVersionSettings = languageVersionSettings) languageVersionSettings = languageVersionSettings,
bodiesOnlyForInlines = bodiesOnlyForInlines,
skipPrivateApi = skipPrivateApi)
} }
@@ -0,0 +1,7 @@
package test
private val x = object { fun f() = 1 }
fun g() =
x.f() +
object { fun f() = 0 }.f()
@@ -0,0 +1,3 @@
package test
fun g() = 1
@@ -0,0 +1,3 @@
package test
class Class
@@ -0,0 +1,3 @@
package test
open class Class
@@ -0,0 +1,18 @@
package test
class A {
val publicVal = 0
fun publicMethod() = 0
internal val internalVal = 0
internal fun internalMethod() = 0
protected val protectedVal = 0
protected fun protectedMethod() = 0
private val privateVal = 0
private fun privateMethod() = 0
val publicValBody = internalMethod() + privateMethod() + 2
val publicMethodBody = publicValBody + 2
}
@@ -0,0 +1,15 @@
package test
class A {
val publicVal = 0
fun publicMethod() = 0
internal val internalVal = 42
internal fun internalMethod() = 42
protected val protectedVal = 0
protected fun protectedMethod() = 0
val publicValBody = internalMethod() + 1
val publicMethodBody = publicValBody + 1
}
@@ -0,0 +1,3 @@
package test
const val x = 0
@@ -0,0 +1,3 @@
package test
const val x = 1
@@ -0,0 +1,4 @@
package test
inline fun f() = 1
inline fun g() = 2
@@ -0,0 +1,7 @@
package test
inline fun g() = 2
inline fun f() = 1
// This changes the line numbers in f, g
@@ -0,0 +1,10 @@
package test
fun sum(x: Int, y: Int): Int =
try {
var result = x
result += y
result
} finally {
// do nothing
}
@@ -0,0 +1,3 @@
package test
fun sum(x: Int, y: Int): Int = y + x
@@ -0,0 +1,9 @@
private class A {
inline fun test(crossinline s: () -> Unit) {
object {
fun run() {
s()
}
}.run()
}
}
@@ -0,0 +1,9 @@
private class A {
inline fun test(crossinline s: () -> Unit) {
object {
fun run() {
//s()
}
}.run()
}
}
@@ -0,0 +1,11 @@
class A {
private class B {
inline fun test(crossinline s: () -> Unit) {
object {
fun run() {
s()
}
}.run()
}
}
}
@@ -0,0 +1,11 @@
class A {
private class B {
inline fun test(crossinline s: () -> Unit) {
object {
fun run() {
//s()
}
}.run()
}
}
}
@@ -0,0 +1,3 @@
package test
inline fun sum(x: Int, y: Int): Int = x + y
@@ -0,0 +1,3 @@
package test
inline fun sum(x: Int, y: Int): Int = y + x
@@ -0,0 +1,4 @@
package test
private inline fun f() = { 1 }()
fun g() = f()
@@ -0,0 +1,3 @@
package test
fun g() = 1
@@ -0,0 +1,3 @@
package test
fun id(x: Int): Int = x
@@ -0,0 +1,3 @@
package test
fun id(y: Int): Int = y
@@ -0,0 +1,10 @@
package test
private interface A {
fun foo() = 0
fun bar(): String
}
class B: A {
override fun bar() = "test${foo()}"
}
@@ -0,0 +1,10 @@
package test
private interface A {
fun foo() = 42
fun bar(): String
}
class B: A {
override fun bar() = "test${foo()}"
}
@@ -0,0 +1,13 @@
package test
class PublicClass1
class PublicClass2
typealias PublicTypeAlias1 = PublicClass1
typealias PublicTypeAlias2 = PublicClass1
internal typealias InternalTypeAlias1 = PublicClass1
internal typealias InternalTypeAlias2 = PublicClass1
private typealias PrivateTypeAlias1 = PublicClass1
private typealias PrivateTypeAlias2 = PublicClass1
@@ -0,0 +1,12 @@
package test
class PublicClass1
class PublicClass2
typealias PublicTypeAlias1 = PublicClass1
typealias PublicTypeAlias2 = PublicClass1
internal typealias InternalTypeAlias1 = PublicClass1
internal typealias InternalTypeAlias2 = PublicClass1
private typealias PrivateTypeAlias1 = PublicClass2
@@ -0,0 +1,3 @@
package test
fun foo() = 0
@@ -0,0 +1,3 @@
package test
fun foo() = "0"
@@ -0,0 +1,4 @@
package test
open class A
class B : A()
@@ -0,0 +1,4 @@
package test
open class A
class B
@@ -0,0 +1,7 @@
package test
private val x = 1
object A { fun f() = x }
val y = 2
@@ -0,0 +1,5 @@
package test
object A { fun f() = 1 }
val y = 2
@@ -0,0 +1,13 @@
package test
val publicVal = 0
const val publicConst = 0
fun publicFun() = 0
internal val internalVal = 0
internal const val internalConst = 0
internal fun internalFun() = 0
private val privateVal = 0
private const val privateConst = 0
private fun privateFun() = 0
@@ -0,0 +1,9 @@
package test
val publicVal = 0
const val publicConst = 0
fun publicFun() = 0
internal val internalVal = 0
internal const val internalConst = 0
internal fun internalFun() = 0
@@ -0,0 +1,10 @@
package lib
interface Interface {
fun getInt(): Int
}
fun getInterface(): Interface =
object : Interface {
override fun getInt(): Int = 10
}
@@ -0,0 +1,11 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
val i = getInterface()
val value = i.getInt()
if (value != 10) error("getInterface().getInt() is '$value', but is expected to be '10'")
return "OK"
}
@@ -0,0 +1,31 @@
package lib
interface I {
val iProperty: Int
fun iMethod(): Int
}
open class A : I {
override val iProperty: Int = 0
override fun iMethod(): Int = 10
val aProperty: Int = 20
fun aMethod(): Int = 30
inline fun aInlineMethod(): Int = 40
private class AB {}
companion object {
const val aConst: Int = 50
}
}
class B : A() {
val bProperty: Int = 60
fun bMethod(): Int = 70
inline fun bInlineMethod(): Int = 80
companion object {
const val bConst: Int = 90
}
}
@@ -0,0 +1,40 @@
package app
import lib.*
fun useI(i: I) {
i.iProperty
i.iMethod()
}
fun useA(a: A) {
a.iProperty
a.iMethod()
a.aProperty
a.aMethod()
a.aInlineMethod()
A.aConst
}
fun useB(b: B) {
b.iProperty
b.iMethod()
b.aProperty
b.aMethod()
b.aInlineMethod()
b.bProperty
b.bMethod()
b.bInlineMethod()
B.bConst
}
fun runAppAndReturnOk(): String {
useI(A())
useA(A())
useB(B())
return "OK"
}
@@ -0,0 +1,7 @@
package lib
object Object {
val x = 1
val y = 2
val z = x + y
}
@@ -0,0 +1,5 @@
package lib
val x = 1
val y = 2
val z = x + y
@@ -0,0 +1,10 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
if (Object.z != 3) error("lib.Object.z is ${Object.z}, but '3' was expected")
if (z != 3) error("lib.z is $z, but '3' was expected")
return "OK"
}
@@ -0,0 +1,5 @@
package lib
annotation class A(val value: String)
inline fun a() = A("OK")
@@ -0,0 +1,7 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
return a().value
}
@@ -0,0 +1,11 @@
package lib
interface Interface {
fun getInt(): Int
}
inline fun getCounter(crossinline init: () -> Int): Interface =
object : Interface {
var value = init()
override fun getInt(): Int = value++
}
@@ -0,0 +1,13 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
val a = lib.getCounter { 100 }
val x = a.getInt()
if (x != 100) error("a returned $x but expected '100'")
val y = a.getInt()
if (y != 101) error("a returned $y but expected '101'")
return "OK"
}
@@ -0,0 +1,10 @@
package lib
fun inlineCapture(s: String): String {
return with(StringBuilder()) {
val o = object {
override fun toString() = s
}
append(o)
}.toString()
}
@@ -0,0 +1,7 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
return inlineCapture("OK")
}
@@ -0,0 +1,19 @@
package lib
var result = "fail"
inline fun foo(crossinline s: () -> String) {
object {
private inline fun test(crossinline z: () -> String) {
result = object { //should be marked as public abi as there is no regenerated abject on inline
fun run(): String {
return "O"
}
}.run() + z()
}
fun foo() {
test { s() }
}
}.foo()
}
@@ -0,0 +1,10 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
foo {
"K"
}
return result
}
@@ -0,0 +1,4 @@
package lib
inline fun <reified T> safeCall(x: Any?, fn: (T) -> T): T? =
if (x is T) fn(x) else null
@@ -0,0 +1,13 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
val a = safeCall<Int>(10) { it * it }
if (a != 100) error("a is '$a', but is expected to be '100'")
val b = safeCall<Int>(null) { it * it }
if (b != null) error("b is '$b', but is expected to be 'null'")
return "OK"
}
@@ -0,0 +1,10 @@
package lib
enum class E {
A, B
}
inline fun value(x: E) = when (x) {
E.A -> "OK"
E.B -> "Fail"
}
@@ -0,0 +1,5 @@
package app
import lib.*
fun runAppAndReturnOk(): String = value(E.A)
@@ -0,0 +1,19 @@
package lib
var result = "fail"
inline fun foo(crossinline s: () -> String) {
object {
private inline fun test(crossinline z: () -> String) {
object {
fun run() {
result = z()
}
}.run()
}
fun foo() {
test { s() } // regenerated object should be marked as public abi
}
}.foo()
}
@@ -0,0 +1,10 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
foo {
"OK"
}
return result
}
@@ -0,0 +1,11 @@
package lib
inline fun anInlineFunction(crossinline crossInlineLamba: () -> Unit) {
Foo().apply {
barMethod { crossInlineLamba() }
}
}
class Foo {
fun barMethod(aLambda: () -> Unit) { aLambda() }
}
@@ -0,0 +1,9 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
var result = "Fail"
anInlineFunction { result = "OK" }
return result
}
@@ -0,0 +1,7 @@
package lib
class A private constructor(val x: Int) {
companion object {
fun create(x: Int): A = A(x * 2)
}
}
@@ -0,0 +1,10 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
val a = A.create(10)
if (a.x != 20) error("a.x is '${a.x}', but is expected to be '20'")
return "OK"
}
@@ -0,0 +1,6 @@
package lib
value class A private constructor(val value: String) {
companion object { fun a() = A("OK") }
inline fun b() = value
}
@@ -0,0 +1,7 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
return A.a().b()
}
@@ -0,0 +1,6 @@
package lib
val prop: Int = 1
fun func(): Int = 2
inline fun inlineFunc(): Int = 3
const val constant: Int = 4
@@ -0,0 +1,14 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
if (prop != 1) error("prop is '$prop', but is expected to be '1'")
val funcValue = func()
if (funcValue != 2) error("func() is '$funcValue', but is expected to be '2'")
val inlineFuncValue = inlineFunc()
if (inlineFuncValue != 3) error("inlineFunc() is '$inlineFuncValue', but is expected to be '3'")
if (constant != 4) error("constant is '$constant', but is expected to be '4'")
return "OK"
}
@@ -0,0 +1,132 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.konan.blackboxtest;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.junit.jupiter.api.Tag;
import org.jetbrains.kotlin.konan.blackboxtest.support.group.FirPipeline;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("native/native.tests/testData/klib/header-klibs/comparison")
@TestDataPath("$PROJECT_ROOT")
@Tag("frontend-fir")
@FirPipeline()
public class FirNativeHeaderKlibComparisonTestGenerated extends AbstractNativeHeaderKlibComparisonTest {
@Test
public void testAllFilesPresentInComparison() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/klib/header-klibs/comparison"), Pattern.compile("^([^\\.]+)$"), null, false);
}
@Test
@TestMetadata("anonymousObjects")
public void testAnonymousObjects() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/anonymousObjects/");
}
@Test
@TestMetadata("classFlags")
public void testClassFlags() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/classFlags/");
}
@Test
@TestMetadata("classPrivateMembers")
public void testClassPrivateMembers() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/classPrivateMembers/");
}
@Test
@TestMetadata("constant")
public void testConstant() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/constant/");
}
@Test
@TestMetadata("declarationOrderInline")
public void testDeclarationOrderInline() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/declarationOrderInline/");
}
@Test
@TestMetadata("functionBody")
public void testFunctionBody() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/functionBody/");
}
@Test
@TestMetadata("inlineFunInPrivateClass")
public void testInlineFunInPrivateClass() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateClass/");
}
@Test
@TestMetadata("inlineFunInPrivateNestedClass")
public void testInlineFunInPrivateNestedClass() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateNestedClass/");
}
@Test
@TestMetadata("inlineFunctionBody")
public void testInlineFunctionBody() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/inlineFunctionBody/");
}
@Test
@TestMetadata("lambdas")
public void testLambdas() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/lambdas/");
}
@Test
@TestMetadata("parameterName")
public void testParameterName() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/parameterName/");
}
@Test
@TestMetadata("privateInterface")
public void testPrivateInterface() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/privateInterface/");
}
@Test
@TestMetadata("privateTypealias")
public void testPrivateTypealias() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/privateTypealias/");
}
@Test
@TestMetadata("returnType")
public void testReturnType() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/returnType/");
}
@Test
@TestMetadata("superClass")
public void testSuperClass() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/superClass/");
}
@Test
@TestMetadata("syntheticAccessors")
public void testSyntheticAccessors() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/syntheticAccessors/");
}
@Test
@TestMetadata("topLevelPrivateMembers")
public void testTopLevelPrivateMembers() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/topLevelPrivateMembers/");
}
}
@@ -0,0 +1,114 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.konan.blackboxtest;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.junit.jupiter.api.Tag;
import org.jetbrains.kotlin.konan.blackboxtest.support.group.FirPipeline;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("native/native.tests/testData/klib/header-klibs/compilation")
@TestDataPath("$PROJECT_ROOT")
@Tag("frontend-fir")
@FirPipeline()
public class FirNativeHeaderKlibCompilationTestGenerated extends AbstractNativeHeaderKlibCompilationTest {
@Test
public void testAllFilesPresentInCompilation() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/klib/header-klibs/compilation"), Pattern.compile("^([^\\.]+)$"), null, false);
}
@Test
@TestMetadata("anonymousObject")
public void testAnonymousObject() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/anonymousObject/");
}
@Test
@TestMetadata("classes")
public void testClasses() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/classes/");
}
@Test
@TestMetadata("clinit")
public void testClinit() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/clinit/");
}
@Test
@TestMetadata("inlineAnnotationInstantiation")
public void testInlineAnnotationInstantiation() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineAnnotationInstantiation/");
}
@Test
@TestMetadata("inlineAnonymousObject")
public void testInlineAnonymousObject() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineAnonymousObject/");
}
@Test
@TestMetadata("inlineCapture")
public void testInlineCapture() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineCapture/");
}
@Test
@TestMetadata("inlineNoRegeneration")
public void testInlineNoRegeneration() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineNoRegeneration/");
}
@Test
@TestMetadata("inlineReifiedFunction")
public void testInlineReifiedFunction() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineReifiedFunction/");
}
@Test
@TestMetadata("inlineWhenMappings")
public void testInlineWhenMappings() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineWhenMappings/");
}
@Test
@TestMetadata("innerObjectRegeneration")
public void testInnerObjectRegeneration() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/innerObjectRegeneration/");
}
@Test
@TestMetadata("kt-40133")
public void testKt_40133() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/kt-40133/");
}
@Test
@TestMetadata("privateOnlyConstructors")
public void testPrivateOnlyConstructors() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/privateOnlyConstructors/");
}
@Test
@TestMetadata("privateValueClassConstructor")
public void testPrivateValueClassConstructor() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/privateValueClassConstructor/");
}
@Test
@TestMetadata("topLevel")
public void testTopLevel() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/topLevel/");
}
}
@@ -0,0 +1,128 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.konan.blackboxtest;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("native/native.tests/testData/klib/header-klibs/comparison")
@TestDataPath("$PROJECT_ROOT")
public class NativeHeaderKlibComparisonTestGenerated extends AbstractNativeHeaderKlibComparisonTest {
@Test
public void testAllFilesPresentInComparison() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/klib/header-klibs/comparison"), Pattern.compile("^([^\\.]+)$"), null, false);
}
@Test
@TestMetadata("anonymousObjects")
public void testAnonymousObjects() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/anonymousObjects/");
}
@Test
@TestMetadata("classFlags")
public void testClassFlags() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/classFlags/");
}
@Test
@TestMetadata("classPrivateMembers")
public void testClassPrivateMembers() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/classPrivateMembers/");
}
@Test
@TestMetadata("constant")
public void testConstant() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/constant/");
}
@Test
@TestMetadata("declarationOrderInline")
public void testDeclarationOrderInline() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/declarationOrderInline/");
}
@Test
@TestMetadata("functionBody")
public void testFunctionBody() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/functionBody/");
}
@Test
@TestMetadata("inlineFunInPrivateClass")
public void testInlineFunInPrivateClass() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateClass/");
}
@Test
@TestMetadata("inlineFunInPrivateNestedClass")
public void testInlineFunInPrivateNestedClass() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateNestedClass/");
}
@Test
@TestMetadata("inlineFunctionBody")
public void testInlineFunctionBody() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/inlineFunctionBody/");
}
@Test
@TestMetadata("lambdas")
public void testLambdas() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/lambdas/");
}
@Test
@TestMetadata("parameterName")
public void testParameterName() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/parameterName/");
}
@Test
@TestMetadata("privateInterface")
public void testPrivateInterface() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/privateInterface/");
}
@Test
@TestMetadata("privateTypealias")
public void testPrivateTypealias() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/privateTypealias/");
}
@Test
@TestMetadata("returnType")
public void testReturnType() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/returnType/");
}
@Test
@TestMetadata("superClass")
public void testSuperClass() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/superClass/");
}
@Test
@TestMetadata("syntheticAccessors")
public void testSyntheticAccessors() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/syntheticAccessors/");
}
@Test
@TestMetadata("topLevelPrivateMembers")
public void testTopLevelPrivateMembers() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/comparison/topLevelPrivateMembers/");
}
}
@@ -0,0 +1,110 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.konan.blackboxtest;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("native/native.tests/testData/klib/header-klibs/compilation")
@TestDataPath("$PROJECT_ROOT")
public class NativeHeaderKlibCompilationTestGenerated extends AbstractNativeHeaderKlibCompilationTest {
@Test
public void testAllFilesPresentInCompilation() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/klib/header-klibs/compilation"), Pattern.compile("^([^\\.]+)$"), null, false);
}
@Test
@TestMetadata("anonymousObject")
public void testAnonymousObject() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/anonymousObject/");
}
@Test
@TestMetadata("classes")
public void testClasses() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/classes/");
}
@Test
@TestMetadata("clinit")
public void testClinit() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/clinit/");
}
@Test
@TestMetadata("inlineAnnotationInstantiation")
public void testInlineAnnotationInstantiation() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineAnnotationInstantiation/");
}
@Test
@TestMetadata("inlineAnonymousObject")
public void testInlineAnonymousObject() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineAnonymousObject/");
}
@Test
@TestMetadata("inlineCapture")
public void testInlineCapture() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineCapture/");
}
@Test
@TestMetadata("inlineNoRegeneration")
public void testInlineNoRegeneration() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineNoRegeneration/");
}
@Test
@TestMetadata("inlineReifiedFunction")
public void testInlineReifiedFunction() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineReifiedFunction/");
}
@Test
@TestMetadata("inlineWhenMappings")
public void testInlineWhenMappings() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/inlineWhenMappings/");
}
@Test
@TestMetadata("innerObjectRegeneration")
public void testInnerObjectRegeneration() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/innerObjectRegeneration/");
}
@Test
@TestMetadata("kt-40133")
public void testKt_40133() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/kt-40133/");
}
@Test
@TestMetadata("privateOnlyConstructors")
public void testPrivateOnlyConstructors() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/privateOnlyConstructors/");
}
@Test
@TestMetadata("privateValueClassConstructor")
public void testPrivateValueClassConstructor() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/privateValueClassConstructor/");
}
@Test
@TestMetadata("topLevel")
public void testTopLevel() throws Exception {
runTest("native/native.tests/testData/klib/header-klibs/compilation/topLevel/");
}
}
@@ -314,6 +314,36 @@ fun main() {
} }
} }
} }
// Header klib comparison tests
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
testClass<AbstractNativeHeaderKlibComparisonTest>(
suiteTestClassName = "NativeHeaderKlibComparisonTestGenerated",
) {
model("klib/header-klibs/comparison", extension = null, recursive = false)
}
testClass<AbstractNativeHeaderKlibComparisonTest>(
suiteTestClassName = "FirNativeHeaderKlibComparisonTestGenerated",
annotations = listOf(*frontendFir()),
) {
model("klib/header-klibs/comparison", extension = null, recursive = false)
}
}
// Header klib compilation tests
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
testClass<AbstractNativeHeaderKlibCompilationTest>(
suiteTestClassName = "NativeHeaderKlibCompilationTestGenerated",
) {
model("klib/header-klibs/compilation", extension = null, recursive = false)
}
testClass<AbstractNativeHeaderKlibCompilationTest>(
suiteTestClassName = "FirNativeHeaderKlibCompilationTestGenerated",
annotations = listOf(*frontendFir()),
) {
model("klib/header-klibs/compilation", extension = null, recursive = false)
}
}
} }
} }
@@ -0,0 +1,103 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.konan.blackboxtest
import com.intellij.testFramework.TestDataFile
import org.jetbrains.kotlin.konan.blackboxtest.support.*
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess
import org.jetbrains.kotlin.konan.blackboxtest.support.group.UsePartialLinkage
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.TestRunChecks
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Timeouts
import org.jetbrains.kotlin.konan.blackboxtest.support.util.getAbsoluteFile
import org.junit.jupiter.api.Tag
import java.io.File
import kotlin.test.assertContentEquals
import kotlin.test.assertFailsWith
@Tag("klib")
@UsePartialLinkage(UsePartialLinkage.Mode.ENABLED_WITH_ERROR)
abstract class AbstractNativeHeaderKlibComparisonTest : AbstractNativeSimpleTest() {
protected fun runTest(@TestDataFile testPath: String) {
val testPathFull = getAbsoluteFile(testPath)
val testCaseBase: TestCase = generateTestcaseFromDirectory(testPathFull, "base", listOf())
compileToLibrary(testCaseBase).assertSuccess()
val headerKlibBase = File(getHeaderPath("base"))
assert(headerKlibBase.exists())
val sameAbiDir = testPathFull.resolve("sameAbi")
val differentAbiDir = testPathFull.resolve("differentAbi")
assert(sameAbiDir.exists() || differentAbiDir.exists()) { "Nothing to compare" }
if (sameAbiDir.exists()) {
val testCaseSameAbi: TestCase = generateTestcaseFromDirectory(testPathFull, "sameAbi", listOf())
compileToLibrary(testCaseSameAbi).assertSuccess()
val headerKlibSameAbi = File(getHeaderPath("sameAbi"))
assert(headerKlibSameAbi.exists())
assertContentEquals(headerKlibBase.readBytes(), headerKlibSameAbi.readBytes())
}
if (differentAbiDir.exists()) {
val testCaseDifferentAbi: TestCase = generateTestcaseFromDirectory(testPathFull, "differentAbi", listOf())
compileToLibrary(testCaseDifferentAbi).assertSuccess()
val headerKlibDifferentAbi = File(getHeaderPath("differentAbi"))
assert(headerKlibDifferentAbi.exists())
assertFailsWith<AssertionError>("base and differentAbi header klib are equal") {
assertContentEquals(headerKlibBase.readBytes(), headerKlibDifferentAbi.readBytes())
}
}
}
}
@Tag("klib")
@UsePartialLinkage(UsePartialLinkage.Mode.ENABLED_WITH_ERROR)
abstract class AbstractNativeHeaderKlibCompilationTest : AbstractNativeSimpleTest() {
protected fun runTest(@TestDataFile testPath: String) {
val testPathFull = getAbsoluteFile(testPath)
assert(testPathFull.exists())
val testCaseLib: TestCase = generateTestcaseFromDirectory(testPathFull, "lib", listOf())
val klibLib = compileToLibrary(testCaseLib)
val headerKlibLib = File(getHeaderPath("lib"))
assert(headerKlibLib.exists())
val testPathApp = testPathFull.resolve("main")
val klibAppFromHeader = compileToLibrary(testPathApp, TestCompilationArtifact.KLIB(headerKlibLib))
val klibAppFromFull = compileToLibrary(testPathApp, klibLib.resultingArtifact)
assertContentEquals(
klibAppFromHeader.klibFile.readBytes(),
klibAppFromFull.klibFile.readBytes()
)
}
}
private fun AbstractNativeSimpleTest.getHeaderPath(rev: String) = buildDir.absolutePath + "/header.$rev.klib"
private fun AbstractNativeSimpleTest.generateTestcaseFromDirectory(source: File, rev: String, extraArgs: List<String>): TestCase {
val moduleName: String = source.name
val module = TestModule.Exclusive(moduleName, emptySet(), emptySet(), emptySet())
source.resolve(rev).listFiles()?.forEach {
muteTestIfNecessary(it)
module.files += TestFile.createCommitted(it, module)
}
val headerKlibPath = "-Xheader-klib-path=" + getHeaderPath(rev)
val relativeBasePath = "-Xklib-relative-path-base=$source/$rev"
return TestCase(
id = TestCaseId.Named(moduleName),
kind = TestKind.STANDALONE,
modules = setOf(module),
freeCompilerArgs = TestCompilerArgs(extraArgs + relativeBasePath + headerKlibPath),
nominalPackageName = PackageName.EMPTY,
checks = TestRunChecks.Default(testRunSettings.get<Timeouts>().executionTimeout),
extras = TestCase.WithTestRunnerExtras(TestRunnerType.DEFAULT)
).apply {
initialize(null, null)
}
}