[ObjCExport][Minor] Reformat Code after move into newly created modules

FL-23390
This commit is contained in:
Sebastian Sellmair
2023-12-05 10:42:19 +01:00
committed by Space Team
parent 5fba2962b9
commit e97463afb3
28 changed files with 1042 additions and 926 deletions
@@ -29,9 +29,9 @@ fun KotlinType.binaryRepresentationIsNullable() = KotlinTypeInlineClassesSupport
@InternalKotlinNativeApi
inline fun <R> KotlinType.unwrapToPrimitiveOrReference(
eachInlinedClass: (inlinedClass: ClassDescriptor, nullable: Boolean) -> Unit,
ifPrimitive: (primitiveType: KonanPrimitiveType, nullable: Boolean) -> R,
ifReference: (type: KotlinType) -> R
eachInlinedClass: (inlinedClass: ClassDescriptor, nullable: Boolean) -> Unit,
ifPrimitive: (primitiveType: KonanPrimitiveType, nullable: Boolean) -> R,
ifReference: (type: KotlinType) -> R,
): R = KotlinTypeInlineClassesSupport.unwrapToPrimitiveOrReference(this, eachInlinedClass, ifPrimitive, ifReference)
@@ -39,7 +39,7 @@ inline fun <R> KotlinType.unwrapToPrimitiveOrReference(
fun KotlinType.binaryTypeIsReference(): Boolean = this.computePrimitiveBinaryTypeOrNull() == null
fun KotlinType.computePrimitiveBinaryTypeOrNull(): PrimitiveBinaryType? =
this.computeBinaryType().primitiveBinaryTypeOrNull()
this.computeBinaryType().primitiveBinaryTypeOrNull()
fun KotlinType.computeBinaryType(): BinaryType<ClassDescriptor> = KotlinTypeInlineClassesSupport.computeBinaryType(this)
@@ -74,9 +74,9 @@ enum class KonanPrimitiveType(val classId: ClassId, val binaryType: BinaryType.P
assert(!it.classId.isNestedClass)
it.classId.packageFqName
}.fold({ _, _ -> mutableMapOf<Name, KonanPrimitiveType>() },
{ _, accumulator, element ->
accumulator.also { it[element.classId.shortClassName] = element }
})
{ _, accumulator, element ->
accumulator.also { it[element.classId.shortClassName] = element }
})
}
}
@@ -84,12 +84,14 @@ enum class KonanPrimitiveType(val classId: ClassId, val binaryType: BinaryType.P
abstract class InlineClassesSupport<Class : Any, Type : Any> {
@InternalKotlinNativeApi
abstract fun isNullable(type: Type): Boolean
@InternalKotlinNativeApi
abstract fun makeNullable(type: Type): Type
protected abstract fun erase(type: Type): Class
protected abstract fun computeFullErasure(type: Type): Sequence<Class>
protected abstract fun hasInlineModifier(clazz: Class): Boolean
protected abstract fun getNativePointedSuperclass(clazz: Class): Class?
@InternalKotlinNativeApi
abstract fun getInlinedClassUnderlyingType(clazz: Class): Type
protected abstract fun getPackageFqName(clazz: Class): FqName?
@@ -103,19 +105,20 @@ abstract class InlineClassesSupport<Class : Any, Type : Any> {
fun isUsedAsBoxClass(clazz: Class) = getInlinedClass(clazz) == clazz // To handle NativePointed subclasses.
fun getInlinedClass(type: Type): Class? =
getInlinedClass(erase(type), isNullable(type))
getInlinedClass(erase(type), isNullable(type))
@InternalKotlinNativeApi
fun getKonanPrimitiveType(clazz: Class): KonanPrimitiveType? =
if (isTopLevelClass(clazz))
KonanPrimitiveType.byFqNameParts[getPackageFqName(clazz)]?.get(getName(clazz))
else null
if (isTopLevelClass(clazz))
KonanPrimitiveType.byFqNameParts[getPackageFqName(clazz)]?.get(getName(clazz))
else null
@InternalKotlinNativeApi
fun isImplicitInlineClass(clazz: Class): Boolean =
isTopLevelClass(clazz) && (getKonanPrimitiveType(clazz) != null ||
getName(clazz) == KonanFqNames.nativePtr.shortName() && getPackageFqName(clazz) == KonanFqNames.internalPackageName ||
getName(clazz) == InteropFqNames.cPointer.shortName() && getPackageFqName(clazz) == InteropFqNames.cPointer.parent().toSafe())
isTopLevelClass(clazz) && (getKonanPrimitiveType(clazz) != null ||
getName(clazz) == KonanFqNames.nativePtr.shortName() && getPackageFqName(clazz) == KonanFqNames.internalPackageName ||
getName(clazz) == InteropFqNames.cPointer.shortName() && getPackageFqName(clazz) == InteropFqNames.cPointer.parent()
.toSafe())
private fun getInlinedClass(erased: Class, isNullable: Boolean): Class? {
val inlinedClass = getInlinedClass(erased) ?: return null
@@ -144,17 +147,17 @@ abstract class InlineClassesSupport<Class : Any, Type : Any> {
@JvmName("classGetInlinedClass")
private fun getInlinedClass(clazz: Class): Class? =
if (hasInlineModifier(clazz) || isImplicitInlineClass(clazz)) {
clazz
} else {
getNativePointedSuperclass(clazz)
}
if (hasInlineModifier(clazz) || isImplicitInlineClass(clazz)) {
clazz
} else {
getNativePointedSuperclass(clazz)
}
inline fun <R> unwrapToPrimitiveOrReference(
type: Type,
eachInlinedClass: (inlinedClass: Class, nullable: Boolean) -> Unit,
ifPrimitive: (primitiveType: KonanPrimitiveType, nullable: Boolean) -> R,
ifReference: (type: Type) -> R
type: Type,
eachInlinedClass: (inlinedClass: Class, nullable: Boolean) -> Unit,
ifPrimitive: (primitiveType: KonanPrimitiveType, nullable: Boolean) -> R,
ifReference: (type: Type) -> R,
): R {
var currentType: Type = type
@@ -179,10 +182,10 @@ abstract class InlineClassesSupport<Class : Any, Type : Any> {
fun representationIsNullable(type: Type): Boolean {
unwrapToPrimitiveOrReference(
type,
eachInlinedClass = { _, nullable -> if (nullable) return true },
ifPrimitive = { _, nullable -> return nullable },
ifReference = { return isNullable(it) }
type,
eachInlinedClass = { _, nullable -> if (nullable) return true },
ifPrimitive = { _, nullable -> return nullable },
ifReference = { return isNullable(it) }
)
}
@@ -204,7 +207,7 @@ abstract class InlineClassesSupport<Class : Any, Type : Any> {
}
private fun createReferenceBinaryType(type: Type): BinaryType.Reference<Class> =
BinaryType.Reference(computeFullErasure(type), true)
BinaryType.Reference(computeFullErasure(type), true)
}
@InternalKotlinNativeApi
@@ -230,16 +233,16 @@ object KotlinTypeInlineClassesSupport : InlineClassesSupport<ClassDescriptor, Ko
override fun hasInlineModifier(clazz: ClassDescriptor): Boolean = clazz.isInlineClass()
override fun getNativePointedSuperclass(clazz: ClassDescriptor): ClassDescriptor? = clazz.getAllSuperClassifiers()
.firstOrNull { it.fqNameUnsafe == InteropFqNames.nativePointed } as ClassDescriptor?
.firstOrNull { it.fqNameUnsafe == InteropFqNames.nativePointed } as ClassDescriptor?
override fun getInlinedClassUnderlyingType(clazz: ClassDescriptor): KotlinType =
clazz.unsubstitutedPrimaryConstructor!!.valueParameters.single().type
clazz.unsubstitutedPrimaryConstructor!!.valueParameters.single().type
override fun getPackageFqName(clazz: ClassDescriptor) =
clazz.findPackage().fqName
clazz.findPackage().fqName
override fun getName(clazz: ClassDescriptor) =
clazz.name
clazz.name
override fun isTopLevelClass(clazz: ClassDescriptor): Boolean = clazz.containingDeclaration is PackageFragmentDescriptor
}
@@ -11,7 +11,7 @@ package org.jetbrains.kotlin.backend.konan
* It is not safe to depend on any internal Kotlin/Native API outside kotlin.git/kotlin-native
*/
@RequiresOptIn(
"This API is internal to the Kotlin/Native compiler and cannot be used outside of kotlin.git",
level = RequiresOptIn.Level.ERROR
"This API is internal to the Kotlin/Native compiler and cannot be used outside of kotlin.git",
level = RequiresOptIn.Level.ERROR
)
annotation class InternalKotlinNativeApi
@@ -106,11 +106,11 @@ class InteropBuiltIns(builtIns: KonanBuiltIns) {
}
private fun MemberScope.getContributedVariables(name: String) =
this.getContributedVariables(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
this.getContributedVariables(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
internal fun MemberScope.getContributedClass(name: String): ClassDescriptor =
this.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BUILTINS) as ClassDescriptor
this.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BUILTINS) as ClassDescriptor
private fun MemberScope.getContributedFunctions(name: String) =
this.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
this.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
@@ -7,42 +7,42 @@ package org.jetbrains.kotlin.backend.konan
@InternalKotlinNativeApi
val cKeywords = setOf(
// Actual C keywords.
"auto", "break", "case",
"char", "const", "continue",
"default", "do", "double",
"else", "enum", "extern",
"float", "for", "goto",
"if", "int", "long",
"register", "return",
"short", "signed", "sizeof", "static", "struct", "switch",
"typedef", "union", "unsigned",
"void", "volatile", "while",
// C99-specific.
"_Bool", "_Complex", "_Imaginary", "inline", "restrict",
// C11-specific.
"_Alignas", "_Alignof", "_Atomic", "_Generic", "_Noreturn", "_Static_assert", "_Thread_local",
// Not exactly keywords, but reserved or standard-defined.
"and", "not", "or", "xor",
"bool", "complex", "imaginary",
// Actual C keywords.
"auto", "break", "case",
"char", "const", "continue",
"default", "do", "double",
"else", "enum", "extern",
"float", "for", "goto",
"if", "int", "long",
"register", "return",
"short", "signed", "sizeof", "static", "struct", "switch",
"typedef", "union", "unsigned",
"void", "volatile", "while",
// C99-specific.
"_Bool", "_Complex", "_Imaginary", "inline", "restrict",
// C11-specific.
"_Alignas", "_Alignof", "_Atomic", "_Generic", "_Noreturn", "_Static_assert", "_Thread_local",
// Not exactly keywords, but reserved or standard-defined.
"and", "not", "or", "xor",
"bool", "complex", "imaginary",
// C++ keywords not listed above.
"alignas", "alignof", "and_eq", "asm",
"bitand", "bitor", "bool",
"catch", "char16_t", "char32_t", "class", "compl", "constexpr", "const_cast",
"decltype", "delete", "dynamic_cast",
"explicit", "export",
"false", "friend",
"inline",
"mutable",
"namespace", "new", "noexcept", "not_eq", "nullptr",
"operator", "or_eq",
"private", "protected", "public",
"reinterpret_cast",
"static_assert",
"template", "this", "thread_local", "throw", "true", "try", "typeid", "typename",
"using",
"virtual",
"wchar_t",
"xor_eq"
// C++ keywords not listed above.
"alignas", "alignof", "and_eq", "asm",
"bitand", "bitor", "bool",
"catch", "char16_t", "char32_t", "class", "compl", "constexpr", "const_cast",
"decltype", "delete", "dynamic_cast",
"explicit", "export",
"false", "friend",
"inline",
"mutable",
"namespace", "new", "noexcept", "not_eq", "nullptr",
"operator", "or_eq",
"private", "protected", "public",
"reinterpret_cast",
"static_assert",
"template", "this", "thread_local", "throw", "true", "try", "typeid", "typename",
"using",
"virtual",
"wchar_t",
"xor_eq"
)
@@ -111,7 +111,7 @@ private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
fun getSubPackages(fqName: FqName) {
result.add(fqName)
val subPackages = packageFragmentProvider?.getSubPackagesOf(fqName) { true }
?: module.getSubPackagesOf(fqName) { true }
?: module.getSubPackagesOf(fqName) { true }
subPackages.forEach { getSubPackages(it) }
}
@@ -120,16 +120,16 @@ private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
}
fun ModuleDescriptor.getPackageFragments(): List<PackageFragmentDescriptor> =
getPackagesFqNames(this).flatMap {
getPackage(it).fragments.filter { it.module == this }.toSet()
}
getPackagesFqNames(this).flatMap {
getPackage(it).fragments.filter { it.module == this }.toSet()
}
val ClassDescriptor.enumEntries: List<ClassDescriptor>
get() {
assert(this.kind == ClassKind.ENUM_CLASS)
return this.unsubstitutedMemberScope.getContributedDescriptors()
.filterIsInstance<ClassDescriptor>()
.filter { it.kind == ClassKind.ENUM_ENTRY }
.filterIsInstance<ClassDescriptor>()
.filter { it.kind == ClassKind.ENUM_ENTRY }
}
@InternalKotlinNativeApi
@@ -138,27 +138,27 @@ val DeclarationDescriptor.isExpectMember: Boolean
@InternalKotlinNativeApi
val arrayTypes = setOf(
"kotlin.Array",
"kotlin.ByteArray",
"kotlin.CharArray",
"kotlin.ShortArray",
"kotlin.IntArray",
"kotlin.LongArray",
"kotlin.FloatArray",
"kotlin.DoubleArray",
"kotlin.BooleanArray",
"kotlin.native.ImmutableBlob",
"kotlin.native.internal.NativePtrArray"
"kotlin.Array",
"kotlin.ByteArray",
"kotlin.CharArray",
"kotlin.ShortArray",
"kotlin.IntArray",
"kotlin.LongArray",
"kotlin.FloatArray",
"kotlin.DoubleArray",
"kotlin.BooleanArray",
"kotlin.native.ImmutableBlob",
"kotlin.native.internal.NativePtrArray"
)
@InternalKotlinNativeApi
val arraysWithFixedSizeItems = setOf(
"kotlin.ByteArray",
"kotlin.CharArray",
"kotlin.ShortArray",
"kotlin.IntArray",
"kotlin.LongArray",
"kotlin.FloatArray",
"kotlin.DoubleArray",
"kotlin.BooleanArray"
"kotlin.ByteArray",
"kotlin.CharArray",
"kotlin.ShortArray",
"kotlin.IntArray",
"kotlin.LongArray",
"kotlin.FloatArray",
"kotlin.DoubleArray",
"kotlin.BooleanArray"
)
@@ -18,14 +18,18 @@ import org.jetbrains.kotlin.types.TypeUtils
@InternalKotlinNativeApi
fun ClassDescriptor.isMappedFunctionClass() =
this.getFunctionTypeKind() == FunctionTypeKind.Function &&
// Type parameters include return type.
declaredTypeParameters.size - 1 < CustomTypeMappers.functionTypeMappersArityLimit
this.getFunctionTypeKind() == FunctionTypeKind.Function &&
// Type parameters include return type.
declaredTypeParameters.size - 1 < CustomTypeMappers.functionTypeMappersArityLimit
@InternalKotlinNativeApi
interface CustomTypeMapper {
val mappedClassId: ClassId
fun mapType(mappedSuperType: KotlinType, translator: ObjCExportTranslatorImpl, objCExportScope: ObjCExportScope): ObjCNonNullReferenceType
fun mapType(
mappedSuperType: KotlinType,
translator: ObjCExportTranslatorImpl,
objCExportScope: ObjCExportScope,
): ObjCNonNullReferenceType
}
internal object CustomTypeMappers {
@@ -89,44 +93,52 @@ internal object CustomTypeMappers {
* Note: can be generated programmatically, but requires stdlib in this case.
*/
val hiddenTypes: Set<ClassId> = listOf(
"kotlin.Any",
"kotlin.CharSequence",
"kotlin.Comparable",
"kotlin.Function",
"kotlin.Number",
"kotlin.collections.Collection",
"kotlin.collections.Iterable",
"kotlin.collections.MutableCollection",
"kotlin.collections.MutableIterable"
"kotlin.Any",
"kotlin.CharSequence",
"kotlin.Comparable",
"kotlin.Function",
"kotlin.Number",
"kotlin.collections.Collection",
"kotlin.collections.Iterable",
"kotlin.collections.MutableCollection",
"kotlin.collections.MutableIterable"
).map { ClassId.topLevel(FqName(it)) }.toSet()
private class Simple(
override val mappedClassId: ClassId,
private val getObjCClassName: ObjCExportTranslatorImpl.() -> String
override val mappedClassId: ClassId,
private val getObjCClassName: ObjCExportTranslatorImpl.() -> String,
) : CustomTypeMapper {
constructor(
mappedClassId: ClassId,
objCClassName: String
mappedClassId: ClassId,
objCClassName: String,
) : this(mappedClassId, { objCClassName })
override fun mapType(mappedSuperType: KotlinType, translator: ObjCExportTranslatorImpl, objCExportScope: ObjCExportScope): ObjCNonNullReferenceType =
ObjCClassType(translator.getObjCClassName())
override fun mapType(
mappedSuperType: KotlinType,
translator: ObjCExportTranslatorImpl,
objCExportScope: ObjCExportScope,
): ObjCNonNullReferenceType =
ObjCClassType(translator.getObjCClassName())
}
private class Collection(
mappedClassFqName: FqName,
private val getObjCClassName: ObjCExportTranslatorImpl.() -> String
mappedClassFqName: FqName,
private val getObjCClassName: ObjCExportTranslatorImpl.() -> String,
) : CustomTypeMapper {
constructor(
mappedClassFqName: FqName,
objCClassName: String
mappedClassFqName: FqName,
objCClassName: String,
) : this(mappedClassFqName, { objCClassName })
override val mappedClassId = ClassId.topLevel(mappedClassFqName)
override fun mapType(mappedSuperType: KotlinType, translator: ObjCExportTranslatorImpl, objCExportScope: ObjCExportScope): ObjCNonNullReferenceType {
override fun mapType(
mappedSuperType: KotlinType,
translator: ObjCExportTranslatorImpl,
objCExportScope: ObjCExportScope,
): ObjCNonNullReferenceType {
val typeArguments = mappedSuperType.arguments.map {
val argument = it.type
if (TypeUtils.isNullableType(argument)) {
@@ -145,7 +157,11 @@ internal object CustomTypeMappers {
override val mappedClassId: ClassId
get() = StandardNames.getFunctionClassId(parameterCount)
override fun mapType(mappedSuperType: KotlinType, translator: ObjCExportTranslatorImpl, objCExportScope: ObjCExportScope): ObjCNonNullReferenceType {
override fun mapType(
mappedSuperType: KotlinType,
translator: ObjCExportTranslatorImpl,
objCExportScope: ObjCExportScope,
): ObjCNonNullReferenceType {
return translator.mapFunctionTypeIgnoringNullability(mappedSuperType, objCExportScope, returnsVoid = false)
}
}
@@ -18,14 +18,14 @@ import org.jetbrains.kotlin.name.isSubpackageOf
@InternalKotlinNativeApi
class MainPackageGuesser {
fun guess(
moduleDescriptor: ModuleDescriptor,
includedLibraryDescriptors: List<ModuleDescriptor>,
exportedDependencies: List<ModuleDescriptor>,
moduleDescriptor: ModuleDescriptor,
includedLibraryDescriptors: List<ModuleDescriptor>,
exportedDependencies: List<ModuleDescriptor>,
): FqName {
// Consider exported libraries only if we cannot infer the package from sources or included libs.
return guessMainPackage(includedLibraryDescriptors + moduleDescriptor)
?: guessMainPackage(exportedDependencies)
?: FqName.ROOT
?: guessMainPackage(exportedDependencies)
?: FqName.ROOT
}
private fun guessMainPackage(modules: List<ModuleDescriptor>): FqName? {
@@ -38,12 +38,12 @@ class MainPackageGuesser {
}
val nonEmptyPackages = allPackages
.filter { it.getMemberScope().getContributedDescriptors().isNotEmpty() }
.map { it.fqName }.distinct()
.filter { it.getMemberScope().getContributedDescriptors().isNotEmpty() }
.map { it.fqName }.distinct()
return allPackages.map { it.fqName }.distinct()
.filter { candidate -> nonEmptyPackages.all { it.isSubpackageOf(candidate) } }
// Now there are all common ancestors of non-empty packages. Longest of them is the least common accessor:
.maxByOrNull { it.asString().length }
.filter { candidate -> nonEmptyPackages.all { it.isSubpackageOf(candidate) } }
// Now there are all common ancestors of non-empty packages. Longest of them is the least common accessor:
.maxByOrNull { it.asString().length }
}
}
@@ -9,9 +9,6 @@ import org.jetbrains.kotlin.backend.common.descriptors.allParameters
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.util.allParameters
@InternalKotlinNativeApi
sealed class TypeBridge
@@ -21,8 +18,8 @@ object ReferenceBridge : TypeBridge()
@InternalKotlinNativeApi
data class BlockPointerBridge(
val numberOfParameters: Int,
val returnsVoid: Boolean
val numberOfParameters: Int,
val returnsVoid: Boolean,
) : TypeBridge()
@InternalKotlinNativeApi
@@ -50,9 +47,9 @@ sealed class MethodBridgeValueParameter : MethodBridgeParameter() {
@InternalKotlinNativeApi
data class MethodBridge(
val returnBridge: ReturnValue,
val receiver: MethodBridgeReceiver,
val valueParameters: List<MethodBridgeValueParameter>
val returnBridge: ReturnValue,
val receiver: MethodBridgeReceiver,
val valueParameters: List<MethodBridgeValueParameter>,
) {
sealed class ReturnValue {
@@ -73,15 +70,17 @@ data class MethodBridge(
}
val paramBridges: List<MethodBridgeParameter> =
listOf(receiver) + MethodBridgeSelector + valueParameters
listOf(receiver) + MethodBridgeSelector + valueParameters
// TODO: it is not exactly true in potential future cases.
val isInstance: Boolean get() = when (receiver) {
MethodBridgeReceiver.Static,
MethodBridgeReceiver.Factory -> false
val isInstance: Boolean
get() = when (receiver) {
MethodBridgeReceiver.Static,
MethodBridgeReceiver.Factory,
-> false
MethodBridgeReceiver.Instance -> true
}
MethodBridgeReceiver.Instance -> true
}
val returnsError: Boolean
get() = returnBridge is ReturnValue.WithError
@@ -89,7 +88,7 @@ data class MethodBridge(
@InternalKotlinNativeApi
fun MethodBridge.valueParametersAssociated(
descriptor: FunctionDescriptor
descriptor: FunctionDescriptor,
): List<Pair<MethodBridgeValueParameter, ParameterDescriptor?>> {
val kotlinParameters = descriptor.allParameters.iterator()
val skipFirstKotlinParameter = when (this.receiver) {
@@ -105,7 +104,8 @@ fun MethodBridge.valueParametersAssociated(
is MethodBridgeValueParameter.Mapped -> it to kotlinParameters.next()
is MethodBridgeValueParameter.SuspendCompletion,
is MethodBridgeValueParameter.ErrorOutParameter -> it to null
is MethodBridgeValueParameter.ErrorOutParameter,
-> it to null
}
}.also { assert(!kotlinParameters.hasNext()) }
}
@@ -8,14 +8,14 @@ package org.jetbrains.kotlin.backend.konan.objcexport
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
internal class ObjCExportHeaderGeneratorImpl(
moduleDescriptors: List<ModuleDescriptor>,
mapper: ObjCExportMapper,
namer: ObjCExportNamer,
problemCollector: ObjCExportProblemCollector,
objcGenerics: Boolean,
override val shouldExportKDoc: Boolean,
private val additionalImports: List<String>,
moduleDescriptors: List<ModuleDescriptor>,
mapper: ObjCExportMapper,
namer: ObjCExportNamer,
problemCollector: ObjCExportProblemCollector,
objcGenerics: Boolean,
override val shouldExportKDoc: Boolean,
private val additionalImports: List<String>,
) : ObjCExportHeaderGenerator(moduleDescriptors, mapper, namer, objcGenerics, problemCollector) {
override fun getAdditionalImports(): List<String> =
additionalImports
additionalImports
}
@@ -9,12 +9,12 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
import org.jetbrains.kotlin.backend.konan.UnitSuspendFunctionObjCExport
import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -61,35 +61,35 @@ interface ObjCExportLazy {
@JvmOverloads
fun createObjCExportLazy(
configuration: ObjCExportLazy.Configuration,
problemCollector: ObjCExportProblemCollector,
codeAnalyzer: KotlinCodeAnalyzer,
typeResolver: TypeResolver,
descriptorResolver: DescriptorResolver,
fileScopeProvider: FileScopeProvider,
builtIns: KotlinBuiltIns,
deprecationResolver: DeprecationResolver? = null
configuration: ObjCExportLazy.Configuration,
problemCollector: ObjCExportProblemCollector,
codeAnalyzer: KotlinCodeAnalyzer,
typeResolver: TypeResolver,
descriptorResolver: DescriptorResolver,
fileScopeProvider: FileScopeProvider,
builtIns: KotlinBuiltIns,
deprecationResolver: DeprecationResolver? = null,
): ObjCExportLazy = ObjCExportLazyImpl(
configuration,
problemCollector,
codeAnalyzer,
typeResolver,
descriptorResolver,
fileScopeProvider,
builtIns,
deprecationResolver
configuration,
problemCollector,
codeAnalyzer,
typeResolver,
descriptorResolver,
fileScopeProvider,
builtIns,
deprecationResolver
)
@InternalKotlinNativeApi
class ObjCExportLazyImpl(
private val configuration: ObjCExportLazy.Configuration,
problemCollector: ObjCExportProblemCollector,
private val codeAnalyzer: KotlinCodeAnalyzer,
private val typeResolver: TypeResolver,
private val descriptorResolver: DescriptorResolver,
private val fileScopeProvider: FileScopeProvider,
builtIns: KotlinBuiltIns,
deprecationResolver: DeprecationResolver?
private val configuration: ObjCExportLazy.Configuration,
problemCollector: ObjCExportProblemCollector,
private val codeAnalyzer: KotlinCodeAnalyzer,
private val typeResolver: TypeResolver,
private val descriptorResolver: DescriptorResolver,
private val fileScopeProvider: FileScopeProvider,
builtIns: KotlinBuiltIns,
deprecationResolver: DeprecationResolver?,
) : ObjCExportLazy {
private val namerConfiguration = createNamerConfiguration(configuration)
@@ -101,11 +101,11 @@ class ObjCExportLazyImpl(
private val namer = ObjCExportNamerImpl(namerConfiguration, builtIns, mapper, problemCollector, local = true)
private val translator: ObjCExportTranslator = ObjCExportTranslatorImpl(
null,
mapper,
namer,
problemCollector,
configuration.objcGenerics
null,
mapper,
namer,
problemCollector,
configuration.objcGenerics
)
private val isValid: Boolean
@@ -114,14 +114,15 @@ class ObjCExportLazyImpl(
override fun generateBase() = translator.generateBaseDeclarations()
override fun translate(file: KtFile): List<ObjCTopLevel<*>> =
translateClasses(file) + translateTopLevels(file)
translateClasses(file) + translateTopLevels(file)
private fun translateClasses(container: KtDeclarationContainer): List<ObjCClass<*>> {
val result = mutableListOf<ObjCClass<*>>()
container.declarations.forEach { declaration ->
// Supposed to be true if ObjCExportMapper.shouldBeVisible is true.
if (declaration is KtClassOrObject && declaration.isPublic && declaration !is KtEnumEntry
&& !declaration.hasExpectModifier()) {
&& !declaration.hasExpectModifier()
) {
if (!declaration.isAnnotation() && !declaration.hasModifier(KtTokens.INLINE_KEYWORD)) {
result += translateClass(declaration)
@@ -144,7 +145,7 @@ class ObjCExportLazyImpl(
LazyObjCProtocolImpl(name, ktClassOrObject, this)
} else {
val isFinal = ktClassOrObject.modalityModifier() == null ||
ktClassOrObject.hasModifier(KtTokens.FINAL_KEYWORD)
ktClassOrObject.hasModifier(KtTokens.FINAL_KEYWORD)
val attributes = if (isFinal) {
listOf(OBJC_SUBCLASSING_RESTRICTED)
@@ -152,30 +153,32 @@ class ObjCExportLazyImpl(
emptyList()
}
LazyObjCInterfaceImpl(name,
attributes,
generics = translateGenerics(ktClassOrObject),
psi = ktClassOrObject,
lazy = this)
LazyObjCInterfaceImpl(
name,
attributes,
generics = translateGenerics(ktClassOrObject),
psi = ktClassOrObject,
lazy = this
)
}
}
private fun translateGenerics(ktClassOrObject: KtClassOrObject): List<ObjCGenericTypeDeclaration> = if (configuration.objcGenerics) {
ktClassOrObject.typeParametersWithOuter
.map {
ObjCGenericTypeRawDeclaration(
nameTranslator.getTypeParameterName(it),
ObjCVariance.fromKotlinVariance(it.variance)
)
}
.toList()
.map {
ObjCGenericTypeRawDeclaration(
nameTranslator.getTypeParameterName(it),
ObjCVariance.fromKotlinVariance(it.variance)
)
}
.toList()
} else {
emptyList()
}
private fun translateTopLevels(file: KtFile): List<ObjCInterface> {
val extensions =
mutableMapOf<ClassDescriptor, MutableList<KtCallableDeclaration>>()
mutableMapOf<ClassDescriptor, MutableList<KtCallableDeclaration>>()
val topLevel = mutableListOf<KtCallableDeclaration>()
@@ -212,9 +215,9 @@ class ObjCExportLazyImpl(
}
private fun translateExtensions(
file: KtFile,
classDescriptor: ClassDescriptor,
declarations: List<KtCallableDeclaration>
file: KtFile,
classDescriptor: ClassDescriptor,
declarations: List<KtCallableDeclaration>,
): ObjCInterface {
// TODO: consider using file-based categories in compiler too.
@@ -228,13 +231,13 @@ class ObjCExportLazyImpl(
}
private fun resolveDeclaration(ktDeclaration: KtDeclaration): DeclarationDescriptor =
codeAnalyzer.resolveToDescriptor(ktDeclaration)
codeAnalyzer.resolveToDescriptor(ktDeclaration)
private fun resolve(ktClassOrObject: KtClassOrObject) =
resolveDeclaration(ktClassOrObject) as ClassDescriptor
resolveDeclaration(ktClassOrObject) as ClassDescriptor
private fun resolve(ktCallableDeclaration: KtCallableDeclaration) =
resolveDeclaration(ktCallableDeclaration) as CallableMemberDescriptor
resolveDeclaration(ktCallableDeclaration) as CallableMemberDescriptor
private fun getClassIfExtension(topLevelDeclaration: KtCallableDeclaration): ClassDescriptor? {
val receiverType = topLevelDeclaration.receiverTypeReference ?: return null
@@ -243,19 +246,19 @@ class ObjCExportLazyImpl(
val trace = BindingTraceContext() // TODO: revise.
val kotlinReceiverType = typeResolver.resolveType(
createHeaderScope(topLevelDeclaration, fileScope, trace),
receiverType,
trace,
checkBounds = false
createHeaderScope(topLevelDeclaration, fileScope, trace),
receiverType,
trace,
checkBounds = false
)
return translator.getClassIfExtension(kotlinReceiverType)
}
private fun createHeaderScope(
declaration: KtCallableDeclaration,
parent: LexicalScope,
trace: BindingTrace
declaration: KtCallableDeclaration,
parent: LexicalScope,
trace: BindingTrace,
): LexicalScope {
if (declaration.typeParameters.isEmpty()) return parent
@@ -268,30 +271,30 @@ class ObjCExportLazyImpl(
when (declaration) {
is KtFunction -> {
descriptor = SimpleFunctionDescriptorImpl.create(
parent.ownerDescriptor,
Annotations.EMPTY,
fakeName,
CallableMemberDescriptor.Kind.DECLARATION,
sourceElement
parent.ownerDescriptor,
Annotations.EMPTY,
fakeName,
CallableMemberDescriptor.Kind.DECLARATION,
sourceElement
)
scopeKind = LexicalScopeKind.FUNCTION_HEADER
}
is KtProperty -> {
descriptor = PropertyDescriptorImpl.create(
parent.ownerDescriptor,
Annotations.EMPTY,
Modality.FINAL,
DescriptorVisibilities.PUBLIC,
declaration.isVar,
fakeName,
CallableMemberDescriptor.Kind.DECLARATION,
sourceElement,
false,
false,
false,
false,
false,
false
parent.ownerDescriptor,
Annotations.EMPTY,
Modality.FINAL,
DescriptorVisibilities.PUBLIC,
declaration.isVar,
fakeName,
CallableMemberDescriptor.Kind.DECLARATION,
sourceElement,
false,
false,
false,
false,
false,
false
)
scopeKind = LexicalScopeKind.PROPERTY_HEADER
}
@@ -299,19 +302,19 @@ class ObjCExportLazyImpl(
}
val result = LexicalWritableScope(
parent,
descriptor,
false,
LocalRedeclarationChecker.DO_NOTHING,
scopeKind
parent,
descriptor,
false,
LocalRedeclarationChecker.DO_NOTHING,
scopeKind
)
val typeParameters = descriptorResolver.resolveTypeParametersForDescriptor(
descriptor,
result,
result,
declaration.typeParameters,
trace
descriptor,
result,
result,
declaration.typeParameters,
trace
)
descriptorResolver.resolveGenericBounds(declaration, descriptor, result, typeParameters, trace)
@@ -322,7 +325,7 @@ class ObjCExportLazyImpl(
private class LazyObjCProtocolImpl(
name: ObjCExportNamer.ClassOrProtocolName,
override val psi: KtClassOrObject,
private val lazy: ObjCExportLazyImpl
private val lazy: ObjCExportLazyImpl,
) : LazyObjCProtocol(name) {
override val descriptor: ClassDescriptor by lazy { lazy.resolve(psi) }
@@ -337,7 +340,7 @@ class ObjCExportLazyImpl(
attributes: List<String>,
generics: List<ObjCGenericTypeDeclaration>,
override val psi: KtClassOrObject,
private val lazy: ObjCExportLazyImpl
private val lazy: ObjCExportLazyImpl,
) : LazyObjCInterface(name = name, generics = generics, categoryName = null, attributes = attributes) {
override val descriptor: ClassDescriptor by lazy { lazy.resolve(psi) }
@@ -351,7 +354,7 @@ class ObjCExportLazyImpl(
name: ObjCExportNamer.ClassOrProtocolName,
private val file: KtFile,
private val declarations: List<KtCallableDeclaration>,
private val lazy: ObjCExportLazyImpl
private val lazy: ObjCExportLazyImpl,
) : LazyObjCInterface(name = name, generics = emptyList(), categoryName = null, attributes = listOf(OBJC_SUBCLASSING_RESTRICTED)) {
override val descriptor: ClassDescriptor?
get() = null
@@ -377,7 +380,7 @@ class ObjCExportLazyImpl(
categoryName: String,
private val classDescriptor: ClassDescriptor,
private val declarations: List<KtCallableDeclaration>,
private val lazy: ObjCExportLazyImpl
private val lazy: ObjCExportLazyImpl,
) : LazyObjCInterface(name = name.objCName, generics = emptyList(), categoryName = categoryName, attributes = emptyList()) {
override val descriptor: ClassDescriptor?
get() = null
@@ -400,17 +403,17 @@ class ObjCExportLazyImpl(
private abstract class LazyObjCInterface : ObjCInterface {
constructor(
name: ObjCExportNamer.ClassOrProtocolName,
generics: List<ObjCGenericTypeDeclaration>,
categoryName: String?,
attributes: List<String>
name: ObjCExportNamer.ClassOrProtocolName,
generics: List<ObjCGenericTypeDeclaration>,
categoryName: String?,
attributes: List<String>,
) : super(name.objCName, generics, categoryName, attributes + name.toNameAttributes())
constructor(
name: String,
generics: List<ObjCGenericTypeDeclaration>,
categoryName: String,
attributes: List<String>
name: String,
generics: List<ObjCGenericTypeDeclaration>,
categoryName: String,
attributes: List<String>,
) : super(name, generics, categoryName, attributes)
protected abstract fun computeRealStub(): ObjCInterface
@@ -431,7 +434,7 @@ private abstract class LazyObjCInterface : ObjCInterface {
}
private abstract class LazyObjCProtocol(
name: ObjCExportNamer.ClassOrProtocolName
name: ObjCExportNamer.ClassOrProtocolName,
) : ObjCProtocol(name.objCName, name.toNameAttributes()) {
protected abstract fun computeRealStub(): ObjCProtocol
@@ -469,7 +472,7 @@ private val kotlinSequenceClassId = ClassId.topLevel(FqName("kotlin.sequences.Se
// This is a special workaround needed for resolve in the IDE.
private fun ModuleDescriptor.isCommonStdlibCheckSpecificallyForIDE() =
findClassAcrossModuleDependencies(kotlinSequenceClassId)?.module == this
findClassAcrossModuleDependencies(kotlinSequenceClassId)?.module == this
private val KtModifierListOwner.isPublic: Boolean
get() = this.visibilityModifierTypeOrDefault() == KtTokens.PUBLIC_KEYWORD
@@ -479,4 +482,4 @@ internal val KtPureClassOrObject.isInterface: Boolean
internal val KtClassOrObject.typeParametersWithOuter
get() = generateSequence(this, { if (it is KtClass && it.isInner()) it.containingClassOrObject else null })
.flatMap { it.typeParameters.asSequence() }
.flatMap { it.typeParameters.asSequence() }
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.psi.KtFile
@InternalKotlinNativeApi
fun ObjCExportLazy.dumpObjCHeader(files: Collection<KtFile>, outputFile: String, shouldExportKDoc: Boolean) {
val lines = (this.generateBase() + files.flatMap { this.translate(it) })
.flatMap { StubRenderer.render(it, shouldExportKDoc) + listOf("") }
.flatMap { StubRenderer.render(it, shouldExportKDoc) + listOf("") }
File(outputFile).writeLines(lines)
}
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.builtins.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.objcinterop.*
import org.jetbrains.kotlin.ir.objcinterop.isObjCObjectType
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.DataClassResolver
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.types.typeUtil.isUnit
class ObjCExportMapper(
internal val deprecationResolver: DeprecationResolver? = null,
private val local: Boolean = false,
internal val unitSuspendFunctionExport: UnitSuspendFunctionObjCExport
internal val unitSuspendFunctionExport: UnitSuspendFunctionObjCExport,
) {
fun getCustomTypeMapper(descriptor: ClassDescriptor): CustomTypeMapper? = CustomTypeMappers.getMapper(descriptor)
@@ -38,7 +38,7 @@ class ObjCExportMapper(
fun isSpecialMapped(descriptor: ClassDescriptor): Boolean {
// TODO: this method duplicates some of the [ObjCExportTranslatorImpl.mapReferenceType] logic.
return KotlinBuiltIns.isAny(descriptor) ||
descriptor.getAllSuperClassifiers().any { it is ClassDescriptor && CustomTypeMappers.hasMapper(it) }
descriptor.getAllSuperClassifiers().any { it is ClassDescriptor && CustomTypeMappers.hasMapper(it) }
}
private val methodBridgeCache = mutableMapOf<FunctionDescriptor, MethodBridge>()
@@ -122,13 +122,14 @@ internal fun ClassDescriptor.isHiddenFromObjC(): Boolean = when {
}
internal fun ObjCExportMapper.shouldBeExposed(descriptor: ClassDescriptor): Boolean =
shouldBeVisible(descriptor) && !isSpecialMapped(descriptor) && !descriptor.defaultType.isObjCObjectType()
shouldBeVisible(descriptor) && !isSpecialMapped(descriptor) && !descriptor.defaultType.isObjCObjectType()
private fun ObjCExportMapper.isHiddenByDeprecation(descriptor: CallableMemberDescriptor): Boolean {
// Note: ObjCExport generally expect overrides of exposed methods to be exposed.
// So don't hide a "deprecated hidden" method which overrides non-hidden one:
if (deprecationResolver != null && deprecationResolver.isDeprecatedHidden(descriptor) &&
descriptor.overriddenDescriptors.all { isHiddenByDeprecation(it) }) {
descriptor.overriddenDescriptors.all { isHiddenByDeprecation(it) }
) {
return true
}
@@ -185,14 +186,14 @@ private fun ObjCExportMapper.isHiddenByDeprecation(descriptor: ClassDescriptor):
// Note: the logic is partially duplicated in ObjCExportLazyImpl.translateClasses.
internal fun ObjCExportMapper.shouldBeVisible(descriptor: ClassDescriptor): Boolean =
descriptor.isEffectivelyPublicApi && when (descriptor.kind) {
descriptor.isEffectivelyPublicApi && when (descriptor.kind) {
ClassKind.CLASS, ClassKind.INTERFACE, ClassKind.ENUM_CLASS, ClassKind.OBJECT -> true
ClassKind.ENUM_ENTRY, ClassKind.ANNOTATION_CLASS -> false
} && !descriptor.isExpect && !descriptor.isInlined() && !isHiddenByDeprecation(descriptor) && !descriptor.isHiddenFromObjC()
private fun ObjCExportMapper.isBase(descriptor: CallableMemberDescriptor): Boolean =
descriptor.overriddenDescriptors.all { !shouldBeExposed(it) }
// e.g. it is not `override`, or overrides only unexposed methods.
descriptor.overriddenDescriptors.all { !shouldBeExposed(it) }
// e.g. it is not `override`, or overrides only unexposed methods.
/**
* Check that given [descriptor] is a so-called "base method", i.e. method
@@ -240,21 +241,21 @@ fun ObjCExportMapper.getBaseProperties(descriptor: PropertyDescriptor): List<Pro
@Suppress("NO_TAIL_CALLS_FOUND", "NON_TAIL_RECURSIVE_CALL") // K2 warning suppression, TODO: KT-62472
internal tailrec fun KotlinType.getErasedTypeClass(): ClassDescriptor =
TypeUtils.getClassDescriptor(this) ?: this.constructor.supertypes.first().getErasedTypeClass()
TypeUtils.getClassDescriptor(this) ?: this.constructor.supertypes.first().getErasedTypeClass()
internal fun ObjCExportMapper.isTopLevel(descriptor: CallableMemberDescriptor): Boolean =
descriptor.containingDeclaration !is ClassDescriptor && this.getClassIfCategory(descriptor) == null
descriptor.containingDeclaration !is ClassDescriptor && this.getClassIfCategory(descriptor) == null
internal fun ObjCExportMapper.isObjCProperty(property: PropertyDescriptor): Boolean =
property.extensionReceiverParameter == null || getClassIfCategory(property) != null
property.extensionReceiverParameter == null || getClassIfCategory(property) != null
@InternalKotlinNativeApi
fun ClassDescriptor.getEnumValuesFunctionDescriptor(): SimpleFunctionDescriptor? {
require(this.kind == ClassKind.ENUM_CLASS)
return this.staticScope.getContributedFunctions(
StandardNames.ENUM_VALUES,
NoLookupLocation.FROM_BACKEND
StandardNames.ENUM_VALUES,
NoLookupLocation.FROM_BACKEND
).singleOrNull { it.extensionReceiverParameter == null && it.valueParameters.size == 0 }
}
@@ -263,8 +264,8 @@ fun ClassDescriptor.getEnumEntriesPropertyDescriptor(): PropertyDescriptor? {
require(this.kind == ClassKind.ENUM_CLASS)
return this.staticScope.getContributedVariables(
StandardNames.ENUM_ENTRIES,
NoLookupLocation.FROM_BACKEND
StandardNames.ENUM_ENTRIES,
NoLookupLocation.FROM_BACKEND
).singleOrNull { it.extensionReceiverParameter == null }
}
@@ -273,38 +274,38 @@ internal fun ObjCExportMapper.doesThrow(method: FunctionDescriptor): Boolean = m
}
private fun ObjCExportMapper.bridgeType(
kotlinType: KotlinType
kotlinType: KotlinType,
): TypeBridge = kotlinType.unwrapToPrimitiveOrReference<TypeBridge>(
eachInlinedClass = { inlinedClass, _ ->
when (inlinedClass.classId) {
UnsignedType.UBYTE.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_CHAR)
UnsignedType.USHORT.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_SHORT)
UnsignedType.UINT.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_INT)
UnsignedType.ULONG.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_LONG_LONG)
}
},
ifPrimitive = { primitiveType, _ ->
val objCValueType = when (primitiveType) {
KonanPrimitiveType.BOOLEAN -> ObjCValueType.BOOL
KonanPrimitiveType.CHAR -> ObjCValueType.UNICHAR
KonanPrimitiveType.BYTE -> ObjCValueType.CHAR
KonanPrimitiveType.SHORT -> ObjCValueType.SHORT
KonanPrimitiveType.INT -> ObjCValueType.INT
KonanPrimitiveType.LONG -> ObjCValueType.LONG_LONG
KonanPrimitiveType.FLOAT -> ObjCValueType.FLOAT
KonanPrimitiveType.DOUBLE -> ObjCValueType.DOUBLE
KonanPrimitiveType.NON_NULL_NATIVE_PTR -> ObjCValueType.POINTER
KonanPrimitiveType.VECTOR128 -> TODO()
}
ValueTypeBridge(objCValueType)
},
ifReference = {
if (kotlinType.isFunctionType) {
bridgeFunctionType(kotlinType)
} else {
ReferenceBridge
}
eachInlinedClass = { inlinedClass, _ ->
when (inlinedClass.classId) {
UnsignedType.UBYTE.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_CHAR)
UnsignedType.USHORT.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_SHORT)
UnsignedType.UINT.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_INT)
UnsignedType.ULONG.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_LONG_LONG)
}
},
ifPrimitive = { primitiveType, _ ->
val objCValueType = when (primitiveType) {
KonanPrimitiveType.BOOLEAN -> ObjCValueType.BOOL
KonanPrimitiveType.CHAR -> ObjCValueType.UNICHAR
KonanPrimitiveType.BYTE -> ObjCValueType.CHAR
KonanPrimitiveType.SHORT -> ObjCValueType.SHORT
KonanPrimitiveType.INT -> ObjCValueType.INT
KonanPrimitiveType.LONG -> ObjCValueType.LONG_LONG
KonanPrimitiveType.FLOAT -> ObjCValueType.FLOAT
KonanPrimitiveType.DOUBLE -> ObjCValueType.DOUBLE
KonanPrimitiveType.NON_NULL_NATIVE_PTR -> ObjCValueType.POINTER
KonanPrimitiveType.VECTOR128 -> TODO()
}
ValueTypeBridge(objCValueType)
},
ifReference = {
if (kotlinType.isFunctionType) {
bridgeFunctionType(kotlinType)
} else {
ReferenceBridge
}
}
)
private fun ObjCExportMapper.bridgeFunctionType(kotlinType: KotlinType): TypeBridge {
@@ -323,8 +324,8 @@ private fun ObjCExportMapper.bridgeParameter(parameter: ParameterDescriptor): Me
MethodBridgeValueParameter.Mapped(bridgeType(parameter.type))
private fun ObjCExportMapper.bridgeReturnType(
descriptor: FunctionDescriptor,
convertExceptionsToErrors: Boolean
descriptor: FunctionDescriptor,
convertExceptionsToErrors: Boolean,
): MethodBridge.ReturnValue {
val returnType = descriptor.returnType!!
return when {
@@ -343,7 +344,7 @@ private fun ObjCExportMapper.bridgeReturnType(
}
descriptor.containingDeclaration.let { it is ClassDescriptor && KotlinBuiltIns.isAny(it) } &&
descriptor.name.asString() == "hashCode" -> {
descriptor.name.asString() == "hashCode" -> {
assert(!convertExceptionsToErrors)
MethodBridge.ReturnValue.HashCode
}
@@ -365,8 +366,8 @@ private fun ObjCExportMapper.bridgeReturnType(
if (convertExceptionsToErrors) {
val canReturnZero = !returnTypeBridge.isReferenceOrPointer() || TypeUtils.isNullableType(returnType)
MethodBridge.ReturnValue.WithError.ZeroForError(
successReturnValueBridge,
successMayBeZero = canReturnZero
successReturnValueBridge,
successMayBeZero = canReturnZero
)
} else {
successReturnValueBridge
@@ -457,7 +458,7 @@ enum class NSNumberKind(val mappedKotlinClassId: ClassId?, val objCType: ObjCTyp
// UNSIGNED_SHORT -> unsignedShort
private val kindName = this.name.split('_')
.joinToString("") { it.lowercase().replaceFirstChar(Char::uppercaseChar) }.replaceFirstChar(Char::lowercaseChar)
.joinToString("") { it.lowercase().replaceFirstChar(Char::uppercaseChar) }.replaceFirstChar(Char::lowercaseChar)
val valueSelector = kindName // unsignedShort
@@ -465,13 +466,13 @@ enum class NSNumberKind(val mappedKotlinClassId: ClassId?, val objCType: ObjCTyp
val factorySelector = "numberWith${kindName.replaceFirstChar(Char::uppercaseChar)}:" // numberWithUnsignedShort:
constructor(
primitiveType: PrimitiveType,
objCPrimitiveType: ObjCPrimitiveType
primitiveType: PrimitiveType,
objCPrimitiveType: ObjCPrimitiveType,
) : this(ClassId.topLevel(primitiveType.typeFqName), objCPrimitiveType)
constructor(
unsignedType: UnsignedType,
objCPrimitiveType: ObjCPrimitiveType
unsignedType: UnsignedType,
objCPrimitiveType: ObjCPrimitiveType,
) : this(unsignedType.classId, objCPrimitiveType)
constructor(objCPrimitiveType: ObjCPrimitiveType) : this(null, objCPrimitiveType)
@@ -39,7 +39,7 @@ internal interface ObjCExportNameTranslator {
fun getCategoryName(file: KtFile): String
fun getClassOrProtocolName(
ktClassOrObject: KtClassOrObject
ktClassOrObject: KtClassOrObject,
): ObjCExportNamer.ClassOrProtocolName
fun getTypeParameterName(ktTypeParameter: KtTypeParameter): String
@@ -90,57 +90,61 @@ interface ObjCExportNamer {
companion object {
@InternalKotlinNativeApi
const val kotlinThrowableAsErrorMethodName: String = "asError"
@InternalKotlinNativeApi
const val objectPropertyName: String = "shared"
@InternalKotlinNativeApi
const val companionObjectPropertyName: String = "companion"
}
}
fun createNamer(moduleDescriptor: ModuleDescriptor,
topLevelNamePrefix: String): ObjCExportNamer =
createNamer(moduleDescriptor, emptyList(), topLevelNamePrefix)
fun createNamer(
moduleDescriptor: ModuleDescriptor,
topLevelNamePrefix: String,
): ObjCExportNamer =
createNamer(moduleDescriptor, emptyList(), topLevelNamePrefix)
fun createNamer(
moduleDescriptor: ModuleDescriptor,
exportedDependencies: List<ModuleDescriptor>,
topLevelNamePrefix: String
moduleDescriptor: ModuleDescriptor,
exportedDependencies: List<ModuleDescriptor>,
topLevelNamePrefix: String,
): ObjCExportNamer = ObjCExportNamerImpl(
(exportedDependencies + moduleDescriptor).toSet(),
moduleDescriptor.builtIns,
ObjCExportMapper(local = true, unitSuspendFunctionExport = UnitSuspendFunctionObjCExport.DEFAULT),
ObjCExportProblemCollector.SILENT,
topLevelNamePrefix,
local = true
(exportedDependencies + moduleDescriptor).toSet(),
moduleDescriptor.builtIns,
ObjCExportMapper(local = true, unitSuspendFunctionExport = UnitSuspendFunctionObjCExport.DEFAULT),
ObjCExportProblemCollector.SILENT,
topLevelNamePrefix,
local = true
)
// Note: this class duplicates some of ObjCExportNamerImpl logic,
// but operates on different representation.
internal open class ObjCExportNameTranslatorImpl(
private val configuration: ObjCExportNamer.Configuration
private val configuration: ObjCExportNamer.Configuration,
) : ObjCExportNameTranslator {
private val helper = ObjCExportNamingHelper(configuration.topLevelNamePrefix, configuration.objcGenerics)
override fun getFileClassName(file: KtFile): ObjCExportNamer.ClassOrProtocolName =
helper.getFileClassName(file)
helper.getFileClassName(file)
override fun getCategoryName(file: KtFile): String =
helper.translateFileName(file)
helper.translateFileName(file)
override fun getClassOrProtocolName(ktClassOrObject: KtClassOrObject): ObjCExportNamer.ClassOrProtocolName =
ObjCExportNamer.ClassOrProtocolName(
swiftName = getClassOrProtocolAsSwiftName(ktClassOrObject, true),
objCName = buildString {
getClassOrProtocolAsSwiftName(ktClassOrObject, false).split('.').forEachIndexed { index, part ->
append(if (index == 0) part else part.replaceFirstChar(Char::uppercaseChar))
}
}
)
ObjCExportNamer.ClassOrProtocolName(
swiftName = getClassOrProtocolAsSwiftName(ktClassOrObject, true),
objCName = buildString {
getClassOrProtocolAsSwiftName(ktClassOrObject, false).split('.').forEachIndexed { index, part ->
append(if (index == 0) part else part.replaceFirstChar(Char::uppercaseChar))
}
}
)
private fun getClassOrProtocolAsSwiftName(
ktClassOrObject: KtClassOrObject,
forSwift: Boolean
ktClassOrObject: KtClassOrObject,
forSwift: Boolean,
): String = buildString {
val objCName = ktClassOrObject.getObjCName()
if (objCName.isExact) {
@@ -157,20 +161,20 @@ internal open class ObjCExportNameTranslatorImpl(
}
private fun StringBuilder.appendNameWithContainer(
ktClassOrObject: KtClassOrObject,
objCName: ObjCName,
outerClass: KtClassOrObject,
forSwift: Boolean
ktClassOrObject: KtClassOrObject,
objCName: ObjCName,
outerClass: KtClassOrObject,
forSwift: Boolean,
) = helper.appendNameWithContainer(
this,
ktClassOrObject, objCName.asIdentifier(forSwift),
outerClass, getClassOrProtocolAsSwiftName(outerClass, forSwift),
object : ObjCExportNamingHelper.ClassInfoProvider<KtClassOrObject> {
override fun hasGenerics(clazz: KtClassOrObject): Boolean =
clazz.typeParametersWithOuter.count() != 0
this,
ktClassOrObject, objCName.asIdentifier(forSwift),
outerClass, getClassOrProtocolAsSwiftName(outerClass, forSwift),
object : ObjCExportNamingHelper.ClassInfoProvider<KtClassOrObject> {
override fun hasGenerics(clazz: KtClassOrObject): Boolean =
clazz.typeParametersWithOuter.count() != 0
override fun isInterface(clazz: KtClassOrObject): Boolean = ktClassOrObject.isInterface
}
override fun isInterface(clazz: KtClassOrObject): Boolean = ktClassOrObject.isInterface
}
)
override fun getTypeParameterName(ktTypeParameter: KtTypeParameter): String = buildString {
@@ -180,12 +184,12 @@ internal open class ObjCExportNameTranslatorImpl(
}
private class ObjCExportNamingHelper(
private val topLevelNamePrefix: String,
private val objcGenerics: Boolean
private val topLevelNamePrefix: String,
private val objcGenerics: Boolean,
) {
fun translateFileName(fileName: String): String =
PackagePartClassUtils.getFilePartShortName(fileName).toIdentifier()
PackagePartClassUtils.getFilePartShortName(fileName).toIdentifier()
fun translateFileName(file: KtFile): String = translateFileName(file.name)
@@ -195,15 +199,15 @@ private class ObjCExportNamingHelper(
}
fun getFileClassName(file: KtFile): ObjCExportNamer.ClassOrProtocolName =
getFileClassName(file.name)
getFileClassName(file.name)
fun <T> appendNameWithContainer(
builder: StringBuilder,
clazz: T,
ownName: String,
containingClass: T,
containerName: String,
provider: ClassInfoProvider<T>
builder: StringBuilder,
clazz: T,
ownName: String,
containingClass: T,
containerName: String,
provider: ClassInfoProvider<T>,
) = builder.apply {
if (clazz.canBeSwiftInner(provider)) {
append(containerName)
@@ -271,54 +275,56 @@ private class ObjCExportNamingHelper(
fun isTypeParameterNameReserved(name: String): Boolean = name in reservedTypeParameterNames
private val reservedTypeParameterNames = setOf("id", "NSObject", "NSArray", "NSCopying", "NSNumber", "NSInteger",
"NSUInteger", "NSString", "NSSet", "NSDictionary", "NSMutableArray", "int", "unsigned", "short",
"char", "long", "float", "double", "int32_t", "int64_t", "int16_t", "int8_t", "unichar")
private val reservedTypeParameterNames = setOf(
"id", "NSObject", "NSArray", "NSCopying", "NSNumber", "NSInteger",
"NSUInteger", "NSString", "NSSet", "NSDictionary", "NSMutableArray", "int", "unsigned", "short",
"char", "long", "float", "double", "int32_t", "int64_t", "int16_t", "int8_t", "unichar"
)
}
@InternalKotlinNativeApi
class ObjCExportNamerImpl(
private val configuration: ObjCExportNamer.Configuration,
builtIns: KotlinBuiltIns,
private val mapper: ObjCExportMapper,
private val problemCollector: ObjCExportProblemCollector,
private val local: Boolean
private val configuration: ObjCExportNamer.Configuration,
builtIns: KotlinBuiltIns,
private val mapper: ObjCExportMapper,
private val problemCollector: ObjCExportProblemCollector,
private val local: Boolean,
) : ObjCExportNamer {
constructor(
moduleDescriptors: Set<ModuleDescriptor>,
builtIns: KotlinBuiltIns,
mapper: ObjCExportMapper,
problemCollector: ObjCExportProblemCollector,
topLevelNamePrefix: String,
local: Boolean,
objcGenerics: Boolean = false,
disableSwiftMemberNameMangling: Boolean = false,
ignoreInterfaceMethodCollisions: Boolean = false,
reportNameCollisions: Boolean = false,
moduleDescriptors: Set<ModuleDescriptor>,
builtIns: KotlinBuiltIns,
mapper: ObjCExportMapper,
problemCollector: ObjCExportProblemCollector,
topLevelNamePrefix: String,
local: Boolean,
objcGenerics: Boolean = false,
disableSwiftMemberNameMangling: Boolean = false,
ignoreInterfaceMethodCollisions: Boolean = false,
reportNameCollisions: Boolean = false,
) : this(
object : ObjCExportNamer.Configuration {
override val topLevelNamePrefix: String
get() = topLevelNamePrefix
object : ObjCExportNamer.Configuration {
override val topLevelNamePrefix: String
get() = topLevelNamePrefix
override fun getAdditionalPrefix(module: ModuleDescriptor): String? =
if (module in moduleDescriptors) null else module.objCExportAdditionalNamePrefix
override fun getAdditionalPrefix(module: ModuleDescriptor): String? =
if (module in moduleDescriptors) null else module.objCExportAdditionalNamePrefix
override val objcGenerics: Boolean
get() = objcGenerics
override val objcGenerics: Boolean
get() = objcGenerics
override val disableSwiftMemberNameMangling: Boolean
get() = disableSwiftMemberNameMangling
override val disableSwiftMemberNameMangling: Boolean
get() = disableSwiftMemberNameMangling
override val ignoreInterfaceMethodCollisions: Boolean
get() = ignoreInterfaceMethodCollisions
override val ignoreInterfaceMethodCollisions: Boolean
get() = ignoreInterfaceMethodCollisions
override val reportNameCollisions: Boolean
get() = reportNameCollisions
},
builtIns,
mapper,
problemCollector,
local
override val reportNameCollisions: Boolean
get() = reportNameCollisions
},
builtIns,
mapper,
problemCollector,
local
)
private val objcGenerics get() = configuration.objcGenerics
@@ -326,8 +332,8 @@ class ObjCExportNamerImpl(
private val helper = ObjCExportNamingHelper(configuration.topLevelNamePrefix, objcGenerics)
private fun String.toSpecialStandardClassOrProtocolName() = ObjCExportNamer.ClassOrProtocolName(
swiftName = "Kotlin$this",
objCName = "${topLevelNamePrefix}$this"
swiftName = "Kotlin$this",
objCName = "${topLevelNamePrefix}$this"
)
override val kotlinAnyName = "Base".toSpecialStandardClassOrProtocolName()
@@ -336,7 +342,7 @@ class ObjCExportNamerImpl(
override val mutableMapName = "MutableDictionary".toSpecialStandardClassOrProtocolName()
override fun numberBoxName(classId: ClassId): ObjCExportNamer.ClassOrProtocolName =
classId.shortClassName.asString().toSpecialStandardClassOrProtocolName()
classId.shortClassName.asString().toSpecialStandardClassOrProtocolName()
override val kotlinNumberName = "Number".toSpecialStandardClassOrProtocolName()
@@ -345,15 +351,15 @@ class ObjCExportNamerImpl(
// Try to avoid clashing with critical NSObject instance methods:
private val reserved = setOf(
"retain", "release", "autorelease",
"class", "superclass",
"hash"
"retain", "release", "autorelease",
"class", "superclass",
"hash"
)
override fun reserved(name: String) = name in reserved
override fun conflict(first: FunctionDescriptor, second: FunctionDescriptor): Boolean =
!mapper.canHaveSameSelector(first, second, configuration.ignoreInterfaceMethodCollisions)
!mapper.canHaveSameSelector(first, second, configuration.ignoreInterfaceMethodCollisions)
}
private val methodSwiftNames = object : Mapping<FunctionDescriptor, String>() {
@@ -393,11 +399,11 @@ class ObjCExportNamerImpl(
// Try to avoid clashing with NSObject class methods:
private val reserved = setOf(
"retain", "release", "autorelease",
"initialize", "load", "alloc", "new", "class", "superclass",
"classFallbacksForKeyedArchiver", "classForKeyedUnarchiver",
"description", "debugDescription", "version", "hash",
"useStoredAccessor"
"retain", "release", "autorelease",
"initialize", "load", "alloc", "new", "class", "superclass",
"classFallbacksForKeyedArchiver", "classForKeyedUnarchiver",
"description", "debugDescription", "version", "hash",
"useStoredAccessor"
)
override fun reserved(name: String) = (name in reserved) || (name in cKeywords)
@@ -409,7 +415,7 @@ class ObjCExportNamerImpl(
private inner class EnumNameMapping : ClassSelectorNameMapping<DeclarationDescriptor>() {
override fun conflict(first: DeclarationDescriptor, second: DeclarationDescriptor) =
first.containingDeclaration == second.containingDeclaration
first.containingDeclaration == second.containingDeclaration
}
private val enumClassSelectors = EnumNameMapping()
@@ -440,13 +446,13 @@ class ObjCExportNamerImpl(
}
override fun getClassOrProtocolName(descriptor: ClassDescriptor): ObjCExportNamer.ClassOrProtocolName =
ObjCExportNamer.ClassOrProtocolName(
swiftName = getClassOrProtocolSwiftName(descriptor),
objCName = getClassOrProtocolObjCName(descriptor)
)
ObjCExportNamer.ClassOrProtocolName(
swiftName = getClassOrProtocolSwiftName(descriptor),
objCName = getClassOrProtocolObjCName(descriptor)
)
private fun getClassOrProtocolSwiftName(
descriptor: ClassDescriptor
descriptor: ClassDescriptor,
): String = swiftClassAndProtocolNames.getOrPut(descriptor) {
StringBuilder().apply {
val objCName = descriptor.getObjCName()
@@ -466,19 +472,19 @@ class ObjCExportNamerImpl(
}
private fun StringBuilder.appendSwiftNameWithContainer(
clazz: ClassDescriptor,
objCName: ObjCName,
containingClass: ClassDescriptor
clazz: ClassDescriptor,
objCName: ObjCName,
containingClass: ClassDescriptor,
) = helper.appendNameWithContainer(
this,
clazz, objCName.asIdentifier(true),
containingClass, getClassOrProtocolSwiftName(containingClass),
object : ObjCExportNamingHelper.ClassInfoProvider<ClassDescriptor> {
override fun hasGenerics(clazz: ClassDescriptor): Boolean =
clazz.typeConstructor.parameters.isNotEmpty()
this,
clazz, objCName.asIdentifier(true),
containingClass, getClassOrProtocolSwiftName(containingClass),
object : ObjCExportNamingHelper.ClassInfoProvider<ClassDescriptor> {
override fun hasGenerics(clazz: ClassDescriptor): Boolean =
clazz.typeConstructor.parameters.isNotEmpty()
override fun isInterface(clazz: ClassDescriptor): Boolean = clazz.isInterface
}
override fun isInterface(clazz: ClassDescriptor): Boolean = clazz.isInterface
}
)
private fun getClassOrProtocolObjCName(descriptor: ClassDescriptor): String {
@@ -492,7 +498,7 @@ class ObjCExportNamerImpl(
val containingDeclaration = descriptor.containingDeclaration
if (containingDeclaration is ClassDescriptor) {
append(getClassOrProtocolObjCName(containingDeclaration))
.append(objCName.asIdentifier(false).replaceFirstChar(Char::uppercaseChar))
.append(objCName.asIdentifier(false).replaceFirstChar(Char::uppercaseChar))
} else if (containingDeclaration is PackageFragmentDescriptor) {
append(topLevelNamePrefix).appendTopLevelClassBaseName(descriptor, objCName, false)
} else {
@@ -537,12 +543,14 @@ class ObjCExportNamerImpl(
}
if (index == 0) {
append(when {
bridge is MethodBridgeValueParameter.ErrorOutParameter -> "AndReturn"
bridge is MethodBridgeValueParameter.SuspendCompletion -> "With"
method is ConstructorDescriptor -> "With"
else -> ""
})
append(
when {
bridge is MethodBridgeValueParameter.ErrorOutParameter -> "AndReturn"
bridge is MethodBridgeValueParameter.SuspendCompletion -> "With"
method is ConstructorDescriptor -> "With"
else -> ""
}
)
append(name.replaceFirstChar(Char::uppercaseChar))
} else {
append(name)
@@ -618,8 +626,8 @@ class ObjCExportNamerImpl(
}
}
return ObjCExportNamer.PropertyName(
swiftName = swiftPropertyNames.getOrPut(true),
objCName = objCPropertyNames.getOrPut(false)
swiftName = swiftPropertyNames.getOrPut(true),
objCName = objCPropertyNames.getOrPut(false)
)
}
@@ -628,7 +636,7 @@ class ObjCExportNamerImpl(
return objectInstanceSelectors.getOrPut(descriptor) {
val name = descriptor.getObjCName().asString(false)
.replaceFirstChar(Char::lowercaseChar).toIdentifier().mangleIfSpecialFamily("get")
.replaceFirstChar(Char::lowercaseChar).toIdentifier().mangleIfSpecialFamily("get")
StringBuilder(name).mangledBySuffixUnderscores()
}
}
@@ -701,9 +709,9 @@ class ObjCExportNamerImpl(
val any = builtIns.any
val predefinedClassNames = mapOf(
builtIns.any to kotlinAnyName,
builtIns.mutableSet to mutableSetName,
builtIns.mutableMap to mutableMapName
builtIns.any to kotlinAnyName,
builtIns.mutableSet to mutableSetName,
builtIns.mutableMap to mutableMapName
)
predefinedClassNames.forEach { (descriptor, name) ->
@@ -712,10 +720,10 @@ class ObjCExportNamerImpl(
}
fun ClassDescriptor.method(name: Name) =
this.unsubstitutedMemberScope.getContributedFunctions(
name,
NoLookupLocation.FROM_BACKEND
).single()
this.unsubstitutedMemberScope.getContributedFunctions(
name,
NoLookupLocation.FROM_BACKEND
).single()
Predefined.anyMethodSelectors.forEach { (name, selector) ->
methodSelectors.forceAssign(any.method(name), selector)
@@ -728,21 +736,21 @@ class ObjCExportNamerImpl(
private object Predefined {
val anyMethodSelectors = mapOf(
"hashCode" to "hash",
"toString" to "description",
"equals" to "isEqual:"
"hashCode" to "hash",
"toString" to "description",
"equals" to "isEqual:"
).mapKeys { Name.identifier(it.key) }
val anyMethodSwiftNames = mapOf(
"hashCode" to "hash()",
"toString" to "description()",
"equals" to "isEqual(_:)"
"hashCode" to "hash()",
"toString" to "description()",
"equals" to "isEqual(_:)"
).mapKeys { Name.identifier(it.key) }
}
private object Reserved {
val propertyNames = cKeywords +
setOf("description") // https://youtrack.jetbrains.com/issue/KT-38641
setOf("description") // https://youtrack.jetbrains.com/issue/KT-38641
}
private fun FunctionDescriptor.getMangledName(forSwift: Boolean): String {
@@ -777,7 +785,7 @@ class ObjCExportNamerImpl(
}
private fun String.startsWithWords(words: String) = this.startsWith(words) &&
(this.length == words.length || !this[words.length].isLowerCase())
(this.length == words.length || !this[words.length].isLowerCase())
private inner class GenericTypeParameterNameMapping {
private val elementToName = mutableMapOf<TypeParameterDescriptor, String>()
@@ -818,7 +826,7 @@ class ObjCExportNamerImpl(
assert(element.containingDeclaration is ClassDescriptor)
return !objCClassNames.nameExists(name) && !objCProtocolNames.nameExists(name) &&
(local || name !in classNameSet(element))
(local || name !in classNameSet(element))
}
private fun classNameSet(element: TypeParameterDescriptor): MutableSet<String> {
@@ -893,14 +901,18 @@ class ObjCExportNamerImpl(
}
private inline fun StringBuilder.mangledSequence(crossinline mangle: StringBuilder.() -> Unit) =
generateSequence(this.toString()) {
this@mangledSequence.mangle()
this@mangledSequence.toString()
}
generateSequence(this.toString()) {
this@mangledSequence.mangle()
this@mangledSequence.toString()
}
private fun StringBuilder.mangledBySuffixUnderscores() = this.mangledSequence { append("_") }
private fun ObjCExportMapper.canHaveCommonSubtype(first: ClassDescriptor, second: ClassDescriptor, ignoreInterfaceMethodCollisions: Boolean): Boolean {
private fun ObjCExportMapper.canHaveCommonSubtype(
first: ClassDescriptor,
second: ClassDescriptor,
ignoreInterfaceMethodCollisions: Boolean,
): Boolean {
if (first.isSubclassOf(second) || second.isSubclassOf(first)) {
return true
}
@@ -913,13 +925,13 @@ private fun ObjCExportMapper.canHaveCommonSubtype(first: ClassDescriptor, second
}
private fun ObjCExportMapper.canBeInheritedBySameClass(
first: CallableMemberDescriptor,
second: CallableMemberDescriptor,
ignoreInterfaceMethodCollisions: Boolean
first: CallableMemberDescriptor,
second: CallableMemberDescriptor,
ignoreInterfaceMethodCollisions: Boolean,
): Boolean {
if (this.isTopLevel(first) || this.isTopLevel(second)) {
return this.isTopLevel(first) && this.isTopLevel(second) &&
first.propertyIfAccessor.findSourceFile() == second.propertyIfAccessor.findSourceFile()
first.propertyIfAccessor.findSourceFile() == second.propertyIfAccessor.findSourceFile()
}
val firstClass = this.getClassIfCategory(first) ?: first.containingDeclaration as ClassDescriptor
@@ -936,7 +948,11 @@ private fun ObjCExportMapper.canBeInheritedBySameClass(
return canHaveCommonSubtype(firstClass, secondClass, ignoreInterfaceMethodCollisions)
}
private fun ObjCExportMapper.canHaveSameSelector(first: FunctionDescriptor, second: FunctionDescriptor, ignoreInterfaceMethodCollisions: Boolean): Boolean {
private fun ObjCExportMapper.canHaveSameSelector(
first: FunctionDescriptor,
second: FunctionDescriptor,
ignoreInterfaceMethodCollisions: Boolean,
): Boolean {
assert(isBaseMethod(first))
assert(isBaseMethod(second))
@@ -968,7 +984,11 @@ private fun ObjCExportMapper.canHaveSameSelector(first: FunctionDescriptor, seco
return bridgeMethod(first) == bridgeMethod(second)
}
private fun ObjCExportMapper.canHaveSameName(first: PropertyDescriptor, second: PropertyDescriptor, ignoreInterfaceMethodCollisions: Boolean): Boolean {
private fun ObjCExportMapper.canHaveSameName(
first: PropertyDescriptor,
second: PropertyDescriptor,
ignoreInterfaceMethodCollisions: Boolean,
): Boolean {
assert(isBaseProperty(first))
assert(isObjCProperty(first))
assert(isBaseProperty(second))
@@ -991,17 +1011,17 @@ private fun ObjCExportMapper.canHaveSameName(first: PropertyDescriptor, second:
}
private class ObjCName(
private val kotlinName: String,
private val objCName: String?,
private val swiftName: String?,
val isExact: Boolean
private val kotlinName: String,
private val objCName: String?,
private val swiftName: String?,
val isExact: Boolean,
) {
// TODO: Prevent mangling when objCName or swiftName is provided
fun asString(forSwift: Boolean): String = swiftName.takeIf { forSwift } ?: objCName ?: kotlinName
fun asIdentifier(forSwift: Boolean, default: (String) -> String = { it.toIdentifier() }): String =
swiftName.takeIf { forSwift } ?: objCName ?: default(kotlinName)
swiftName.takeIf { forSwift } ?: objCName ?: default(kotlinName)
}
private fun DeclarationDescriptor.getObjCName(): ObjCName {
@@ -1019,7 +1039,7 @@ private fun DeclarationDescriptor.getObjCName(): ObjCName {
private fun <T> T.upcast(): T = this
private fun CallableDescriptor.getObjCName(): ObjCName =
overriddenDescriptors.firstOrNull()?.getObjCName() ?: upcast<DeclarationDescriptor>().getObjCName()
overriddenDescriptors.firstOrNull()?.getObjCName() ?: upcast<DeclarationDescriptor>().getObjCName()
private fun ParameterDescriptor.getObjCName(): ObjCName {
val callableDescriptor = containingDeclaration as? CallableDescriptor ?: return upcast<CallableDescriptor>().getObjCName()
@@ -1053,7 +1073,7 @@ private fun KtClassOrObject.getObjCName(): ObjCName {
}
fun ValueArgument.getBooleanValue(): Boolean =
(getArgumentExpression() as? KtConstantExpression)?.text?.toBooleanStrictOrNull() ?: false
(getArgumentExpression() as? KtConstantExpression)?.text?.toBooleanStrictOrNull() ?: false
val argNames = setOf("name", "swiftName", "exact")
val processedArgs = mutableSetOf<String>()
@@ -1070,26 +1090,27 @@ private fun KtClassOrObject.getObjCName(): ObjCName {
return ObjCName(name!!, objCName, swiftName, isExact)
}
internal val ModuleDescriptor.objCExportAdditionalNamePrefix: String get() {
if (this.isNativeStdlib()) return "Kotlin"
internal val ModuleDescriptor.objCExportAdditionalNamePrefix: String
get() {
if (this.isNativeStdlib()) return "Kotlin"
val fullPrefix = when(val module = this.klibModuleOrigin) {
CurrentKlibModuleOrigin ->
error("expected deserialized module, got $this (origin = $module)")
SyntheticModulesOrigin ->
this.name.asString().let { it.substring(1, it.lastIndex) }
is DeserializedKlibModuleOrigin ->
module.library.let { it.shortName ?: it.uniqueName }
val fullPrefix = when (val module = this.klibModuleOrigin) {
CurrentKlibModuleOrigin ->
error("expected deserialized module, got $this (origin = $module)")
SyntheticModulesOrigin ->
this.name.asString().let { it.substring(1, it.lastIndex) }
is DeserializedKlibModuleOrigin ->
module.library.let { it.shortName ?: it.uniqueName }
}
return abbreviate(fullPrefix)
}
return abbreviate(fullPrefix)
}
fun abbreviate(name: String): String {
val normalizedName = name
.replaceFirstChar(Char::uppercaseChar)
.replace("-|\\.".toRegex(), "_")
.replaceFirstChar(Char::uppercaseChar)
.replace("-|\\.".toRegex(), "_")
val uppers = normalizedName.filterIndexed { index, character -> index == 0 || character.isUpperCase() }
if (uppers.length >= 3) return uppers
@@ -1104,8 +1125,8 @@ internal fun String.toValidObjCSwiftIdentifier(): String {
if (this.isEmpty()) return "__"
return this.replace('$', '_') // TODO: handle more special characters.
.let { if (it.first().isDigit()) "_$it" else it }
.let { if (it == "_") "__" else it }
.let { if (it.first().isDigit()) "_$it" else it }
.let { if (it == "_") "__" else it }
}
// Private shortcut.
@@ -22,7 +22,7 @@ interface ObjCExportScope {
fun deriveForType(kotlinType: KotlinType): ObjCTypeExportScope = ObjCTypeExportScopeImpl(kotlinType, this)
fun deriveForClass(container: DeclarationDescriptor, namer: ObjCExportNamer): ObjCClassExportScope =
ObjCClassExportScopeImpl(container, namer, this)
ObjCClassExportScopeImpl(container, namer, this)
}
internal inline fun <reified T : ObjCExportScope> ObjCExportScope.nearestScopeOfType(): T? {
@@ -44,16 +44,16 @@ interface ObjCClassExportScope : ObjCExportScope {
}
private class ObjCClassExportScopeImpl constructor(
container: DeclarationDescriptor,
val namer: ObjCExportNamer,
override val parent: ObjCExportScope?,
container: DeclarationDescriptor,
val namer: ObjCExportNamer,
override val parent: ObjCExportScope?,
) : ObjCClassExportScope {
private val typeParameterNames: List<TypeParameterDescriptor> =
if (container is ClassDescriptor && !container.isInterface) {
container.typeConstructor.parameters
} else {
emptyList<TypeParameterDescriptor>()
}
if (container is ClassDescriptor && !container.isInterface) {
container.typeConstructor.parameters
} else {
emptyList<TypeParameterDescriptor>()
}
override fun getGenericTypeUsage(typeParameterDescriptor: TypeParameterDescriptor?): ObjCGenericTypeUsage? {
return typeParameterDescriptor?.let { descriptor ->
@@ -12,7 +12,15 @@ class ObjCExportTranslatorMobile internal constructor(private val delegate: ObjC
companion object {
fun create(namer: ObjCExportNamer, configuration: ObjCExportLazy.Configuration): ObjCExportTranslatorMobile {
val mapper = ObjCExportMapper(local = true, unitSuspendFunctionExport = configuration.unitSuspendFunctionExport)
return ObjCExportTranslatorMobile(ObjCExportTranslatorImpl(null, mapper, namer, ObjCExportProblemCollector.SILENT, configuration.objcGenerics))
return ObjCExportTranslatorMobile(
ObjCExportTranslatorImpl(
null,
mapper,
namer,
ObjCExportProblemCollector.SILENT,
configuration.objcGenerics
)
)
}
}
@@ -17,5 +17,5 @@ class ObjCExportedInterface internal constructor(
val topLevel: Map<SourceFile, List<CallableMemberDescriptor>>,
val headerLines: List<String>,
val namer: ObjCExportNamer,
val mapper: ObjCExportMapper
val mapper: ObjCExportMapper,
)
@@ -8,5 +8,5 @@ package org.jetbrains.kotlin.backend.konan.objcexport
data class ObjCExportedStubs(
val classForwardDeclarations: Set<ObjCClassForwardDeclaration>,
val protocolForwardDeclarations: Set<String>,
val stubs: List<Stub<*>>
val stubs: List<Stub<*>>,
)
@@ -11,9 +11,9 @@ import org.jetbrains.kotlin.konan.file.File
// Later it will accept an object with ObjC declarations instead of lines.
class ObjCHeaderWriter {
fun write(
headerName: String,
headerLines: List<String>,
headersDirectory: File,
headerName: String,
headerLines: List<String>,
headersDirectory: File,
) {
headersDirectory.child(headerName).writeLines(headerLines)
}
@@ -7,23 +7,24 @@ import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.module
class ObjcExportHeaderGeneratorMobile internal constructor(
moduleDescriptors: List<ModuleDescriptor>,
mapper: ObjCExportMapper,
namer: ObjCExportNamer,
problemCollector: ObjCExportProblemCollector,
objcGenerics: Boolean,
private val restrictToLocalModules: Boolean
moduleDescriptors: List<ModuleDescriptor>,
mapper: ObjCExportMapper,
namer: ObjCExportNamer,
problemCollector: ObjCExportProblemCollector,
objcGenerics: Boolean,
private val restrictToLocalModules: Boolean,
) : ObjCExportHeaderGenerator(moduleDescriptors, mapper, namer, objcGenerics, problemCollector) {
companion object {
fun createInstance(
configuration: ObjCExportLazy.Configuration,
problemCollector: ObjCExportProblemCollector,
builtIns: KotlinBuiltIns,
moduleDescriptors: List<ModuleDescriptor>,
deprecationResolver: DeprecationResolver? = null,
local: Boolean = false,
restrictToLocalModules: Boolean = false): ObjCExportHeaderGenerator {
configuration: ObjCExportLazy.Configuration,
problemCollector: ObjCExportProblemCollector,
builtIns: KotlinBuiltIns,
moduleDescriptors: List<ModuleDescriptor>,
deprecationResolver: DeprecationResolver? = null,
local: Boolean = false,
restrictToLocalModules: Boolean = false,
): ObjCExportHeaderGenerator {
val mapper = ObjCExportMapper(deprecationResolver, local, configuration.unitSuspendFunctionExport)
val namerConfiguration = createNamerConfiguration(configuration)
val namer = ObjCExportNamerImpl(namerConfiguration, builtIns, mapper, problemCollector, local)
@@ -5,11 +5,11 @@
package org.jetbrains.kotlin.backend.konan.objcexport
import org.jetbrains.kotlin.backend.common.serialization.extractSerializedKdocString
import org.jetbrains.kotlin.backend.common.serialization.metadata.findKDocString
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.backend.common.serialization.extractSerializedKdocString
import org.jetbrains.kotlin.backend.common.serialization.metadata.findKDocString
object StubRenderer {
fun render(stub: Stub<*>): List<String> = render(stub, false)
@@ -39,7 +39,8 @@ object StubRenderer {
if (it.startsWith("/**") && it.endsWith("*/")) {
// Nested comment is allowed inside of preformatted ``` block in kdoc but not in ObjC
val kdocClean = "/**${it.substring(3, it.length - 2).replace("*/", "**").replace("/*", "**")}$kDocEnding"
kdocClean.lines().map { it.trim().let {
kdocClean.lines().map {
it.trim().let {
if (it.isNotEmpty() && it[0] == '*') " $it"
else it
}
@@ -51,7 +52,7 @@ object StubRenderer {
val kDocAndComment = kDoc?.filterNot { it.isEmpty() }.orEmpty().toMutableList()
comment?.contentLines?.let { commentLine ->
if (!kDoc.isNullOrEmpty()) kDocAndComment.add(" *") // Separator between nonempty kDoc and nonempty comment
commentLine.forEach { kDocAndComment.add(findPositionToInsertGeneratedCommentLine(kDocAndComment, it), " * $it")}
commentLine.forEach { kDocAndComment.add(findPositionToInsertGeneratedCommentLine(kDocAndComment, it), " * $it") }
}
if (kDocAndComment.isNotEmpty()) {
+"" // Probably makes the output more readable.
@@ -137,8 +138,10 @@ object StubRenderer {
}
fun appendParameters() {
assert(method.selectors.size == method.parameters.size ||
method.selectors.size == 1 && method.parameters.size == 0)
assert(
method.selectors.size == method.parameters.size ||
method.selectors.size == 1 && method.parameters.size == 0
)
if (method.selectors.size == 1 && method.parameters.size == 0) {
append(method.selectors[0])
@@ -248,5 +251,5 @@ fun formatGenerics(buffer: Appendable, generics: List<Any>) {
private fun DeclarationDescriptor.extractKDocString(): String? {
return (this as? DeclarationDescriptorWithSource)?.findKDocString()
?: extractSerializedKdocString()
?: extractSerializedKdocString()
}
@@ -17,11 +17,11 @@ sealed class ObjCType {
fun render() = render("")
protected fun String.withAttrsAndName(attrsAndName: String) =
if (attrsAndName.isEmpty()) this else "$this ${attrsAndName.trimStart()}"
if (attrsAndName.isEmpty()) this else "$this ${attrsAndName.trimStart()}"
}
data class ObjCRawType(
val rawText: String
val rawText: String,
) : ObjCType() {
override fun render(attrsAndName: String): String = rawText.withAttrsAndName(attrsAndName)
}
@@ -31,8 +31,8 @@ sealed class ObjCReferenceType : ObjCType()
sealed class ObjCNonNullReferenceType : ObjCReferenceType()
data class ObjCNullableReferenceType(
val nonNullType: ObjCNonNullReferenceType,
val isNullableResult: Boolean = false
val nonNullType: ObjCNonNullReferenceType,
val isNullableResult: Boolean = false,
) : ObjCReferenceType() {
override fun render(attrsAndName: String): String {
val attribute = if (isNullableResult) objcNullableResultAttribute else objcNullableAttribute
@@ -41,8 +41,8 @@ data class ObjCNullableReferenceType(
}
data class ObjCClassType(
val className: String,
val typeArguments: List<ObjCNonNullReferenceType> = emptyList()
val className: String,
val typeArguments: List<ObjCNonNullReferenceType> = emptyList(),
) : ObjCNonNullReferenceType() {
override fun render(attrsAndName: String) = buildString {
@@ -57,7 +57,7 @@ data class ObjCClassType(
}
}
sealed class ObjCGenericTypeUsage: ObjCNonNullReferenceType() {
sealed class ObjCGenericTypeUsage : ObjCNonNullReferenceType() {
abstract val typeName: String
final override fun render(attrsAndName: String): String {
return typeName.withAttrsAndName(attrsAndName)
@@ -67,15 +67,15 @@ sealed class ObjCGenericTypeUsage: ObjCNonNullReferenceType() {
data class ObjCGenericTypeRawUsage(override val typeName: String) : ObjCGenericTypeUsage()
data class ObjCGenericTypeParameterUsage(
val typeParameterDescriptor: TypeParameterDescriptor,
val namer: ObjCExportNamer
val typeParameterDescriptor: TypeParameterDescriptor,
val namer: ObjCExportNamer,
) : ObjCGenericTypeUsage() {
override val typeName: String
get() = namer.getTypeParameterName(typeParameterDescriptor)
}
data class ObjCProtocolType(
val protocolName: String
val protocolName: String,
) : ObjCNonNullReferenceType() {
override fun render(attrsAndName: String) = "id<$protocolName>".withAttrsAndName(attrsAndName)
}
@@ -89,8 +89,8 @@ object ObjCInstanceType : ObjCNonNullReferenceType() {
}
data class ObjCBlockPointerType(
val returnType: ObjCType,
val parameterTypes: List<ObjCReferenceType>
val returnType: ObjCType,
val parameterTypes: List<ObjCReferenceType>,
) : ObjCNonNullReferenceType() {
override fun render(attrsAndName: String) = returnType.render(buildString {
@@ -108,7 +108,7 @@ object ObjCMetaClassType : ObjCNonNullReferenceType() {
}
sealed class ObjCPrimitiveType(
val cName: String
val cName: String,
) : ObjCType() {
object NSUInteger : ObjCPrimitiveType("NSUInteger")
object BOOL : ObjCPrimitiveType("BOOL")
@@ -125,29 +125,33 @@ sealed class ObjCPrimitiveType(
object double : ObjCPrimitiveType("double")
object NSInteger : ObjCPrimitiveType("NSInteger")
object char : ObjCPrimitiveType("char")
object unsigned_char: ObjCPrimitiveType("unsigned char")
object unsigned_short: ObjCPrimitiveType("unsigned short")
object int: ObjCPrimitiveType("int")
object unsigned_int: ObjCPrimitiveType("unsigned int")
object long: ObjCPrimitiveType("long")
object unsigned_long: ObjCPrimitiveType("unsigned long")
object long_long: ObjCPrimitiveType("long long")
object unsigned_long_long: ObjCPrimitiveType("unsigned long long")
object short: ObjCPrimitiveType("short")
object unsigned_char : ObjCPrimitiveType("unsigned char")
object unsigned_short : ObjCPrimitiveType("unsigned short")
object int : ObjCPrimitiveType("int")
object unsigned_int : ObjCPrimitiveType("unsigned int")
object long : ObjCPrimitiveType("long")
object unsigned_long : ObjCPrimitiveType("unsigned long")
object long_long : ObjCPrimitiveType("long long")
object unsigned_long_long : ObjCPrimitiveType("unsigned long long")
object short : ObjCPrimitiveType("short")
override fun render(attrsAndName: String) = cName.withAttrsAndName(attrsAndName)
}
data class ObjCPointerType(
val pointee: ObjCType,
val nullable: Boolean = false
val pointee: ObjCType,
val nullable: Boolean = false,
) : ObjCType() {
override fun render(attrsAndName: String) =
pointee.render("*${if (nullable) {
" $objcNullableAttribute".withAttrsAndName(attrsAndName)
} else {
attrsAndName
}}")
pointee.render(
"*${
if (nullable) {
" $objcNullableAttribute".withAttrsAndName(attrsAndName)
} else {
attrsAndName
}
}"
)
}
object ObjCVoidType : ObjCType() {
@@ -158,6 +162,7 @@ object ObjCVoidType : ObjCType() {
enum class ObjCValueType(val encoding: String) {
BOOL("c"),
UNICHAR("S"),
// TODO: Switch to explicit SIGNED_CHAR
CHAR("c"),
SHORT("s"),
@@ -193,13 +198,13 @@ sealed class ObjCGenericTypeDeclaration {
}
data class ObjCGenericTypeRawDeclaration(
override val typeName: String,
override val variance: ObjCVariance = ObjCVariance.INVARIANT
override val typeName: String,
override val variance: ObjCVariance = ObjCVariance.INVARIANT,
) : ObjCGenericTypeDeclaration()
data class ObjCGenericTypeParameterDeclaration(
val typeParameterDescriptor: TypeParameterDescriptor,
val namer: ObjCExportNamer
val typeParameterDescriptor: TypeParameterDescriptor,
val namer: ObjCExportNamer,
) : ObjCGenericTypeDeclaration() {
override val typeName: String
get() = namer.getTypeParameterName(typeParameterDescriptor)
@@ -6,7 +6,10 @@
package org.jetbrains.kotlin.backend.konan.objcexport
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
@@ -15,8 +18,8 @@ class ObjCComment(val contentLines: List<String>) {
}
data class ObjCClassForwardDeclaration(
val className: String,
val typeDeclarations: List<ObjCGenericTypeDeclaration> = emptyList()
val className: String,
val typeDeclarations: List<ObjCGenericTypeDeclaration> = emptyList(),
)
abstract class Stub<out D : DeclarationDescriptor>(val name: String, val comment: ObjCComment? = null) {
@@ -29,78 +32,89 @@ abstract class Stub<out D : DeclarationDescriptor>(val name: String, val comment
abstract class ObjCTopLevel<out D : DeclarationDescriptor>(name: String, comment: ObjCComment? = null) : Stub<D>(name, comment)
abstract class ObjCClass<out D : DeclarationDescriptor>(name: String,
val attributes: List<String>,
comment: ObjCComment? = null) : ObjCTopLevel<D>(name, comment) {
abstract class ObjCClass<out D : DeclarationDescriptor>(
name: String,
val attributes: List<String>,
comment: ObjCComment? = null,
) : ObjCTopLevel<D>(name, comment) {
abstract val superProtocols: List<String>
abstract val members: List<Stub<*>>
}
abstract class ObjCProtocol(name: String,
attributes: List<String>,
comment: ObjCComment? = null) : ObjCClass<ClassDescriptor>(name, attributes, comment)
abstract class ObjCProtocol(
name: String,
attributes: List<String>,
comment: ObjCComment? = null,
) : ObjCClass<ClassDescriptor>(name, attributes, comment)
class ObjCProtocolImpl(
name: String,
override val descriptor: ClassDescriptor,
override val superProtocols: List<String>,
override val members: List<Stub<*>>,
attributes: List<String> = emptyList(),
comment: ObjCComment? = null) : ObjCProtocol(name, attributes, comment)
name: String,
override val descriptor: ClassDescriptor,
override val superProtocols: List<String>,
override val members: List<Stub<*>>,
attributes: List<String> = emptyList(),
comment: ObjCComment? = null,
) : ObjCProtocol(name, attributes, comment)
abstract class ObjCInterface(name: String,
val generics: List<ObjCGenericTypeDeclaration>,
val categoryName: String?,
attributes: List<String>,
comment: ObjCComment? = null) : ObjCClass<ClassDescriptor>(name, attributes, comment) {
abstract class ObjCInterface(
name: String,
val generics: List<ObjCGenericTypeDeclaration>,
val categoryName: String?,
attributes: List<String>,
comment: ObjCComment? = null,
) : ObjCClass<ClassDescriptor>(name, attributes, comment) {
abstract val superClass: String?
abstract val superClassGenerics: List<ObjCNonNullReferenceType>
}
class ObjCInterfaceImpl(
name: String,
generics: List<ObjCGenericTypeDeclaration> = emptyList(),
override val descriptor: ClassDescriptor? = null,
override val superClass: String? = null,
override val superClassGenerics: List<ObjCNonNullReferenceType> = emptyList(),
override val superProtocols: List<String> = emptyList(),
categoryName: String? = null,
override val members: List<Stub<*>> = emptyList(),
attributes: List<String> = emptyList(),
comment: ObjCComment? = null
name: String,
generics: List<ObjCGenericTypeDeclaration> = emptyList(),
override val descriptor: ClassDescriptor? = null,
override val superClass: String? = null,
override val superClassGenerics: List<ObjCNonNullReferenceType> = emptyList(),
override val superProtocols: List<String> = emptyList(),
categoryName: String? = null,
override val members: List<Stub<*>> = emptyList(),
attributes: List<String> = emptyList(),
comment: ObjCComment? = null,
) : ObjCInterface(name, generics, categoryName, attributes, comment)
class ObjCMethod(
override val descriptor: DeclarationDescriptor?,
val isInstanceMethod: Boolean,
val returnType: ObjCType,
val selectors: List<String>,
val parameters: List<ObjCParameter>,
val attributes: List<String>,
comment: ObjCComment? = null
override val descriptor: DeclarationDescriptor?,
val isInstanceMethod: Boolean,
val returnType: ObjCType,
val selectors: List<String>,
val parameters: List<ObjCParameter>,
val attributes: List<String>,
comment: ObjCComment? = null,
) : Stub<DeclarationDescriptor>(buildMethodName(selectors, parameters), comment)
class ObjCParameter(name: String,
override val descriptor: ParameterDescriptor?,
val type: ObjCType) : Stub<ParameterDescriptor>(name)
class ObjCParameter(
name: String,
override val descriptor: ParameterDescriptor?,
val type: ObjCType,
) : Stub<ParameterDescriptor>(name)
class ObjCProperty(name: String,
override val descriptor: DeclarationDescriptorWithSource?,
val type: ObjCType,
val propertyAttributes: List<String>,
val setterName: String? = null,
val getterName: String? = null,
val declarationAttributes: List<String> = emptyList(),
comment: ObjCComment? = null) : Stub<DeclarationDescriptorWithSource>(name, comment) {
class ObjCProperty(
name: String,
override val descriptor: DeclarationDescriptorWithSource?,
val type: ObjCType,
val propertyAttributes: List<String>,
val setterName: String? = null,
val getterName: String? = null,
val declarationAttributes: List<String> = emptyList(),
comment: ObjCComment? = null,
) : Stub<DeclarationDescriptorWithSource>(name, comment) {
@Deprecated("", ReplaceWith("this.propertyAttributes"), DeprecationLevel.WARNING)
val attributes: List<String> get() = propertyAttributes
}
private fun buildMethodName(selectors: List<String>, parameters: List<ObjCParameter>): String =
if (selectors.size == 1 && parameters.size == 0) {
selectors[0]
} else {
assert(selectors.size == parameters.size)
selectors.joinToString(separator = "")
}
if (selectors.size == 1 && parameters.size == 0) {
selectors[0]
} else {
assert(selectors.size == parameters.size)
selectors.joinToString(separator = "")
}
@@ -13,7 +13,7 @@ import java.io.File
import kotlin.test.fail
abstract class AbstractObjCExportHeaderGeneratorTest(
private val generator: ObjCExportHeaderGenerator
private val generator: ObjCExportHeaderGenerator,
) {
fun interface ObjCExportHeaderGenerator {
@@ -39,7 +39,7 @@ import java.io.File
fun createModuleDescriptor(
environment: KotlinCoreEnvironment,
tempDir: File,
kotlinSources: List<String>
kotlinSources: List<String>,
): ModuleDescriptor {
val testModuleRoot = tempDir.resolve("testModule")
testModuleRoot.mkdirs()
@@ -74,7 +74,7 @@ fun createModuleDescriptor(
}
fun createKotlinCoreEnvironment(
disposable: Disposable, compilerConfiguration: CompilerConfiguration = createCompilerConfiguration()
disposable: Disposable, compilerConfiguration: CompilerConfiguration = createCompilerConfiguration(),
): KotlinCoreEnvironment {
return KotlinCoreEnvironment.createForTests(
parentDisposable = disposable,
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
internal fun createObjCExportNamerConfiguration(
topLevelNamePrefix: String = "",
additionalPrefix: (moduleName: Name) -> String? = { null }
additionalPrefix: (moduleName: Name) -> String? = { null },
): ObjCExportNamer.Configuration {
return object : ObjCExportNamer.Configuration {
override val topLevelNamePrefix: String get() = topLevelNamePrefix
@@ -30,7 +30,7 @@ internal fun createObjCExportNamerConfiguration(
internal fun createObjCExportMapper(
deprecationResolver: DeprecationResolver? = null,
local: Boolean = false,
unitSuspendFunctionObjCExport: UnitSuspendFunctionObjCExport = UnitSuspendFunctionObjCExport.DEFAULT
unitSuspendFunctionObjCExport: UnitSuspendFunctionObjCExport = UnitSuspendFunctionObjCExport.DEFAULT,
): ObjCExportMapper {
return ObjCExportMapper(deprecationResolver, local, unitSuspendFunctionObjCExport)
}
@@ -84,9 +84,11 @@ class ObjCExportMapperTest : InlineSourceTestEnvironment {
val intClassDescriptor = module.findClassAcrossModuleDependencies(ClassId.fromString("kotlin/Int"))!!
/* Represents List<Int> */
val listOfIntType = KotlinTypeFactory.simpleNotNullType(TypeAttributes.Empty, listClassDescriptor, listOf(
TypeProjectionImpl(KotlinTypeFactory.simpleNotNullType(TypeAttributes.Empty, intClassDescriptor, emptyList()))
))
val listOfIntType = KotlinTypeFactory.simpleNotNullType(
TypeAttributes.Empty, listClassDescriptor, listOf(
TypeProjectionImpl(KotlinTypeFactory.simpleNotNullType(TypeAttributes.Empty, intClassDescriptor, emptyList()))
)
)
val typeMapper = assertNotNull(objcExportMapper.getCustomTypeMapper(listClassDescriptor))
assertEquals(ClassId.fromString("kotlin/collections/List"), typeMapper.mappedClassId)
@@ -96,12 +96,14 @@ class ObjCExportNamerTest : InlineSourceTestEnvironment {
val foo = module.getPackage(FqName.ROOT).memberScope.findFirstVariable("foo") { true }!!
assertEquals(
PropertyName("foo", "foo"),
createObjCExportNamer(createObjCExportNamerConfiguration(topLevelNamePrefix = "X")).getPropertyName(foo))
createObjCExportNamer(createObjCExportNamerConfiguration(topLevelNamePrefix = "X")).getPropertyName(foo)
)
}
@Test
fun `test - function inside class`() {
val module = createModuleDescriptor("""
val module = createModuleDescriptor(
"""
package bar
class Foo {
fun someFunction(a: Int, b: Int) = a + b
@@ -117,10 +119,12 @@ class ObjCExportNamerTest : InlineSourceTestEnvironment {
@Test
fun `test - class with ObjCName annotation`() {
val module = createModuleDescriptor("""
val module = createModuleDescriptor(
"""
@kotlin.native.ObjCName("ObjCFoo", "SwiftFoo")
class Foo
""".trimIndent())
""".trimIndent()
)
val fooClass = module.findClassAcrossModuleDependencies(ClassId.fromString("Foo"))!!
assertEquals(
@@ -139,10 +143,12 @@ class ObjCExportNamerTest : InlineSourceTestEnvironment {
@Test
fun `test - parameter with ObjCName annotation`() {
val module = createModuleDescriptor("""
val module = createModuleDescriptor(
"""
import kotlin.native.ObjCName
fun foo(@ObjCName("aObjC", "aSwift") a: Int)
""".trimIndent())
""".trimIndent()
)
val foo = module.getPackage(FqName.ROOT).memberScope.findSingleFunction(Name.identifier("foo"))
val parameterA = foo.valueParameters.find { it.name == Name.identifier("a") }!!
@@ -152,14 +158,18 @@ class ObjCExportNamerTest : InlineSourceTestEnvironment {
@Test
fun `test - class mangling`() {
val module = createModuleDescriptor {
source("""
source(
"""
package a
class Foo
""".trimIndent())
source("""
""".trimIndent()
)
source(
"""
package b
class Foo
""".trimIndent())
""".trimIndent()
)
}
val aFoo = module.findClassAcrossModuleDependencies(ClassId.fromString("a/Foo"))!!
@@ -175,11 +185,13 @@ class ObjCExportNamerTest : InlineSourceTestEnvironment {
@Test
fun `test - simple enum`() {
val module = createModuleDescriptor("""
val module = createModuleDescriptor(
"""
enum class Foo {
A, B, C
}
""".trimIndent())
""".trimIndent()
)
val foo = module.findClassAcrossModuleDependencies(ClassId.fromString("Foo"))!!
val fooA = foo.enumEntries.find { it.name == Name.identifier("A") }!!