[CInterop] Fix global property mangling

Do not mangle properties with the same name but with different receivers
This commit is contained in:
Sergey Bogolepov
2020-04-29 18:52:24 +07:00
committed by Sergey Bogolepov
parent ed36f02c26
commit 567210da9c
4 changed files with 36 additions and 18 deletions
@@ -33,7 +33,7 @@ interface KotlinScope {
* @return the string to be used as a name in the declaration of the property in current scope, * @return the string to be used as a name in the declaration of the property in current scope,
* or `null` if the property with given name can't be declared. * or `null` if the property with given name can't be declared.
*/ */
fun declareProperty(name: String): String? fun declareProperty(receiver: String?, name: String): String?
val mappingBridgeGenerator: MappingBridgeGenerator val mappingBridgeGenerator: MappingBridgeGenerator
} }
@@ -314,14 +314,16 @@ abstract class KotlinFile(
return topLevelName return topLevelName
} }
override fun declareProperty(name: String): String? = override fun declareProperty(receiver: String?, name: String): String? {
if (name in declaredProperties || name in namesToBeDeclared || name in importedNameToPkg) { val fullName = receiver?.let { "$it.${name}" } ?: name
null return if (fullName in declaredProperties || name in namesToBeDeclared || name in importedNameToPkg) {
// TODO: using original global name should be preferred to importing the clashed name. null
} else { // TODO: using original global name should be preferred to importing the clashed name.
declaredProperties.add(name) } else {
name declaredProperties.add(fullName)
} name
}
}
fun buildImports(): List<String> = importedNameToPkg.mapNotNull { (name, pkg) -> fun buildImports(): List<String> = importedNameToPkg.mapNotNull { (name, pkg) ->
if (pkg == "kotlin" || pkg == "kotlinx.cinterop") { if (pkg == "kotlin" || pkg == "kotlinx.cinterop") {
@@ -334,6 +336,11 @@ abstract class KotlinFile(
} }
internal fun getTopLevelPropertyDeclarationName(scope: KotlinScope, property: PropertyStub): String {
val receiverName = property.receiverType?.underlyingTypeFqName
return getTopLevelPropertyDeclarationName(scope, receiverName, property.name)
}
// Try to use the provided name. If failed, mangle it with underscore and try again: // Try to use the provided name. If failed, mangle it with underscore and try again:
internal tailrec fun getTopLevelPropertyDeclarationName(scope: KotlinScope, name: String): String = private tailrec fun getTopLevelPropertyDeclarationName(scope: KotlinScope, receiver: String?, name: String): String =
scope.declareProperty(name) ?: getTopLevelPropertyDeclarationName(scope, name + "_") scope.declareProperty(receiver, name) ?: getTopLevelPropertyDeclarationName(scope, receiver, name + "_")
@@ -87,3 +87,14 @@ fun ConstantStub.determineConstantAnnotationClassifier(): Classifier = when (thi
else -> error("Real constant with unexpected size of $size.") else -> error("Real constant with unexpected size of $size.")
} }
}.let { Classifier.topLevel(cinteropInternalPackage, "ConstantValue").nested(it) } }.let { Classifier.topLevel(cinteropInternalPackage, "ConstantValue").nested(it) }
/**
* Returns the original name of the given type.
*/
val StubType.underlyingTypeFqName: String
get() = when (this) {
is ClassifierStubType -> classifier.fqName
is AbbreviatedType -> underlyingType.underlyingTypeFqName
is FunctionalType -> classifier.fqName
is TypeParameterType -> name
}
@@ -98,11 +98,11 @@ internal class ModuleMetadataEmitter(
private fun isTopLevelContainer(container: StubContainer?): Boolean = private fun isTopLevelContainer(container: StubContainer?): Boolean =
container == null container == null
private fun getPropertyNameInScope(originalName: String, container: StubContainer?): String = private fun getPropertyNameInScope(property: PropertyStub, container: StubContainer?): String =
if (isTopLevelContainer(container)) { if (isTopLevelContainer(container)) {
getTopLevelPropertyDeclarationName(bridgeBuilderResult.kotlinFile, originalName) getTopLevelPropertyDeclarationName(bridgeBuilderResult.kotlinFile, property)
} else { } else {
originalName property.name
} }
private val visitor = object : StubIrVisitor<VisitingContext, Any?> { private val visitor = object : StubIrVisitor<VisitingContext, Any?> {
@@ -170,7 +170,7 @@ internal class ModuleMetadataEmitter(
data.withMappingExtensions { data.withMappingExtensions {
val kind = element.bridgeSupportedKind val kind = element.bridgeSupportedKind
if (kind != null) { if (kind != null) {
val name = getPropertyNameInScope(element.name, data.container) val name = getPropertyNameInScope(element, data.container)
KmProperty(element.flags, name, kind.getterFlags, kind.setterFlags).also { km -> KmProperty(element.flags, name, kind.getterFlags, kind.setterFlags).also { km ->
element.annotations.mapTo(km.annotations) { it.map() } element.annotations.mapTo(km.annotations) { it.map() }
km.uniqId = data.uniqIds.uniqIdForProperty(element) km.uniqId = data.uniqIds.uniqIdForProperty(element)
@@ -30,7 +30,7 @@ class StubIrTextEmitter(
get() = context.configuration.pkgName get() = context.configuration.pkgName
private val StubContainer.isTopLevelContainer: Boolean private val StubContainer.isTopLevelContainer: Boolean
get() = this == builderResult.stubs get() = this == builderResult.stubs || this in builderResult.stubs.simpleContainers
/** /**
* The output currently used by the generator. * The output currently used by the generator.
@@ -286,7 +286,7 @@ class StubIrTextEmitter(
val modality = "$override${renderMemberModality(element.modality, owner)}" val modality = "$override${renderMemberModality(element.modality, owner)}"
val receiver = if (element.receiverType != null) "${renderStubType(element.receiverType)}." else "" val receiver = if (element.receiverType != null) "${renderStubType(element.receiverType)}." else ""
val name = if (owner?.isTopLevelContainer == true) { val name = if (owner?.isTopLevelContainer == true) {
getTopLevelPropertyDeclarationName(kotlinFile, element.name).asSimpleName() getTopLevelPropertyDeclarationName(kotlinFile, element).asSimpleName()
} else { } else {
element.name.asSimpleName() element.name.asSimpleName()
} }