[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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* i.e. transforms `foo$bar` to `"foo\$bar"`.
|
||||
|
||||
+1
@@ -407,6 +407,7 @@ fun mirror(declarationMapper: DeclarationMapper, type: Type): TypeMirror = when
|
||||
is EnumType -> {
|
||||
val pkg = declarationMapper.getPackageFor(type.def)
|
||||
val kotlinName = declarationMapper.getKotlinNameForValue(type.def)
|
||||
.let { mangleSimple(it) } // enum class requires additional mangling
|
||||
|
||||
when {
|
||||
declarationMapper.isMappedToStrict(type.def) -> {
|
||||
|
||||
+1
-1
@@ -583,7 +583,7 @@ private class ObjCPropertyStubBuilder(
|
||||
is ObjCCategory -> ClassifierStubType(context.getKotlinClassFor(container.clazz, isMeta = property.getter.isClass))
|
||||
}
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -88,6 +88,7 @@ internal class StructStubBuilder(
|
||||
val fieldRefType = context.mirror(field.type)
|
||||
val unwrappedFieldType = field.type.unwrapTypedefs()
|
||||
val origin = StubOrigin.StructMember(field)
|
||||
val fieldName = mangleSimple(field.name)
|
||||
if (unwrappedFieldType is ArrayType) {
|
||||
val type = (fieldRefType as TypeMirror.ByValue).valueType
|
||||
val annotations = if (platform == KotlinPlatform.JVM) {
|
||||
@@ -103,7 +104,7 @@ internal class StructStubBuilder(
|
||||
}
|
||||
val kind = PropertyStub.Kind.Val(getter)
|
||||
// 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 {
|
||||
val pointedType = fieldRefType.pointedType.toStubIrType()
|
||||
val pointedTypeArgument = TypeArgumentStub(pointedType)
|
||||
@@ -121,14 +122,14 @@ internal class StructStubBuilder(
|
||||
}
|
||||
}
|
||||
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 {
|
||||
val accessor = when (context.generationMode) {
|
||||
GenerationMode.SOURCE_CODE -> PropertyAccessor.Getter.MemberAt(offset, hasValueAccessor = false)
|
||||
GenerationMode.METADATA -> PropertyAccessor.Getter.ExternalGetter(listOf(AnnotationStub.CStruct.MemberAt(offset)))
|
||||
}
|
||||
val kind = PropertyStub.Kind.Val(accessor)
|
||||
PropertyStub(field.name, pointedType, kind, origin = origin)
|
||||
PropertyStub(fieldName, pointedType, kind, origin = origin)
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
@@ -141,6 +142,7 @@ internal class StructStubBuilder(
|
||||
val typeInfo = typeMirror.info
|
||||
val kotlinType = typeMirror.argType
|
||||
val signed = field.type.isIntegerTypeSigned()
|
||||
val fieldName = mangleSimple(field.name)
|
||||
val kind = when (context.generationMode) {
|
||||
GenerationMode.SOURCE_CODE -> {
|
||||
val readBits = PropertyAccessor.Getter.ReadBits(field.offset, field.size, signed)
|
||||
@@ -155,7 +157,7 @@ internal class StructStubBuilder(
|
||||
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")
|
||||
@@ -277,7 +279,7 @@ internal class EnumStubBuilder(
|
||||
.mapIndexed { index, constant ->
|
||||
val literal = context.tryCreateIntegralStub(enumDef.baseType, constant.value)
|
||||
?: 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
|
||||
.filter { it.value == constant.value }
|
||||
.map { constructAliasProperty(it, entry) }
|
||||
@@ -715,4 +717,4 @@ internal class TypedefStubBuilder(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3348,6 +3348,14 @@ createInterop("ccallbacksAndVarargs") {
|
||||
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)) {
|
||||
createInterop("objcSmoke") {
|
||||
it.defFile 'interop/objc/objcSmoke.def'
|
||||
@@ -3505,6 +3513,18 @@ interopTest("interop_types") {
|
||||
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") {
|
||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -248,4 +248,28 @@ extern BOOL customStringDeallocated;
|
||||
@property int value;
|
||||
- (int)instanceMethod;
|
||||
+ (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()
|
||||
testConstructorReturnsNull()
|
||||
testCallableReferences()
|
||||
testMangling()
|
||||
|
||||
assertEquals(2, ForwardDeclaredEnum.TWO.value)
|
||||
|
||||
@@ -514,6 +515,21 @@ fun testCallableReferences() {
|
||||
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
|
||||
get() = object_getClassName(this)!!.toKString()
|
||||
|
||||
|
||||
@@ -335,4 +335,10 @@ BOOL customStringDeallocated = NO;
|
||||
+ (int)classMethod:(int)first :(int)second {
|
||||
return first + second;
|
||||
}
|
||||
@end;
|
||||
@end;
|
||||
|
||||
|
||||
// [KT-36067] mangling
|
||||
@implementation FooMangled : NSObject
|
||||
@synthesize Companion;
|
||||
@end;
|
||||
|
||||
Reference in New Issue
Block a user