[Commonizer] Create approximation keys based on Cir instead of metadata

This commit is contained in:
sebastian.sellmair
2021-07-06 10:36:24 +02:00
committed by Space
parent 09f9a1ce5b
commit f3ff9814a8
21 changed files with 356 additions and 175 deletions

View File

@@ -82,7 +82,7 @@ data class CirPropertyImpl(
override val kind: CallableMemberDescriptor.Kind,
override val isVar: Boolean,
override val isLateInit: Boolean,
override var isConst: Boolean,
override val isConst: Boolean,
override val isDelegate: Boolean,
override val getter: CirPropertyGetter?,
override val setter: CirPropertySetter?,

View File

@@ -8,9 +8,7 @@ package org.jetbrains.kotlin.commonizer.core
import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.commonizer.cir.CirConstantValue.*
import org.jetbrains.kotlin.commonizer.core.AnnotationsCommonizer.Companion.FALLBACK_MESSAGE
import org.jetbrains.kotlin.commonizer.utils.DEPRECATED_ANNOTATION_CLASS_ID
import org.jetbrains.kotlin.commonizer.utils.compactMap
import org.jetbrains.kotlin.commonizer.utils.compactMapOf
import org.jetbrains.kotlin.commonizer.utils.*
import org.jetbrains.kotlin.descriptors.Visibilities
import kotlin.DeprecationLevel.WARNING
@@ -19,15 +17,38 @@ import kotlin.DeprecationLevel.WARNING
*/
class AnnotationsCommonizer : AbstractStandardCommonizer<List<CirAnnotation>, List<CirAnnotation>>() {
private var deprecatedAnnotationCommonizer: DeprecatedAnnotationCommonizer? = null
private var deprecatedAnnotationCommonizerHasResult: Boolean = true
private val objCInteropCallableAnnotationCommonizer = ObjCInteropCallableAnnotationCommonizer.asCommonizer()
private var objCInteropCallableAnnotationCommonizerHasResult = true
override fun commonizationResult(): List<CirAnnotation> {
val deprecatedAnnotation = deprecatedAnnotationCommonizer?.result ?: return emptyList()
return listOf(deprecatedAnnotation)
val deprecatedAnnotation = if (deprecatedAnnotationCommonizerHasResult)
deprecatedAnnotationCommonizer?.result else null
val objCInteropCallableAnnotations = if (objCInteropCallableAnnotationCommonizerHasResult)
objCInteropCallableAnnotationCommonizer.result else emptyList()
return if (deprecatedAnnotation != null) {
objCInteropCallableAnnotations.plus(deprecatedAnnotation)
} else objCInteropCallableAnnotations
}
override fun initialize(first: List<CirAnnotation>) = Unit
override fun doCommonizeWith(next: List<CirAnnotation>): Boolean {
if (deprecatedAnnotationCommonizerHasResult) {
deprecatedAnnotationCommonizerHasResult = doCommonizeDeprecatedAnnotation(next)
}
if (objCInteropCallableAnnotationCommonizerHasResult) {
objCInteropCallableAnnotationCommonizerHasResult = objCInteropCallableAnnotationCommonizer.commonizeWith(next)
}
return true
}
private fun doCommonizeDeprecatedAnnotation(next: List<CirAnnotation>): Boolean {
val nextDeprecatedAnnotation = next.firstOrNull { it.type.classifierId == DEPRECATED_ANNOTATION_CLASS_ID } ?: return true
val deprecatedAnnotationCommonizer = deprecatedAnnotationCommonizer
@@ -41,6 +62,27 @@ class AnnotationsCommonizer : AbstractStandardCommonizer<List<CirAnnotation>, Li
}
}
object ObjCInteropCallableAnnotationCommonizer : AssociativeCommonizer<List<CirAnnotation>> {
override fun commonize(first: List<CirAnnotation>, second: List<CirAnnotation>): List<CirAnnotation> {
return if (first.any { it.type.classifierId.isObjCInteropCallableAnnotation } &&
second.any { it.type.classifierId.isObjCInteropCallableAnnotation }
) {
objCCallableAnnotationList
} else emptyList()
}
private val objCCallableAnnotation = CirAnnotation.createInterned(
CirClassType.createInterned(
classId = COMMONIZER_OBJC_INTEROP_CALLABLE_ANNOTATION_ID,
outerType = null, visibility = Visibilities.Public, arguments = emptyList(), isMarkedNullable = false
),
constantValueArguments = emptyMap(),
annotationValueArguments = emptyMap()
)
private val objCCallableAnnotationList = listOf(objCCallableAnnotation)
}
private class DeprecatedAnnotationCommonizer : Commonizer<CirAnnotation, CirAnnotation> {
private var level: DeprecationLevel? = null // null level means that state is empty
private var message: String? = null // null -> message is not equal

View File

@@ -18,13 +18,14 @@ class ClassConstructorCommonizer(
private val visibility = VisibilityCommonizer.equalizing()
private val typeParameters = TypeParameterListCommonizer(classifiers)
private val valueParameters = CallableValueParametersCommonizer(classifiers)
private val annotationsCommonizer = AnnotationsCommonizer()
override fun commonizationResult(): CirClassConstructor {
val valueParameters = valueParameters.result
valueParameters.patchCallables()
return CirClassConstructor.create(
annotations = emptyList(),
annotations = annotationsCommonizer.result,
typeParameters = typeParameters.result,
visibility = visibility.result,
containingClass = CONTAINING_CLASS_DOES_NOT_MATTER, // does not matter
@@ -45,6 +46,7 @@ class ClassConstructorCommonizer(
&& visibility.commonizeWith(next)
&& typeParameters.commonizeWith(next.typeParameters)
&& valueParameters.commonizeWith(next)
&& annotationsCommonizer.commonizeWith(next.annotations)
}
companion object {

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.commonizer.mergedtree
import org.jetbrains.kotlin.commonizer.cir.CirClass
internal class CirMemberContext private constructor(val classes: List<CirClass>) {
companion object {
val empty = CirMemberContext(emptyList())
}
fun withContextOf(clazz: CirClass) = CirMemberContext(classes = classes + clazz)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CirMemberContext
if (classes != other.classes) return false
return true
}
override fun hashCode(): Int {
return classes.hashCode()
}
}

View File

@@ -3,50 +3,61 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.commonizer.mergedtree
import kotlinx.metadata.*
import kotlinx.metadata.klib.annotations
import org.jetbrains.kotlin.commonizer.cir.CirName
import org.jetbrains.kotlin.commonizer.cir.CirTypeSignature
import org.jetbrains.kotlin.commonizer.core.Commonizer
import org.jetbrains.kotlin.commonizer.metadata.CirTypeParameterResolver
import gnu.trove.TIntHashSet
import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.commonizer.utils.Interner
import org.jetbrains.kotlin.commonizer.utils.appendHashCode
import org.jetbrains.kotlin.commonizer.utils.computeSignature
import org.jetbrains.kotlin.commonizer.utils.hashCode
import org.jetbrains.kotlin.commonizer.utils.isObjCInteropCallableAnnotation
import org.jetbrains.kotlin.types.Variance
typealias ObjCFunctionApproximation = Int
/** Used for approximation of [KmProperty]s before running concrete [Commonizer]s */
data class PropertyApproximationKey(
val name: CirName,
val extensionReceiverParameterType: CirTypeSignature?
) {
constructor(property: KmProperty, typeParameterResolver: CirTypeParameterResolver) : this(
CirName.create(property.name),
property.receiverParameterType?.computeSignature(typeParameterResolver)
)
companion object {
internal fun create(context: CirMemberContext, property: CirProperty): PropertyApproximationKey {
return PropertyApproximationKey(
name = property.name,
extensionReceiverParameterType = property.extensionReceiver
?.let { buildApproximationSignature(SignatureBuildingContext.create(context, property), it.type) }
)
}
}
}
/** Used for approximation of [KmFunction]s before running concrete [Commonizer]s */
data class FunctionApproximationKey(
val name: CirName,
val valueParametersTypes: Array<CirTypeSignature>,
private val additionalValueParametersNamesHash: Int,
val extensionReceiverParameterType: CirTypeSignature?
val extensionReceiverParameterType: CirTypeSignature?,
val objCFunctionApproximation: ObjCFunctionApproximation
) {
constructor(function: KmFunction, typeParameterResolver: CirTypeParameterResolver) : this(
CirName.create(function.name),
function.valueParameters.computeSignatures(typeParameterResolver),
additionalValueParameterNamesHash(function.annotations, function.valueParameters),
function.receiverParameterType?.computeSignature(typeParameterResolver)
)
companion object {
internal fun create(context: CirMemberContext, function: CirFunction): FunctionApproximationKey {
return FunctionApproximationKey(
name = function.name,
valueParametersTypes = valueParameterTypes(context, function),
extensionReceiverParameterType = function.extensionReceiver
?.let { buildApproximationSignature(SignatureBuildingContext.create(context, function), it.type) },
objCFunctionApproximation = objCFunctionApproximation(function)
)
}
}
override fun equals(other: Any?): Boolean {
if (other !is FunctionApproximationKey)
return false
return name == other.name
&& additionalValueParametersNamesHash == other.additionalValueParametersNamesHash
&& objCFunctionApproximation == other.objCFunctionApproximation
&& valueParametersTypes.contentEquals(other.valueParametersTypes)
&& extensionReceiverParameterType == other.extensionReceiverParameterType
}
@@ -54,39 +65,155 @@ data class FunctionApproximationKey(
override fun hashCode() = hashCode(name)
.appendHashCode(valueParametersTypes)
.appendHashCode(extensionReceiverParameterType)
.appendHashCode(additionalValueParametersNamesHash)
.appendHashCode(objCFunctionApproximation)
}
/** Used for approximation of [KmConstructor]s before running concrete [Commonizer]s */
data class ConstructorApproximationKey(
val valueParametersTypes: Array<CirTypeSignature>,
private val additionalValueParametersNamesHash: Int
private val objCFunctionApproximation: ObjCFunctionApproximation
) {
constructor(constructor: KmConstructor, typeParameterResolver: CirTypeParameterResolver) : this(
constructor.valueParameters.computeSignatures(typeParameterResolver),
additionalValueParameterNamesHash(constructor.annotations, constructor.valueParameters)
)
companion object {
internal fun create(context: CirMemberContext, constructor: CirClassConstructor): ConstructorApproximationKey {
return ConstructorApproximationKey(
valueParametersTypes = valueParameterTypes(context, constructor),
objCFunctionApproximation = objCFunctionApproximation(constructor)
)
}
}
override fun equals(other: Any?): Boolean {
if (other !is ConstructorApproximationKey)
return false
return additionalValueParametersNamesHash == other.additionalValueParametersNamesHash
return objCFunctionApproximation == other.objCFunctionApproximation
&& valueParametersTypes.contentEquals(other.valueParametersTypes)
}
override fun hashCode() = hashCode(valueParametersTypes)
.appendHashCode(additionalValueParametersNamesHash)
.appendHashCode(objCFunctionApproximation)
}
@Suppress("NOTHING_TO_INLINE")
private inline fun List<KmValueParameter>.computeSignatures(typeParameterResolver: CirTypeParameterResolver): Array<CirTypeSignature> =
if (isEmpty()) emptyArray() else Array(size) { index -> this[index].type?.computeSignature(typeParameterResolver).orEmpty() }
private fun additionalValueParameterNamesHash(annotations: List<KmAnnotation>, valueParameters: List<KmValueParameter>): Int {
// TODO: add more precise checks when more languages than C & ObjC are supported
if (annotations.none { it.isObjCInteropCallableAnnotation })
return 0 // do not calculate hash for non-ObjC callables
return valueParameters.fold(0) { acc, next -> acc.appendHashCode(next.name) }
private fun <T> objCFunctionApproximation(value: T): ObjCFunctionApproximation
where T : CirHasAnnotations, T : CirCallableMemberWithParameters {
return if (value.annotations.any { it.type.classifierId.isObjCInteropCallableAnnotation }) {
value.valueParameters.fold(0) { acc, next -> acc.appendHashCode(next.name) }
} else 0
}
private fun <T> valueParameterTypes(context: CirMemberContext, callable: T): Array<CirTypeSignature>
where T : CirHasTypeParameters, T : CirCallableMemberWithParameters, T : CirMaybeCallableMemberOfClass {
if (callable.valueParameters.isEmpty()) return emptyArray()
return Array(callable.valueParameters.size) { index ->
val parameter = callable.valueParameters[index]
buildApproximationSignature(SignatureBuildingContext.create(context, callable), parameter.returnType)
}
}
private val typeSignatureInterner = Interner<CirTypeSignature>()
internal fun buildApproximationSignature(context: SignatureBuildingContext, type: CirType): CirTypeSignature {
return typeSignatureInterner.intern(StringBuilder().apply { appendTypeApproximationSignature(context, type) }.toString())
}
internal fun StringBuilder.appendTypeApproximationSignature(context: SignatureBuildingContext, type: CirType) {
return when (type) {
is CirFlexibleType -> appendFlexibleTypeApproximationSignature(context, type)
is CirTypeParameterType -> appendTypeParameterTypeApproximationSignature(context.forTypeParameterTypes(), type)
is CirClassOrTypeAliasType -> appendClassOrTypeAliasTypeApproximationSignature(context, type)
}
}
internal fun StringBuilder.appendClassOrTypeAliasTypeApproximationSignature(
context: SignatureBuildingContext, type: CirClassOrTypeAliasType
) {
append(type.classifierId.toString())
if (type.arguments.isNotEmpty()) {
append("<")
type.arguments.forEachIndexed { index, argument ->
when (argument) {
is CirRegularTypeProjection -> {
when (argument.projectionKind) {
Variance.INVARIANT -> Unit
Variance.IN_VARIANCE -> append("in ")
Variance.OUT_VARIANCE -> append("out ")
}
appendTypeApproximationSignature(context, argument.type)
}
is CirStarTypeProjection -> append("*")
}
if (index != type.arguments.lastIndex) {
append(", ")
}
}
append(">")
}
if (type.isMarkedNullable) append("?")
}
private fun StringBuilder.appendTypeParameterTypeApproximationSignature(
context: TypeParameterTypeSignatureBuildingContext, type: CirTypeParameterType
) {
val typeParameter = context.resolveTypeParameter(type.index)
append(typeParameter.name)
if (context.isVisitedFirstTime(type.index)) {
append(" : [")
typeParameter.upperBounds.forEachIndexed { index, upperBound ->
appendTypeApproximationSignature(context, upperBound)
if (index != typeParameter.upperBounds.lastIndex) append(", ")
}
}
append("]")
if (type.isMarkedNullable) append("?")
}
private fun StringBuilder.appendFlexibleTypeApproximationSignature(
context: SignatureBuildingContext, type: CirFlexibleType
) {
appendTypeApproximationSignature(context, type.lowerBound)
append("..")
appendTypeApproximationSignature(context, type.upperBound)
}
internal sealed interface SignatureBuildingContext {
companion object {
fun create(memberContext: CirMemberContext, functionOrPropertyOrConstructor: CirHasTypeParameters): SignatureBuildingContext {
return DefaultSignatureBuildingContext(memberContext, functionOrPropertyOrConstructor)
}
}
}
private fun SignatureBuildingContext.forTypeParameterTypes(): TypeParameterTypeSignatureBuildingContext = when (this) {
is DefaultSignatureBuildingContext -> TypeParameterTypeSignatureBuildingContext(memberContext, functionOrPropertyOrConstructor)
is TypeParameterTypeSignatureBuildingContext -> this
}
private class DefaultSignatureBuildingContext(
val memberContext: CirMemberContext,
val functionOrPropertyOrConstructor: CirHasTypeParameters
) : SignatureBuildingContext
private class TypeParameterTypeSignatureBuildingContext(
private val memberContext: CirMemberContext,
private val functionOrPropertyOrConstructor: CirHasTypeParameters
) : SignatureBuildingContext {
private val alreadyVisitedParameterTypeIndices = TIntHashSet()
fun isVisitedFirstTime(typeParameterIndex: Int): Boolean {
return alreadyVisitedParameterTypeIndices.add(typeParameterIndex)
}
fun resolveTypeParameter(index: Int): CirTypeParameter {
var indexOffset = 0
memberContext.classes.forEach { clazz ->
val indexInClass = index - indexOffset
if (indexInClass >= 0 && indexInClass <= clazz.typeParameters.lastIndex) {
return clazz.typeParameters[indexInClass]
}
indexOffset += clazz.typeParameters.size
}
return functionOrPropertyOrConstructor.typeParameters[index - indexOffset]
}
}

View File

@@ -21,22 +21,12 @@ data class CirTreeModule(
data class CirTreePackage(
val pkg: CirPackage,
val properties: List<CirTreeProperty> = emptyList(),
val functions: List<CirTreeFunction> = emptyList(),
val properties: List<CirProperty> = emptyList(),
val functions: List<CirFunction> = emptyList(),
val classes: List<CirTreeClass> = emptyList(),
val typeAliases: List<CirTreeTypeAlias> = emptyList()
)
data class CirTreeProperty(
val approximationKey: PropertyApproximationKey,
val property: CirProperty
)
data class CirTreeFunction(
val approximationKey: FunctionApproximationKey,
val function: CirFunction
)
sealed interface CirTreeClassifier {
val id: CirEntityId
}
@@ -49,14 +39,10 @@ data class CirTreeTypeAlias(
data class CirTreeClass(
override val id: CirEntityId,
val clazz: CirClass,
val properties: List<CirTreeProperty> = emptyList(),
val functions: List<CirTreeFunction> = emptyList(),
val constructors: List<CirTreeClassConstructor> = emptyList(),
val properties: List<CirProperty> = emptyList(),
val functions: List<CirFunction> = emptyList(),
val constructors: List<CirClassConstructor> = emptyList(),
val classes: List<CirTreeClass> = emptyList(),
) : CirTreeClassifier
class CirTreeClassConstructor(
val approximationKey: ConstructorApproximationKey,
val constructor: CirClassConstructor
)

View File

@@ -28,8 +28,8 @@ internal fun CirPackageNode.assembleCirTree(): CirTreePackage? {
return CirTreePackage(
pkg = commonizedPackage,
properties = properties.mapNotNull { (key, property) -> property.assembleCirTree(key) },
functions = functions.mapNotNull { (key, function) -> function.assembleCirTree(key) },
properties = properties.mapNotNull { (key, property) -> property.commonDeclaration() },
functions = functions.mapNotNull { (key, function) -> function.commonDeclaration() },
typeAliases = commonizedTypeAliases.filterIsInstance<CirTreeTypeAlias>(),
classes = classes.mapNotNull { (_, clazz) -> clazz.assembleCirTree() } + commonizedTypeAliases.filterIsInstance<CirTreeClass>()
)
@@ -39,9 +39,9 @@ internal fun CirClassNode.assembleCirTree(): CirTreeClass? {
return CirTreeClass(
id = id,
clazz = commonDeclaration() ?: return null,
properties = properties.mapNotNull { (key, property) -> property.assembleCirTree(key) },
functions = functions.mapNotNull { (key, function) -> function.assembleCirTree(key) },
constructors = constructors.mapNotNull { (key, constructor) -> constructor.assembleCirTree(key) },
properties = properties.mapNotNull { (key, property) -> property.commonDeclaration() },
functions = functions.mapNotNull { (key, function) -> function.commonDeclaration() },
constructors = constructors.mapNotNull { (key, constructor) -> constructor.commonDeclaration() },
classes = classes.mapNotNull { (_, clazz) -> clazz.assembleCirTree() }
)
}
@@ -54,24 +54,3 @@ internal fun CirTypeAliasNode.assembleCirTree(): CirTreeClassifier? {
}
}
internal fun CirPropertyNode.assembleCirTree(approximationKey: PropertyApproximationKey): CirTreeProperty? {
return CirTreeProperty(
approximationKey = approximationKey,
property = commonDeclaration() ?: return null,
)
}
internal fun CirFunctionNode.assembleCirTree(approximationKey: FunctionApproximationKey): CirTreeFunction? {
return CirTreeFunction(
approximationKey = approximationKey,
function = commonDeclaration() ?: return null,
)
}
internal fun CirClassConstructorNode.assembleCirTree(approximationKey: ConstructorApproximationKey): CirTreeClassConstructor? {
return CirTreeClassConstructor(
approximationKey = approximationKey,
constructor = commonDeclaration() ?: return null
)
}

View File

@@ -6,23 +6,19 @@
package org.jetbrains.kotlin.commonizer.tree.deserializer
import kotlinx.metadata.KmConstructor
import org.jetbrains.kotlin.commonizer.cir.CirClassConstructor
import org.jetbrains.kotlin.commonizer.cir.CirContainingClass
import org.jetbrains.kotlin.commonizer.mergedtree.ConstructorApproximationKey
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.tree.CirTreeClassConstructor
internal object CirTreeClassConstructorDeserializer {
operator fun invoke(
constructor: KmConstructor, containingClass: CirContainingClass, typeResolver: CirTypeResolver
): CirTreeClassConstructor {
return CirTreeClassConstructor(
approximationKey = ConstructorApproximationKey(constructor, typeResolver),
constructor = CirDeserializers.constructor(
source = constructor,
containingClass = containingClass,
typeResolver = typeResolver
)
): CirClassConstructor {
return CirDeserializers.constructor(
source = constructor,
containingClass = containingClass,
typeResolver = typeResolver
)
}
}

View File

@@ -8,16 +8,16 @@ package org.jetbrains.kotlin.commonizer.tree.deserializer
import kotlinx.metadata.KmFunction
import org.jetbrains.kotlin.commonizer.cir.CirClass
import org.jetbrains.kotlin.commonizer.cir.CirContainingClass
import org.jetbrains.kotlin.commonizer.mergedtree.FunctionApproximationKey
import org.jetbrains.kotlin.commonizer.cir.CirFunction
import org.jetbrains.kotlin.commonizer.cir.CirName
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.tree.CirTreeFunction
import org.jetbrains.kotlin.commonizer.utils.isFakeOverride
import org.jetbrains.kotlin.commonizer.utils.isKniBridgeFunction
import org.jetbrains.kotlin.commonizer.utils.isTopLevelDeprecatedFunction
object CirTreeFunctionDeserializer {
operator fun invoke(function: KmFunction, containingClass: CirContainingClass?, typeResolver: CirTypeResolver): CirTreeFunction? {
operator fun invoke(function: KmFunction, containingClass: CirContainingClass?, typeResolver: CirTypeResolver): CirFunction? {
val functionTypeResolver = typeResolver.create(function.typeParameters)
if (function.isFakeOverride()
|| function.isKniBridgeFunction()
@@ -26,15 +26,11 @@ object CirTreeFunctionDeserializer {
return null
}
val approximationKey = FunctionApproximationKey(function, functionTypeResolver)
return CirTreeFunction(
approximationKey = approximationKey,
function = CirDeserializers.function(
name = approximationKey.name,
source = function,
containingClass = containingClass,
typeResolver = functionTypeResolver
)
return CirDeserializers.function(
name = CirName.create(function.name),
source = function,
containingClass = containingClass,
typeResolver = functionTypeResolver
)
}
}

View File

@@ -7,25 +7,21 @@ package org.jetbrains.kotlin.commonizer.tree.deserializer
import kotlinx.metadata.KmProperty
import org.jetbrains.kotlin.commonizer.cir.CirContainingClass
import org.jetbrains.kotlin.commonizer.mergedtree.PropertyApproximationKey
import org.jetbrains.kotlin.commonizer.cir.CirName
import org.jetbrains.kotlin.commonizer.cir.CirProperty
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.tree.CirTreeProperty
import org.jetbrains.kotlin.commonizer.utils.isFakeOverride
object CirTreePropertyDeserializer {
operator fun invoke(property: KmProperty, containingClass: CirContainingClass?, typeResolver: CirTypeResolver): CirTreeProperty? {
operator fun invoke(property: KmProperty, containingClass: CirContainingClass?, typeResolver: CirTypeResolver): CirProperty? {
if (property.isFakeOverride()) return null
val propertyTypeResolver = typeResolver.create(property.typeParameters)
val approximationKey = PropertyApproximationKey(property, propertyTypeResolver)
return CirTreeProperty(
approximationKey = PropertyApproximationKey(property, propertyTypeResolver),
property = CirDeserializers.property(
name = approximationKey.name,
source = property,
containingClass = containingClass,
typeResolver = propertyTypeResolver
)
return CirDeserializers.property(
name = CirName.create(property.name),
source = property,
containingClass = containingClass,
typeResolver = propertyTypeResolver
)
}
}

View File

@@ -6,13 +6,16 @@
package org.jetbrains.kotlin.commonizer.tree
import org.jetbrains.kotlin.commonizer.TargetDependent
import org.jetbrains.kotlin.commonizer.cir.CirRoot
import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.commonizer.mergedtree.*
import org.jetbrains.kotlin.storage.StorageManager
internal data class TargetBuildingContext(
val storageManager: StorageManager, val classifiers: CirKnownClassifiers, val targets: Int, val targetIndex: Int
)
val storageManager: StorageManager, val classifiers: CirKnownClassifiers, val memberContext: CirMemberContext = CirMemberContext.empty,
val targets: Int, val targetIndex: Int
) {
fun withMemberContextOf(clazz: CirClass) = copy(memberContext = memberContext.withContextOf(clazz))
}
internal fun mergeCirTree(
storageManager: StorageManager, classifiers: CirKnownClassifiers, roots: TargetDependent<CirTreeRoot>
@@ -20,7 +23,9 @@ internal fun mergeCirTree(
val node = buildRootNode(storageManager, roots.size)
roots.targets.withIndex().forEach { (targetIndex, target) ->
node.targetDeclarations[targetIndex] = CirRoot.create(target)
node.buildModules(TargetBuildingContext(storageManager, classifiers, roots.size, targetIndex), roots[target].modules)
node.buildModules(
TargetBuildingContext(storageManager, classifiers, CirMemberContext.empty, roots.size, targetIndex), roots[target].modules
)
}
return node
}
@@ -55,37 +60,38 @@ internal fun CirNodeWithMembers<*, *>.buildClass(
buildClassNode(context.storageManager, context.targets, context.classifiers, CirNodeRelationship.ParentNode(parent), treeClass.id)
}
classNode.targetDeclarations[context.targetIndex] = treeClass.clazz
treeClass.functions.forEach { function -> classNode.buildFunction(context, function, classNode) }
treeClass.properties.forEach { property -> classNode.buildProperty(context, property, classNode) }
treeClass.constructors.forEach { constructor -> classNode.buildConstructor(context, constructor, classNode) }
treeClass.classes.forEach { clazz -> classNode.buildClass(context, clazz, classNode) }
val contextWithClass = context.withMemberContextOf(treeClass.clazz)
treeClass.functions.forEach { function -> classNode.buildFunction(contextWithClass, function, classNode) }
treeClass.properties.forEach { property -> classNode.buildProperty(contextWithClass, property, classNode) }
treeClass.constructors.forEach { constructor -> classNode.buildConstructor(contextWithClass, constructor, classNode) }
treeClass.classes.forEach { clazz -> classNode.buildClass(contextWithClass, clazz, classNode) }
}
internal fun CirNodeWithMembers<*, *>.buildFunction(
context: TargetBuildingContext, treeFunction: CirTreeFunction, parent: CirNode<*, *>? = null
context: TargetBuildingContext, function: CirFunction, parent: CirNode<*, *>? = null
) {
val functionNode = functions.getOrPut(treeFunction.approximationKey) {
val functionNode = functions.getOrPut(FunctionApproximationKey.create(context.memberContext, function)) {
buildFunctionNode(context.storageManager, context.targets, context.classifiers, CirNodeRelationship.ParentNode(parent))
}
functionNode.targetDeclarations[context.targetIndex] = treeFunction.function
functionNode.targetDeclarations[context.targetIndex] = function
}
internal fun CirNodeWithMembers<*, *>.buildProperty(
context: TargetBuildingContext, treeProperty: CirTreeProperty, parent: CirNode<*, *>? = null
context: TargetBuildingContext, property: CirProperty, parent: CirNode<*, *>? = null
) {
val propertyNode = properties.getOrPut(treeProperty.approximationKey) {
val propertyNode = properties.getOrPut(PropertyApproximationKey.create(context.memberContext, property)) {
buildPropertyNode(context.storageManager, context.targets, context.classifiers, CirNodeRelationship.ParentNode(parent))
}
propertyNode.targetDeclarations[context.targetIndex] = treeProperty.property
propertyNode.targetDeclarations[context.targetIndex] = property
}
internal fun CirClassNode.buildConstructor(
context: TargetBuildingContext, treeConstructor: CirTreeClassConstructor, parent: CirNode<*, *>
context: TargetBuildingContext, constructor: CirClassConstructor, parent: CirNode<*, *>
) {
val constructorNode = constructors.getOrPut(treeConstructor.approximationKey) {
val constructorNode = constructors.getOrPut(ConstructorApproximationKey.create(context.memberContext, constructor)) {
buildClassConstructorNode(context.storageManager, context.targets, context.classifiers, CirNodeRelationship.ParentNode(parent))
}
constructorNode.targetDeclarations[context.targetIndex] = treeConstructor.constructor
constructorNode.targetDeclarations[context.targetIndex] = constructor
}
internal fun CirPackageNode.buildTypeAlias(context: TargetBuildingContext, treeTypeAlias: CirTreeTypeAlias) {

View File

@@ -25,8 +25,13 @@ class CommonizedGroup<T : Any>(
operator fun set(index: Int, value: T) {
val oldValue = this[index]
check(oldValue == null) { "$oldValue can not be overwritten with $value at index $index" }
check(oldValue == null) {
"$oldValue can not be overwritten with $value at index $index"
}
elements[index] = value
}
}
interface I<T>

View File

@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.commonizer.utils
import kotlinx.metadata.ClassName
import kotlinx.metadata.KmAnnotation
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.commonizer.cir.CirName
@@ -52,9 +51,8 @@ private val OBJC_INTEROP_CALLABLE_ANNOTATIONS: List<CirName> = listOf(
CirName.create("ObjCFactory")
)
private val OBJC_INTEROP_CALLABLE_ANNOTATION_FULL_NAMES: List<ClassName> = OBJC_INTEROP_CALLABLE_ANNOTATIONS.map { name ->
CirEntityId.create(CINTEROP_PACKAGE, name).toString()
}
internal val COMMONIZER_OBJC_INTEROP_CALLABLE_ANNOTATION_ID =
CirEntityId.create(CirPackageName.create("kotlin.commonizer"), CirName.create("ObjCCallable"))
internal val DEFAULT_CONSTRUCTOR_NAME: CirName = CirName.create("<init>")
internal val DEFAULT_SETTER_VALUE_NAME: CirName = CirName.create("value")
@@ -69,7 +67,7 @@ internal val CirPackageName.isUnderKotlinNativeSyntheticPackages: Boolean
get() = KOTLIN_NATIVE_SYNTHETIC_PACKAGES.any(::startsWith)
internal val CirEntityId.isObjCInteropCallableAnnotation: Boolean
get() = packageName == CINTEROP_PACKAGE && relativeNameSegments.singleOrNull() in OBJC_INTEROP_CALLABLE_ANNOTATIONS
get() = this == COMMONIZER_OBJC_INTEROP_CALLABLE_ANNOTATION_ID ||
packageName == CINTEROP_PACKAGE && relativeNameSegments.singleOrNull() in OBJC_INTEROP_CALLABLE_ANNOTATIONS
internal val KmAnnotation.isObjCInteropCallableAnnotation: Boolean
get() = className in OBJC_INTEROP_CALLABLE_ANNOTATION_FULL_NAMES

View File

@@ -85,29 +85,41 @@ expect fun functionMismatchedParameterNames29(vararg variadicArguments: Int)
expect fun functionMismatchedParameterNames30(arg0: Int, vararg variadicArguments: Int)
expect fun functionMismatchedParameterNames31(i: Int, s: String)
@kotlin.commonizer.ObjCCallable
expect fun functionMismatchedParameterNames34(i: Int, s: String)
@kotlin.commonizer.ObjCCallable
expect fun functionMismatchedParameterNames37(arg0: Int, arg1: String)
// hasStableParameterNames=false
@kotlin.commonizer.ObjCCallable
expect fun functionMismatchedParameterNames38(i: Int, s: String)
// hasStableParameterNames=false
@kotlin.commonizer.ObjCCallable
expect fun functionMismatchedParameterNames39(i: Int, s: String)
// hasStableParameterNames=false
@kotlin.commonizer.ObjCCallable
expect fun functionMismatchedParameterNames40(i: Int, s: String)
// hasStableParameterNames=false
@kotlin.commonizer.ObjCCallable
expect fun functionMismatchedParameterNames41(arg0: Int, arg1: String)
// hasStableParameterNames=false
@kotlin.commonizer.ObjCCallable
expect fun functionMismatchedParameterNames42(arg0: Int, arg1: String)
// hasStableParameterNames=false
@kotlin.commonizer.ObjCCallable
expect fun functionMismatchedParameterNames43(arg0: Int, arg1: String)
@kotlin.commonizer.ObjCCallable
expect fun overloadedFunctionByParameterNames(i: Int, s: String)
@kotlin.commonizer.ObjCCallable
expect fun overloadedFunctionByParameterNames(xi: Int, xs: String)
expect inline fun inlineFunction1(lazyMessage: () -> String)

View File

@@ -0,0 +1,5 @@
package kotlin.commonizer
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.BINARY)
annotation class ObjCCallable()

View File

@@ -4,3 +4,4 @@ package kotlinx.cinterop
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.BINARY)
annotation class ObjCMethod() // fake annotation class without properties

View File

@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.commonizer.tree.deserializer
import org.jetbrains.kotlin.commonizer.cir.CirFunction
import org.jetbrains.kotlin.commonizer.cir.CirProperty
import org.jetbrains.kotlin.commonizer.tree.*
import org.jetbrains.kotlin.commonizer.utils.KtInlineSourceCommonizerTestCase
@@ -14,14 +16,14 @@ abstract class AbstractCirTreeDeserializerTest : KtInlineSourceCommonizerTestCas
?: kotlin.test.fail("Expected single package. Found ${packages.map { it.pkg.packageName }}")
}
protected fun CirTreeModule.assertSingleProperty(): CirTreeProperty {
protected fun CirTreeModule.assertSingleProperty(): CirProperty {
return assertSinglePackage().properties.singleOrNull()
?: kotlin.test.fail("Expected single property. Found ${assertSinglePackage().properties.map { it.property.name }}")
?: kotlin.test.fail("Expected single property. Found ${assertSinglePackage().properties.map { it.name }}")
}
protected fun CirTreeModule.assertSingleFunction(): CirTreeFunction {
protected fun CirTreeModule.assertSingleFunction(): CirFunction {
return assertSinglePackage().functions.singleOrNull()
?: kotlin.test.fail("Expected single property. Found ${assertSinglePackage().functions.map { it.function.name }}")
?: kotlin.test.fail("Expected single property. Found ${assertSinglePackage().functions.map { it.name }}")
}
protected fun CirTreeModule.assertSingleClass(): CirTreeClass {

View File

@@ -150,12 +150,12 @@ class CirTreeClassDeserializerTest : AbstractCirTreeDeserializerTest() {
val clazz = module.assertSingleClass()
fun assertContainsProperty(name: String) {
clazz.properties.singleOrNull { it.property.name.toStrippedString() == name }
clazz.properties.singleOrNull { it.name.toStrippedString() == name }
?: kotlin.test.fail("Missing property '$name'")
}
fun assertContainsFunction(name: String) {
clazz.functions.singleOrNull { it.function.name.toStrippedString() == name }
clazz.functions.singleOrNull { it.name.toStrippedString() == name }
?: kotlin.test.fail("Missing function '$name'")
}

View File

@@ -17,7 +17,7 @@ class CirTreeFunctionDeserializerTest : AbstractCirTreeDeserializerTest() {
fun `test simple function`() {
val module = createCirTreeFromSourceCode("fun x() = Unit")
val (_, function) = module.assertSingleFunction()
val function = module.assertSingleFunction()
assertNull(function.containingClass, "Expected function to *not* have containing class")
assertEquals(Visibilities.Public, function.visibility, "Expected function to be public")
@@ -30,7 +30,7 @@ class CirTreeFunctionDeserializerTest : AbstractCirTreeDeserializerTest() {
fun `test generic function`() {
val module = createCirTreeFromSourceCode("""fun <T: Any> T.isHappy(): Boolean = true""")
val (_, function) = module.assertSingleFunction()
val function = module.assertSingleFunction()
val extensionReceiver = assertNotNull(function.extensionReceiver, "Expected function being extension receiver")
val extensionReceiverType = extensionReceiver.type as? CirTypeParameterType
@@ -59,8 +59,8 @@ class CirTreeFunctionDeserializerTest : AbstractCirTreeDeserializerTest() {
)
val parent = module.assertSingleClass()
val function = parent.functions.singleOrNull()?.function
?: kotlin.test.fail("Expected single function in parent. Found ${parent.functions.map { it.function.name }}")
val function = parent.functions.singleOrNull()
?: kotlin.test.fail("Expected single function in parent. Found ${parent.functions.map { it.name }}")
val containingClass = assertIs<CirClass>(kotlin.test.assertNotNull(function.containingClass))
assertEquals(ClassKind.OBJECT, containingClass.kind, "Expected containing class being object")

View File

@@ -58,12 +58,12 @@ class CirTreePackageDeserializerTest : AbstractCirTreeDeserializerTest() {
)
kotlin.test.assertTrue(
properties.any { it.property.name.toStrippedString() == "rootProperty" },
properties.any { it.name.toStrippedString() == "rootProperty" },
"Expected 'rootProperty'"
)
kotlin.test.assertTrue(
functions.any { it.function.name.toStrippedString() == "rootFunction" },
functions.any { it.name.toStrippedString() == "rootFunction" },
"Expected 'rootFunction'"
)
@@ -80,12 +80,12 @@ class CirTreePackageDeserializerTest : AbstractCirTreeDeserializerTest() {
)
kotlin.test.assertTrue(
properties.any { it.property.name.toStrippedString() == "pkg1Property" },
properties.any { it.name.toStrippedString() == "pkg1Property" },
"Expected 'pkg1Property'"
)
kotlin.test.assertTrue(
functions.any { it.function.name.toStrippedString() == "pkg1Function" },
functions.any { it.name.toStrippedString() == "pkg1Function" },
"Expected 'pkg1Function'"
)
@@ -102,12 +102,12 @@ class CirTreePackageDeserializerTest : AbstractCirTreeDeserializerTest() {
)
kotlin.test.assertTrue(
properties.any { it.property.name.toStrippedString() == "pkg2Property" },
properties.any { it.name.toStrippedString() == "pkg2Property" },
"Expected 'pkg2Property'"
)
kotlin.test.assertTrue(
functions.any { it.function.name.toStrippedString() == "pkg2Function" },
functions.any { it.name.toStrippedString() == "pkg2Function" },
"Expected 'pkg2Function'"
)

View File

@@ -18,8 +18,7 @@ class CirTreePropertyDeserializerTest : AbstractCirTreeDeserializerTest() {
fun `test simple val property`() {
val module = createCirTreeFromSourceCode("val x: Int = 42")
val (key, property) = module.assertSingleProperty()
assertEquals(PropertyApproximationKey(CirName.Companion.create("x"), null), key)
val property = module.assertSingleProperty()
assertEquals("x", property.name.toStrippedString())
assertFalse(property.isConst, "Expected property to is *no* const")
@@ -33,7 +32,7 @@ class CirTreePropertyDeserializerTest : AbstractCirTreeDeserializerTest() {
fun `test simple var property`() {
val module = createCirTreeFromSourceCode("var x: Int = 42")
val (_, property) = module.assertSingleProperty()
val property = module.assertSingleProperty()
assertNotNull(property.getter, "Expected property has getter")
assertNotNull(property.setter, "Expected property has setter")
assertFalse(property.isLateInit, "Expected property to be not lateinit")
@@ -42,7 +41,7 @@ class CirTreePropertyDeserializerTest : AbstractCirTreeDeserializerTest() {
fun `test lateinit var property`() {
val module = createCirTreeFromSourceCode("lateinit var x: Int")
val (_, property) = module.assertSingleProperty()
val property = module.assertSingleProperty()
assertNotNull(property.getter, "Expected property has getter")
assertNotNull(property.setter, "Expected property has setter")
@@ -52,7 +51,7 @@ class CirTreePropertyDeserializerTest : AbstractCirTreeDeserializerTest() {
fun `test generic var property`() {
val module = createCirTreeFromSourceCode("var <T> T.x: T get() = this")
val (_, property) = module.assertSingleProperty()
val property = module.assertSingleProperty()
assertNotNull(property.extensionReceiver, "Expected property has extension receiver")
assertTrue(
@@ -74,8 +73,8 @@ class CirTreePropertyDeserializerTest : AbstractCirTreeDeserializerTest() {
val pkg = module.assertSinglePackage()
assertEquals(4, pkg.properties.size, "Expected exactly 4 properties in package")
val answerProperty = pkg.properties.single { it.property.name.toStrippedString() == "answer" }
val answerReturnType = answerProperty.property.returnType as? CirClassType
val answerProperty = pkg.properties.single { it.name.toStrippedString() == "answer" }
val answerReturnType = answerProperty.returnType as? CirClassType
?: kotlin.test.fail("Expected answer return type is class")
assertEquals("kotlin/Int", answerReturnType.classifierId.toString())
assertTrue(answerReturnType.isMarkedNullable, "Expected answer return type being marked nullable")