[Commonizer] Limited annotation commonization (@Deprecated for functions)
^KMM-238 ^KMM-53
This commit is contained in:
+7
-20
@@ -10,22 +10,16 @@ import org.jetbrains.kotlin.descriptors.ClassKind.ANNOTATION_CLASS
|
|||||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirAnnotation
|
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirAnnotation
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.utils.concat
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.resolve.constants.AnnotationValue
|
import org.jetbrains.kotlin.resolve.constants.AnnotationValue
|
||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
|
||||||
import org.jetbrains.kotlin.storage.getValue
|
import org.jetbrains.kotlin.storage.getValue
|
||||||
|
|
||||||
class CommonizedAnnotationDescriptor(
|
class CommonizedAnnotationDescriptor(
|
||||||
private val targetComponents: TargetDeclarationsBuilderComponents,
|
targetComponents: TargetDeclarationsBuilderComponents,
|
||||||
override val fqName: FqName,
|
cirAnnotation: CirAnnotation
|
||||||
rawValueArguments: Map<Name, ConstantValue<*>>
|
|
||||||
) : AnnotationDescriptor {
|
) : AnnotationDescriptor {
|
||||||
constructor(targetComponents: TargetDeclarationsBuilderComponents, cirAnnotation: CirAnnotation) : this(
|
override val fqName: FqName = cirAnnotation.fqName
|
||||||
targetComponents,
|
|
||||||
cirAnnotation.fqName,
|
|
||||||
cirAnnotation.allValueArguments
|
|
||||||
)
|
|
||||||
|
|
||||||
override val type by targetComponents.storageManager.createLazyValue {
|
override val type by targetComponents.storageManager.createLazyValue {
|
||||||
val annotationClass = findClassOrTypeAlias(targetComponents, fqName)
|
val annotationClass = findClassOrTypeAlias(targetComponents, fqName)
|
||||||
@@ -36,17 +30,10 @@ class CommonizedAnnotationDescriptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val allValueArguments by targetComponents.storageManager.createLazyValue {
|
override val allValueArguments by targetComponents.storageManager.createLazyValue {
|
||||||
rawValueArguments.mapValues { (_, value) -> substituteValueArgument(value) }
|
cirAnnotation.constantValueArguments concat cirAnnotation.annotationValueArguments.mapValues { (_, nestedCirAnnotation) ->
|
||||||
|
AnnotationValue(CommonizedAnnotationDescriptor(targetComponents, nestedCirAnnotation))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val source: SourceElement get() = SourceElement.NO_SOURCE
|
override val source: SourceElement get() = SourceElement.NO_SOURCE
|
||||||
|
|
||||||
private fun substituteValueArgument(value: ConstantValue<*>) =
|
|
||||||
(value as? AnnotationValue)?.value?.let { nestedAnnotationDescriptor ->
|
|
||||||
// re-build annotation descriptors
|
|
||||||
val fqName = nestedAnnotationDescriptor.fqName
|
|
||||||
?: error("Annotation with no FQ name: ${nestedAnnotationDescriptor::class.java}, $nestedAnnotationDescriptor")
|
|
||||||
|
|
||||||
AnnotationValue(CommonizedAnnotationDescriptor(targetComponents, fqName, nestedAnnotationDescriptor.allValueArguments))
|
|
||||||
} ?: value // keep other values as they are platform agnostic
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-4
@@ -120,11 +120,8 @@ internal fun CirSimpleType.buildType(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: commonize annotations, KT-34234
|
|
||||||
val typeAnnotations = if (!targetComponents.isCommon) annotations.buildDescriptors(targetComponents) else Annotations.EMPTY
|
|
||||||
|
|
||||||
val simpleType = simpleType(
|
val simpleType = simpleType(
|
||||||
annotations = typeAnnotations,
|
annotations = annotations.buildDescriptors(targetComponents),
|
||||||
constructor = classifier.typeConstructor,
|
constructor = classifier.typeConstructor,
|
||||||
arguments = arguments.map { it.buildArgument(targetComponents, typeParameterResolver) },
|
arguments = arguments.map { it.buildArgument(targetComponents, typeParameterResolver) },
|
||||||
nullable = isMarkedNullable,
|
nullable = isMarkedNullable,
|
||||||
|
|||||||
+3
-1
@@ -13,7 +13,9 @@ import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirFunctionOrPr
|
|||||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.isNonAbstractMemberInInterface
|
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.isNonAbstractMemberInInterface
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
abstract class AbstractFunctionOrPropertyCommonizer<T : CirFunctionOrProperty>(cache: CirClassifiersCache) : AbstractStandardCommonizer<T, T>() {
|
abstract class AbstractFunctionOrPropertyCommonizer<T : CirFunctionOrProperty>(
|
||||||
|
cache: CirClassifiersCache
|
||||||
|
) : AbstractStandardCommonizer<T, T>() {
|
||||||
protected lateinit var name: Name
|
protected lateinit var name: Name
|
||||||
protected val modality = ModalityCommonizer.default()
|
protected val modality = ModalityCommonizer.default()
|
||||||
protected val visibility = VisibilityCommonizer.lowering()
|
protected val visibility = VisibilityCommonizer.lowering()
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ abstract class AbstractNullableCommonizer<T : Any, R : Any, WT, WR>(
|
|||||||
|
|
||||||
final override fun commonizeWith(next: T?): Boolean {
|
final override fun commonizeWith(next: T?): Boolean {
|
||||||
state = when (state) {
|
state = when (state) {
|
||||||
State.ERROR -> State.ERROR
|
State.ERROR -> return false
|
||||||
State.EMPTY -> next?.let {
|
State.EMPTY -> next?.let {
|
||||||
wrapped = wrappedCommonizerFactory()
|
wrapped = wrappedCommonizerFactory()
|
||||||
doCommonizeWith(next)
|
doCommonizeWith(next)
|
||||||
|
|||||||
+209
@@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.descriptors.commonizer.core
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirAnnotation
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.utils.DEPRECATED_ANNOTATION_FQN
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is limited implementation of annotations commonizer. It helps to commonize only [kotlin.Deprecated] annotations.
|
||||||
|
*/
|
||||||
|
class AnnotationsCommonizer : AbstractStandardCommonizer<List<CirAnnotation>, List<CirAnnotation>>() {
|
||||||
|
private var deprecatedAnnotationCommonizer: DeprecatedAnnotationCommonizer? = null
|
||||||
|
|
||||||
|
override fun commonizationResult(): List<CirAnnotation> {
|
||||||
|
val deprecatedAnnotation = deprecatedAnnotationCommonizer?.result ?: return emptyList()
|
||||||
|
return listOf(deprecatedAnnotation)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initialize(first: List<CirAnnotation>) = Unit
|
||||||
|
|
||||||
|
override fun doCommonizeWith(next: List<CirAnnotation>): Boolean {
|
||||||
|
val nextDeprecatedAnnotation = next.firstOrNull { it.fqName == DEPRECATED_ANNOTATION_FQN } ?: return true
|
||||||
|
val deprecatedAnnotationCommonizer = deprecatedAnnotationCommonizer ?: DeprecatedAnnotationCommonizer()
|
||||||
|
return deprecatedAnnotationCommonizer.commonizeWith(nextDeprecatedAnnotation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
private var replaceWithExpression: String? = null // null -> replaceWith is not equal
|
||||||
|
private var replaceWithImports: List<String>? = null
|
||||||
|
|
||||||
|
override val result: CirAnnotation
|
||||||
|
get() {
|
||||||
|
if (level == null) throw IllegalCommonizerStateException()
|
||||||
|
|
||||||
|
return CirAnnotation.create(
|
||||||
|
fqName = DEPRECATED_ANNOTATION_FQN,
|
||||||
|
constantValueArguments = mapOf<Name, ConstantValue<*>>(
|
||||||
|
PROPERTY_NAME_LEVEL to level!!.toDeprecationLevelValue(),
|
||||||
|
PROPERTY_NAME_MESSAGE to message.toDeprecationMessageValue()
|
||||||
|
),
|
||||||
|
annotationValueArguments = mapOf(
|
||||||
|
PROPERTY_NAME_REPLACE_WITH to replaceWithExpression.toReplaceWithValue(replaceWithImports)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun commonizeWith(next: CirAnnotation): Boolean {
|
||||||
|
val nextLevel: DeprecationLevel = next.getDeprecationLevel() ?: DeprecationLevel.HIDDEN
|
||||||
|
val nextMessage: String? = next.getDeprecationMessage()
|
||||||
|
val nextReplaceWith: CirAnnotation? = next.getReplaceWith()
|
||||||
|
val nextReplaceWithExpression: String? = nextReplaceWith?.getReplaceWithExpression()
|
||||||
|
val nextReplaceWithImports: List<String>? = nextReplaceWith?.getReplaceWithImports()
|
||||||
|
|
||||||
|
return if (level != null) {
|
||||||
|
doCommonizeWith(nextLevel, nextMessage, nextReplaceWithExpression, nextReplaceWithImports)
|
||||||
|
} else {
|
||||||
|
// empty, just fill in
|
||||||
|
initialize(nextLevel, nextMessage, nextReplaceWithExpression, nextReplaceWithImports)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initialize(
|
||||||
|
nextLevel: DeprecationLevel,
|
||||||
|
nextMessage: String?,
|
||||||
|
nextReplaceWithExpression: String?,
|
||||||
|
nextReplaceWithImports: List<String>?
|
||||||
|
) {
|
||||||
|
level = nextLevel
|
||||||
|
message = nextMessage
|
||||||
|
|
||||||
|
if (nextReplaceWithExpression != null && nextReplaceWithImports != null) {
|
||||||
|
replaceWithExpression = nextReplaceWithExpression
|
||||||
|
replaceWithImports = nextReplaceWithImports
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doCommonizeWith(
|
||||||
|
nextLevel: DeprecationLevel,
|
||||||
|
nextMessage: String?,
|
||||||
|
nextReplaceWithExpression: String?,
|
||||||
|
nextReplaceWithImports: List<String>?
|
||||||
|
): Boolean {
|
||||||
|
if (nextLevel.ordinal > level!!.ordinal)
|
||||||
|
level = nextLevel
|
||||||
|
|
||||||
|
if (nextMessage != message)
|
||||||
|
message = null
|
||||||
|
|
||||||
|
if (nextReplaceWithExpression != replaceWithExpression || nextReplaceWithImports != replaceWithImports) {
|
||||||
|
replaceWithExpression = null
|
||||||
|
replaceWithImports = null
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
companion object {
|
||||||
|
private val PROPERTY_NAME_MESSAGE = Name.identifier(Deprecated::message.name)
|
||||||
|
private val PROPERTY_NAME_REPLACE_WITH = Name.identifier(Deprecated::replaceWith.name)
|
||||||
|
private val PROPERTY_NAME_LEVEL = Name.identifier(Deprecated::level.name)
|
||||||
|
|
||||||
|
private val PROPERTY_NAME_EXPRESSION = Name.identifier(ReplaceWith::expression.name)
|
||||||
|
private val PROPERTY_NAME_IMPORTS = Name.identifier(ReplaceWith::imports.name)
|
||||||
|
|
||||||
|
// Optimization: Keep most frequently used message constants.
|
||||||
|
private val FREQUENTLY_USED_MESSAGE_VALUES: Map<String, StringValue> = listOf(
|
||||||
|
"Use constructor instead",
|
||||||
|
"Use factory method instead"
|
||||||
|
).associateWith { StringValue(it) }
|
||||||
|
|
||||||
|
private val FALLBACK_MESSAGE_VALUE = StringValue("See actual declarations for concrete deprecation messages")
|
||||||
|
|
||||||
|
private val DEPRECATION_LEVEL_FQN = FqName(DeprecationLevel::class.java.name)
|
||||||
|
private val DEPRECATION_LEVEL_CLASS_ID = ClassId.topLevel(DEPRECATION_LEVEL_FQN)
|
||||||
|
|
||||||
|
// Optimization: Keep DeprecationLevel enum constants.
|
||||||
|
private val DEPRECATION_LEVEL_ENUM_ENTRY_VALUES: Map<String, EnumValue> = DeprecationLevel.values().associate {
|
||||||
|
it.name to EnumValue(DEPRECATION_LEVEL_CLASS_ID, Name.identifier(it.name))
|
||||||
|
}
|
||||||
|
|
||||||
|
private val REPLACE_WITH_FQN = FqName(ReplaceWith::class.java.name)
|
||||||
|
|
||||||
|
// Optimization: Keep empty ReplaceWith instance of CirAnnotation.
|
||||||
|
private val EMPTY_REPLACE_WITH_CIR_ANNOTATION = createReplaceWithAnnotation("", emptyList())
|
||||||
|
|
||||||
|
private fun CirAnnotation.getDeprecationMessage(): String? = constantValueArguments.getString(PROPERTY_NAME_MESSAGE)
|
||||||
|
|
||||||
|
private fun String?.toDeprecationMessageValue(): StringValue =
|
||||||
|
if (this == null)
|
||||||
|
FALLBACK_MESSAGE_VALUE
|
||||||
|
else
|
||||||
|
FREQUENTLY_USED_MESSAGE_VALUES[this] ?: StringValue(this)
|
||||||
|
|
||||||
|
private fun CirAnnotation.getDeprecationLevel(): DeprecationLevel? {
|
||||||
|
val enumEntryName = constantValueArguments.getEnumEntryName(PROPERTY_NAME_LEVEL) ?: return null
|
||||||
|
return DeprecationLevel.values().firstOrNull { it.name == enumEntryName }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DeprecationLevel.toDeprecationLevelValue(): EnumValue =
|
||||||
|
DEPRECATION_LEVEL_ENUM_ENTRY_VALUES.getValue(name)
|
||||||
|
|
||||||
|
private fun CirAnnotation.getReplaceWith(): CirAnnotation? =
|
||||||
|
annotationValueArguments.getAnnotation(PROPERTY_NAME_REPLACE_WITH)
|
||||||
|
|
||||||
|
private fun CirAnnotation.getReplaceWithExpression(): String? =
|
||||||
|
constantValueArguments.getString(PROPERTY_NAME_EXPRESSION)
|
||||||
|
|
||||||
|
private fun CirAnnotation.getReplaceWithImports(): List<String>? =
|
||||||
|
constantValueArguments.getStringArray(PROPERTY_NAME_IMPORTS)
|
||||||
|
|
||||||
|
private fun String?.toReplaceWithValue(imports: List<String>?): CirAnnotation =
|
||||||
|
if (this == null || imports == null)
|
||||||
|
EMPTY_REPLACE_WITH_CIR_ANNOTATION
|
||||||
|
else
|
||||||
|
createReplaceWithAnnotation(this, imports)
|
||||||
|
|
||||||
|
private inline fun Map<Name, ConstantValue<*>>.getString(name: Name): String? =
|
||||||
|
(this[name] as? StringValue)?.value
|
||||||
|
|
||||||
|
private inline fun Map<Name, ConstantValue<*>>.getEnumEntryName(name: Name): String? =
|
||||||
|
(this[name] as? EnumValue)?.enumEntryName?.asString()
|
||||||
|
|
||||||
|
private inline fun Map<Name, CirAnnotation>.getAnnotation(name: Name): CirAnnotation? =
|
||||||
|
this[name]
|
||||||
|
|
||||||
|
private inline fun Map<Name, ConstantValue<*>>.getStringArray(name: Name): List<String>? {
|
||||||
|
val elements: List<ConstantValue<*>> = (this[name] as? ArrayValue)?.value ?: return null
|
||||||
|
if (elements.isEmpty()) return emptyList()
|
||||||
|
|
||||||
|
val result = mutableListOf<String>()
|
||||||
|
for (element in elements) {
|
||||||
|
if (element is StringValue) {
|
||||||
|
result += element.value
|
||||||
|
} else
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun createReplaceWithAnnotation(expression: String, imports: List<String>): CirAnnotation =
|
||||||
|
CirAnnotation.create(
|
||||||
|
fqName = REPLACE_WITH_FQN,
|
||||||
|
constantValueArguments = mapOf(
|
||||||
|
PROPERTY_NAME_EXPRESSION to StringValue(expression),
|
||||||
|
PROPERTY_NAME_IMPORTS to ArrayValue(
|
||||||
|
value = imports.map { StringValue(it) },
|
||||||
|
computeType = { it.builtIns.getArrayElementType(it.builtIns.stringType) }
|
||||||
|
)
|
||||||
|
),
|
||||||
|
annotationValueArguments = emptyMap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-6
@@ -26,13 +26,15 @@ abstract class AbstractStandardCommonizer<T, R> : Commonizer<T, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final override fun commonizeWith(next: T): Boolean {
|
final override fun commonizeWith(next: T): Boolean {
|
||||||
if (state == State.ERROR)
|
val result = when (state) {
|
||||||
return false
|
State.ERROR -> return false
|
||||||
|
State.EMPTY -> {
|
||||||
|
initialize(next)
|
||||||
|
doCommonizeWith(next)
|
||||||
|
}
|
||||||
|
State.IN_PROGRESS -> doCommonizeWith(next)
|
||||||
|
}
|
||||||
|
|
||||||
if (state == State.EMPTY)
|
|
||||||
initialize(next)
|
|
||||||
|
|
||||||
val result = doCommonizeWith(next)
|
|
||||||
state = if (!result) State.ERROR else State.IN_PROGRESS
|
state = if (!result) State.ERROR else State.IN_PROGRESS
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
+3
@@ -10,12 +10,14 @@ import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirCommonFuncti
|
|||||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirFunction
|
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirFunction
|
||||||
|
|
||||||
class FunctionCommonizer(cache: CirClassifiersCache) : AbstractFunctionOrPropertyCommonizer<CirFunction>(cache) {
|
class FunctionCommonizer(cache: CirClassifiersCache) : AbstractFunctionOrPropertyCommonizer<CirFunction>(cache) {
|
||||||
|
private val annotations = AnnotationsCommonizer()
|
||||||
private val modifiers = FunctionModifiersCommonizer.default()
|
private val modifiers = FunctionModifiersCommonizer.default()
|
||||||
private val valueParameters = ValueParameterListCommonizer.default(cache)
|
private val valueParameters = ValueParameterListCommonizer.default(cache)
|
||||||
private var hasStableParameterNames = true
|
private var hasStableParameterNames = true
|
||||||
private var hasSynthesizedParameterNames = false
|
private var hasSynthesizedParameterNames = false
|
||||||
|
|
||||||
override fun commonizationResult() = CirCommonFunction(
|
override fun commonizationResult() = CirCommonFunction(
|
||||||
|
annotations = annotations.result,
|
||||||
name = name,
|
name = name,
|
||||||
modality = modality.result,
|
modality = modality.result,
|
||||||
visibility = visibility.result,
|
visibility = visibility.result,
|
||||||
@@ -31,6 +33,7 @@ class FunctionCommonizer(cache: CirClassifiersCache) : AbstractFunctionOrPropert
|
|||||||
|
|
||||||
override fun doCommonizeWith(next: CirFunction): Boolean {
|
override fun doCommonizeWith(next: CirFunction): Boolean {
|
||||||
val result = super.doCommonizeWith(next)
|
val result = super.doCommonizeWith(next)
|
||||||
|
&& annotations.commonizeWith(next.annotations)
|
||||||
&& modifiers.commonizeWith(next)
|
&& modifiers.commonizeWith(next)
|
||||||
&& valueParameters.commonizeWith(next.valueParameters)
|
&& valueParameters.commonizeWith(next.valueParameters)
|
||||||
|
|
||||||
|
|||||||
+59
-20
@@ -13,24 +13,17 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.constants.*
|
import org.jetbrains.kotlin.resolve.constants.*
|
||||||
|
|
||||||
class CirAnnotation private constructor(original: AnnotationDescriptor) {
|
class CirAnnotation private constructor(
|
||||||
val fqName: FqName = original.fqName?.intern() ?: error("Annotation with no FQ name: ${original::class.java}, $original")
|
val fqName: FqName,
|
||||||
val allValueArguments: Map<Name, ConstantValue<*>> = original.allValueArguments.mapKeys { it.key.intern() }
|
val constantValueArguments: Map<Name, ConstantValue<*>>,
|
||||||
|
val annotationValueArguments: Map<Name, CirAnnotation>
|
||||||
init {
|
) {
|
||||||
allValueArguments.forEach { (name, constantValue) ->
|
|
||||||
checkConstantSupportedInCommonization(
|
|
||||||
constantValue = constantValue,
|
|
||||||
constantName = name,
|
|
||||||
owner = original
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See also org.jetbrains.kotlin.types.KotlinType.cachedHashCode
|
// See also org.jetbrains.kotlin.types.KotlinType.cachedHashCode
|
||||||
private var cachedHashCode = 0
|
private var cachedHashCode = 0
|
||||||
|
|
||||||
private fun computeHashCode() = hashCode(fqName).appendHashCode(allValueArguments)
|
private fun computeHashCode() = hashCode(fqName)
|
||||||
|
.appendHashCode(constantValueArguments)
|
||||||
|
.appendHashCode(annotationValueArguments)
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var currentHashCode = cachedHashCode
|
var currentHashCode = cachedHashCode
|
||||||
@@ -41,15 +34,61 @@ class CirAnnotation private constructor(original: AnnotationDescriptor) {
|
|||||||
return currentHashCode
|
return currentHashCode
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean = when {
|
override fun equals(other: Any?): Boolean {
|
||||||
other === this -> true
|
if (other === this) return true
|
||||||
other is CirAnnotation -> fqName == other.fqName && allValueArguments == other.allValueArguments
|
|
||||||
else -> false
|
return other is CirAnnotation
|
||||||
|
&& fqName == other.fqName
|
||||||
|
&& constantValueArguments == other.constantValueArguments
|
||||||
|
&& annotationValueArguments == other.annotationValueArguments
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val interner = Interner<CirAnnotation>()
|
private val interner = Interner<CirAnnotation>()
|
||||||
|
|
||||||
fun create(original: AnnotationDescriptor): CirAnnotation = interner.intern(CirAnnotation(original))
|
fun create(original: AnnotationDescriptor): CirAnnotation {
|
||||||
|
val fqName: FqName = original.fqName?.intern() ?: error("Annotation with no FQ name: ${original::class.java}, $original")
|
||||||
|
|
||||||
|
val allValueArguments: Map<Name, ConstantValue<*>> = original.allValueArguments
|
||||||
|
if (allValueArguments.isEmpty())
|
||||||
|
return create(fqName = fqName, constantValueArguments = emptyMap(), annotationValueArguments = emptyMap())
|
||||||
|
|
||||||
|
val constantValueArguments: MutableMap<Name, ConstantValue<*>> = HashMap()
|
||||||
|
val annotationValueArguments: MutableMap<Name, CirAnnotation> = HashMap()
|
||||||
|
|
||||||
|
allValueArguments.forEach { (name, constantValue) ->
|
||||||
|
checkConstantSupportedInCommonization(
|
||||||
|
constantValue = constantValue,
|
||||||
|
constantName = name,
|
||||||
|
owner = original,
|
||||||
|
allowAnnotationValues = true
|
||||||
|
)
|
||||||
|
|
||||||
|
if (constantValue is AnnotationValue)
|
||||||
|
annotationValueArguments[name.intern()] = create(original = constantValue.value)
|
||||||
|
else
|
||||||
|
constantValueArguments[name.intern()] = constantValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return create(
|
||||||
|
fqName = fqName,
|
||||||
|
constantValueArguments = constantValueArguments,
|
||||||
|
annotationValueArguments = annotationValueArguments
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(
|
||||||
|
fqName: FqName,
|
||||||
|
constantValueArguments: Map<Name, ConstantValue<*>>,
|
||||||
|
annotationValueArguments: Map<Name, CirAnnotation>
|
||||||
|
): CirAnnotation {
|
||||||
|
return interner.intern(
|
||||||
|
CirAnnotation(
|
||||||
|
fqName = fqName,
|
||||||
|
constantValueArguments = constantValueArguments,
|
||||||
|
annotationValueArguments = annotationValueArguments
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -40,7 +40,7 @@ data class CirCommonClass(
|
|||||||
override val isInline: Boolean,
|
override val isInline: Boolean,
|
||||||
override val isInner: Boolean
|
override val isInner: Boolean
|
||||||
) : CirClass {
|
) : CirClass {
|
||||||
override val annotations: List<CirAnnotation> get() = emptyList() // TODO: commonize annotations, KT-34234
|
override val annotations: List<CirAnnotation> get() = emptyList()
|
||||||
override val isData get() = false
|
override val isData get() = false
|
||||||
override val isExternal get() = false
|
override val isExternal get() = false
|
||||||
override var companion: FqName? = null
|
override var companion: FqName? = null
|
||||||
@@ -56,7 +56,7 @@ data class CirCommonClassConstructor(
|
|||||||
override val hasStableParameterNames: Boolean,
|
override val hasStableParameterNames: Boolean,
|
||||||
override val hasSynthesizedParameterNames: Boolean
|
override val hasSynthesizedParameterNames: Boolean
|
||||||
) : CirClassConstructor {
|
) : CirClassConstructor {
|
||||||
override val annotations: List<CirAnnotation> get() = emptyList() // TODO: commonize annotations, KT-34234
|
override val annotations: List<CirAnnotation> get() = emptyList()
|
||||||
override val containingClassKind get() = unsupported()
|
override val containingClassKind get() = unsupported()
|
||||||
override val containingClassModality get() = unsupported()
|
override val containingClassModality get() = unsupported()
|
||||||
override val containingClassIsData get() = unsupported()
|
override val containingClassIsData get() = unsupported()
|
||||||
|
|||||||
+1
@@ -30,6 +30,7 @@ interface CirCallableMemberWithParameters {
|
|||||||
interface CirFunction : CirFunctionOrProperty, CirFunctionModifiers, CirCallableMemberWithParameters
|
interface CirFunction : CirFunctionOrProperty, CirFunctionModifiers, CirCallableMemberWithParameters
|
||||||
|
|
||||||
data class CirCommonFunction(
|
data class CirCommonFunction(
|
||||||
|
override val annotations: List<CirAnnotation>,
|
||||||
override val name: Name,
|
override val name: Name,
|
||||||
override val modality: Modality,
|
override val modality: Modality,
|
||||||
override val visibility: Visibility,
|
override val visibility: Visibility,
|
||||||
|
|||||||
+8
-4
@@ -9,7 +9,8 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirExtensionReceiver.Companion.toReceiver
|
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirExtensionReceiver.Companion.toReceiver
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.utils.intern
|
import org.jetbrains.kotlin.descriptors.commonizer.utils.intern
|
||||||
|
|
||||||
interface CirFunctionOrProperty : CirAnnotatedDeclaration, CirNamedDeclaration, CirDeclarationWithTypeParameters, CirDeclarationWithVisibility, CirDeclarationWithModality, CirMaybeCallableMemberOfClass {
|
interface CirFunctionOrProperty : CirAnnotatedDeclaration, CirNamedDeclaration, CirDeclarationWithTypeParameters,
|
||||||
|
CirDeclarationWithVisibility, CirDeclarationWithModality, CirMaybeCallableMemberOfClass {
|
||||||
val isExternal: Boolean
|
val isExternal: Boolean
|
||||||
val extensionReceiver: CirExtensionReceiver?
|
val extensionReceiver: CirExtensionReceiver?
|
||||||
val returnType: CirType
|
val returnType: CirType
|
||||||
@@ -17,7 +18,6 @@ interface CirFunctionOrProperty : CirAnnotatedDeclaration, CirNamedDeclaration,
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class CirCommonFunctionOrProperty : CirFunctionOrProperty {
|
abstract class CirCommonFunctionOrProperty : CirFunctionOrProperty {
|
||||||
final override val annotations: List<CirAnnotation> get() = emptyList() // TODO: commonize annotations, KT-34234
|
|
||||||
final override val containingClassKind: ClassKind? get() = unsupported()
|
final override val containingClassKind: ClassKind? get() = unsupported()
|
||||||
final override val containingClassModality: Modality? get() = unsupported()
|
final override val containingClassModality: Modality? get() = unsupported()
|
||||||
final override val containingClassIsData: Boolean? get() = unsupported()
|
final override val containingClassIsData: Boolean? get() = unsupported()
|
||||||
@@ -50,8 +50,12 @@ data class CirExtensionReceiver(
|
|||||||
val type: CirType
|
val type: CirType
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun CirType.toReceiverNoAnnotations() = CirExtensionReceiver( /* TODO: commonize annotations, KT-34234 */ emptyList(), this)
|
fun CirType.toReceiverNoAnnotations() = CirExtensionReceiver(annotations = emptyList(), type = this)
|
||||||
fun ReceiverParameterDescriptor.toReceiver() = CirExtensionReceiver(annotations.map(CirAnnotation.Companion::create), CirType.create(type))
|
|
||||||
|
fun ReceiverParameterDescriptor.toReceiver() = CirExtensionReceiver(
|
||||||
|
annotations = annotations.map(CirAnnotation.Companion::create),
|
||||||
|
type = CirType.create(type)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -36,6 +36,7 @@ data class CirCommonProperty(
|
|||||||
override val setter: CirSetter?,
|
override val setter: CirSetter?,
|
||||||
override val typeParameters: List<CirTypeParameter>
|
override val typeParameters: List<CirTypeParameter>
|
||||||
) : CirCommonFunctionOrProperty(), CirProperty {
|
) : CirCommonFunctionOrProperty(), CirProperty {
|
||||||
|
override val annotations: List<CirAnnotation> get() = emptyList()
|
||||||
override val isVar get() = setter != null
|
override val isVar get() = setter != null
|
||||||
override val isLateInit get() = false
|
override val isLateInit get() = false
|
||||||
override val isConst get() = false
|
override val isConst get() = false
|
||||||
|
|||||||
@@ -7,11 +7,8 @@ package org.jetbrains.kotlin.descriptors.commonizer.utils
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.types.getAbbreviation
|
import org.jetbrains.kotlin.types.getAbbreviation
|
||||||
|
|
||||||
private val DEPRECATED_ANNOTATION_FQN = FqName(Deprecated::class.java.name)
|
|
||||||
|
|
||||||
internal fun SimpleFunctionDescriptor.isKniBridgeFunction() =
|
internal fun SimpleFunctionDescriptor.isKniBridgeFunction() =
|
||||||
name.asString().startsWith("kniBridge")
|
name.asString().startsWith("kniBridge")
|
||||||
|
|
||||||
|
|||||||
+14
-4
@@ -12,11 +12,13 @@ internal fun checkConstantSupportedInCommonization(
|
|||||||
constantValue: ConstantValue<*>,
|
constantValue: ConstantValue<*>,
|
||||||
constantName: Name? = null,
|
constantName: Name? = null,
|
||||||
owner: Any,
|
owner: Any,
|
||||||
|
allowAnnotationValues: Boolean = false,
|
||||||
onError: (String) -> Nothing = ::error
|
onError: (String) -> Nothing = ::error
|
||||||
) {
|
) {
|
||||||
checkConstantSupportedInCommonization(
|
checkConstantSupportedInCommonization(
|
||||||
constantValue = constantValue,
|
constantValue = constantValue,
|
||||||
location = { "${owner::class.java}, $owner" + constantName?.asString()?.let { "[$it]" } },
|
location = { "${owner::class.java}, $owner" + constantName?.asString()?.let { "[$it]" } },
|
||||||
|
allowAnnotationValues = allowAnnotationValues,
|
||||||
onError = onError
|
onError = onError
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -24,6 +26,7 @@ internal fun checkConstantSupportedInCommonization(
|
|||||||
private fun checkConstantSupportedInCommonization(
|
private fun checkConstantSupportedInCommonization(
|
||||||
constantValue: ConstantValue<*>,
|
constantValue: ConstantValue<*>,
|
||||||
location: () -> String,
|
location: () -> String,
|
||||||
|
allowAnnotationValues: Boolean,
|
||||||
onError: (String) -> Nothing
|
onError: (String) -> Nothing
|
||||||
) {
|
) {
|
||||||
@Suppress("TrailingComma")
|
@Suppress("TrailingComma")
|
||||||
@@ -36,21 +39,28 @@ private fun checkConstantSupportedInCommonization(
|
|||||||
is DoubleValue,
|
is DoubleValue,
|
||||||
is FloatValue,
|
is FloatValue,
|
||||||
is EnumValue -> {
|
is EnumValue -> {
|
||||||
// OK
|
return // OK
|
||||||
}
|
}
|
||||||
is AnnotationValue -> {
|
is AnnotationValue -> {
|
||||||
if (constantValue.value.fqName?.isUnderStandardKotlinPackages != true)
|
if (allowAnnotationValues) {
|
||||||
onError("Only ${constantValue::class.java} const values from Kotlin standard packages are supported, $constantValue at ${location()}")
|
if (constantValue.value.fqName?.isUnderStandardKotlinPackages != true)
|
||||||
|
onError("Only ${constantValue::class.java} const values from Kotlin standard packages are supported, $constantValue at ${location()}")
|
||||||
|
return // OK
|
||||||
|
} // else fail (see below)
|
||||||
}
|
}
|
||||||
is ArrayValue -> {
|
is ArrayValue -> {
|
||||||
constantValue.value.forEachIndexed { index, innerConstantValue ->
|
constantValue.value.forEachIndexed { index, innerConstantValue ->
|
||||||
checkConstantSupportedInCommonization(
|
checkConstantSupportedInCommonization(
|
||||||
constantValue = innerConstantValue,
|
constantValue = innerConstantValue,
|
||||||
location = { "${location()}[$index]" },
|
location = { "${location()}[$index]" },
|
||||||
|
allowAnnotationValues = allowAnnotationValues,
|
||||||
onError = onError
|
onError = onError
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
return // OK
|
||||||
}
|
}
|
||||||
else -> onError("Unsupported const value type: ${constantValue::class.java}, $constantValue at ${location()}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onError("Unsupported const value type: ${constantValue::class.java}, $constantValue at ${location()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.serialization.konan.impl.ForwardDeclarationsFqNames
|
import org.jetbrains.kotlin.serialization.konan.impl.ForwardDeclarationsFqNames
|
||||||
|
|
||||||
|
internal val DEPRECATED_ANNOTATION_FQN: FqName = FqName(Deprecated::class.java.name)
|
||||||
|
|
||||||
private val STANDARD_KOTLIN_PACKAGE_PREFIXES = listOf(
|
private val STANDARD_KOTLIN_PACKAGE_PREFIXES = listOf(
|
||||||
KotlinBuiltIns.BUILT_INS_PACKAGE_NAME.asString(),
|
KotlinBuiltIns.BUILT_INS_PACKAGE_NAME.asString(),
|
||||||
"kotlinx"
|
"kotlinx"
|
||||||
|
|||||||
@@ -13,6 +13,16 @@ internal fun <T> Sequence<T>.toList(expectedCapacity: Int): List<T> {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal infix fun <K, V> Map<K, V>.concat(other: Map<K, V>): Map<K, V> =
|
||||||
|
when {
|
||||||
|
isEmpty() -> other
|
||||||
|
other.isEmpty() -> this
|
||||||
|
else -> HashMap<K, V>(size + other.size, 1F).apply {
|
||||||
|
putAll(this@concat)
|
||||||
|
putAll(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal inline fun <reified T> Iterable<T?>.firstNonNull() = firstIsInstance<T>()
|
internal inline fun <reified T> Iterable<T?>.firstNonNull() = firstIsInstance<T>()
|
||||||
|
|
||||||
internal fun Any?.isNull(): Boolean = this == null
|
internal fun Any?.isNull(): Boolean = this == null
|
||||||
|
|||||||
Reference in New Issue
Block a user