diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AnnotationsCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AnnotationsCommonizer.kt index e460991d02a..740b92049b9 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AnnotationsCommonizer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AnnotationsCommonizer.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.descriptors.commonizer.core +import org.jetbrains.kotlin.descriptors.commonizer.core.AnnotationsCommonizer.Companion.FALLBACK_MESSAGE 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 @@ -14,6 +15,7 @@ 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 +import kotlin.DeprecationLevel.WARNING /** * This is limited implementation of annotations commonizer. It helps to commonize only [kotlin.Deprecated] annotations. @@ -30,39 +32,55 @@ class AnnotationsCommonizer : AbstractStandardCommonizer, Li override fun doCommonizeWith(next: List): Boolean { val nextDeprecatedAnnotation = next.firstOrNull { it.fqName == DEPRECATED_ANNOTATION_FQN } ?: return true - val deprecatedAnnotationCommonizer = deprecatedAnnotationCommonizer ?: DeprecatedAnnotationCommonizer() + 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" + } } private class DeprecatedAnnotationCommonizer : Commonizer { 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? = null + private lateinit var replaceWithExpression: String + private lateinit var replaceWithImports: List override val result: CirAnnotation get() { - if (level == null) throw IllegalCommonizerStateException() + val level: DeprecationLevel = level ?: throw IllegalCommonizerStateException() + val messageValue: StringValue = message.toDeprecationMessageValue() + + val constantValueArguments: Map> = if (level == WARNING) { + // don't populate with the default level value + mapOf(PROPERTY_NAME_MESSAGE to messageValue) + } else + hashMapOf( + PROPERTY_NAME_MESSAGE to messageValue, + PROPERTY_NAME_LEVEL to level.toDeprecationLevelValue() + ) + + val annotationValueArguments: Map = if (replaceWithExpression.isEmpty() && replaceWithImports.isEmpty()) { + // don't populate with empty (default) ReplaceWith + emptyMap() + } else + mapOf(PROPERTY_NAME_REPLACE_WITH to replaceWithExpression.toReplaceWithValue(replaceWithImports)) return CirAnnotation.create( fqName = DEPRECATED_ANNOTATION_FQN, - constantValueArguments = mapOf>( - PROPERTY_NAME_LEVEL to level!!.toDeprecationLevelValue(), - PROPERTY_NAME_MESSAGE to message.toDeprecationMessageValue() - ), - annotationValueArguments = mapOf( - PROPERTY_NAME_REPLACE_WITH to replaceWithExpression.toReplaceWithValue(replaceWithImports) - ) + constantValueArguments = constantValueArguments, + annotationValueArguments = annotationValueArguments ) } override fun commonizeWith(next: CirAnnotation): Boolean { - val nextLevel: DeprecationLevel = next.getDeprecationLevel() ?: DeprecationLevel.HIDDEN - val nextMessage: String? = next.getDeprecationMessage() + val nextLevel: DeprecationLevel = next.getDeprecationLevel() ?: WARNING + val nextMessage: String = next.getDeprecationMessage().orEmpty() val nextReplaceWith: CirAnnotation? = next.getReplaceWith() - val nextReplaceWithExpression: String? = nextReplaceWith?.getReplaceWithExpression() - val nextReplaceWithImports: List? = nextReplaceWith?.getReplaceWithImports() + val nextReplaceWithExpression: String = nextReplaceWith?.getReplaceWithExpression().orEmpty() + val nextReplaceWithImports: List = nextReplaceWith?.getReplaceWithImports().orEmpty() return if (level != null) { doCommonizeWith(nextLevel, nextMessage, nextReplaceWithExpression, nextReplaceWithImports) @@ -76,23 +94,20 @@ private class DeprecatedAnnotationCommonizer : Commonizer? + nextReplaceWithExpression: String, + nextReplaceWithImports: List ) { level = nextLevel message = nextMessage - - if (nextReplaceWithExpression != null && nextReplaceWithImports != null) { - replaceWithExpression = nextReplaceWithExpression - replaceWithImports = nextReplaceWithImports - } + replaceWithExpression = nextReplaceWithExpression + replaceWithImports = nextReplaceWithImports } private fun doCommonizeWith( nextLevel: DeprecationLevel, nextMessage: String?, - nextReplaceWithExpression: String?, - nextReplaceWithImports: List? + nextReplaceWithExpression: String, + nextReplaceWithImports: List ): Boolean { if (nextLevel.ordinal > level!!.ordinal) level = nextLevel @@ -101,8 +116,8 @@ private class DeprecatedAnnotationCommonizer : Commonizer? = constantValueArguments.getStringArray(PROPERTY_NAME_IMPORTS) - private fun String?.toReplaceWithValue(imports: List?): CirAnnotation = - if (this == null || imports == null) - EMPTY_REPLACE_WITH_CIR_ANNOTATION - else - createReplaceWithAnnotation(this, imports) + private fun String.toReplaceWithValue(imports: List): CirAnnotation = + createReplaceWithAnnotation(this, imports) private inline fun Map>.getString(name: Name): String? = (this[name] as? StringValue)?.value diff --git a/native/commonizer/testData/functionCommonization/annotations/commonized/common/package_root.kt b/native/commonizer/testData/functionCommonization/annotations/commonized/common/package_root.kt new file mode 100644 index 00000000000..ce54f4ef979 --- /dev/null +++ b/native/commonizer/testData/functionCommonization/annotations/commonized/common/package_root.kt @@ -0,0 +1,45 @@ +expect class Holder() { + @Deprecated("This function is deprecated") + expect fun deprecatedFunction1() + + @Deprecated("See concrete deprecation messages in actual declarations") + expect fun deprecatedFunctionWithCustomizedAnnotation1() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation2() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation3() + @Deprecated("This function is deprecated", level = DeprecationLevel.ERROR) + expect fun deprecatedFunctionWithCustomizedAnnotation4() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation5() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation6() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation7() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation8() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation9() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation10() + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()")) + expect fun deprecatedFunctionWithCustomizedAnnotation11() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation12() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation13() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation14() + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.foo"))) + expect fun deprecatedFunctionWithCustomizedAnnotation15() + @Deprecated("This function is deprecated") + expect fun deprecatedFunctionWithCustomizedAnnotation16() + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()", imports = arrayOf("org.sample.foo"))) + fun deprecatedFunctionWithCustomizedAnnotation17() {} + @Deprecated("This function is deprecated") + fun deprecatedFunctionWithCustomizedAnnotation18() {} + @Deprecated("This function is deprecated") + fun deprecatedFunctionWithCustomizedAnnotation19() {} + + expect fun nonDeprecatedFunction1() +} diff --git a/native/commonizer/testData/functionCommonization/annotations/commonized/js/package_root.kt b/native/commonizer/testData/functionCommonization/annotations/commonized/js/package_root.kt new file mode 100644 index 00000000000..33068c11803 --- /dev/null +++ b/native/commonizer/testData/functionCommonization/annotations/commonized/js/package_root.kt @@ -0,0 +1,48 @@ +actual class Holder actual constructor() { + @Deprecated("This function is deprecated") + actual fun deprecatedFunction1() {} + @Deprecated("This function is deprecated") + fun deprecatedFunction2() {} + + @Deprecated("This function is deprecated") + actual fun deprecatedFunctionWithCustomizedAnnotation1() {} + @Deprecated("This function is deprecated") + actual fun deprecatedFunctionWithCustomizedAnnotation2() {} + @Deprecated("This function is deprecated", level = DeprecationLevel.WARNING) + actual fun deprecatedFunctionWithCustomizedAnnotation3() {} + @Deprecated("This function is deprecated") + actual fun deprecatedFunctionWithCustomizedAnnotation4() {} + @Deprecated("This function is deprecated") + actual fun deprecatedFunctionWithCustomizedAnnotation5() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("")) + actual fun deprecatedFunctionWithCustomizedAnnotation6() {} + @Deprecated("This function is deprecated") + actual fun deprecatedFunctionWithCustomizedAnnotation7() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("")) + actual fun deprecatedFunctionWithCustomizedAnnotation8() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = emptyArray())) + actual fun deprecatedFunctionWithCustomizedAnnotation9() {} + @Deprecated("This function is deprecated") + actual fun deprecatedFunctionWithCustomizedAnnotation10() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()")) + actual fun deprecatedFunctionWithCustomizedAnnotation11() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("bar()")) + actual fun deprecatedFunctionWithCustomizedAnnotation12() {} + @Deprecated("This function is deprecated") + actual fun deprecatedFunctionWithCustomizedAnnotation13() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("")) + actual fun deprecatedFunctionWithCustomizedAnnotation14() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.foo"))) + actual fun deprecatedFunctionWithCustomizedAnnotation15() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.bar"))) + actual fun deprecatedFunctionWithCustomizedAnnotation16() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()", imports = arrayOf("org.sample.foo"))) + actual fun deprecatedFunctionWithCustomizedAnnotation17() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()", imports = arrayOf("org.sample.bar"))) + actual fun deprecatedFunctionWithCustomizedAnnotation18() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("bar()", imports = arrayOf("org.sample.foo"))) + actual fun deprecatedFunctionWithCustomizedAnnotation19() {} + + actual fun nonDeprecatedFunction1() {} + fun nonDeprecatedFunction2() {} +} diff --git a/native/commonizer/testData/functionCommonization/annotations/commonized/jvm/package_root.kt b/native/commonizer/testData/functionCommonization/annotations/commonized/jvm/package_root.kt new file mode 100644 index 00000000000..4661283164e --- /dev/null +++ b/native/commonizer/testData/functionCommonization/annotations/commonized/jvm/package_root.kt @@ -0,0 +1,48 @@ +actual class Holder actual constructor() { + @Deprecated("This function is deprecated") + actual fun deprecatedFunction1() {} + @Deprecated("This function is deprecated") + fun deprecatedFunction3() {} + + @Deprecated("This function is deprecated as well") + actual fun deprecatedFunctionWithCustomizedAnnotation1() {} + @Deprecated("This function is deprecated", level = DeprecationLevel.WARNING) + actual fun deprecatedFunctionWithCustomizedAnnotation2() {} + @Deprecated("This function is deprecated", level = DeprecationLevel.WARNING) + actual fun deprecatedFunctionWithCustomizedAnnotation3() {} + @Deprecated("This function is deprecated", level = DeprecationLevel.ERROR) + actual fun deprecatedFunctionWithCustomizedAnnotation4() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("")) + actual fun deprecatedFunctionWithCustomizedAnnotation5() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("")) + actual fun deprecatedFunctionWithCustomizedAnnotation6() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = emptyArray())) + actual fun deprecatedFunctionWithCustomizedAnnotation7() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = emptyArray())) + actual fun deprecatedFunctionWithCustomizedAnnotation8() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = emptyArray())) + actual fun deprecatedFunctionWithCustomizedAnnotation9() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()")) + actual fun deprecatedFunctionWithCustomizedAnnotation10() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()")) + actual fun deprecatedFunctionWithCustomizedAnnotation11() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()")) + actual fun deprecatedFunctionWithCustomizedAnnotation12() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.foo"))) + actual fun deprecatedFunctionWithCustomizedAnnotation13() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.foo"))) + actual fun deprecatedFunctionWithCustomizedAnnotation14() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.foo"))) + actual fun deprecatedFunctionWithCustomizedAnnotation15() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.foo"))) + actual fun deprecatedFunctionWithCustomizedAnnotation16() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()", imports = arrayOf("org.sample.foo"))) + actual fun deprecatedFunctionWithCustomizedAnnotation17() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()", imports = arrayOf("org.sample.foo"))) + actual fun deprecatedFunctionWithCustomizedAnnotation18() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()", imports = arrayOf("org.sample.foo"))) + actual fun deprecatedFunctionWithCustomizedAnnotation19() {} + + actual fun nonDeprecatedFunction1() {} + fun nonDeprecatedFunction3() {} +} diff --git a/native/commonizer/testData/functionCommonization/annotations/original/js/package_root.kt b/native/commonizer/testData/functionCommonization/annotations/original/js/package_root.kt new file mode 100644 index 00000000000..84376d32918 --- /dev/null +++ b/native/commonizer/testData/functionCommonization/annotations/original/js/package_root.kt @@ -0,0 +1,53 @@ +@Deprecated("This function is deprecated") +fun deprecatedFunction1() {} +@Deprecated("This function is deprecated") +fun deprecatedFunction2() {} + +class Holder { + @Deprecated("This function is deprecated") + fun deprecatedFunction1() {} + @Deprecated("This function is deprecated") + fun deprecatedFunction2() {} + + @Deprecated("This function is deprecated") + fun deprecatedFunctionWithCustomizedAnnotation1() {} + @Deprecated("This function is deprecated") + fun deprecatedFunctionWithCustomizedAnnotation2() {} + @Deprecated("This function is deprecated", level = DeprecationLevel.WARNING) + fun deprecatedFunctionWithCustomizedAnnotation3() {} + @Deprecated("This function is deprecated") + fun deprecatedFunctionWithCustomizedAnnotation4() {} + @Deprecated("This function is deprecated") + fun deprecatedFunctionWithCustomizedAnnotation5() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("")) + fun deprecatedFunctionWithCustomizedAnnotation6() {} + @Deprecated("This function is deprecated") + fun deprecatedFunctionWithCustomizedAnnotation7() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("")) + fun deprecatedFunctionWithCustomizedAnnotation8() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = emptyArray())) + fun deprecatedFunctionWithCustomizedAnnotation9() {} + @Deprecated("This function is deprecated") + fun deprecatedFunctionWithCustomizedAnnotation10() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()")) + fun deprecatedFunctionWithCustomizedAnnotation11() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("bar()")) + fun deprecatedFunctionWithCustomizedAnnotation12() {} + @Deprecated("This function is deprecated") + fun deprecatedFunctionWithCustomizedAnnotation13() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("")) + fun deprecatedFunctionWithCustomizedAnnotation14() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.foo"))) + fun deprecatedFunctionWithCustomizedAnnotation15() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.bar"))) + fun deprecatedFunctionWithCustomizedAnnotation16() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()", imports = arrayOf("org.sample.foo"))) + fun deprecatedFunctionWithCustomizedAnnotation17() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()", imports = arrayOf("org.sample.bar"))) + fun deprecatedFunctionWithCustomizedAnnotation18() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("bar()", imports = arrayOf("org.sample.foo"))) + fun deprecatedFunctionWithCustomizedAnnotation19() {} + + fun nonDeprecatedFunction1() {} + fun nonDeprecatedFunction2() {} +} diff --git a/native/commonizer/testData/functionCommonization/annotations/original/jvm/package_root.kt b/native/commonizer/testData/functionCommonization/annotations/original/jvm/package_root.kt new file mode 100644 index 00000000000..8eb18b4dae0 --- /dev/null +++ b/native/commonizer/testData/functionCommonization/annotations/original/jvm/package_root.kt @@ -0,0 +1,53 @@ +@Deprecated("This function is deprecated") +fun deprecatedFunction1() {} +@Deprecated("This function is deprecated") +fun deprecatedFunction3() {} + +class Holder { + @Deprecated("This function is deprecated") + fun deprecatedFunction1() {} + @Deprecated("This function is deprecated") + fun deprecatedFunction3() {} + + @Deprecated("This function is deprecated as well") + fun deprecatedFunctionWithCustomizedAnnotation1() {} + @Deprecated("This function is deprecated", level = DeprecationLevel.WARNING) + fun deprecatedFunctionWithCustomizedAnnotation2() {} + @Deprecated("This function is deprecated", level = DeprecationLevel.WARNING) + fun deprecatedFunctionWithCustomizedAnnotation3() {} + @Deprecated("This function is deprecated", level = DeprecationLevel.ERROR) + fun deprecatedFunctionWithCustomizedAnnotation4() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("")) + fun deprecatedFunctionWithCustomizedAnnotation5() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("")) + fun deprecatedFunctionWithCustomizedAnnotation6() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = emptyArray())) + fun deprecatedFunctionWithCustomizedAnnotation7() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = emptyArray())) + fun deprecatedFunctionWithCustomizedAnnotation8() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = emptyArray())) + fun deprecatedFunctionWithCustomizedAnnotation9() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()")) + fun deprecatedFunctionWithCustomizedAnnotation10() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()")) + fun deprecatedFunctionWithCustomizedAnnotation11() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()")) + fun deprecatedFunctionWithCustomizedAnnotation12() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.foo"))) + fun deprecatedFunctionWithCustomizedAnnotation13() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.foo"))) + fun deprecatedFunctionWithCustomizedAnnotation14() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.foo"))) + fun deprecatedFunctionWithCustomizedAnnotation15() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("", imports = arrayOf("org.sample.foo"))) + fun deprecatedFunctionWithCustomizedAnnotation16() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()", imports = arrayOf("org.sample.foo"))) + fun deprecatedFunctionWithCustomizedAnnotation17() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()", imports = arrayOf("org.sample.foo"))) + fun deprecatedFunctionWithCustomizedAnnotation18() {} + @Deprecated("This function is deprecated", replaceWith = ReplaceWith("foo()", imports = arrayOf("org.sample.foo"))) + fun deprecatedFunctionWithCustomizedAnnotation19() {} + + fun nonDeprecatedFunction1() {} + fun nonDeprecatedFunction3() {} +} diff --git a/native/commonizer/testData/functionCommonization/specifics/commonized/common/package_root.kt b/native/commonizer/testData/functionCommonization/specifics/commonized/common/package_root.kt index 4711ca2507e..43d5aa82a9f 100644 --- a/native/commonizer/testData/functionCommonization/specifics/commonized/common/package_root.kt +++ b/native/commonizer/testData/functionCommonization/specifics/commonized/common/package_root.kt @@ -16,8 +16,3 @@ expect fun externalFunction2() expect inline fun inlineFunction1() {} expect fun inlineFunction2() {} - -expect class Holder() { - expect fun deprecatedFunction1() - expect fun nonDeprecatedFunction1() -} diff --git a/native/commonizer/testData/functionCommonization/specifics/commonized/js/package_root.kt b/native/commonizer/testData/functionCommonization/specifics/commonized/js/package_root.kt index c07798f3e7d..b4d1d29b05b 100644 --- a/native/commonizer/testData/functionCommonization/specifics/commonized/js/package_root.kt +++ b/native/commonizer/testData/functionCommonization/specifics/commonized/js/package_root.kt @@ -17,13 +17,3 @@ actual external fun externalFunction2() actual inline fun inlineFunction1() {} actual inline fun inlineFunction2() {} - -actual class Holder actual constructor() { - @Deprecated("This function is deprecated") - actual fun deprecatedFunction1() {} - @Deprecated("This function is deprecated") - fun deprecatedFunction2() {} - - actual fun nonDeprecatedFunction1() {} - fun nonDeprecatedFunction2() {} -} diff --git a/native/commonizer/testData/functionCommonization/specifics/commonized/jvm/package_root.kt b/native/commonizer/testData/functionCommonization/specifics/commonized/jvm/package_root.kt index 0eb81473183..9559cf2288a 100644 --- a/native/commonizer/testData/functionCommonization/specifics/commonized/jvm/package_root.kt +++ b/native/commonizer/testData/functionCommonization/specifics/commonized/jvm/package_root.kt @@ -17,13 +17,3 @@ actual fun externalFunction2() {} actual inline fun inlineFunction1() {} actual fun inlineFunction2() {} - -actual class Holder actual constructor() { - @Deprecated("This function is deprecated") - actual fun deprecatedFunction1() {} - @Deprecated("This function is deprecated") - fun deprecatedFunction3() {} - - actual fun nonDeprecatedFunction1() {} - fun nonDeprecatedFunction3() {} -} diff --git a/native/commonizer/testData/functionCommonization/specifics/original/js/package_root.kt b/native/commonizer/testData/functionCommonization/specifics/original/js/package_root.kt index b0580e2367c..c3f22b47b56 100644 --- a/native/commonizer/testData/functionCommonization/specifics/original/js/package_root.kt +++ b/native/commonizer/testData/functionCommonization/specifics/original/js/package_root.kt @@ -17,18 +17,3 @@ external fun externalFunction2() inline fun inlineFunction1() {} inline fun inlineFunction2() {} - -@Deprecated("This function is deprecated") -fun deprecatedFunction1() {} -@Deprecated("This function is deprecated") -fun deprecatedFunction2() {} - -class Holder { - @Deprecated("This function is deprecated") - fun deprecatedFunction1() {} - @Deprecated("This function is deprecated") - fun deprecatedFunction2() {} - - fun nonDeprecatedFunction1() {} - fun nonDeprecatedFunction2() {} -} diff --git a/native/commonizer/testData/functionCommonization/specifics/original/jvm/package_root.kt b/native/commonizer/testData/functionCommonization/specifics/original/jvm/package_root.kt index 9bd00b7f5fa..59b0f9d204c 100644 --- a/native/commonizer/testData/functionCommonization/specifics/original/jvm/package_root.kt +++ b/native/commonizer/testData/functionCommonization/specifics/original/jvm/package_root.kt @@ -17,18 +17,3 @@ fun externalFunction2() {} inline fun inlineFunction1() {} fun inlineFunction2() {} - -@Deprecated("This function is deprecated") -fun deprecatedFunction1() {} -@Deprecated("This function is deprecated") -fun deprecatedFunction3() {} - -class Holder { - @Deprecated("This function is deprecated") - fun deprecatedFunction1() {} - @Deprecated("This function is deprecated") - fun deprecatedFunction3() {} - - fun nonDeprecatedFunction1() {} - fun nonDeprecatedFunction3() {} -} diff --git a/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/FunctionCommonizationFromSourcesTest.kt b/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/FunctionCommonizationFromSourcesTest.kt index 2e103ad2f2f..a3469857839 100644 --- a/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/FunctionCommonizationFromSourcesTest.kt +++ b/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/FunctionCommonizationFromSourcesTest.kt @@ -12,5 +12,7 @@ class FunctionCommonizationFromSourcesTest : AbstractCommonizationFromSourcesTes fun testValueParameters() = doTestSuccessfulCommonization() + fun testAnnotations() = doTestSuccessfulCommonization() + fun testSpecifics() = doTestSuccessfulCommonization() } diff --git a/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/AnnotationsCommonizerTest.kt b/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/AnnotationsCommonizerTest.kt new file mode 100644 index 00000000000..a391dbe4907 --- /dev/null +++ b/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/AnnotationsCommonizerTest.kt @@ -0,0 +1,330 @@ +/* + * 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.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 +import org.junit.Test +import kotlin.DeprecationLevel.* + +class AnnotationsCommonizerTest : AbstractCommonizerTest, List>() { + + @Test + fun noAnnotations() = doTestSuccess( + expected = emptyList(), + emptyList(), + emptyList(), + emptyList() + ) + + @Test + fun noRelevantAnnotations1() = doTestSuccess( + expected = emptyList(), + emptyList(), + emptyList(), + listOf(mockAnnotation("org.sample.Foo")) + ) + + @Test + fun noRelevantAnnotations2() = doTestSuccess( + expected = emptyList(), + listOf(mockAnnotation("org.sample.Foo")), + emptyList(), + emptyList() + ) + + @Test + fun noRelevantAnnotations3() = doTestSuccess( + expected = emptyList(), + listOf(mockAnnotation("org.sample.Foo")), + listOf(mockAnnotation("org.sample.Foo")), + listOf(mockAnnotation("org.sample.Foo")) + ) + + @Test + fun noRelevantAnnotations4() = doTestSuccess( + expected = emptyList(), + listOf(mockAnnotation("org.sample.Foo")), + listOf(mockAnnotation("org.sample.Bar")), + listOf(mockAnnotation("org.sample.Baz")) + ) + + @Test + fun noRelevantAnnotations5() = doTestSuccess( + expected = emptyList(), + listOf(mockAnnotation("kotlin.PublishedApi")), + listOf(mockAnnotation("kotlin.PublishedApi")), + listOf(mockAnnotation("kotlin.PublishedApi")) + ) + + @Test + fun sameMessages() = doTestSuccess( + expected = listOf(mockDeprecated(message = "please don't use it because ...")), + listOf(mockDeprecated(message = "please don't use it because ...")), + listOf(mockDeprecated(message = "please don't use it because ...")), + listOf(mockDeprecated(message = "please don't use it because ...")) + ) + + @Test + fun differentMessages() = doTestSuccess( + expected = listOf(mockDeprecated(message = AnnotationsCommonizer.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 ...")) + ) + + @Test + fun sameLevels1() = doTestSuccess( + expected = listOf(mockDeprecated(level = WARNING)), + listOf(mockDeprecated(level = WARNING)), + listOf(mockDeprecated(level = WARNING)), + listOf(mockDeprecated(level = WARNING)) + ) + + @Test + fun sameLevels2() = doTestSuccess( + expected = listOf(mockDeprecated(level = ERROR)), + listOf(mockDeprecated(level = ERROR)), + listOf(mockDeprecated(level = ERROR)), + listOf(mockDeprecated(level = ERROR)) + ) + + @Test + fun sameLevels3() = doTestSuccess( + expected = listOf(mockDeprecated(level = HIDDEN)), + listOf(mockDeprecated(level = HIDDEN)), + listOf(mockDeprecated(level = HIDDEN)), + listOf(mockDeprecated(level = HIDDEN)) + ) + + @Test + fun differentLevels1() = doTestSuccess( + expected = listOf(mockDeprecated(level = ERROR)), + listOf(mockDeprecated(level = WARNING)), + listOf(mockDeprecated(level = ERROR)), + listOf(mockDeprecated(level = WARNING)) + ) + + @Test + fun differentLevels2() = doTestSuccess( + expected = listOf(mockDeprecated(level = HIDDEN)), + listOf(mockDeprecated(level = WARNING)), + listOf(mockDeprecated(level = HIDDEN)), + listOf(mockDeprecated(level = WARNING)) + ) + + @Test + fun differentLevels3() = doTestSuccess( + expected = listOf(mockDeprecated(level = HIDDEN)), + listOf(mockDeprecated(level = ERROR)), + listOf(mockDeprecated(level = HIDDEN)), + listOf(mockDeprecated(level = ERROR)) + ) + + @Test + fun differentLevels4() = doTestSuccess( + expected = listOf(mockDeprecated(level = HIDDEN)), + listOf(mockDeprecated(level = ERROR)), + listOf(mockDeprecated(level = HIDDEN)), + listOf(mockDeprecated(level = WARNING)) + ) + + @Test + fun sameReplaceWith1() = doTestSuccess( + expected = listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = emptyArray() + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = emptyArray() + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = emptyArray() + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = emptyArray() + ) + ) + ) + + @Test + fun sameReplaceWith2() = doTestSuccess( + expected = listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo") + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo") + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo") + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo") + ) + ) + ) + + @Test + fun sameReplaceWith3() = doTestSuccess( + expected = listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo", "org.sample.foo.*") + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo", "org.sample.foo.*") + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo", "org.sample.foo.*") + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo", "org.sample.foo.*") + ) + ) + ) + + @Test + fun differentReplaceWith1() = doTestSuccess( + expected = listOf( + mockDeprecated( + replaceWithExpression = "", + replaceWithImports = emptyArray() + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo", "org.sample.foo.*") + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Bar", + replaceWithImports = arrayOf("org.sample.Foo", "org.sample.foo.*") + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo", "org.sample.foo.*") + ) + ) + ) + + @Test + fun differentReplaceWith2() = doTestSuccess( + expected = listOf( + mockDeprecated( + replaceWithExpression = "", + replaceWithImports = emptyArray() + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo", "org.sample.foo.*") + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo") + ) + ), + listOf( + mockDeprecated( + replaceWithExpression = "org.sample.Foo", + replaceWithImports = arrayOf("org.sample.Foo", "org.sample.foo.*") + ) + ) + ) + + override fun createCommonizer() = AnnotationsCommonizer() + + override fun isEqual(a: List?, b: List?): Boolean { + return super.isEqual(a, b) + } +} + +private fun mockAnnotation( + fqName: String, + constantValueArguments: Map> = emptyMap(), + annotationValueArguments: Map = emptyMap() +): CirAnnotation = CirAnnotation.create( + fqName = FqName(fqName), + constantValueArguments = constantValueArguments, + annotationValueArguments = annotationValueArguments +) + +private fun mockDeprecated( + message: String = "", + level: DeprecationLevel = WARNING, + replaceWithExpression: String = "", + replaceWithImports: Array = emptyArray() +): CirAnnotation { + val replaceWith: CirAnnotation? = if (replaceWithExpression.isNotEmpty() || replaceWithImports.isNotEmpty()) { + mockAnnotation( + fqName = "kotlin.ReplaceWith", + constantValueArguments = mapOf( + Name.identifier("expression") to StringValue(replaceWithExpression), + Name.identifier("imports") to ArrayValue(replaceWithImports.map(::StringValue)) { + it.builtIns.getArrayElementType(it.builtIns.stringType) + } + ), + annotationValueArguments = emptyMap() + ) + } else null + + return mockAnnotation( + fqName = "kotlin.Deprecated", + constantValueArguments = HashMap>().apply { + this[Name.identifier("message")] = StringValue(message) + + if (level != WARNING) + this[Name.identifier("level")] = EnumValue( + ClassId.topLevel(FqName("kotlin.DeprecationLevel")), + Name.identifier(level.name) + ) + }, + annotationValueArguments = if (replaceWith != null) mapOf(Name.identifier("replaceWith") to replaceWith) else emptyMap() + ) +} diff --git a/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/utils/ComparingDeclarationsVisitor.kt b/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/utils/ComparingDeclarationsVisitor.kt index 563f8845bba..ac8a3954a1e 100644 --- a/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/utils/ComparingDeclarationsVisitor.kt +++ b/native/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/utils/ComparingDeclarationsVisitor.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.* 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.ConstantValue import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -429,6 +430,7 @@ internal class ComparingDeclarationsVisitor( constantValue = expectedValueArgument, constantName = name, owner = expected, + allowAnnotationValues = true, onError = { context.fail(it) } ) @@ -437,11 +439,26 @@ internal class ComparingDeclarationsVisitor( constantValue = actualValueArgument, constantName = name, owner = actual, + allowAnnotationValues = true, onError = { context.fail(it) } ) - context.assertEquals(expectedValueArgument::class, actualValueArgument::class, "annotation value argument classe") - context.assertEquals(expectedValueArgument.value, actualValueArgument.value, "annotation value argument value") + context.assertEquals(expectedValueArgument::class, actualValueArgument::class, "annotation value argument value") + if (expectedValueArgument is AnnotationValue && actualValueArgument is AnnotationValue) { + context.assertEquals( + expectedValueArgument.value.fqName, + actualValueArgument.value.fqName, + "nested annotation FQ name" + ) + + visitAnnotation( + expectedValueArgument.value, + actualValueArgument.value, + context.nextLevel("Annotation ${expectedValueArgument.value.fqName}") + ) + } else { + context.assertEquals(expectedValueArgument.value, actualValueArgument.value, "annotation value argument value") + } } }