[Commonizer] Limited annotation commonization. Tests

^KMM-238
^KMM-53
This commit is contained in:
Dmitriy Dolovov
2020-05-08 16:34:17 +07:00
parent 600daaa320
commit 5bb5d7f892
14 changed files with 642 additions and 93 deletions
@@ -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<List<CirAnnotation>, Li
override fun doCommonizeWith(next: List<CirAnnotation>): 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<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
private lateinit var replaceWithExpression: String
private lateinit var replaceWithImports: List<String>
override val result: CirAnnotation
get() {
if (level == null) throw IllegalCommonizerStateException()
val level: DeprecationLevel = level ?: throw IllegalCommonizerStateException()
val messageValue: StringValue = message.toDeprecationMessageValue()
val constantValueArguments: Map<Name, ConstantValue<*>> = 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<Name, CirAnnotation> = 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<Name, ConstantValue<*>>(
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<String>? = nextReplaceWith?.getReplaceWithImports()
val nextReplaceWithExpression: String = nextReplaceWith?.getReplaceWithExpression().orEmpty()
val nextReplaceWithImports: List<String> = nextReplaceWith?.getReplaceWithImports().orEmpty()
return if (level != null) {
doCommonizeWith(nextLevel, nextMessage, nextReplaceWithExpression, nextReplaceWithImports)
@@ -76,23 +94,20 @@ private class DeprecatedAnnotationCommonizer : Commonizer<CirAnnotation, CirAnno
private fun initialize(
nextLevel: DeprecationLevel,
nextMessage: String?,
nextReplaceWithExpression: String?,
nextReplaceWithImports: List<String>?
nextReplaceWithExpression: String,
nextReplaceWithImports: List<String>
) {
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<String>?
nextReplaceWithExpression: String,
nextReplaceWithImports: List<String>
): Boolean {
if (nextLevel.ordinal > level!!.ordinal)
level = nextLevel
@@ -101,8 +116,8 @@ private class DeprecatedAnnotationCommonizer : Commonizer<CirAnnotation, CirAnno
message = null
if (nextReplaceWithExpression != replaceWithExpression || nextReplaceWithImports != replaceWithImports) {
replaceWithExpression = null
replaceWithImports = null
replaceWithExpression = ""
replaceWithImports = emptyList()
}
return true
@@ -122,8 +137,7 @@ private class DeprecatedAnnotationCommonizer : Commonizer<CirAnnotation, CirAnno
"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 FALLBACK_MESSAGE_VALUE = StringValue(FALLBACK_MESSAGE)
private val DEPRECATION_LEVEL_FQN = FqName(DeprecationLevel::class.java.name)
private val DEPRECATION_LEVEL_CLASS_ID = ClassId.topLevel(DEPRECATION_LEVEL_FQN)
@@ -135,9 +149,6 @@ private class DeprecatedAnnotationCommonizer : Commonizer<CirAnnotation, CirAnno
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 =
@@ -163,11 +174,8 @@ private class DeprecatedAnnotationCommonizer : Commonizer<CirAnnotation, CirAnno
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 fun String.toReplaceWithValue(imports: List<String>): CirAnnotation =
createReplaceWithAnnotation(this, imports)
private inline fun Map<Name, ConstantValue<*>>.getString(name: Name): String? =
(this[name] as? StringValue)?.value
@@ -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()
}
@@ -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() {}
}
@@ -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() {}
}
@@ -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() {}
}
@@ -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() {}
}
@@ -16,8 +16,3 @@ expect fun externalFunction2()
expect inline fun inlineFunction1() {}
expect fun inlineFunction2() {}
expect class Holder() {
expect fun deprecatedFunction1()
expect fun nonDeprecatedFunction1()
}
@@ -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() {}
}
@@ -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() {}
}
@@ -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() {}
}
@@ -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() {}
}
@@ -12,5 +12,7 @@ class FunctionCommonizationFromSourcesTest : AbstractCommonizationFromSourcesTes
fun testValueParameters() = doTestSuccessfulCommonization()
fun testAnnotations() = doTestSuccessfulCommonization()
fun testSpecifics() = doTestSuccessfulCommonization()
}
@@ -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<CirAnnotation>, List<CirAnnotation>>() {
@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<CirAnnotation>?, b: List<CirAnnotation>?): Boolean {
return super.isEqual(a, b)
}
}
private fun mockAnnotation(
fqName: String,
constantValueArguments: Map<Name, ConstantValue<*>> = emptyMap(),
annotationValueArguments: Map<Name, CirAnnotation> = emptyMap()
): CirAnnotation = CirAnnotation.create(
fqName = FqName(fqName),
constantValueArguments = constantValueArguments,
annotationValueArguments = annotationValueArguments
)
private fun mockDeprecated(
message: String = "",
level: DeprecationLevel = WARNING,
replaceWithExpression: String = "",
replaceWithImports: Array<String> = 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<Name, ConstantValue<*>>().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()
)
}
@@ -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")
}
}
}