[Commonizer] Support generic/simple annotation commonization (to support kotlinx.cinterop.* annotations)

^KT-59302 Verification Pending
This commit is contained in:
Sebastian Sellmair
2023-08-03 13:10:26 +02:00
committed by Space Team
parent c2ad475153
commit d510c93241
14 changed files with 245 additions and 245 deletions
@@ -1,3 +1,4 @@
fun c(){
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
dummy.max(2,3)
}
@@ -1,3 +1,4 @@
fun sn(){
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
dummy.max(1,2)
}
@@ -1,5 +1,6 @@
package includedLib
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
fun linuxArm64(
a: cinterop.a.StructA
) {
@@ -4,6 +4,7 @@ import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
fun linuxMain() {
cinterop.a.a()
@OptIn(ExperimentalForeignApi::class)
@@ -1,5 +1,6 @@
package includedLib
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
fun linuxX64(
a: cinterop.a.StructA
) {
@@ -1,5 +1,6 @@
package lib
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
fun linuxArm64(
a: cinterop.lib.a.StructA
) {
@@ -4,6 +4,7 @@ import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
fun linuxMain() {
cinterop.lib.a.a()
@OptIn(ExperimentalForeignApi::class)
@@ -1,5 +1,6 @@
package lib
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
fun linuxX64(
a: cinterop.lib.a.StructA
) {
@@ -5,69 +5,48 @@
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.*
import kotlin.DeprecationLevel.WARNING
import org.jetbrains.kotlin.commonizer.cir.CirAnnotation
import org.jetbrains.kotlin.commonizer.cir.CirClassType
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.commonizer.utils.COMMONIZER_OBJC_INTEROP_CALLABLE_ANNOTATION_ID
import org.jetbrains.kotlin.commonizer.utils.DEPRECATED_ANNOTATION_CLASS_ID
import org.jetbrains.kotlin.commonizer.utils.isObjCInteropCallableAnnotation
/**
* 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
private var deprecatedAnnotationCommonizerHasResult: Boolean = true
private typealias Annotations = Map<CirEntityId, CirAnnotation>
private val objCInteropCallableAnnotationCommonizer = ObjCInteropCallableAnnotationCommonizer.asCommonizer()
private var objCInteropCallableAnnotationCommonizerHasResult = true
object AnnotationsCommonizer : AssociativeCommonizer<List<CirAnnotation>> {
override fun commonizationResult(): List<CirAnnotation> {
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
?: DeprecatedAnnotationCommonizer().also { this.deprecatedAnnotationCommonizer = it }
return deprecatedAnnotationCommonizer.commonizeWith(nextDeprecatedAnnotation)
}
companion object {
internal const val FALLBACK_MESSAGE = "See concrete deprecation messages in actual declarations"
}
}
object ObjCInteropCallableAnnotationCommonizer : AssociativeCommonizer<List<CirAnnotation>> {
override fun commonize(first: List<CirAnnotation>, second: List<CirAnnotation>): List<CirAnnotation> {
val firstAnnotations = first.associateBy { it.type.classifierId }
val secondAnnotations = second.associateBy { it.type.classifierId }
return setOfNotNull(
commonizedObjcCallableAnnotation(first, second),
commonizedDeprecatedAnnotation(firstAnnotations, secondAnnotations)
).plus(commonizedSimpleAnnotations(firstAnnotations, secondAnnotations)).toList()
}
private fun commonizedObjcCallableAnnotation(first: List<CirAnnotation>, second: List<CirAnnotation>): CirAnnotation? {
return if (first.any { it.type.classifierId.isObjCInteropCallableAnnotation } &&
second.any { it.type.classifierId.isObjCInteropCallableAnnotation }
) {
objCCallableAnnotationList
} else emptyList()
) objCCallableAnnotation else null
}
private fun commonizedSimpleAnnotations(first: Annotations, second: Annotations): List<CirAnnotation> {
fun CirAnnotation.isSimple() = type.arguments.isEmpty() && !type.classifierId.isObjCInteropCallableAnnotation &&
annotationValueArguments.isEmpty() && constantValueArguments.isEmpty()
return first.values.filter { annotation ->
annotation.isSimple() && second[annotation.type.classifierId].let { secondAnnotation ->
secondAnnotation != null && secondAnnotation.isSimple()
}
}
}
private fun commonizedDeprecatedAnnotation(first: Annotations, second: Annotations): CirAnnotation? {
val firstDeprecation = first[DEPRECATED_ANNOTATION_CLASS_ID] ?: return null
val secondDeprecation = second[DEPRECATED_ANNOTATION_CLASS_ID] ?: return null
return DeprecationAnnotationCommonizer.commonize(firstDeprecation, secondDeprecation)
}
private val objCCallableAnnotation = CirAnnotation.createInterned(
@@ -78,186 +57,4 @@ object ObjCInteropCallableAnnotationCommonizer : AssociativeCommonizer<List<CirA
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
private lateinit var replaceWithExpression: String
private lateinit var replaceWithImports: List<String>
override val result: CirAnnotation
get() {
val level: DeprecationLevel = level ?: failInEmptyState()
val messageValue: StringValue = message.toDeprecationMessageValue()
val constantValueArguments: Map<CirName, CirConstantValue> =
if (level == WARNING) {
// don't populate with the default level value
compactMapOf(PROPERTY_NAME_MESSAGE, messageValue)
} else
compactMapOf(
PROPERTY_NAME_MESSAGE, messageValue,
PROPERTY_NAME_LEVEL, level.toDeprecationLevelValue()
)
val annotationValueArguments: Map<CirName, CirAnnotation> =
if (replaceWithExpression.isEmpty() && replaceWithImports.isEmpty()) {
// don't populate with empty (default) ReplaceWith
emptyMap()
} else
compactMapOf(PROPERTY_NAME_REPLACE_WITH, replaceWithExpression.toReplaceWithValue(replaceWithImports))
return CirAnnotation.createInterned(
type = DEPRECATED_ANNOTATION_TYPE,
constantValueArguments = constantValueArguments,
annotationValueArguments = annotationValueArguments
)
}
override fun commonizeWith(next: CirAnnotation): Boolean {
val nextLevel: DeprecationLevel = next.getDeprecationLevel() ?: WARNING
val nextMessage: String = next.getDeprecationMessage().orEmpty()
val nextReplaceWith: CirAnnotation? = next.getReplaceWith()
val nextReplaceWithExpression: String = nextReplaceWith?.getReplaceWithExpression().orEmpty()
val nextReplaceWithImports: List<String> = nextReplaceWith?.getReplaceWithImports().orEmpty()
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
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 = ""
replaceWithImports = emptyList()
}
return true
}
@Suppress("NOTHING_TO_INLINE")
companion object {
private val PROPERTY_NAME_MESSAGE = CirName.create(Deprecated::message.name)
private val PROPERTY_NAME_REPLACE_WITH = CirName.create(Deprecated::replaceWith.name)
private val PROPERTY_NAME_LEVEL = CirName.create(Deprecated::level.name)
private val PROPERTY_NAME_EXPRESSION = CirName.create(ReplaceWith::expression.name)
private val PROPERTY_NAME_IMPORTS = CirName.create(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(FALLBACK_MESSAGE)
private val DEPRECATED_ANNOTATION_TYPE = buildAnnotationType(DEPRECATED_ANNOTATION_CLASS_ID)
private val REPLACE_WITH_ANNOTATION_TYPE = buildAnnotationType(CirEntityId.create("kotlin/ReplaceWith"))
private val DEPRECATION_LEVEL_CLASS_ID = CirEntityId.create("kotlin/DeprecationLevel")
// 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, CirName.create(it.name))
}
private fun buildAnnotationType(classId: CirEntityId) = CirClassType.createInterned(
classId = classId,
outerType = null,
arguments = emptyList(),
isMarkedNullable = false
)
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 =
createReplaceWithAnnotation(this, imports)
private inline fun Map<CirName, CirConstantValue>.getString(name: CirName): String? =
(this[name] as? StringValue)?.value
private inline fun Map<CirName, CirConstantValue>.getEnumEntryName(name: CirName): String? =
(this[name] as? EnumValue)?.enumEntryName?.name
private inline fun Map<CirName, CirAnnotation>.getAnnotation(name: CirName): CirAnnotation? =
this[name]
private inline fun Map<CirName, CirConstantValue>.getStringArray(name: CirName): List<String>? {
val elements: List<CirConstantValue> = (this[name] as? ArrayValue)?.elements ?: return null
if (elements.isEmpty()) return emptyList()
val result = ArrayList<String>(elements.size)
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.createInterned(
type = REPLACE_WITH_ANNOTATION_TYPE,
constantValueArguments = compactMapOf(
PROPERTY_NAME_EXPRESSION, StringValue(expression),
PROPERTY_NAME_IMPORTS, ArrayValue(imports.compactMap(::StringValue))
),
annotationValueArguments = emptyMap()
)
}
}
@@ -17,7 +17,7 @@ class ClassConstructorCommonizer(
private val visibility = VisibilityCommonizer.equalizing()
private val typeParameterListCommonizer = TypeParameterListCommonizer(typeCommonizer)
private val valueParametersCommonizer = CallableValueParametersCommonizer(typeCommonizer)
private val annotationsCommonizer: AnnotationsCommonizer = AnnotationsCommonizer()
private val annotationsCommonizer = AnnotationsCommonizer.asCommonizer()
override fun commonizationResult(): CirClassConstructor? {
val valueParameters = valueParametersCommonizer.result ?: return null
@@ -0,0 +1,162 @@
/*
* Copyright 2010-2023 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.core
import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.commonizer.utils.DEPRECATED_ANNOTATION_CLASS_ID
import org.jetbrains.kotlin.commonizer.utils.compactMap
import org.jetbrains.kotlin.commonizer.utils.compactMapOf
@Suppress("NOTHING_TO_INLINE")
object DeprecationAnnotationCommonizer : AssociativeCommonizer<CirAnnotation> {
override fun commonize(first: CirAnnotation, second: CirAnnotation): CirAnnotation {
val deprecationLevel = run {
val firstLevel = first.getDeprecationLevel() ?: DeprecationLevel.WARNING
val secondLevel = second.getDeprecationLevel() ?: DeprecationLevel.WARNING
if (secondLevel.ordinal > firstLevel.ordinal) secondLevel else firstLevel
}
val deprecationMessage = run {
val firstMessage = first.getDeprecationMessage() ?: return@run null
val secondMessage = second.getDeprecationMessage() ?: return@run null
if (firstMessage == secondMessage) firstMessage else null
}
val replaceWith = run {
val firstReplaceWith = first.getReplaceWith() ?: return@run null
val secondReplaceWith = second.getReplaceWith() ?: return@run null
val firstReplaceWithExpression = firstReplaceWith.getReplaceWithExpression().orEmpty()
val secondReplaceWithExpression = secondReplaceWith.getReplaceWithExpression().orEmpty()
val firstReplaceWithImports = firstReplaceWith.getReplaceWithImports().orEmpty()
val secondReplaceWithImports = secondReplaceWith.getReplaceWithImports().orEmpty()
if (
firstReplaceWithExpression == secondReplaceWithExpression &&
firstReplaceWithImports == secondReplaceWithImports &&
/* Empty replace with */
(firstReplaceWithExpression.isNotEmpty() || firstReplaceWithImports.isNotEmpty())
) firstReplaceWithExpression.toReplaceWithValue(firstReplaceWithImports) else null
}
val constantValueArguments: Map<CirName, CirConstantValue> = if (deprecationLevel == DeprecationLevel.WARNING) {
// don't populate with the default level value
compactMapOf(PROPERTY_NAME_MESSAGE, deprecationMessage.toDeprecationMessageValue())
} else compactMapOf(
PROPERTY_NAME_MESSAGE, deprecationMessage.toDeprecationMessageValue(),
PROPERTY_NAME_LEVEL, deprecationLevel.toDeprecationLevelValue()
)
val annotationValueArguments: Map<CirName, CirAnnotation> = if (replaceWith == null) {
// don't populate with empty (default) ReplaceWith
emptyMap()
} else compactMapOf(PROPERTY_NAME_REPLACE_WITH, replaceWith)
return CirAnnotation.createInterned(
type = DEPRECATED_ANNOTATION_TYPE,
constantValueArguments = constantValueArguments,
annotationValueArguments = annotationValueArguments
)
}
private val PROPERTY_NAME_MESSAGE = CirName.create(Deprecated::message.name)
private val PROPERTY_NAME_REPLACE_WITH = CirName.create(Deprecated::replaceWith.name)
private val PROPERTY_NAME_LEVEL = CirName.create(Deprecated::level.name)
private val PROPERTY_NAME_EXPRESSION = CirName.create(ReplaceWith::expression.name)
private val PROPERTY_NAME_IMPORTS = CirName.create(ReplaceWith::imports.name)
internal const val FALLBACK_MESSAGE = "See concrete deprecation messages in actual declarations"
// Optimization: Keep most frequently used message constants.
private val FREQUENTLY_USED_MESSAGE_VALUES: Map<String, CirConstantValue.StringValue> = listOf(
"Use constructor instead",
"Use factory method instead"
).associateWith { CirConstantValue.StringValue(it) }
private val FALLBACK_MESSAGE_VALUE = CirConstantValue.StringValue(FALLBACK_MESSAGE)
private val DEPRECATED_ANNOTATION_TYPE = buildAnnotationType(DEPRECATED_ANNOTATION_CLASS_ID)
private val REPLACE_WITH_ANNOTATION_TYPE = buildAnnotationType(CirEntityId.create("kotlin/ReplaceWith"))
private val DEPRECATION_LEVEL_CLASS_ID = CirEntityId.create("kotlin/DeprecationLevel")
// Optimization: Keep DeprecationLevel enum constants.
private val DEPRECATION_LEVEL_ENUM_ENTRY_VALUES: Map<String, CirConstantValue.EnumValue> = DeprecationLevel.entries.associate {
it.name to CirConstantValue.EnumValue(DEPRECATION_LEVEL_CLASS_ID, CirName.create(it.name))
}
private fun buildAnnotationType(classId: CirEntityId) = CirClassType.createInterned(
classId = classId,
outerType = null,
arguments = emptyList(),
isMarkedNullable = false
)
private fun CirAnnotation.getDeprecationMessage(): String? = constantValueArguments.getString(PROPERTY_NAME_MESSAGE)
private fun String?.toDeprecationMessageValue(): CirConstantValue.StringValue =
if (this == null)
FALLBACK_MESSAGE_VALUE
else
FREQUENTLY_USED_MESSAGE_VALUES[this] ?: CirConstantValue.StringValue(this)
private fun CirAnnotation.getDeprecationLevel(): DeprecationLevel? {
val enumEntryName = constantValueArguments.getEnumEntryName(PROPERTY_NAME_LEVEL) ?: return null
return DeprecationLevel.entries.firstOrNull { it.name == enumEntryName }
}
private fun DeprecationLevel.toDeprecationLevelValue(): CirConstantValue.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 =
createReplaceWithAnnotation(this, imports)
private inline fun Map<CirName, CirConstantValue>.getString(name: CirName): String? =
(this[name] as? CirConstantValue.StringValue)?.value
private inline fun Map<CirName, CirConstantValue>.getEnumEntryName(name: CirName): String? =
(this[name] as? CirConstantValue.EnumValue)?.enumEntryName?.name
private inline fun Map<CirName, CirAnnotation>.getAnnotation(name: CirName): CirAnnotation? =
this[name]
private inline fun Map<CirName, CirConstantValue>.getStringArray(name: CirName): List<String>? {
val elements: List<CirConstantValue> = (this[name] as? CirConstantValue.ArrayValue)?.elements ?: return null
if (elements.isEmpty()) return emptyList()
val result = ArrayList<String>(elements.size)
for (element in elements) {
if (element is CirConstantValue.StringValue) {
result += element.value
} else
return null
}
return result
}
private inline fun createReplaceWithAnnotation(expression: String, imports: List<String>): CirAnnotation =
CirAnnotation.createInterned(
type = REPLACE_WITH_ANNOTATION_TYPE,
constantValueArguments = compactMapOf(
PROPERTY_NAME_EXPRESSION, CirConstantValue.StringValue(expression),
PROPERTY_NAME_IMPORTS, CirConstantValue.ArrayValue(imports.compactMap(CirConstantValue::StringValue))
),
annotationValueArguments = emptyMap()
)
}
@@ -16,7 +16,7 @@ class FunctionCommonizer(
val functionOrProperty = functionOrPropertyBaseCommonizer(values) ?: return null
val valueParametersResult = CallableValueParametersCommonizer(typeCommonizer).commonize(values) ?: return null
return CirFunction(
annotations = AnnotationsCommonizer().commonize(values.map { it.annotations })
annotations = AnnotationsCommonizer.commonize(values.map { it.annotations.toList() })
?.plus(functionOrProperty.additionalAnnotations)
?: return null,
name = values.first().name,
@@ -42,7 +42,7 @@ class AnnotationsCommonizerTest : AbstractCommonizerTest<List<CirAnnotation>, Li
@Test
fun noRelevantAnnotations3() = doTestSuccess(
expected = emptyList(),
expected = listOf(mockAnnotation("org/sample/Foo")),
listOf(mockAnnotation("org/sample/Foo")),
listOf(mockAnnotation("org/sample/Foo")),
listOf(mockAnnotation("org/sample/Foo"))
@@ -58,7 +58,7 @@ class AnnotationsCommonizerTest : AbstractCommonizerTest<List<CirAnnotation>, Li
@Test
fun noRelevantAnnotations5() = doTestSuccess(
expected = emptyList(),
expected = listOf(mockAnnotation("kotlin/PublishedApi")),
listOf(mockAnnotation("kotlin/PublishedApi")),
listOf(mockAnnotation("kotlin/PublishedApi")),
listOf(mockAnnotation("kotlin/PublishedApi"))
@@ -74,7 +74,7 @@ class AnnotationsCommonizerTest : AbstractCommonizerTest<List<CirAnnotation>, Li
@Test
fun differentMessages() = doTestSuccess(
expected = listOf(mockDeprecated(message = AnnotationsCommonizer.FALLBACK_MESSAGE)),
expected = listOf(mockDeprecated(message = DeprecationAnnotationCommonizer.FALLBACK_MESSAGE)),
listOf(mockDeprecated(message = "please don't use it because ...")),
listOf(mockDeprecated(message = "it should not be used due to ...")),
listOf(mockDeprecated(message = "please don't use it because ..."))
@@ -276,7 +276,7 @@ class AnnotationsCommonizerTest : AbstractCommonizerTest<List<CirAnnotation>, Li
)
)
override fun createCommonizer() = AnnotationsCommonizer()
override fun createCommonizer() = AnnotationsCommonizer.asCommonizer()
}
private fun mockAnnotation(
@@ -135,4 +135,37 @@ class HierarchicalFunctionCommonizationTest : AbstractInlineSourcesCommonization
result.assertCommonized("(a, b)", "expect fun x(): ABCD")
result.assertCommonized("((a,b), c)", "expect fun x(): ABCD")
}
fun `test function with simple annotation`() {
val result = commonize {
outputTarget("(a, b)")
registerDependency("a", "b", "(a, b)") { source("annotation class FooAnnotation") }
simpleSingleSourceTarget("a", "@FooAnnotation fun x() = Unit")
simpleSingleSourceTarget("b", "@FooAnnotation fun x() = Unit")
}
result.assertCommonized("(a, b)", "@FooAnnotation expect fun x()")
}
fun `test function with non-simple annotation - 1`() {
val result = commonize {
outputTarget("(a, b)")
registerDependency("a", "b", "(a, b)") { source("annotation class FooAnnotation(val param: String)") }
simpleSingleSourceTarget("a", """@FooAnnotation("a") fun x() = Unit""")
simpleSingleSourceTarget("b", """@FooAnnotation("b") fun x() = Unit""")
}
result.assertCommonized("(a, b)", "expect fun x()")
}
fun `test function with non-simple annotation - 2`() {
val result = commonize {
outputTarget("(a, b)")
registerDependency("a", "b", "(a, b)") { source("annotation class FooAnnotation<T: Any>(val param: String)") }
simpleSingleSourceTarget("a", """@FooAnnotation<Unit>("a") fun x() = Unit""")
simpleSingleSourceTarget("b", """@FooAnnotation<Unit>("b") fun x() = Unit""")
}
result.assertCommonized("(a, b)", "expect fun x()")
}
}