[Interop] Additional simple mangling of special names such as Companion (#3919)

This commit is contained in:
Vladimir Ivanov
2020-02-28 15:29:52 +03:00
committed by GitHub
parent 576431e42b
commit ee7917cf36
12 changed files with 124 additions and 9 deletions
@@ -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"`.
@@ -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) -> {
@@ -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))
}
}
@@ -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(
}
}
}
}
}
+20
View File
@@ -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)
}
+25 -1
View File
@@ -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()
+7 -1
View File
@@ -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;