[Interop] Additional simple mangling of special names such as Companion (#3919)
This commit is contained in:
+16
@@ -44,6 +44,22 @@ fun String.asSimpleName(): String = if (this in kotlinKeywords || this.contains(
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Yet another mangler, particularly to avoid secondary clash, e.g. when a property
|
||||||
|
* in prototype (interface) is mangled and that will cause another clash in the class
|
||||||
|
* which implements this interface.
|
||||||
|
* Rationale: keep algorithm simple but use the mangling characters which are rare
|
||||||
|
* in normal code, and keep mangling easy readable.
|
||||||
|
*/
|
||||||
|
internal fun mangleSimple(name: String): String {
|
||||||
|
val reserved = setOf("Companion")
|
||||||
|
val postfix = "\$"
|
||||||
|
return if (name in reserved)
|
||||||
|
"$name$postfix"
|
||||||
|
else
|
||||||
|
name
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the expression to be parsed by Kotlin as string literal with given contents,
|
* Returns the expression to be parsed by Kotlin as string literal with given contents,
|
||||||
* i.e. transforms `foo$bar` to `"foo\$bar"`.
|
* i.e. transforms `foo$bar` to `"foo\$bar"`.
|
||||||
|
|||||||
+1
@@ -407,6 +407,7 @@ fun mirror(declarationMapper: DeclarationMapper, type: Type): TypeMirror = when
|
|||||||
is EnumType -> {
|
is EnumType -> {
|
||||||
val pkg = declarationMapper.getPackageFor(type.def)
|
val pkg = declarationMapper.getPackageFor(type.def)
|
||||||
val kotlinName = declarationMapper.getKotlinNameForValue(type.def)
|
val kotlinName = declarationMapper.getKotlinNameForValue(type.def)
|
||||||
|
.let { mangleSimple(it) } // enum class requires additional mangling
|
||||||
|
|
||||||
when {
|
when {
|
||||||
declarationMapper.isMappedToStrict(type.def) -> {
|
declarationMapper.isMappedToStrict(type.def) -> {
|
||||||
|
|||||||
+1
-1
@@ -583,7 +583,7 @@ private class ObjCPropertyStubBuilder(
|
|||||||
is ObjCCategory -> ClassifierStubType(context.getKotlinClassFor(container.clazz, isMeta = property.getter.isClass))
|
is ObjCCategory -> ClassifierStubType(context.getKotlinClassFor(container.clazz, isMeta = property.getter.isClass))
|
||||||
}
|
}
|
||||||
val origin = StubOrigin.ObjCProperty(property, container)
|
val origin = StubOrigin.ObjCProperty(property, container)
|
||||||
return listOf(PropertyStub(property.name, kotlinType.toStubIrType(), kind, modality, receiver, origin = origin))
|
return listOf(PropertyStub(mangleSimple(property.name), kotlinType.toStubIrType(), kind, modality, receiver, origin = origin))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-5
@@ -88,6 +88,7 @@ internal class StructStubBuilder(
|
|||||||
val fieldRefType = context.mirror(field.type)
|
val fieldRefType = context.mirror(field.type)
|
||||||
val unwrappedFieldType = field.type.unwrapTypedefs()
|
val unwrappedFieldType = field.type.unwrapTypedefs()
|
||||||
val origin = StubOrigin.StructMember(field)
|
val origin = StubOrigin.StructMember(field)
|
||||||
|
val fieldName = mangleSimple(field.name)
|
||||||
if (unwrappedFieldType is ArrayType) {
|
if (unwrappedFieldType is ArrayType) {
|
||||||
val type = (fieldRefType as TypeMirror.ByValue).valueType
|
val type = (fieldRefType as TypeMirror.ByValue).valueType
|
||||||
val annotations = if (platform == KotlinPlatform.JVM) {
|
val annotations = if (platform == KotlinPlatform.JVM) {
|
||||||
@@ -103,7 +104,7 @@ internal class StructStubBuilder(
|
|||||||
}
|
}
|
||||||
val kind = PropertyStub.Kind.Val(getter)
|
val kind = PropertyStub.Kind.Val(getter)
|
||||||
// TODO: Should receiver be added?
|
// TODO: Should receiver be added?
|
||||||
PropertyStub(field.name, type.toStubIrType(), kind, annotations = annotations, origin = origin)
|
PropertyStub(fieldName, type.toStubIrType(), kind, annotations = annotations, origin = origin)
|
||||||
} else {
|
} else {
|
||||||
val pointedType = fieldRefType.pointedType.toStubIrType()
|
val pointedType = fieldRefType.pointedType.toStubIrType()
|
||||||
val pointedTypeArgument = TypeArgumentStub(pointedType)
|
val pointedTypeArgument = TypeArgumentStub(pointedType)
|
||||||
@@ -121,14 +122,14 @@ internal class StructStubBuilder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val kind = PropertyStub.Kind.Var(getter, setter)
|
val kind = PropertyStub.Kind.Var(getter, setter)
|
||||||
PropertyStub(field.name, fieldRefType.argType.toStubIrType(), kind, origin = origin)
|
PropertyStub(fieldName, fieldRefType.argType.toStubIrType(), kind, origin = origin)
|
||||||
} else {
|
} else {
|
||||||
val accessor = when (context.generationMode) {
|
val accessor = when (context.generationMode) {
|
||||||
GenerationMode.SOURCE_CODE -> PropertyAccessor.Getter.MemberAt(offset, hasValueAccessor = false)
|
GenerationMode.SOURCE_CODE -> PropertyAccessor.Getter.MemberAt(offset, hasValueAccessor = false)
|
||||||
GenerationMode.METADATA -> PropertyAccessor.Getter.ExternalGetter(listOf(AnnotationStub.CStruct.MemberAt(offset)))
|
GenerationMode.METADATA -> PropertyAccessor.Getter.ExternalGetter(listOf(AnnotationStub.CStruct.MemberAt(offset)))
|
||||||
}
|
}
|
||||||
val kind = PropertyStub.Kind.Val(accessor)
|
val kind = PropertyStub.Kind.Val(accessor)
|
||||||
PropertyStub(field.name, pointedType, kind, origin = origin)
|
PropertyStub(fieldName, pointedType, kind, origin = origin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
@@ -141,6 +142,7 @@ internal class StructStubBuilder(
|
|||||||
val typeInfo = typeMirror.info
|
val typeInfo = typeMirror.info
|
||||||
val kotlinType = typeMirror.argType
|
val kotlinType = typeMirror.argType
|
||||||
val signed = field.type.isIntegerTypeSigned()
|
val signed = field.type.isIntegerTypeSigned()
|
||||||
|
val fieldName = mangleSimple(field.name)
|
||||||
val kind = when (context.generationMode) {
|
val kind = when (context.generationMode) {
|
||||||
GenerationMode.SOURCE_CODE -> {
|
GenerationMode.SOURCE_CODE -> {
|
||||||
val readBits = PropertyAccessor.Getter.ReadBits(field.offset, field.size, signed)
|
val readBits = PropertyAccessor.Getter.ReadBits(field.offset, field.size, signed)
|
||||||
@@ -155,7 +157,7 @@ internal class StructStubBuilder(
|
|||||||
PropertyStub.Kind.Var(readBits, writeBits)
|
PropertyStub.Kind.Var(readBits, writeBits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PropertyStub(field.name, kotlinType.toStubIrType(), kind, origin = StubOrigin.StructMember(field))
|
PropertyStub(fieldName, kotlinType.toStubIrType(), kind, origin = StubOrigin.StructMember(field))
|
||||||
}
|
}
|
||||||
|
|
||||||
val superClass = context.platform.getRuntimeType("CStructVar")
|
val superClass = context.platform.getRuntimeType("CStructVar")
|
||||||
@@ -277,7 +279,7 @@ internal class EnumStubBuilder(
|
|||||||
.mapIndexed { index, constant ->
|
.mapIndexed { index, constant ->
|
||||||
val literal = context.tryCreateIntegralStub(enumDef.baseType, constant.value)
|
val literal = context.tryCreateIntegralStub(enumDef.baseType, constant.value)
|
||||||
?: error("Cannot create enum value ${constant.value} of type ${enumDef.baseType}")
|
?: error("Cannot create enum value ${constant.value} of type ${enumDef.baseType}")
|
||||||
val entry = EnumEntryStub(constant.name, literal, StubOrigin.EnumEntry(constant), index)
|
val entry = EnumEntryStub(mangleSimple(constant.name), literal, StubOrigin.EnumEntry(constant), index)
|
||||||
val aliases = aliasConstants
|
val aliases = aliasConstants
|
||||||
.filter { it.value == constant.value }
|
.filter { it.value == constant.value }
|
||||||
.map { constructAliasProperty(it, entry) }
|
.map { constructAliasProperty(it, entry) }
|
||||||
|
|||||||
@@ -3348,6 +3348,14 @@ createInterop("ccallbacksAndVarargs") {
|
|||||||
it.defFile 'interop/basics/ccallbacksAndVarargs.def'
|
it.defFile 'interop/basics/ccallbacksAndVarargs.def'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createInterop("cmangling") {
|
||||||
|
it.defFile 'interop/basics/mangling.def'
|
||||||
|
}
|
||||||
|
|
||||||
|
createInterop("cmangling2") {
|
||||||
|
it.defFile 'interop/basics/mangling2.def'
|
||||||
|
}
|
||||||
|
|
||||||
if (PlatformInfo.isAppleTarget(project)) {
|
if (PlatformInfo.isAppleTarget(project)) {
|
||||||
createInterop("objcSmoke") {
|
createInterop("objcSmoke") {
|
||||||
it.defFile 'interop/objc/objcSmoke.def'
|
it.defFile 'interop/objc/objcSmoke.def'
|
||||||
@@ -3505,6 +3513,18 @@ interopTest("interop_types") {
|
|||||||
interop = 'ctypes'
|
interop = 'ctypes'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interopTest("interop_mangling") {
|
||||||
|
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||||
|
source = "interop/basics/mangling.kt"
|
||||||
|
interop = 'cmangling'
|
||||||
|
}
|
||||||
|
|
||||||
|
interopTest("interop_mangling2") {
|
||||||
|
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||||
|
source = "interop/basics/mangling2.kt"
|
||||||
|
interop = 'cmangling2'
|
||||||
|
}
|
||||||
|
|
||||||
interopTest("interop_values") {
|
interopTest("interop_values") {
|
||||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||||
source = "interop/basics/values.kt"
|
source = "interop/basics/values.kt"
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
// test mangling of special names
|
||||||
|
|
||||||
|
enum _Companion {Companion, Any};
|
||||||
|
enum _Companion companion = Companion;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import kotlinx.cinterop.*
|
||||||
|
import kotlin.test.*
|
||||||
|
import mangling.*
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
companion = _Companion.`Companion$`
|
||||||
|
assertEquals(_Companion.`Companion$`, companion)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
// test mangling of special names
|
||||||
|
|
||||||
|
enum Companion {One, Two};
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import kotlinx.cinterop.*
|
||||||
|
import kotlin.test.*
|
||||||
|
import mangling2.*
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val mangled = `Companion$`.Two
|
||||||
|
assertEquals(`Companion$`.Two, mangled)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -249,3 +249,27 @@ extern BOOL customStringDeallocated;
|
|||||||
- (int)instanceMethod;
|
- (int)instanceMethod;
|
||||||
+ (int)classMethod:(int)first :(int)second;
|
+ (int)classMethod:(int)first :(int)second;
|
||||||
@end;
|
@end;
|
||||||
|
|
||||||
|
// [KT-36067] cinterop tool fails when there is a structure member named Companion
|
||||||
|
|
||||||
|
struct EnumFieldMangleStruct {
|
||||||
|
enum {Companion, Any} smth;
|
||||||
|
};
|
||||||
|
struct EnumFieldMangleStruct enumMangledStruct = { Any };
|
||||||
|
|
||||||
|
struct MyStruct {
|
||||||
|
int Companion; // simple clash
|
||||||
|
int _Companion;
|
||||||
|
int $_Companion;
|
||||||
|
int super;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MyStruct myStruct = {11, 12, 13, 14};
|
||||||
|
|
||||||
|
@protocol Proto
|
||||||
|
@property int Companion; // clash on implementing
|
||||||
|
@end;
|
||||||
|
|
||||||
|
@interface FooMangled : NSObject<Proto>
|
||||||
|
//- (void) CompanionS; // mangleSimple does not support this: it may clash after mangling
|
||||||
|
@end;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ fun run() {
|
|||||||
testLocalizedStrings()
|
testLocalizedStrings()
|
||||||
testConstructorReturnsNull()
|
testConstructorReturnsNull()
|
||||||
testCallableReferences()
|
testCallableReferences()
|
||||||
|
testMangling()
|
||||||
|
|
||||||
assertEquals(2, ForwardDeclaredEnum.TWO.value)
|
assertEquals(2, ForwardDeclaredEnum.TWO.value)
|
||||||
|
|
||||||
@@ -514,6 +515,21 @@ fun testCallableReferences() {
|
|||||||
assertEquals(42, boundInstanceMethodRef())
|
assertEquals(42, boundInstanceMethodRef())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testMangling() {
|
||||||
|
assertEquals(11, myStruct.`Companion$`)
|
||||||
|
assertEquals(12, myStruct._Companion)
|
||||||
|
assertEquals(13, myStruct.`$_Companion`)
|
||||||
|
assertEquals(14, myStruct.`super`)
|
||||||
|
|
||||||
|
val objc = FooMangled()
|
||||||
|
objc.`Companion$` = 99
|
||||||
|
assertEquals(99, objc.Companion())
|
||||||
|
assertEquals(99, objc.`Companion$`)
|
||||||
|
|
||||||
|
enumMangledStruct.smth = Companion
|
||||||
|
assertEquals(Companion, enumMangledStruct.smth)
|
||||||
|
}
|
||||||
|
|
||||||
private val Any.objCClassName: String
|
private val Any.objCClassName: String
|
||||||
get() = object_getClassName(this)!!.toKString()
|
get() = object_getClassName(this)!!.toKString()
|
||||||
|
|
||||||
|
|||||||
@@ -336,3 +336,9 @@ BOOL customStringDeallocated = NO;
|
|||||||
return first + second;
|
return first + second;
|
||||||
}
|
}
|
||||||
@end;
|
@end;
|
||||||
|
|
||||||
|
|
||||||
|
// [KT-36067] mangling
|
||||||
|
@implementation FooMangled : NSObject
|
||||||
|
@synthesize Companion;
|
||||||
|
@end;
|
||||||
|
|||||||
Reference in New Issue
Block a user