[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,
* 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
}
@@ -314,14 +314,16 @@ abstract class KotlinFile(
return topLevelName
}
override fun declareProperty(name: String): String? =
if (name in declaredProperties || name in namesToBeDeclared || name in importedNameToPkg) {
null
// TODO: using original global name should be preferred to importing the clashed name.
} else {
declaredProperties.add(name)
name
}
override fun declareProperty(receiver: String?, name: String): String? {
val fullName = receiver?.let { "$it.${name}" } ?: name
return if (fullName in declaredProperties || name in namesToBeDeclared || name in importedNameToPkg) {
null
// TODO: using original global name should be preferred to importing the clashed name.
} else {
declaredProperties.add(fullName)
name
}
}
fun buildImports(): List<String> = importedNameToPkg.mapNotNull { (name, pkg) ->
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:
internal tailrec fun getTopLevelPropertyDeclarationName(scope: KotlinScope, name: String): String =
scope.declareProperty(name) ?: getTopLevelPropertyDeclarationName(scope, name + "_")
private tailrec fun getTopLevelPropertyDeclarationName(scope: KotlinScope, receiver: String?, name: String): String =
scope.declareProperty(receiver, name) ?: getTopLevelPropertyDeclarationName(scope, receiver, name + "_")
@@ -86,4 +86,15 @@ fun ConstantStub.determineConstantAnnotationClassifier(): Classifier = when (thi
8 -> "Double"
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 =
container == null
private fun getPropertyNameInScope(originalName: String, container: StubContainer?): String =
private fun getPropertyNameInScope(property: PropertyStub, container: StubContainer?): String =
if (isTopLevelContainer(container)) {
getTopLevelPropertyDeclarationName(bridgeBuilderResult.kotlinFile, originalName)
getTopLevelPropertyDeclarationName(bridgeBuilderResult.kotlinFile, property)
} else {
originalName
property.name
}
private val visitor = object : StubIrVisitor<VisitingContext, Any?> {
@@ -170,7 +170,7 @@ internal class ModuleMetadataEmitter(
data.withMappingExtensions {
val kind = element.bridgeSupportedKind
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 ->
element.annotations.mapTo(km.annotations) { it.map() }
km.uniqId = data.uniqIds.uniqIdForProperty(element)
@@ -30,7 +30,7 @@ class StubIrTextEmitter(
get() = context.configuration.pkgName
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.
@@ -286,7 +286,7 @@ class StubIrTextEmitter(
val modality = "$override${renderMemberModality(element.modality, owner)}"
val receiver = if (element.receiverType != null) "${renderStubType(element.receiverType)}." else ""
val name = if (owner?.isTopLevelContainer == true) {
getTopLevelPropertyDeclarationName(kotlinFile, element.name).asSimpleName()
getTopLevelPropertyDeclarationName(kotlinFile, element).asSimpleName()
} else {
element.name.asSimpleName()
}