Introduce DeprecatedSinceKotlin annotation
This annotation will be used in the standard library to prevent the new compiler from reporting deprecation diagnostics in case an older API version is used (where the declaration was not deprecated yet). #KT-23575 Fixed
This commit is contained in:
committed by
Mikhail Zarechenskiy
parent
b2022144e6
commit
0aaf29c045
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.deprecation
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
@@ -14,27 +15,78 @@ import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.shouldWarnAboutDeprecatedModFromBuiltIns
|
||||
import org.jetbrains.kotlin.resolve.constants.AnnotationValue
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
internal data class DeprecatedByAnnotation(
|
||||
internal sealed class DeprecatedByAnnotation(
|
||||
val annotation: AnnotationDescriptor,
|
||||
override val target: DeclarationDescriptor,
|
||||
override val propagatesToOverrides: Boolean
|
||||
) : Deprecation {
|
||||
override val deprecationLevel: DeprecationLevelValue
|
||||
get() = when (annotation.argumentValue("level")?.safeAs<EnumValue>()?.enumEntryName?.asString()) {
|
||||
"WARNING" -> WARNING
|
||||
"ERROR" -> ERROR
|
||||
"HIDDEN" -> HIDDEN
|
||||
else -> WARNING
|
||||
}
|
||||
|
||||
override val message: String?
|
||||
get() = annotation.argumentValue("message")?.safeAs<StringValue>()?.value
|
||||
|
||||
internal val replaceWithValue: String?
|
||||
get() {
|
||||
val replaceWithAnnotation = annotation.argumentValue(Deprecated::replaceWith.name)?.safeAs<AnnotationValue>()?.value
|
||||
return replaceWithAnnotation?.argumentValue(ReplaceWith::expression.name)?.safeAs<StringValue>()?.value
|
||||
}
|
||||
|
||||
class StandardDeprecated(
|
||||
annotation: AnnotationDescriptor,
|
||||
target: DeclarationDescriptor,
|
||||
propagatesToOverrides: Boolean
|
||||
) : DeprecatedByAnnotation(annotation, target, propagatesToOverrides) {
|
||||
override val deprecationLevel: DeprecationLevelValue
|
||||
get() = when (annotation.argumentValue("level")?.safeAs<EnumValue>()?.enumEntryName?.asString()) {
|
||||
"WARNING" -> WARNING
|
||||
"ERROR" -> ERROR
|
||||
"HIDDEN" -> HIDDEN
|
||||
else -> WARNING
|
||||
}
|
||||
}
|
||||
|
||||
class DeprecatedSince(
|
||||
annotation: AnnotationDescriptor,
|
||||
target: DeclarationDescriptor,
|
||||
propagatesToOverrides: Boolean,
|
||||
override val deprecationLevel: DeprecationLevelValue
|
||||
) : DeprecatedByAnnotation(annotation, target, propagatesToOverrides)
|
||||
|
||||
companion object {
|
||||
fun create(
|
||||
annotation: AnnotationDescriptor,
|
||||
target: DeclarationDescriptor,
|
||||
propagatesToOverrides: Boolean,
|
||||
apiVersion: ApiVersion
|
||||
): DeprecatedByAnnotation? {
|
||||
if (annotation.fqName == KotlinBuiltIns.FQ_NAMES.deprecatedSinceKotlin) {
|
||||
val level = computeLevelForDeprecatedSinceKotlin(annotation, apiVersion) ?: return null
|
||||
return DeprecatedSince(annotation, target, propagatesToOverrides, level)
|
||||
}
|
||||
return StandardDeprecated(annotation, target, propagatesToOverrides)
|
||||
}
|
||||
|
||||
private fun computeLevelForDeprecatedSinceKotlin(annotation: AnnotationDescriptor, apiVersion: ApiVersion): DeprecationLevelValue? {
|
||||
fun getSinceVersion(name: String): ApiVersion? =
|
||||
annotation.argumentValue(name)?.safeAs<StringValue>()?.value?.takeUnless(String::isEmpty)?.let(ApiVersion.Companion::parse)
|
||||
|
||||
val hiddenSince = getSinceVersion("hiddenSince")
|
||||
if (hiddenSince != null && apiVersion >= hiddenSince) return HIDDEN
|
||||
|
||||
val errorSince = getSinceVersion("errorSince")
|
||||
if (errorSince != null && apiVersion >= errorSince) return ERROR
|
||||
|
||||
val warningSince = getSinceVersion("warningSince")
|
||||
if (warningSince != null && apiVersion >= warningSince) return WARNING
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal data class DeprecatedByOverridden(private val deprecations: Collection<Deprecation>) : Deprecation {
|
||||
|
||||
+13
-9
@@ -187,23 +187,27 @@ class DeprecationResolver(
|
||||
|
||||
private fun DeclarationDescriptor.addDeprecationIfPresent(result: MutableList<Deprecation>) {
|
||||
val annotation = annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated)
|
||||
?: annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecatedSinceKotlin)
|
||||
?: annotations.findAnnotation(JAVA_DEPRECATED)
|
||||
if (annotation != null) {
|
||||
val deprecatedByAnnotation =
|
||||
DeprecatedByAnnotation(
|
||||
DeprecatedByAnnotation.create(
|
||||
annotation, this,
|
||||
deprecationSettings.propagatedToOverrides(annotation)
|
||||
deprecationSettings.propagatedToOverrides(annotation),
|
||||
languageVersionSettings.apiVersion
|
||||
)
|
||||
val deprecation = when {
|
||||
this is TypeAliasConstructorDescriptor ->
|
||||
DeprecatedTypealiasByAnnotation(typeAliasDescriptor, deprecatedByAnnotation)
|
||||
if (deprecatedByAnnotation != null) {
|
||||
val deprecation = when {
|
||||
this is TypeAliasConstructorDescriptor ->
|
||||
DeprecatedTypealiasByAnnotation(typeAliasDescriptor, deprecatedByAnnotation)
|
||||
|
||||
isBuiltInOperatorMod ->
|
||||
DeprecatedOperatorMod(languageVersionSettings, deprecatedByAnnotation)
|
||||
isBuiltInOperatorMod ->
|
||||
DeprecatedOperatorMod(languageVersionSettings, deprecatedByAnnotation)
|
||||
|
||||
else -> deprecatedByAnnotation
|
||||
else -> deprecatedByAnnotation
|
||||
}
|
||||
result.add(deprecation)
|
||||
}
|
||||
result.add(deprecation)
|
||||
}
|
||||
|
||||
for (deprecation in getDeprecationByVersionRequirement(this)) {
|
||||
|
||||
@@ -13,20 +13,11 @@ import org.jetbrains.kotlin.container.PlatformSpecificExtension
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
||||
import org.jetbrains.kotlin.resolve.constants.AnnotationValue
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
fun Deprecation.deprecatedByOverriddenMessage(): String? = (this as? DeprecatedByOverridden)?.additionalMessage()
|
||||
|
||||
fun Deprecation.deprecatedByAnnotationReplaceWithExpression(): String? {
|
||||
val annotation = (this as? DeprecatedByAnnotation)?.annotation ?: return null
|
||||
val replaceWithAnnotation =
|
||||
annotation.argumentValue(kotlin.Deprecated::replaceWith.name)?.safeAs<AnnotationValue>()?.value ?: return null
|
||||
return replaceWithAnnotation.argumentValue(kotlin.ReplaceWith::expression.name)?.safeAs<StringValue>()?.value
|
||||
}
|
||||
fun Deprecation.deprecatedByAnnotationReplaceWithExpression(): String? = (this as? DeprecatedByAnnotation)?.replaceWithValue
|
||||
|
||||
internal fun createDeprecationDiagnostic(
|
||||
element: PsiElement, deprecation: Deprecation, languageVersionSettings: LanguageVersionSettings
|
||||
|
||||
Reference in New Issue
Block a user