[FIR] Implement VERSION_REQUIREMENT_DEPRECATION diagnostics

This commit is contained in:
Kirill Rakhman
2023-08-04 17:20:49 +02:00
committed by Space Team
parent 65ea9697ab
commit 09f895efe6
23 changed files with 285 additions and 55 deletions
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -370,6 +371,7 @@ internal object FirToKtConversionCreator {
CallableId::class,
ClassKind::class,
FunctionTypeKind::class,
VersionRequirement.Version::class,
)
private val KType.kClass: KClass<*>
@@ -327,6 +327,26 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.VERSION_REQUIREMENT_DEPRECATION_ERROR) { firDiagnostic ->
VersionRequirementDeprecationErrorImpl(
firSymbolBuilder.buildSymbol(firDiagnostic.a),
firDiagnostic.b,
firDiagnostic.c,
firDiagnostic.d,
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.VERSION_REQUIREMENT_DEPRECATION) { firDiagnostic ->
VersionRequirementDeprecationImpl(
firSymbolBuilder.buildSymbol(firDiagnostic.a),
firDiagnostic.b,
firDiagnostic.c,
firDiagnostic.d,
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.TYPEALIAS_EXPANSION_DEPRECATION_ERROR) { firDiagnostic ->
TypealiasExpansionDeprecationErrorImpl(
firSymbolBuilder.buildSymbol(firDiagnostic.a),
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement.Version
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -271,6 +272,22 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
val message: String
}
interface VersionRequirementDeprecationError : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = VersionRequirementDeprecationError::class
val reference: KtSymbol
val version: Version
val currentVersion: String
val message: String
}
interface VersionRequirementDeprecation : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = VersionRequirementDeprecation::class
val reference: KtSymbol
val version: Version
val currentVersion: String
val message: String
}
interface TypealiasExpansionDeprecationError : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = TypealiasExpansionDeprecationError::class
val alias: KtSymbol
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement.Version
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -311,6 +312,24 @@ internal class DeprecationImpl(
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.Deprecation
internal class VersionRequirementDeprecationErrorImpl(
override val reference: KtSymbol,
override val version: Version,
override val currentVersion: String,
override val message: String,
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.VersionRequirementDeprecationError
internal class VersionRequirementDeprecationImpl(
override val reference: KtSymbol,
override val version: Version,
override val currentVersion: String,
override val message: String,
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.VersionRequirementDeprecation
internal class TypealiasExpansionDeprecationErrorImpl(
override val alias: KtSymbol,
override val reference: KtSymbol,
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -130,6 +131,20 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<String>("message")
}
val VERSION_REQUIREMENT_DEPRECATION_ERROR by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
parameter<Symbol>("reference")
parameter<VersionRequirement.Version>("version")
parameter<String>("currentVersion")
parameter<String>("message")
}
val VERSION_REQUIREMENT_DEPRECATION by warning<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
parameter<Symbol>("reference")
parameter<VersionRequirement.Version>("version")
parameter<String>("currentVersion")
parameter<String>("message")
}
val TYPEALIAS_EXPANSION_DEPRECATION_ERROR by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
parameter<Symbol>("alias")
parameter<Symbol>("reference")
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement.Version
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -161,6 +162,8 @@ object FirErrors {
val NO_THIS by error0<PsiElement>()
val DEPRECATION_ERROR by error2<PsiElement, FirBasedSymbol<*>, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val DEPRECATION by warning2<PsiElement, FirBasedSymbol<*>, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val VERSION_REQUIREMENT_DEPRECATION_ERROR by error4<PsiElement, FirBasedSymbol<*>, Version, String, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val VERSION_REQUIREMENT_DEPRECATION by warning4<PsiElement, FirBasedSymbol<*>, Version, String, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val TYPEALIAS_EXPANSION_DEPRECATION_ERROR by error3<PsiElement, FirBasedSymbol<*>, FirBasedSymbol<*>, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val TYPEALIAS_EXPANSION_DEPRECATION by warning3<PsiElement, FirBasedSymbol<*>, FirBasedSymbol<*>, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val API_NOT_AVAILABLE by error2<PsiElement, ApiVersion, ApiVersion>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
@@ -8,17 +8,23 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.KtRealSourceElementKind
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.isLhsOfAssignment
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FutureApiDeprecationInfo
import org.jetbrains.kotlin.fir.analysis.checkers.isLhsOfAssignment
import org.jetbrains.kotlin.fir.declarations.RequireKotlinDeprecationInfo
import org.jetbrains.kotlin.fir.declarations.getDeprecation
import org.jetbrains.kotlin.fir.declarations.getOwnDeprecation
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.calleeReference
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.references.resolved
import org.jetbrains.kotlin.fir.resolve.firClassLike
import org.jetbrains.kotlin.fir.resolve.typeAliasForConstructor
@@ -26,6 +32,7 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue
@@ -97,13 +104,42 @@ object FirDeprecationChecker : FirBasicExpressionChecker() {
reporter: DiagnosticReporter,
context: CheckerContext,
) {
if (deprecationInfo is FutureApiDeprecationInfo) {
reportApiNotAvailable(source, deprecationInfo, reporter, context)
} else {
reportDeprecation(source, referencedSymbol, isTypealiasExpansion, deprecationInfo, reporter, context)
when (deprecationInfo) {
is FutureApiDeprecationInfo -> reportApiNotAvailable(source, deprecationInfo, reporter, context)
is RequireKotlinDeprecationInfo -> reportVersionRequirementDeprecation(source, referencedSymbol, deprecationInfo, reporter, context)
else -> reportDeprecation(source, referencedSymbol, isTypealiasExpansion, deprecationInfo, reporter, context)
}
}
private fun reportVersionRequirementDeprecation(
source: KtSourceElement?,
referencedSymbol: FirBasedSymbol<*>,
deprecationInfo: RequireKotlinDeprecationInfo,
reporter: DiagnosticReporter,
context: CheckerContext,
) {
val diagnostic = when (deprecationInfo.deprecationLevel) {
DeprecationLevelValue.WARNING -> FirErrors.VERSION_REQUIREMENT_DEPRECATION
else -> FirErrors.VERSION_REQUIREMENT_DEPRECATION_ERROR
}
val languageVersionSettings = context.session.languageVersionSettings
val currentVersionString = when (deprecationInfo.versionRequirement.kind) {
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION -> KotlinCompilerVersion.VERSION
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION -> languageVersionSettings.languageVersion.versionString
ProtoBuf.VersionRequirement.VersionKind.API_VERSION -> languageVersionSettings.apiVersion.versionString
}
reporter.reportOn(
source,
diagnostic,
referencedSymbol,
deprecationInfo.versionRequirement.version,
currentVersionString,
deprecationInfo.message ?: "",
context
)
}
private fun reportDeprecation(
source: KtSourceElement?,
referencedSymbol: FirBasedSymbol<*>,
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.renderReadableWithFqNames
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
@@ -33,7 +34,8 @@ object FirDiagnosticRenderers {
val SYMBOL = Renderer { symbol: FirBasedSymbol<*> ->
when (symbol) {
is FirClassLikeSymbol<*>,
is FirCallableSymbol<*> -> FirRenderer(
is FirCallableSymbol<*>,
-> FirRenderer(
typeRenderer = ConeTypeRenderer(),
idRenderer = ConeIdShortRenderer(),
classMemberRenderer = FirNoClassMemberRenderer(),
@@ -179,4 +181,12 @@ object FirDiagnosticRenderers {
}
val FUNCTIONAL_TYPE_KINDS = KtDiagnosticRenderers.COLLECTION(FUNCTIONAL_TYPE_KIND)
val REQUIRE_KOTLIN_VERSION = Renderer { version: VersionRequirement.Version ->
if (version == VersionRequirement.Version.INFINITY) "" else " is only available since Kotlin ${version.asString()} and"
}
val OPTIONAL_SENTENCE = Renderer { it: String? ->
if (!it.isNullOrBlank()) " $it." else ""
}
}
@@ -27,10 +27,12 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FUNC
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.MODULE_DATA
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NAME_OF_CONTAINING_DECLARATION_OR_FILE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NAME_OF_DECLARATION_OR_FILE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.OPTIONAL_SENTENCE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_COLLECTION_OF_TYPES
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.REQUIRE_KOTLIN_VERSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOLS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOLS_ON_NEWLINE_WITH_INDENT
@@ -183,6 +185,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATED_SINCE_
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATED_TYPE_PARAMETER_SYNTAX
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATION_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VERSION_REQUIREMENT_DEPRECATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VERSION_REQUIREMENT_DEPRECATION_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DESERIALIZATION_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DIVISION_BY_ZERO
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DSL_SCOPE_VIOLATION
@@ -697,6 +701,8 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER, "''{0}'' on secondary constructor parameter is not allowed", TO_STRING)
map.put(DEPRECATION, "''{0}'' is deprecated. {1}", SYMBOL, STRING)
map.put(DEPRECATION_ERROR, "''{0}'' is deprecated. {1}", SYMBOL, STRING)
map.put(VERSION_REQUIREMENT_DEPRECATION, "''{0}''{1} should not be used in Kotlin {2}.{3}", SYMBOL, REQUIRE_KOTLIN_VERSION, STRING, OPTIONAL_SENTENCE)
map.put(VERSION_REQUIREMENT_DEPRECATION_ERROR, "''{0}''{1} cannot be used in Kotlin {2}.{3}", SYMBOL, REQUIRE_KOTLIN_VERSION, STRING, OPTIONAL_SENTENCE)
map.put(TYPEALIAS_EXPANSION_DEPRECATION, "''{0}'' uses ''{1}'', which is deprecated. {2}", SYMBOL, SYMBOL, STRING)
map.put(TYPEALIAS_EXPANSION_DEPRECATION_ERROR, "''{0}'' uses ''{1}'', which is an error. {2}", SYMBOL, SYMBOL, STRING)
@@ -113,6 +113,8 @@ fun deserializeClassToSymbol(
}
}
val versionRequirements = VersionRequirement.create(classProto, context)
buildRegularClass {
this.moduleData = moduleData
this.origin = origin
@@ -140,7 +142,7 @@ fun deserializeClassToSymbol(
)
addDeclarations(
classProto.propertiesInOrder(context).map {
classProto.propertiesInOrder(versionRequirements).map {
classDeserializer.loadProperty(it, classProto, symbol)
}
)
@@ -225,7 +227,7 @@ fun deserializeClassToSymbol(
context.annotationDeserializer.loadClassAnnotations(classProto, context.nameResolver)
)
versionRequirementsTable = context.versionRequirementTable
this.versionRequirements = versionRequirements
sourceElement = containerSource
@@ -296,9 +298,8 @@ fun FirRegularClassBuilder.addCloneForArrayIfNeeded(classId: ClassId, dispatchRe
}
}
private fun ProtoBuf.ClassOrBuilder.propertiesInOrder(context: FirDeserializationContext): List<ProtoBuf.Property> {
private fun ProtoBuf.ClassOrBuilder.propertiesInOrder(versionRequirements: List<VersionRequirement>): List<ProtoBuf.Property> {
val properties = propertyList
val versionRequirements = VersionRequirement.create(this, context.nameResolver, context.versionRequirementTable)
if (versionRequirements.any { it.version.major >= 2 }) return properties
val order = getExtension(SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder)
.takeIf { it.isNotEmpty() }
@@ -0,0 +1,17 @@
/*
* 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.fir.deserialization
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
import org.jetbrains.kotlin.protobuf.MessageLiteOrBuilder
/*
* 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.
*/
internal fun VersionRequirement.Companion.create(proto: MessageLiteOrBuilder, context: FirDeserializationContext): List<VersionRequirement> =
create(proto, context.nameResolver, context.versionRequirementTable)
@@ -204,6 +204,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
val classId = ClassId(c.packageFqName, name)
val symbol = preComputedSymbol ?: FirTypeAliasSymbol(classId)
val local = c.childContext(proto.typeParameterList, containingDeclarationSymbol = symbol)
val versionRequirements = VersionRequirement.create(proto, c)
return buildTypeAlias {
moduleData = c.moduleData
origin = FirDeclarationOrigin.Library
@@ -223,8 +224,9 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
expandedTypeRef = proto.underlyingType(c.typeTable).toTypeRef(local)
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
typeParameters += local.typeDeserializer.ownTypeParameters.map { it.fir }
deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(c.session, fromJava = false, versionRequirements)
}.apply {
versionRequirementsTable = c.versionRequirementTable
this.versionRequirements = versionRequirements
sourceElement = c.containerSource
}
}
@@ -257,7 +259,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
dispatchReceiverType = c.dispatchReceiver
this.propertySymbol = propertySymbol
}.apply {
versionRequirementsTable = c.versionRequirementTable
this.versionRequirements = VersionRequirement.create(proto, c)
}
} else {
FirDefaultPropertyGetter(
@@ -317,7 +319,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
)
this.propertySymbol = propertySymbol
}.apply {
versionRequirementsTable = c.versionRequirementTable
this.versionRequirements = VersionRequirement.create(proto, c)
}
} else {
FirDefaultPropertySetter(
@@ -375,6 +377,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
val propertyModality = ProtoEnumFlags.modality(Flags.MODALITY.get(flags))
val isVar = Flags.IS_VAR.get(flags)
val versionRequirements = VersionRequirement.create(proto, c)
return buildProperty {
moduleData = c.moduleData
origin = FirDeclarationOrigin.Library
@@ -463,12 +466,12 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
}
else -> null
}
deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(c.session, fromJava = false)
proto.contextReceiverTypes(c.typeTable).mapTo(contextReceivers, ::loadContextReceiver)
}.apply {
initializer?.replaceTypeRef(returnTypeRef)
versionRequirementsTable = c.versionRequirementTable
this.versionRequirements = versionRequirements
replaceDeprecationsProvider(getDeprecationsProvider(c.session))
setLazyPublishedVisibility(c.session)
getter?.setLazyPublishedVisibility(annotations, this, c.session)
setter?.setLazyPublishedVisibility(annotations, this, c.session)
@@ -509,6 +512,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
val symbol = FirNamedFunctionSymbol(callableId)
val local = c.childContext(proto.typeParameterList, containingDeclarationSymbol = symbol)
val versionRequirements = VersionRequirement.create(proto, c)
val simpleFunction = buildSimpleFunction {
moduleData = c.moduleData
origin = deserializationOrigin
@@ -551,12 +555,12 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
)
annotations +=
c.annotationDeserializer.loadFunctionAnnotations(c.containerSource, proto, local.nameResolver, local.typeTable)
deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(c.session, fromJava = false)
deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(c.session, fromJava = false, versionRequirements)
this.containerSource = c.containerSource
proto.contextReceiverTypes(c.typeTable).mapTo(contextReceivers, ::loadContextReceiver)
}.apply {
versionRequirementsTable = c.versionRequirementTable
this.versionRequirements = versionRequirements
setLazyPublishedVisibility(c.session)
}
if (proto.hasContract()) {
@@ -640,7 +644,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
contextReceivers.addAll(createContextReceiversForClass(classProto))
}.build().apply {
containingClassForStaticMemberAttr = c.dispatchReceiver!!.lookupTag
versionRequirementsTable = c.versionRequirementTable
this.versionRequirements = VersionRequirement.create(proto, c)
setLazyPublishedVisibility(c.session)
}
}
@@ -688,8 +692,6 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
callableKind,
index,
)
}.apply {
versionRequirementsTable = c.versionRequirementTable
}
}.toList()
}
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.forEachType
import org.jetbrains.kotlin.fir.types.toSymbol
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames
@@ -115,9 +116,14 @@ fun FirAnnotationContainer.extractDeprecationInfoPerUseSite(
getterAnnotations: List<FirAnnotation>? = null,
setterAnnotations: List<FirAnnotation>? = null,
): DeprecationAnnotationInfoPerUseSiteStorage {
val fromJava = this is FirDeclaration && this.isJavaOrEnhancement
var fromJava = false
var versionRequirements: List<VersionRequirement>? = null
if (this is FirDeclaration) {
fromJava = this.isJavaOrEnhancement
versionRequirements = this.versionRequirements
}
return buildDeprecationAnnotationInfoPerUseSiteStorage {
add((customAnnotations ?: annotations).extractDeprecationAnnotationInfoPerUseSite(fromJava))
add((customAnnotations ?: annotations).extractDeprecationAnnotationInfoPerUseSite(fromJava, versionRequirements))
if (this@extractDeprecationInfoPerUseSite is FirProperty) {
add(
getDeprecationsAnnotationInfoByUseSiteFromAccessors(
@@ -170,9 +176,10 @@ fun getDeprecationsAnnotationInfoByUseSiteFromAccessors(
fun List<FirAnnotation>.getDeprecationsProviderFromAnnotations(
session: FirSession,
fromJava: Boolean
fromJava: Boolean,
versionRequirements: List<VersionRequirement>? = null,
): DeprecationsProvider {
val deprecationAnnotationByUseSite = extractDeprecationAnnotationInfoPerUseSite(fromJava)
val deprecationAnnotationByUseSite = extractDeprecationAnnotationInfoPerUseSite(fromJava, versionRequirements)
return deprecationAnnotationByUseSite.toDeprecationsProvider(session.firCachesFactory)
}
@@ -251,7 +258,10 @@ val deprecationAnnotationSimpleNames: Set<String> = setOf(
StandardClassIds.Annotations.SinceKotlin.shortClassName.asString(),
)
private fun List<FirAnnotation>.extractDeprecationAnnotationInfoPerUseSite(fromJava: Boolean): DeprecationAnnotationInfoPerUseSiteStorage {
private fun List<FirAnnotation>.extractDeprecationAnnotationInfoPerUseSite(
fromJava: Boolean,
versionRequirements: List<VersionRequirement>?,
): DeprecationAnnotationInfoPerUseSiteStorage {
// NB: We can't expand typealiases (`toAnnotationClassId`), because it
// requires `lookupTag.tySymbol()`, but we can have cycles in annotations.
// See the commit message for an example.
@@ -298,6 +308,10 @@ private fun List<FirAnnotation>.extractDeprecationAnnotationInfoPerUseSite(fromJ
add(deprecated.useSiteTarget, deprecatedInfo)
}
}
versionRequirements?.forEach {
add(null, RequireKotlinInfo(it))
}
}
}
@@ -11,9 +11,11 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.caches.FirCache
import org.jetbrains.kotlin.fir.caches.FirCachesFactory
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue
import org.jetbrains.kotlin.resolve.deprecation.SimpleDeprecationInfo
import org.jetbrains.kotlin.resolve.deprecation.isFulfilled
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
abstract class DeprecationsProvider {
@@ -55,8 +57,8 @@ object UnresolvedDeprecationProvider : DeprecationsProvider() {
}
}
sealed interface DeprecationAnnotationInfo {
fun computeDeprecationInfo(languageVersionSettings: LanguageVersionSettings): DeprecationInfo?
sealed class DeprecationAnnotationInfo {
abstract fun computeDeprecationInfo(languageVersionSettings: LanguageVersionSettings): DeprecationInfo?
}
data class FutureApiDeprecationInfo(
@@ -67,7 +69,30 @@ data class FutureApiDeprecationInfo(
override val message: String? get() = null
}
class SinceKotlinInfo(val sinceVersion: ApiVersion) : DeprecationAnnotationInfo {
data class RequireKotlinDeprecationInfo(
override val deprecationLevel: DeprecationLevelValue,
val versionRequirement: VersionRequirement
) : DeprecationInfo() {
override val message: String? get() = versionRequirement.message
override val propagatesToOverrides: Boolean get() = false
}
class RequireKotlinInfo(private val versionRequirement: VersionRequirement) : DeprecationAnnotationInfo() {
override fun computeDeprecationInfo(languageVersionSettings: LanguageVersionSettings): DeprecationInfo? {
return runUnless(versionRequirement.isFulfilled(languageVersionSettings)) {
RequireKotlinDeprecationInfo(
deprecationLevel = when (versionRequirement.level) {
DeprecationLevel.WARNING -> DeprecationLevelValue.WARNING
DeprecationLevel.ERROR -> DeprecationLevelValue.ERROR
DeprecationLevel.HIDDEN -> DeprecationLevelValue.HIDDEN
},
versionRequirement = versionRequirement
)
}
}
}
class SinceKotlinInfo(val sinceVersion: ApiVersion) : DeprecationAnnotationInfo() {
override fun computeDeprecationInfo(languageVersionSettings: LanguageVersionSettings): DeprecationInfo? {
return runUnless(sinceVersion <= languageVersionSettings.apiVersion) {
FutureApiDeprecationInfo(
@@ -83,7 +108,7 @@ class DeprecatedInfo(
val level: DeprecationLevelValue,
val propagatesToOverride: Boolean,
val message: String?
) : DeprecationAnnotationInfo {
) : DeprecationAnnotationInfo() {
override fun computeDeprecationInfo(languageVersionSettings: LanguageVersionSettings): DeprecationInfo {
return SimpleDeprecationInfo(
level,
@@ -99,7 +124,7 @@ class DeprecatedSinceKotlinInfo(
val hiddenVersion: ApiVersion?,
val message: String?,
val propagatesToOverride: Boolean
) : DeprecationAnnotationInfo {
) : DeprecationAnnotationInfo() {
override fun computeDeprecationInfo(languageVersionSettings: LanguageVersionSettings): DeprecationInfo? {
fun ApiVersion.takeLevelIfDeprecated(level: DeprecationLevelValue) = level.takeIf { this <= languageVersionSettings.apiVersion }
@@ -1,12 +1,12 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.fir.declarations
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirementTable
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
object FirVersionRequirementsTableKey : FirDeclarationDataKey()
var FirDeclaration.versionRequirementsTable: VersionRequirementTable? by FirDeclarationDataRegistry.data(FirVersionRequirementsTableKey)
var FirDeclaration.versionRequirements: List<VersionRequirement>? by FirDeclarationDataRegistry.data(FirVersionRequirementsTableKey)
@@ -30,7 +30,7 @@ sealed class FirClassLikeSymbol<D : FirClassLikeDeclaration>(
val name get() = classId.shortClassName
fun getOwnDeprecation(languageVersionSettings: LanguageVersionSettings): DeprecationsPerUseSite? {
if (annotations.isEmpty()) return null
if (annotations.isEmpty() && fir.versionRequirements.isNullOrEmpty()) return null
lazyResolveToPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS)
return fir.deprecationsProvider.getDeprecationsInfo(languageVersionSettings)
}
@@ -0,0 +1,34 @@
/*
* 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.resolve.deprecation
import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.MavenComparableVersion
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
fun VersionRequirement.isFulfilled(languageVersionSettings: LanguageVersionSettings): Boolean {
val requiredVersion = createVersion(version.asString())
val currentVersion = when (kind) {
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION ->
MavenComparableVersion(languageVersionSettings.languageVersion.versionString)
ProtoBuf.VersionRequirement.VersionKind.API_VERSION ->
languageVersionSettings.apiVersion.version
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION ->
KotlinCompilerVersion.getVersion()?.substringBefore('-')?.let(::createVersion)
else -> null
}
return currentVersion == null || currentVersion >= requiredVersion
}
private fun createVersion(version: String): MavenComparableVersion? = try {
MavenComparableVersion(version)
} catch (e: Exception) {
null
}
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.DescriptorDerivedFromTypeAlias
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.KtElement
@@ -300,29 +299,13 @@ class DeprecationResolver(
(target as? CallableDescriptor)?.getUserData(DEPRECATED_FUNCTION_KEY)
private fun getDeprecationByVersionRequirement(target: DeclarationDescriptor): List<DeprecatedByVersionRequirement> {
fun createVersion(version: String): MavenComparableVersion? = try {
MavenComparableVersion(version)
} catch (e: Exception) {
null
}
val versionRequirements =
(target as? DeserializedMemberDescriptor)?.versionRequirements
?: (target as? DeserializedClassDescriptor)?.versionRequirements
?: return emptyList()
return versionRequirements.mapNotNull { versionRequirement ->
val requiredVersion = createVersion(versionRequirement.version.asString())
val currentVersion = when (versionRequirement.kind) {
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION ->
MavenComparableVersion(languageVersionSettings.languageVersion.versionString)
ProtoBuf.VersionRequirement.VersionKind.API_VERSION ->
languageVersionSettings.apiVersion.version
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION ->
KotlinCompilerVersion.getVersion()?.substringBefore('-')?.let(::createVersion)
else -> null
}
if (currentVersion != null && currentVersion < requiredVersion)
if (!versionRequirement.isFulfilled(this.languageVersionSettings))
DeprecatedByVersionRequirement(versionRequirement, target)
else
null
@@ -0,0 +1,7 @@
$TESTDATA_DIR$/requireKotlinCompilerVersion.kt
-classpath
$TESTDATA_DIR$/requireKotlinCompilerVersion
-d
$TEMP_DIR$
-language-version
2.0
@@ -0,0 +1,8 @@
warning: language version 2.0 is experimental, there are no backwards compatibility guarantees for new language and library features
compiler/testData/cli/jvm/requireKotlinCompilerVersion.kt:12:8: error: 'class Foo : Any' is only available since Kotlin 9.9.90 and cannot be used in Kotlin $VERSION$.
import test.access.Foo
^
compiler/testData/cli/jvm/requireKotlinCompilerVersion.kt:15:5: error: 'constructor(): Foo' is only available since Kotlin 9.9.90 and cannot be used in Kotlin $VERSION$.
Foo()
^
COMPILATION_ERROR
@@ -1,5 +1,8 @@
// !LANGUAGE: +TypeAliases
// !API_VERSION: 1.0
// IGNORE_DIAGNOSTIC_API
// IGNORE_REVERSED_RESOLVE
// ^KT-60996
// FILE: test.kt
val fooException = Exception("foo")
val barException = kotlin.Exception("bar")
val fooException = <!API_NOT_AVAILABLE!>Exception<!>("foo")
val barException = kotlin.<!API_NOT_AVAILABLE!>Exception<!>("bar")
@@ -1,5 +1,8 @@
// !LANGUAGE: +TypeAliases
// !API_VERSION: 1.0
// IGNORE_DIAGNOSTIC_API
// IGNORE_REVERSED_RESOLVE
// ^KT-60996
// FILE: test.kt
val fooException = Exception("foo")
val barException = kotlin.<!UNRESOLVED_REFERENCE!>Exception<!>("bar")
@@ -1100,6 +1100,11 @@ public class CliTestGenerated extends AbstractCliTest {
runTest("compiler/testData/cli/jvm/requireKotlinCompilerVersion.args");
}
@TestMetadata("requireKotlinCompilerVersionK2.args")
public void testRequireKotlinCompilerVersionK2() throws Exception {
runTest("compiler/testData/cli/jvm/requireKotlinCompilerVersionK2.args");
}
@TestMetadata("resultInReturnTypeSupportedByDefault15.args")
public void testResultInReturnTypeSupportedByDefault15() throws Exception {
runTest("compiler/testData/cli/jvm/resultInReturnTypeSupportedByDefault15.args");