diff --git a/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArgumentsCopyGenerated.kt b/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArgumentsCopyGenerated.kt index 7bbacf119a7..e5aa6d4d64d 100644 --- a/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArgumentsCopyGenerated.kt +++ b/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArgumentsCopyGenerated.kt @@ -45,6 +45,7 @@ fun copyK2NativeCompilerArguments(from: K2NativeCompilerArguments, to: K2NativeC to.generateNoExitTestRunner = from.generateNoExitTestRunner to.generateTestRunner = from.generateTestRunner to.generateWorkerTestRunner = from.generateWorkerTestRunner + to.headerKlibPath = from.headerKlibPath to.includeBinaries = from.includeBinaries?.copyOf() to.includes = from.includes?.copyOf() to.incrementalCacheDir = from.incrementalCacheDir @@ -104,4 +105,4 @@ fun copyK2NativeCompilerArguments(from: K2NativeCompilerArguments, to: K2NativeC to.workerExceptionHandling = from.workerExceptionHandling return to -} +} \ No newline at end of file diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt index 6c3f5f3a376..e52bc25caa7 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt @@ -372,6 +372,12 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { @Argument(value = "-Xmetadata-klib", description = "Produce a klib that only contains the declarations metadata") 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 = "", description = "Remap file source directory paths in debug info") var debugPrefixMap: Array? = null diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataKlibSerializer.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataKlibSerializer.kt index 956c0920518..1c0e7185e45 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataKlibSerializer.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataKlibSerializer.kt @@ -58,7 +58,8 @@ internal class K2MetadataKlibSerializer( project, exportKDoc = false, skipExpects = false, - includeOnlyModuleContent = true + includeOnlyModuleContent = true, + produceHeaderKlib = false, ).serializeModule(module) buildKotlinMetadataLibrary(configuration, serializedMetadata, destDir) diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt index 76353fa3371..d649992c4a0 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt @@ -74,6 +74,7 @@ class FirElementSerializer private constructor( private val serializeTypeTableToFunction: Boolean, private val typeApproximator: AbstractTypeApproximator, private val languageVersionSettings: LanguageVersionSettings, + private val produceHeaderKlib: Boolean, ) { private val contractSerializer = FirContractSerializer() private val providedDeclarationsService = session.providedDeclarationsForMetadataService @@ -89,7 +90,8 @@ class FirElementSerializer private constructor( fun addDeclaration(declaration: FirDeclaration, onUnsupportedDeclaration: (FirDeclaration) -> Unit) { if (declaration is FirMemberDeclaration) { - if (!declaration.shouldBeSerialized(actualizedExpectDeclarations)) return + if (!declaration.isNotExpectOrShouldBeSerialized(actualizedExpectDeclarations)) return + if (!declaration.isNotPrivateOrShouldBeSerialized(produceHeaderKlib)) return when (declaration) { is FirProperty -> propertyProto(declaration)?.let { builder.addProperty(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) { for (constructor in regularClass.constructors()) { + if (!constructor.isNotPrivateOrShouldBeSerialized(produceHeaderKlib)) continue builder.addConstructor(constructorProto(constructor)) } @@ -203,6 +206,7 @@ class FirElementSerializer private constructor( for (declaration in callableMembers) { if (declaration !is FirEnumEntry && declaration.isStatic) continue // ??? Miss values() & valueOf() + if (!declaration.isNotPrivateOrShouldBeSerialized(produceHeaderKlib)) continue when (declaration) { is FirProperty -> propertyProto(declaration)?.let { builder.addProperty(it) } is FirSimpleFunction -> functionProto(declaration)?.let { builder.addFunction(it) } @@ -1042,7 +1046,7 @@ class FirElementSerializer private constructor( FirElementSerializer( session, scopeSession, declaration, Interner(typeParameters), extension, typeTable, versionRequirementTable, serializeTypeTableToFunction = false, - typeApproximator, languageVersionSettings + typeApproximator, languageVersionSettings, produceHeaderKlib ) val stringTable: FirElementAwareStringTable @@ -1148,6 +1152,7 @@ class FirElementSerializer private constructor( extension: FirSerializerExtension, typeApproximator: AbstractTypeApproximator, languageVersionSettings: LanguageVersionSettings, + produceHeaderKlib: Boolean = false, ): FirElementSerializer = FirElementSerializer( session, scopeSession, null, @@ -1155,6 +1160,7 @@ class FirElementSerializer private constructor( serializeTypeTableToFunction = false, typeApproximator, languageVersionSettings, + produceHeaderKlib, ) @JvmStatic @@ -1171,6 +1177,7 @@ class FirElementSerializer private constructor( versionRequirementTable = null, serializeTypeTableToFunction = true, typeApproximator, languageVersionSettings, + produceHeaderKlib = false, ) @JvmStatic @@ -1182,16 +1189,17 @@ class FirElementSerializer private constructor( parentSerializer: FirElementSerializer?, typeApproximator: AbstractTypeApproximator, languageVersionSettings: LanguageVersionSettings, + produceHeaderKlib: Boolean = false, ): FirElementSerializer { val parentClassId = klass.symbol.classId.outerClassId val parent = if (parentClassId != null && !parentClassId.isLocal) { val parentClass = session.symbolProvider.getClassLikeSymbolByClassId(parentClassId)!!.fir as FirRegularClass parentSerializer ?: create( session, scopeSession, parentClass, extension, null, typeApproximator, - languageVersionSettings, + languageVersionSettings, produceHeaderKlib ) } 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 @@ -1212,6 +1220,7 @@ class FirElementSerializer private constructor( serializeTypeTableToFunction = false, typeApproximator, languageVersionSettings, + produceHeaderKlib, ) for (typeParameter in klass.typeParameters) { if (typeParameter !is FirTypeParameter) continue 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 345628fbc80..0d8a166067b 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 @@ -22,12 +22,14 @@ fun serializeSingleFirFile( actualizedExpectDeclarations: Set?, serializerExtension: FirKLibSerializerExtension, languageVersionSettings: LanguageVersionSettings, + produceHeaderKlib: Boolean = false, ): ProtoBuf.PackageFragment { val approximator = TypeApproximatorForMetadataSerializer(session) val packageSerializer = FirElementSerializer.createTopLevel( session, scopeSession, serializerExtension, approximator, - languageVersionSettings + languageVersionSettings, + produceHeaderKlib ) // TODO: typealiases (see klib serializer) @@ -40,13 +42,16 @@ fun serializeSingleFirFile( fun List>.makeClassesProtoWithNested() { val classSymbols = this - .filter { it.fir.shouldBeSerialized(actualizedExpectDeclarations) } + .filter { + it.fir.isNotExpectOrShouldBeSerialized(actualizedExpectDeclarations) && + it.fir.isNotPrivateOrShouldBeSerialized(produceHeaderKlib) + } .sortedBy { it.classId.asFqNameString() } for (symbol in classSymbols) { val klass = symbol.fir val classSerializer = FirElementSerializer.create( session, scopeSession, klass, serializerExtension, null, - approximator, languageVersionSettings + approximator, languageVersionSettings, produceHeaderKlib ) val index = classSerializer.stringTable.getFqNameIndex(klass) @@ -60,7 +65,8 @@ fun serializeSingleFirFile( } 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) } diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/serializationUtil.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/serializationUtil.kt index f88099dd321..ef0b7ff44ad 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/serializationUtil.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/serializationUtil.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration 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.languageVersionSettings import org.jetbrains.kotlin.fir.resolve.fullyExpandedType @@ -47,6 +48,10 @@ fun ConeKotlinType.suspendFunctionTypeToFunctionTypeWithContinuation(session: Fi ) } -fun FirMemberDeclaration.shouldBeSerialized(actualizedExpectDeclaration: Set?): Boolean { +fun FirMemberDeclaration.isNotExpectOrShouldBeSerialized(actualizedExpectDeclaration: Set?): Boolean { return !isExpect || actualizedExpectDeclaration == null || this !in actualizedExpectDeclaration } + +fun FirMemberDeclaration.isNotPrivateOrShouldBeSerialized(produceHeaderKlib: Boolean): Boolean { + return !produceHeaderKlib || visibility.isPublicAPI +} diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt index 777cb28d7d7..43c283c5cf6 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.library.impl.IrMemoryStringWriter import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.utils.filterIsInstanceAnd +import org.jetbrains.kotlin.utils.addToStdlib.applyIf import java.io.File import org.jetbrains.kotlin.backend.common.serialization.proto.AccessorIdSignature as ProtoAccessorIdSignature import org.jetbrains.kotlin.backend.common.serialization.proto.CommonIdSignature as ProtoCommonIdSignature @@ -118,6 +119,7 @@ open class IrFileSerializer( private val languageVersionSettings: LanguageVersionSettings, private val bodiesOnlyForInlines: Boolean = false, private val normalizeAbsolutePaths: Boolean = false, + private val skipPrivateApi: Boolean = false, private val sourceBaseDirs: Collection ) { private val loopIndex = hashMapOf() @@ -183,7 +185,11 @@ open class IrFileSerializer( private fun serializeIrStatementOrigin(origin: IrStatementOrigin): Int = 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 ---------------------------------------------------------- */ @@ -1340,9 +1346,9 @@ open class IrFileSerializer( // ---------- Top level ------------------------------------------------------ - private fun serializeFileEntry(entry: IrFileEntry): ProtoFileEntry = ProtoFileEntry.newBuilder() + private fun serializeFileEntry(entry: IrFileEntry, includeLineStartOffsets: Boolean = true): ProtoFileEntry = ProtoFileEntry.newBuilder() .setName(entry.matchAndNormalizeFilePath()) - .addAllLineStartOffset(entry.lineStartOffsets.asIterable()) + .applyIf(includeLineStartOffsets) { addAllLineStartOffset(entry.lineStartOffsets.asIterable()) } .build() open fun backendSpecificExplicitRoot(node: IrAnnotationContainer): Boolean = false @@ -1351,12 +1357,18 @@ open class IrFileSerializer( open fun backendSpecificSerializeAllMembers(irClass: IrClass) = false 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 { val parent = member.parent require(parent is IrClass) if (backendSpecificSerializeAllMembers(parent)) return true if (bodiesOnlyForInlines && member is IrAnonymousInitializer && parent.visibility != DescriptorVisibilities.LOCAL) return false + if (skipIfPrivate(member)) { + return false + } return (!member.isFakeOverride) } @@ -1414,11 +1426,15 @@ open class IrFileSerializer( val topLevelDeclarations = mutableListOf() val proto = ProtoFile.newBuilder() - .setFileEntry(serializeFileEntry(file.fileEntry)) + .setFileEntry(serializeFileEntry(file.fileEntry, includeLineStartOffsets = !skipPrivateApi)) .addAllFqName(serializeFqName(file.packageFqName.asString())) .addAllAnnotation(serializeAnnotations(file.annotations)) 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) { // Skip the declaration unless it is `expect annotation class` marked with `OptionalExpectation` // 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. file.declarations - .filterIsInstanceAnd { it.backingField?.initializer != null && keepOrderOfProperties(it) } + .filterIsInstanceAnd { it.backingField?.initializer != null && keepOrderOfProperties(it) && !skipIfPrivate(it) } .forEach { val fieldSymbol = it.backingField?.symbol ?: error("Not found ID ${it.render()}") proto.addExplicitlyExportedToCompiler(serializeIrSymbol(fieldSymbol)) diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataMonolithicSerializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataMonolithicSerializer.kt index c46c4455c42..02a6b8b4bdd 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataMonolithicSerializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataMonolithicSerializer.kt @@ -27,8 +27,9 @@ class KlibMetadataMonolithicSerializer( exportKDoc: Boolean, skipExpects: Boolean, includeOnlyModuleContent: Boolean = false, - allowErrorTypes: Boolean = false -) : KlibMetadataSerializer(languageVersionSettings, metadataVersion, project, exportKDoc, skipExpects, includeOnlyModuleContent, allowErrorTypes) { + allowErrorTypes: Boolean = false, + produceHeaderKlib: Boolean = false, +) : KlibMetadataSerializer(languageVersionSettings, metadataVersion, project, exportKDoc, skipExpects, includeOnlyModuleContent, allowErrorTypes, produceHeaderKlib) { private fun serializePackageFragment(fqName: FqName, module: ModuleDescriptor): List { diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializer.kt index 8a1bbc74390..10db46b7dd6 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializer.kt @@ -18,7 +18,7 @@ import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.name.ClassId 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.serialization.ApproximatingStringTable import org.jetbrains.kotlin.serialization.DescriptorSerializer @@ -36,7 +36,8 @@ abstract class KlibMetadataSerializer( val exportKDoc: Boolean = false, val skipExpects: Boolean = false, val includeOnlyModuleContent: Boolean = false, - private val allowErrorTypes: Boolean + private val allowErrorTypes: Boolean, + val produceHeaderKlib: Boolean = false, ) { lateinit var serializerContext: SerializerContext @@ -54,7 +55,8 @@ abstract class KlibMetadataSerializer( metadataVersion, ApproximatingStringTable(), allowErrorTypes, - exportKDoc + exportKDoc, + produceHeaderKlib ) return SerializerContext( extension, @@ -94,8 +96,8 @@ abstract class KlibMetadataSerializer( // TODO: we filter out expects with present actuals. // This is done because deserialized member scope doesn't give us actuals // when it has a choice - private fun List.filterOutExpectsWithActuals(): List { - val actualClassIds = this.filter{ !it.isExpectMember }.map { ClassId.topLevel(it.fqNameSafe) } + private fun Sequence.filterOutExpectsWithActuals(): Sequence { + val actualClassIds = this.filter { !it.isExpectMember }.map { ClassId.topLevel(it.fqNameSafe) } return this.filterNot { // TODO: this only filters classes for now. // Need to do the same for functions etc @@ -103,12 +105,20 @@ abstract class KlibMetadataSerializer( } } - protected fun List.filterOutExpects(): List = + private fun Sequence.filterOutExpects(): Sequence = if (skipExpects) this.filterNot { it.isExpectMember && !it.isSerializableExpectClass } else this.filterOutExpectsWithActuals() + private fun Sequence.filterPrivate(): Sequence = + 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, //builder: ProtoBuf.PackageFragment.Builder, descriptors: Collection): List> { @@ -131,8 +141,8 @@ abstract class KlibMetadataSerializer( allTopLevelDescriptors: List ): List { - val classifierDescriptors = allClassifierDescriptors.filterOutExpects() - val topLevelDescriptors = allTopLevelDescriptors.filterOutExpects() + val classifierDescriptors = allClassifierDescriptors.asSequence().filterOutExpects().filterPrivate().toList() + val topLevelDescriptors = allTopLevelDescriptors.asSequence().filterOutExpects().filterPrivate().toList() if (TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE == null && TOP_LEVEL_DECLARATION_COUNT_PER_FILE == null) { diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializerExtension.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializerExtension.kt index 298b3719b58..4bc9ca7751d 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializerExtension.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataSerializerExtension.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.backend.common.serialization.metadata -import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* 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.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtPrimaryConstructor +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.source.getPsi 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.StringTableImpl import org.jetbrains.kotlin.serialization.deserialization.DYNAMIC_TYPE_DESERIALIZER_ID @@ -28,9 +29,22 @@ class KlibMetadataSerializerExtension( override val metadataVersion: BinaryVersion, override val stringTable: StringTableImpl, private val allowErrorTypes: Boolean, - private val exportKDoc: Boolean + private val exportKDoc: Boolean, + private val produceHeaderKlib: Boolean ) : KotlinSerializerExtensionBase(KlibMetadataSerializerProtocol) { 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() + .filter { it.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE } + .filter { it.visibility.isPublicAPI } + ) + } + else super.customClassMembersProducer private fun descriptorFileId(descriptor: DeclarationDescriptorWithSource): Int? { val fileName = descriptor.source.containingFile.name ?: return null diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt index f218c38bbae..e7c4d55ac69 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt @@ -163,10 +163,15 @@ class DescriptorSerializer private constructor( classDescriptor.inlineClassRepresentation?.let { inlineClassRepresentation -> builder.inlineClassUnderlyingPropertyName = getSimpleNameIndex(inlineClassRepresentation.underlyingPropertyName) - val property = callableMembers.single { - it is PropertyDescriptor && it.extensionReceiverParameter == null && it.name == inlineClassRepresentation.underlyingPropertyName - } - if (!property.visibility.isPublicAPI) { + // The underlying property might be missing from `callableMembers` if we are producing a header klib and + // the inline class is a part of the public API but the underlying property is not. + val property = callableMembers.singleOrNull { candidate -> + candidate is PropertyDescriptor + && candidate.extensionReceiverParameter == null + && candidate.name == inlineClassRepresentation.underlyingPropertyName + } ?: return@let + + if (property.visibility.isPublicAPI) { if (useTypeTable()) { builder.inlineClassUnderlyingTypeId = typeId(inlineClassRepresentation.underlyingType) } else { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt index bb1ce700430..8e1ad7eb0dd 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt @@ -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.phases.Fir2IrOutput 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.serialization.KonanIrModuleSerializer import org.jetbrains.kotlin.config.CommonConfigurationKeys @@ -34,11 +35,13 @@ internal fun PhaseContext.firSerializer(input: FirOutput): SerializerOutput? = w 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( firResult: FirResult, fir2IrInput: Fir2IrOutput?, + produceHeaderKlib: Boolean = false, ): SerializerOutput { val configuration = config.configuration val sourceFiles = mutableListOf() @@ -71,6 +74,8 @@ internal fun PhaseContext.firSerializerBase( moduleName = fir2IrInput?.irModuleFragment?.descriptor?.name?.asString() ?: firResult.outputs.last().session.moduleData.name.asString(), firFilesAndSessionsBySourceFile, + bodiesOnlyForInlines = produceHeaderKlib, + skipPrivateApi = produceHeaderKlib, ) { firFile, session, scopeSession -> serializeSingleFirFile( firFile, @@ -87,6 +92,7 @@ internal fun PhaseContext.firSerializerBase( additionalAnnotationsProvider = fir2IrInput?.components?.annotationsFromPluginRegistrar?.createMetadataAnnotationsProvider() ), configuration.languageVersionSettings, + produceHeaderKlib, ) } } @@ -102,14 +108,16 @@ class KotlinFileSerializedData( } internal fun PhaseContext.serializeNativeModule( - configuration: CompilerConfiguration, - messageLogger: IrMessageLogger, - files: List, - dependencies: List?, - moduleFragment: IrModuleFragment?, - moduleName: String, - firFilesAndSessionsBySourceFile: Map>, - serializeSingleFile: (FirFile, FirSession, ScopeSession) -> ProtoBuf.PackageFragment + configuration: CompilerConfiguration, + messageLogger: IrMessageLogger, + files: List, + dependencies: List?, + moduleFragment: IrModuleFragment?, + moduleName: String, + firFilesAndSessionsBySourceFile: Map>, + bodiesOnlyForInlines: Boolean = false, + skipPrivateApi: Boolean = false, + serializeSingleFile: (FirFile, FirSession, ScopeSession) -> ProtoBuf.PackageFragment ): SerializerOutput { if (moduleFragment != null) { assert(files.size == moduleFragment.files.size) @@ -126,6 +134,8 @@ internal fun PhaseContext.serializeNativeModule( normalizeAbsolutePaths = absolutePathNormalization, sourceBaseDirs = sourceBaseDirs, languageVersionSettings = configuration.languageVersionSettings, + bodiesOnlyForInlines = bodiesOnlyForInlines, + skipPrivateApi = skipPrivateApi ).serializedIrModule(moduleFragment) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index ccee5323c12..0d376e8e9ae 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt @@ -225,6 +225,8 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration 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 purgeUserLibs: Boolean diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index 0fdab57a874..651f71aad7d 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -75,6 +75,8 @@ class KonanConfigKeys { = CompilerConfigurationKey.create("provide manifest addend file") val METADATA_KLIB: CompilerConfigurationKey = CompilerConfigurationKey.create("metadata klib") + val HEADER_KLIB: CompilerConfigurationKey + = CompilerConfigurationKey.create("path to file where header klib should be produced") val MODULE_NAME: CompilerConfigurationKey = CompilerConfigurationKey.create("module name") val NATIVE_LIBRARY_FILES: CompilerConfigurationKey> diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/SetupConfiguration.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/SetupConfiguration.kt index bbbcfb78f46..27781077654 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/SetupConfiguration.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/SetupConfiguration.kt @@ -56,6 +56,7 @@ fun CompilerConfiguration.setupFromArguments(arguments: K2NativeCompilerArgument (arguments.produce ?: "program").uppercase()) put(PRODUCE, outputKind) put(METADATA_KLIB, arguments.metadataKlib) + putIfNotNull(HEADER_KLIB, arguments.headerKlibPath) arguments.libraryVersion?.let { put(LIBRARY_VERSION, it) } 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 e7e949f7b7d..f9f6aaa694f 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 @@ -108,8 +108,15 @@ internal class DynamicCompilerDriver : CompilerDriver() { engine.runFirSerializer(frontendOutput) } else { 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.runFir2IrSerializer(fir2IrOutput) + engine.runFir2IrSerializer(FirSerializerInput(fir2IrOutput)) } } @@ -124,6 +131,10 @@ internal class DynamicCompilerDriver : CompilerDriver() { } else { 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) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/FirSerializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/FirSerializer.kt index 5624604b93a..e6c7e840567 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/FirSerializer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/FirSerializer.kt @@ -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.fir2IrSerializer + +internal data class FirSerializerInput( + val firToIrOutput: Fir2IrOutput, + val produceHeaderKlib: Boolean = false, +) + internal val FirSerializerPhase = createSimpleNamedCompilerPhase( "FirSerializer", "Fir serializer", outputIfNotEnabled = { _, _, _, _ -> SerializerOutput(null, null, null, listOf()) } @@ -17,10 +23,10 @@ internal val FirSerializerPhase = createSimpleNamedCompilerPhase( +internal val Fir2IrSerializerPhase = createSimpleNamedCompilerPhase( "Fir2IrSerializer", "Fir2Ir serializer", outputIfNotEnabled = { _, _, _, _ -> SerializerOutput(null, null, null, listOf()) } -) { context: PhaseContext, input: Fir2IrOutput -> +) { context: PhaseContext, input: FirSerializerInput -> context.fir2IrSerializer(input) } @@ -31,7 +37,7 @@ internal fun PhaseEngine.runFirSerializer( } internal fun PhaseEngine.runFir2IrSerializer( - fir2irOutput: Fir2IrOutput + firSerializerInput: FirSerializerInput ): SerializerOutput { - return this.runPhase(Fir2IrSerializerPhase, fir2irOutput) + return this.runPhase(Fir2IrSerializerPhase, firSerializerInput) } \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt index f2ba8bd4837..02ac7da4634 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.library.SerializedMetadata internal data class SerializerInput( val moduleDescriptor: ModuleDescriptor, val psiToIrOutput: PsiToIrOutput.ForKlib?, + val produceHeaderKlib: Boolean, ) data class SerializerOutput( @@ -48,24 +49,27 @@ internal val SerializerPhase = createSimpleNamedCompilerPhase PhaseEngine.runSerializer( - moduleDescriptor: ModuleDescriptor, - psiToIrResult: PsiToIrOutput.ForKlib?, + moduleDescriptor: ModuleDescriptor, + psiToIrResult: PsiToIrOutput.ForKlib?, + produceHeaderKlib: Boolean = false, ): SerializerOutput { - val input = SerializerInput(moduleDescriptor, psiToIrResult) + val input = SerializerInput(moduleDescriptor, psiToIrResult, produceHeaderKlib) return this.runPhase(SerializerPhase, input) } \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/WriteKlib.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/WriteKlib.kt index b337820cbe2..645f1c74a4a 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/WriteKlib.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/WriteKlib.kt @@ -14,13 +14,19 @@ import org.jetbrains.kotlin.konan.library.impl.buildLibrary import org.jetbrains.kotlin.library.KotlinAbiVersion import org.jetbrains.kotlin.library.KotlinLibraryVersioning import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion +import org.jetbrains.kotlin.util.removeSuffixIfPresent -internal val WriteKlibPhase = createSimpleNamedCompilerPhase( +internal data class KlibWriterInput( + val serializerOutput: SerializerOutput, + val customOutputPath: String? +) +internal val WriteKlibPhase = createSimpleNamedCompilerPhase( "WriteKlib", "Write klib output", ) { context, input -> val config = context.config 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 output = outputFiles.klibOutputFileName(!nopack) val libraryName = config.moduleId @@ -51,14 +57,14 @@ internal val WriteKlibPhase = createSimpleNamedCompilerPhase PhaseEngine.writeKlib( serializationOutput: SerializerOutput, + customOutputPath: String? = null, ) { - this.runPhase(WriteKlibPhase, serializationOutput) + this.runPhase(WriteKlibPhase, KlibWriterInput(serializationOutput, customOutputPath)) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrFileSerializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrFileSerializer.kt index 70a6aacf902..123c9860423 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrFileSerializer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrFileSerializer.kt @@ -12,21 +12,23 @@ import org.jetbrains.kotlin.ir.util.IrMessageLogger import org.jetbrains.kotlin.ir.util.hasAnnotation class KonanIrFileSerializer( - messageLogger: IrMessageLogger, - declarationTable: DeclarationTable, - languageVersionSettings: LanguageVersionSettings, - bodiesOnlyForInlines: Boolean = false, - compatibilityMode: CompatibilityMode, - normalizeAbsolutePaths: Boolean, - sourceBaseDirs: Collection + messageLogger: IrMessageLogger, + declarationTable: DeclarationTable, + languageVersionSettings: LanguageVersionSettings, + bodiesOnlyForInlines: Boolean = false, + compatibilityMode: CompatibilityMode, + normalizeAbsolutePaths: Boolean, + sourceBaseDirs: Collection, + skipPrivateApi: Boolean = false, ) : IrFileSerializer( - messageLogger = messageLogger, - declarationTable = declarationTable, - compatibilityMode = compatibilityMode, - languageVersionSettings = languageVersionSettings, - bodiesOnlyForInlines = bodiesOnlyForInlines, - normalizeAbsolutePaths = normalizeAbsolutePaths, - sourceBaseDirs = sourceBaseDirs + messageLogger, + declarationTable, + compatibilityMode, + languageVersionSettings, + skipPrivateApi = skipPrivateApi, + bodiesOnlyForInlines = bodiesOnlyForInlines, + normalizeAbsolutePaths = normalizeAbsolutePaths, + sourceBaseDirs = sourceBaseDirs ) { override fun backendSpecificExplicitRoot(node: IrAnnotationContainer): Boolean { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrModuleSerializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrModuleSerializer.kt index 253c1a29502..dd57c47f78e 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrModuleSerializer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrModuleSerializer.kt @@ -15,6 +15,8 @@ class KonanIrModuleSerializer( normalizeAbsolutePaths: Boolean, sourceBaseDirs: Collection, private val languageVersionSettings: LanguageVersionSettings, + private val bodiesOnlyForInlines: Boolean = false, + private val skipPrivateApi: Boolean = false, ) : IrModuleSerializer(messageLogger, compatibilityMode, normalizeAbsolutePaths, sourceBaseDirs) { private val globalDeclarationTable = KonanGlobalDeclarationTable(irBuiltIns) @@ -33,5 +35,7 @@ class KonanIrModuleSerializer( compatibilityMode = compatibilityMode, normalizeAbsolutePaths = normalizeAbsolutePaths, sourceBaseDirs = sourceBaseDirs, - languageVersionSettings = languageVersionSettings) + languageVersionSettings = languageVersionSettings, + bodiesOnlyForInlines = bodiesOnlyForInlines, + skipPrivateApi = skipPrivateApi) } diff --git a/native/native.tests/testData/klib/header-klibs/comparison/anonymousObjects/base/test.kt b/native/native.tests/testData/klib/header-klibs/comparison/anonymousObjects/base/test.kt new file mode 100644 index 00000000000..bc74a64f21a --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/anonymousObjects/base/test.kt @@ -0,0 +1,7 @@ +package test + +private val x = object { fun f() = 1 } + +fun g() = + x.f() + + object { fun f() = 0 }.f() diff --git a/native/native.tests/testData/klib/header-klibs/comparison/anonymousObjects/sameAbi/test.kt b/native/native.tests/testData/klib/header-klibs/comparison/anonymousObjects/sameAbi/test.kt new file mode 100644 index 00000000000..043f6716eeb --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/anonymousObjects/sameAbi/test.kt @@ -0,0 +1,3 @@ +package test + +fun g() = 1 \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/classFlags/base/Class.kt b/native/native.tests/testData/klib/header-klibs/comparison/classFlags/base/Class.kt new file mode 100644 index 00000000000..6671676d981 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/classFlags/base/Class.kt @@ -0,0 +1,3 @@ +package test + +class Class \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/classFlags/differentAbi/Class.kt b/native/native.tests/testData/klib/header-klibs/comparison/classFlags/differentAbi/Class.kt new file mode 100644 index 00000000000..bf877a0f6a5 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/classFlags/differentAbi/Class.kt @@ -0,0 +1,3 @@ +package test + +open class Class \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/classPrivateMembers/base/A.kt b/native/native.tests/testData/klib/header-klibs/comparison/classPrivateMembers/base/A.kt new file mode 100644 index 00000000000..e24b9db70c6 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/classPrivateMembers/base/A.kt @@ -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 +} \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/classPrivateMembers/sameAbi/A.kt b/native/native.tests/testData/klib/header-klibs/comparison/classPrivateMembers/sameAbi/A.kt new file mode 100644 index 00000000000..8cadf0f42fe --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/classPrivateMembers/sameAbi/A.kt @@ -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 +} \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/constant/base/const.kt b/native/native.tests/testData/klib/header-klibs/comparison/constant/base/const.kt new file mode 100644 index 00000000000..de62917855d --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/constant/base/const.kt @@ -0,0 +1,3 @@ +package test + +const val x = 0 \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/constant/differentAbi/const.kt b/native/native.tests/testData/klib/header-klibs/comparison/constant/differentAbi/const.kt new file mode 100644 index 00000000000..56faca17769 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/constant/differentAbi/const.kt @@ -0,0 +1,3 @@ +package test + +const val x = 1 \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/declarationOrderInline/base/test.kt b/native/native.tests/testData/klib/header-klibs/comparison/declarationOrderInline/base/test.kt new file mode 100644 index 00000000000..e166d32abd1 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/declarationOrderInline/base/test.kt @@ -0,0 +1,4 @@ +package test + +inline fun f() = 1 +inline fun g() = 2 diff --git a/native/native.tests/testData/klib/header-klibs/comparison/declarationOrderInline/differentAbi/test.kt b/native/native.tests/testData/klib/header-klibs/comparison/declarationOrderInline/differentAbi/test.kt new file mode 100644 index 00000000000..a333a462fbe --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/declarationOrderInline/differentAbi/test.kt @@ -0,0 +1,7 @@ +package test + +inline fun g() = 2 + +inline fun f() = 1 + +// This changes the line numbers in f, g diff --git a/native/native.tests/testData/klib/header-klibs/comparison/functionBody/base/function.kt b/native/native.tests/testData/klib/header-klibs/comparison/functionBody/base/function.kt new file mode 100644 index 00000000000..46c201a8e7e --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/functionBody/base/function.kt @@ -0,0 +1,10 @@ +package test + +fun sum(x: Int, y: Int): Int = + try { + var result = x + result += y + result + } finally { + // do nothing + } \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/functionBody/sameAbi/function.kt b/native/native.tests/testData/klib/header-klibs/comparison/functionBody/sameAbi/function.kt new file mode 100644 index 00000000000..56079d760c1 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/functionBody/sameAbi/function.kt @@ -0,0 +1,3 @@ +package test + +fun sum(x: Int, y: Int): Int = y + x \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateClass/base/anonymousObject.kt b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateClass/base/anonymousObject.kt new file mode 100644 index 00000000000..fdd7de502f7 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateClass/base/anonymousObject.kt @@ -0,0 +1,9 @@ +private class A { + inline fun test(crossinline s: () -> Unit) { + object { + fun run() { + s() + } + }.run() + } +} diff --git a/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateClass/sameAbi/anonymousObject.kt b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateClass/sameAbi/anonymousObject.kt new file mode 100644 index 00000000000..7fb3b194a46 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateClass/sameAbi/anonymousObject.kt @@ -0,0 +1,9 @@ +private class A { + inline fun test(crossinline s: () -> Unit) { + object { + fun run() { + //s() + } + }.run() + } +} diff --git a/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateNestedClass/base/anonymousObject.kt b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateNestedClass/base/anonymousObject.kt new file mode 100644 index 00000000000..6493cee8b4c --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateNestedClass/base/anonymousObject.kt @@ -0,0 +1,11 @@ +class A { + private class B { + inline fun test(crossinline s: () -> Unit) { + object { + fun run() { + s() + } + }.run() + } + } +} diff --git a/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateNestedClass/sameAbi/anonymousObject.kt b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateNestedClass/sameAbi/anonymousObject.kt new file mode 100644 index 00000000000..1b7d4766100 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunInPrivateNestedClass/sameAbi/anonymousObject.kt @@ -0,0 +1,11 @@ +class A { + private class B { + inline fun test(crossinline s: () -> Unit) { + object { + fun run() { + //s() + } + }.run() + } + } +} diff --git a/native/native.tests/testData/klib/header-klibs/comparison/inlineFunctionBody/base/function.kt b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunctionBody/base/function.kt new file mode 100644 index 00000000000..855baa992a0 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunctionBody/base/function.kt @@ -0,0 +1,3 @@ +package test + +inline fun sum(x: Int, y: Int): Int = x + y \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/inlineFunctionBody/differentAbi/function.kt b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunctionBody/differentAbi/function.kt new file mode 100644 index 00000000000..aec93d375d7 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/inlineFunctionBody/differentAbi/function.kt @@ -0,0 +1,3 @@ +package test + +inline fun sum(x: Int, y: Int): Int = y + x \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/lambdas/base/test.kt b/native/native.tests/testData/klib/header-klibs/comparison/lambdas/base/test.kt new file mode 100644 index 00000000000..b83f5854458 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/lambdas/base/test.kt @@ -0,0 +1,4 @@ +package test + +private inline fun f() = { 1 }() +fun g() = f() diff --git a/native/native.tests/testData/klib/header-klibs/comparison/lambdas/sameAbi/test.kt b/native/native.tests/testData/klib/header-klibs/comparison/lambdas/sameAbi/test.kt new file mode 100644 index 00000000000..043f6716eeb --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/lambdas/sameAbi/test.kt @@ -0,0 +1,3 @@ +package test + +fun g() = 1 \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/parameterName/base/function.kt b/native/native.tests/testData/klib/header-klibs/comparison/parameterName/base/function.kt new file mode 100644 index 00000000000..2d757154620 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/parameterName/base/function.kt @@ -0,0 +1,3 @@ +package test + +fun id(x: Int): Int = x \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/parameterName/differentAbi/function.kt b/native/native.tests/testData/klib/header-klibs/comparison/parameterName/differentAbi/function.kt new file mode 100644 index 00000000000..f83fa593cc6 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/parameterName/differentAbi/function.kt @@ -0,0 +1,3 @@ +package test + +fun id(y: Int): Int = y \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/privateInterface/base/test.kt b/native/native.tests/testData/klib/header-klibs/comparison/privateInterface/base/test.kt new file mode 100644 index 00000000000..6398d40d5ce --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/privateInterface/base/test.kt @@ -0,0 +1,10 @@ +package test + +private interface A { + fun foo() = 0 + fun bar(): String +} + +class B: A { + override fun bar() = "test${foo()}" +} \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/privateInterface/sameAbi/test.kt b/native/native.tests/testData/klib/header-klibs/comparison/privateInterface/sameAbi/test.kt new file mode 100644 index 00000000000..ffde83123f6 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/privateInterface/sameAbi/test.kt @@ -0,0 +1,10 @@ +package test + +private interface A { + fun foo() = 42 + fun bar(): String +} + +class B: A { + override fun bar() = "test${foo()}" +} diff --git a/native/native.tests/testData/klib/header-klibs/comparison/privateTypealias/base/typealiases.kt b/native/native.tests/testData/klib/header-klibs/comparison/privateTypealias/base/typealiases.kt new file mode 100644 index 00000000000..8654b9c3d81 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/privateTypealias/base/typealiases.kt @@ -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 diff --git a/native/native.tests/testData/klib/header-klibs/comparison/privateTypealias/sameAbi/typealiases.kt b/native/native.tests/testData/klib/header-klibs/comparison/privateTypealias/sameAbi/typealiases.kt new file mode 100644 index 00000000000..b9cf0d124e2 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/privateTypealias/sameAbi/typealiases.kt @@ -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 diff --git a/native/native.tests/testData/klib/header-klibs/comparison/returnType/base/function.kt b/native/native.tests/testData/klib/header-klibs/comparison/returnType/base/function.kt new file mode 100644 index 00000000000..78c05ecf35d --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/returnType/base/function.kt @@ -0,0 +1,3 @@ +package test + +fun foo() = 0 \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/returnType/differentAbi/function.kt b/native/native.tests/testData/klib/header-klibs/comparison/returnType/differentAbi/function.kt new file mode 100644 index 00000000000..df46051863d --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/returnType/differentAbi/function.kt @@ -0,0 +1,3 @@ +package test + +fun foo() = "0" \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/superClass/base/classes.kt b/native/native.tests/testData/klib/header-klibs/comparison/superClass/base/classes.kt new file mode 100644 index 00000000000..70c2dd49327 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/superClass/base/classes.kt @@ -0,0 +1,4 @@ +package test + +open class A +class B : A() \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/superClass/differentAbi/classes.kt b/native/native.tests/testData/klib/header-klibs/comparison/superClass/differentAbi/classes.kt new file mode 100644 index 00000000000..9c2f6abc1f1 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/superClass/differentAbi/classes.kt @@ -0,0 +1,4 @@ +package test + +open class A +class B \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/comparison/syntheticAccessors/base/test.kt b/native/native.tests/testData/klib/header-klibs/comparison/syntheticAccessors/base/test.kt new file mode 100644 index 00000000000..7f35cefcfbd --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/syntheticAccessors/base/test.kt @@ -0,0 +1,7 @@ +package test + +private val x = 1 + +object A { fun f() = x } + +val y = 2 diff --git a/native/native.tests/testData/klib/header-klibs/comparison/syntheticAccessors/sameAbi/test.kt b/native/native.tests/testData/klib/header-klibs/comparison/syntheticAccessors/sameAbi/test.kt new file mode 100644 index 00000000000..f7917a1690c --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/syntheticAccessors/sameAbi/test.kt @@ -0,0 +1,5 @@ +package test + +object A { fun f() = 1 } + +val y = 2 diff --git a/native/native.tests/testData/klib/header-klibs/comparison/topLevelPrivateMembers/base/utils.kt b/native/native.tests/testData/klib/header-klibs/comparison/topLevelPrivateMembers/base/utils.kt new file mode 100644 index 00000000000..9a80bf38e00 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/topLevelPrivateMembers/base/utils.kt @@ -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 diff --git a/native/native.tests/testData/klib/header-klibs/comparison/topLevelPrivateMembers/sameAbi/utils.kt b/native/native.tests/testData/klib/header-klibs/comparison/topLevelPrivateMembers/sameAbi/utils.kt new file mode 100644 index 00000000000..323c16dee50 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/comparison/topLevelPrivateMembers/sameAbi/utils.kt @@ -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 \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/anonymousObject/lib/lib.kt b/native/native.tests/testData/klib/header-klibs/compilation/anonymousObject/lib/lib.kt new file mode 100644 index 00000000000..68f19cb9e21 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/anonymousObject/lib/lib.kt @@ -0,0 +1,10 @@ +package lib + +interface Interface { + fun getInt(): Int +} + +fun getInterface(): Interface = + object : Interface { + override fun getInt(): Int = 10 + } \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/anonymousObject/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/anonymousObject/main/main.kt new file mode 100644 index 00000000000..de1ba3196cb --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/anonymousObject/main/main.kt @@ -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" +} \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/classes/lib/classes.kt b/native/native.tests/testData/klib/header-klibs/compilation/classes/lib/classes.kt new file mode 100644 index 00000000000..c26a85c3556 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/classes/lib/classes.kt @@ -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 + } +} \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/classes/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/classes/main/main.kt new file mode 100644 index 00000000000..a0c7bd965a1 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/classes/main/main.kt @@ -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" +} \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/clinit/lib/object.kt b/native/native.tests/testData/klib/header-klibs/compilation/clinit/lib/object.kt new file mode 100644 index 00000000000..2e13c86ad99 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/clinit/lib/object.kt @@ -0,0 +1,7 @@ +package lib + +object Object { + val x = 1 + val y = 2 + val z = x + y +} \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/clinit/lib/topLevel.kt b/native/native.tests/testData/klib/header-klibs/compilation/clinit/lib/topLevel.kt new file mode 100644 index 00000000000..9dfe37e6722 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/clinit/lib/topLevel.kt @@ -0,0 +1,5 @@ +package lib + +val x = 1 +val y = 2 +val z = x + y \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/clinit/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/clinit/main/main.kt new file mode 100644 index 00000000000..acdac19a713 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/clinit/main/main.kt @@ -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" +} \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineAnnotationInstantiation/lib/lib.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineAnnotationInstantiation/lib/lib.kt new file mode 100644 index 00000000000..320eb9db33e --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineAnnotationInstantiation/lib/lib.kt @@ -0,0 +1,5 @@ +package lib + +annotation class A(val value: String) + +inline fun a() = A("OK") diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineAnnotationInstantiation/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineAnnotationInstantiation/main/main.kt new file mode 100644 index 00000000000..b4ce58037db --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineAnnotationInstantiation/main/main.kt @@ -0,0 +1,7 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + return a().value +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineAnonymousObject/lib/lib.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineAnonymousObject/lib/lib.kt new file mode 100644 index 00000000000..70413b3fee0 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineAnonymousObject/lib/lib.kt @@ -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++ + } diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineAnonymousObject/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineAnonymousObject/main/main.kt new file mode 100644 index 00000000000..b392da6485d --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineAnonymousObject/main/main.kt @@ -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" +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineCapture/lib/lib.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineCapture/lib/lib.kt new file mode 100644 index 00000000000..05c9bb35146 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineCapture/lib/lib.kt @@ -0,0 +1,10 @@ +package lib + +fun inlineCapture(s: String): String { + return with(StringBuilder()) { + val o = object { + override fun toString() = s + } + append(o) + }.toString() +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineCapture/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineCapture/main/main.kt new file mode 100644 index 00000000000..ed1c0c023fa --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineCapture/main/main.kt @@ -0,0 +1,7 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + return inlineCapture("OK") +} \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineNoRegeneration/lib/lib.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineNoRegeneration/lib/lib.kt new file mode 100644 index 00000000000..d1e07a76c0e --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineNoRegeneration/lib/lib.kt @@ -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() +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineNoRegeneration/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineNoRegeneration/main/main.kt new file mode 100644 index 00000000000..ef5e12af7bf --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineNoRegeneration/main/main.kt @@ -0,0 +1,10 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + foo { + "K" + } + return result +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineReifiedFunction/lib/utils.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineReifiedFunction/lib/utils.kt new file mode 100644 index 00000000000..1d71238bc81 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineReifiedFunction/lib/utils.kt @@ -0,0 +1,4 @@ +package lib + +inline fun safeCall(x: Any?, fn: (T) -> T): T? = + if (x is T) fn(x) else null \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineReifiedFunction/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineReifiedFunction/main/main.kt new file mode 100644 index 00000000000..292d620a0ab --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineReifiedFunction/main/main.kt @@ -0,0 +1,13 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + val a = safeCall(10) { it * it } + if (a != 100) error("a is '$a', but is expected to be '100'") + + val b = safeCall(null) { it * it } + if (b != null) error("b is '$b', but is expected to be 'null'") + + return "OK" +} \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineWhenMappings/lib/lib.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineWhenMappings/lib/lib.kt new file mode 100644 index 00000000000..170ec9d5dc3 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineWhenMappings/lib/lib.kt @@ -0,0 +1,10 @@ +package lib + +enum class E { + A, B +} + +inline fun value(x: E) = when (x) { + E.A -> "OK" + E.B -> "Fail" +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/inlineWhenMappings/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/inlineWhenMappings/main/main.kt new file mode 100644 index 00000000000..ed5a53b51f9 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/inlineWhenMappings/main/main.kt @@ -0,0 +1,5 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String = value(E.A) diff --git a/native/native.tests/testData/klib/header-klibs/compilation/innerObjectRegeneration/lib/lib.kt b/native/native.tests/testData/klib/header-klibs/compilation/innerObjectRegeneration/lib/lib.kt new file mode 100644 index 00000000000..c1b04950d4c --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/innerObjectRegeneration/lib/lib.kt @@ -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() +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/innerObjectRegeneration/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/innerObjectRegeneration/main/main.kt new file mode 100644 index 00000000000..b176501b9fd --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/innerObjectRegeneration/main/main.kt @@ -0,0 +1,10 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + foo { + "OK" + } + return result +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/kt-40133/lib/lib.kt b/native/native.tests/testData/klib/header-klibs/compilation/kt-40133/lib/lib.kt new file mode 100644 index 00000000000..963c1012f0d --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/kt-40133/lib/lib.kt @@ -0,0 +1,11 @@ +package lib + +inline fun anInlineFunction(crossinline crossInlineLamba: () -> Unit) { + Foo().apply { + barMethod { crossInlineLamba() } + } +} + +class Foo { + fun barMethod(aLambda: () -> Unit) { aLambda() } +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/kt-40133/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/kt-40133/main/main.kt new file mode 100644 index 00000000000..c0e3e508d83 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/kt-40133/main/main.kt @@ -0,0 +1,9 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + var result = "Fail" + anInlineFunction { result = "OK" } + return result +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/privateOnlyConstructors/lib/classes.kt b/native/native.tests/testData/klib/header-klibs/compilation/privateOnlyConstructors/lib/classes.kt new file mode 100644 index 00000000000..1ad66a402d5 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/privateOnlyConstructors/lib/classes.kt @@ -0,0 +1,7 @@ +package lib + +class A private constructor(val x: Int) { + companion object { + fun create(x: Int): A = A(x * 2) + } +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/privateOnlyConstructors/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/privateOnlyConstructors/main/main.kt new file mode 100644 index 00000000000..99092a0cb1a --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/privateOnlyConstructors/main/main.kt @@ -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" +} \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/privateValueClassConstructor/lib/lib.kt b/native/native.tests/testData/klib/header-klibs/compilation/privateValueClassConstructor/lib/lib.kt new file mode 100644 index 00000000000..4ab6e09bf1a --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/privateValueClassConstructor/lib/lib.kt @@ -0,0 +1,6 @@ +package lib + +value class A private constructor(val value: String) { + companion object { fun a() = A("OK") } + inline fun b() = value +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/privateValueClassConstructor/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/privateValueClassConstructor/main/main.kt new file mode 100644 index 00000000000..40ec9322929 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/privateValueClassConstructor/main/main.kt @@ -0,0 +1,7 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + return A.a().b() +} diff --git a/native/native.tests/testData/klib/header-klibs/compilation/topLevel/lib/utils.kt b/native/native.tests/testData/klib/header-klibs/compilation/topLevel/lib/utils.kt new file mode 100644 index 00000000000..c3cd59c36de --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/topLevel/lib/utils.kt @@ -0,0 +1,6 @@ +package lib + +val prop: Int = 1 +fun func(): Int = 2 +inline fun inlineFunc(): Int = 3 +const val constant: Int = 4 \ No newline at end of file diff --git a/native/native.tests/testData/klib/header-klibs/compilation/topLevel/main/main.kt b/native/native.tests/testData/klib/header-klibs/compilation/topLevel/main/main.kt new file mode 100644 index 00000000000..47419838c80 --- /dev/null +++ b/native/native.tests/testData/klib/header-klibs/compilation/topLevel/main/main.kt @@ -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" +} \ No newline at end of file diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeHeaderKlibComparisonTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeHeaderKlibComparisonTestGenerated.java new file mode 100644 index 00000000000..cc3878c5e54 --- /dev/null +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeHeaderKlibComparisonTestGenerated.java @@ -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/"); + } +} diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeHeaderKlibCompilationTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeHeaderKlibCompilationTestGenerated.java new file mode 100644 index 00000000000..5c567fa98e0 --- /dev/null +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeHeaderKlibCompilationTestGenerated.java @@ -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/"); + } +} diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeHeaderKlibComparisonTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeHeaderKlibComparisonTestGenerated.java new file mode 100644 index 00000000000..4c97fe792f4 --- /dev/null +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeHeaderKlibComparisonTestGenerated.java @@ -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/"); + } +} diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeHeaderKlibCompilationTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeHeaderKlibCompilationTestGenerated.java new file mode 100644 index 00000000000..489083b0ee9 --- /dev/null +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeHeaderKlibCompilationTestGenerated.java @@ -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/"); + } +} diff --git a/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt b/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt index 3ce72e81106..56097a4a2b7 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt @@ -314,6 +314,36 @@ fun main() { } } } + + // Header klib comparison tests + testGroup("native/native.tests/tests-gen", "native/native.tests/testData") { + testClass( + suiteTestClassName = "NativeHeaderKlibComparisonTestGenerated", + ) { + model("klib/header-klibs/comparison", extension = null, recursive = false) + } + testClass( + 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( + suiteTestClassName = "NativeHeaderKlibCompilationTestGenerated", + ) { + model("klib/header-klibs/compilation", extension = null, recursive = false) + } + testClass( + suiteTestClassName = "FirNativeHeaderKlibCompilationTestGenerated", + annotations = listOf(*frontendFir()), + ) { + model("klib/header-klibs/compilation", extension = null, recursive = false) + } + } } } diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeHeaderKlibTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeHeaderKlibTest.kt new file mode 100644 index 00000000000..3890e4af249 --- /dev/null +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeHeaderKlibTest.kt @@ -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("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): 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().executionTimeout), + extras = TestCase.WithTestRunnerExtras(TestRunnerType.DEFAULT) + ).apply { + initialize(null, null) + } +}