FIR: handle 'SinceKotlin' as a special kind of deprecated
#KT-51850 Fixed
This commit is contained in:
committed by
teamcity
parent
07b5bd72ae
commit
9bd6a9c069
+6
@@ -17255,6 +17255,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/fir/CustomThrowableMessage.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("differentSinceKotlin.kt")
|
||||
public void testDifferentSinceKotlin() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/fir/differentSinceKotlin.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ExtensionAlias.kt")
|
||||
public void testExtensionAlias() throws Exception {
|
||||
|
||||
+12
@@ -120,6 +120,18 @@ fun List<FirAnnotation>.getAnnotationsByClassId(classId: ClassId): List<FirAnnot
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> List<FirAnnotation>.mapAnnotationsWithClassIdTo(
|
||||
classId: ClassId,
|
||||
destination: MutableCollection<T>,
|
||||
func: (FirAnnotation) -> T
|
||||
) {
|
||||
for (annotation in this) {
|
||||
if (annotation.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.classId == classId) {
|
||||
destination.add(func(annotation))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun FirExpression.unwrapVarargValue(): List<FirExpression> {
|
||||
return when (this) {
|
||||
is FirVarargArgumentsExpression -> arguments
|
||||
|
||||
+25
-7
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames.dep
|
||||
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.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
|
||||
|
||||
fun FirBasedSymbol<*>.getDeprecation(callSite: FirElement?): DeprecationInfo? {
|
||||
return when (this) {
|
||||
@@ -111,20 +111,38 @@ private fun List<FirAnnotation>.extractDeprecationInfoPerUseSite(
|
||||
currentVersion: ApiVersion,
|
||||
fromJava: Boolean
|
||||
): List<Pair<AnnotationUseSiteTarget?, DeprecationInfo>> {
|
||||
val annotations = getAnnotationsByClassId(StandardClassIds.Annotations.Deprecated).map { it to false } +
|
||||
getAnnotationsByClassId(StandardClassIds.Annotations.Java.Deprecated).map { it to true }
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
val annotations = buildList<Pair<FirAnnotation, Boolean>> {
|
||||
mapAnnotationsWithClassIdTo(StandardClassIds.Annotations.Deprecated, this) { it to false }
|
||||
mapAnnotationsWithClassIdTo(StandardClassIds.Annotations.Java.Deprecated, this) { it to true }
|
||||
mapAnnotationsWithClassIdTo(StandardClassIds.Annotations.SinceKotlin, this) { it to false }
|
||||
}
|
||||
return annotations.mapNotNull { (deprecated, fromJavaAnnotation) ->
|
||||
if (deprecated.classId == StandardClassIds.Annotations.SinceKotlin) {
|
||||
val sinceKotlinSingleArgument = deprecated.findArgumentByName(ParameterNames.sinceKotlinVersion)
|
||||
val apiVersion = ((sinceKotlinSingleArgument as? FirConstExpression<*>)?.value as? String)
|
||||
?.let(ApiVersion.Companion::parse) ?: return@mapNotNull null
|
||||
if (apiVersion <= currentVersion) return@mapNotNull null
|
||||
val wasExperimental = this.any { it.classId == StandardClassIds.Annotations.WasExperimental }
|
||||
return@mapNotNull runUnless(wasExperimental) {
|
||||
deprecated.useSiteTarget to SimpleDeprecationInfo(
|
||||
deprecationLevel = DeprecationLevelValue.HIDDEN,
|
||||
propagatesToOverrides = true,
|
||||
message = null
|
||||
)
|
||||
}
|
||||
}
|
||||
val deprecationLevel = deprecated.getDeprecationLevel() ?: DeprecationLevelValue.WARNING
|
||||
val deprecatedSinceKotlin = getAnnotationsByClassId(StandardClassIds.Annotations.DeprecatedSinceKotlin).firstOrNull()
|
||||
|
||||
fun levelApplied(name: Name, level: DeprecationLevelValue): DeprecationLevelValue? {
|
||||
fun deprecatedLevelApplied(name: Name, level: DeprecationLevelValue): DeprecationLevelValue? {
|
||||
deprecatedSinceKotlin?.getVersionFromArgument(name)?.takeIf { it <= currentVersion }?.let { return level }
|
||||
return level.takeIf { deprecatedSinceKotlin == null && level == deprecationLevel }
|
||||
}
|
||||
|
||||
val appliedLevel = (levelApplied(deprecatedSinceKotlinHiddenSince, DeprecationLevelValue.HIDDEN)
|
||||
?: levelApplied(deprecatedSinceKotlinErrorSince, DeprecationLevelValue.ERROR)
|
||||
?: levelApplied(deprecatedSinceKotlinWarningSince, DeprecationLevelValue.WARNING))
|
||||
val appliedLevel = (deprecatedLevelApplied(deprecatedSinceKotlinHiddenSince, DeprecationLevelValue.HIDDEN)
|
||||
?: deprecatedLevelApplied(deprecatedSinceKotlinErrorSince, DeprecationLevelValue.ERROR)
|
||||
?: deprecatedLevelApplied(deprecatedSinceKotlinWarningSince, DeprecationLevelValue.WARNING))
|
||||
|
||||
appliedLevel?.let {
|
||||
val inheritable = !fromJavaAnnotation && !fromJava
|
||||
|
||||
+12
-3
@@ -27,9 +27,12 @@ import org.jetbrains.kotlin.fir.resolve.transformers.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.FirUserTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.Deprecated
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.DeprecatedSinceKotlin
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.WasExperimental
|
||||
|
||||
class FirCompilerRequiredAnnotationsResolveProcessor(
|
||||
session: FirSession,
|
||||
@@ -120,6 +123,14 @@ private class FirAnnotationResolveTransformer(
|
||||
) : FirAbstractAnnotationResolveTransformer<Multimap<AnnotationFqn, FirRegularClass>, PersistentList<FirDeclaration>>(
|
||||
session, scopeSession
|
||||
) {
|
||||
companion object {
|
||||
private val REQUIRED_ANNOTATIONS: Set<ClassId> = setOf(
|
||||
Deprecated, DeprecatedSinceKotlin, WasExperimental
|
||||
)
|
||||
|
||||
private val REQUIRED_ANNOTATION_NAMES: Set<Name> = REQUIRED_ANNOTATIONS.mapTo(mutableSetOf()) { it.shortClassName }
|
||||
}
|
||||
|
||||
private val predicateBasedProvider = session.predicateBasedProvider
|
||||
|
||||
var acceptableFqNames: Set<AnnotationFqn> = emptySet()
|
||||
@@ -156,9 +167,7 @@ private class FirAnnotationResolveTransformer(
|
||||
val annotationTypeRef = annotation.annotationTypeRef
|
||||
if (annotationTypeRef !is FirUserTypeRef) return annotation
|
||||
val name = annotationTypeRef.qualifier.last().name
|
||||
if (name != Deprecated.shortClassName && name != DeprecatedSinceKotlin.shortClassName &&
|
||||
acceptableFqNames.none { it.shortName() == name }
|
||||
) return annotation
|
||||
if (name !in REQUIRED_ANNOTATION_NAMES && acceptableFqNames.none { it.shortName() == name }) return annotation
|
||||
|
||||
val transformedAnnotation = annotation.transformAnnotationTypeRef(
|
||||
typeResolverTransformer,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// !API_VERSION: 1.4
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1
|
||||
// FILE: m1.kt
|
||||
|
||||
package kotlin
|
||||
|
||||
@SinceKotlin("1.7")
|
||||
@kotlin.jvm.JvmName("bar")
|
||||
@Suppress("CONFLICTING_OVERLOADS")
|
||||
fun <T> List<T>.foo(): T = this[1]
|
||||
|
||||
// MODULE: m2
|
||||
// FILE: m2.kt
|
||||
|
||||
package kotlin
|
||||
|
||||
@Deprecated("")
|
||||
@DeprecatedSinceKotlin(warningSince = "1.4", errorSince = "1.5", hiddenSince = "1.6")
|
||||
@Suppress("CONFLICTING_OVERLOADS")
|
||||
fun <T> List<T>.foo(): T? = getOrNull(0)
|
||||
|
||||
// MODULE: m3(m1, m2)
|
||||
// FILE: test.kt
|
||||
|
||||
fun box(): String = listOf("OK", "FAIL").foo()!!
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
// !API_VERSION: 1.0
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
|
||||
package p1
|
||||
|
||||
@SinceKotlin("1.1")
|
||||
fun foo(s: Int): String = s.toString()
|
||||
|
||||
// MODULE: m2
|
||||
// FILE: b.kt
|
||||
|
||||
package p2
|
||||
|
||||
fun foo(s: Int): Int = s
|
||||
|
||||
// MODULE: m3(m1, m2)
|
||||
// FILE: severalStarImports.kt
|
||||
import p1.*
|
||||
import p2.*
|
||||
|
||||
fun test1(): Int {
|
||||
val r = <!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>(42)
|
||||
return r
|
||||
}
|
||||
|
||||
// FILE: explicitlyImportP1.kt
|
||||
import p1.foo // TODO: consider reporting API_NOT_AVAILABLE here
|
||||
import p2.*
|
||||
|
||||
fun test2(): Int {
|
||||
val r = foo(42)
|
||||
return <!RETURN_TYPE_MISMATCH!>r<!>
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !API_VERSION: 1.0
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
|
||||
+1
-1
@@ -7,5 +7,5 @@ annotation class Anno2 @SinceKotlin("1.1") constructor()
|
||||
|
||||
|
||||
@Anno1("")
|
||||
@Anno2
|
||||
@<!UNRESOLVED_REFERENCE!>Anno2<!>
|
||||
fun t1() {}
|
||||
|
||||
Vendored
+2
-2
@@ -16,8 +16,8 @@ fun t1(): Foo = Foo()
|
||||
// TODO: do not report API_NOT_AVAILABLE twice
|
||||
fun t2() = object : Foo() {}
|
||||
|
||||
fun t3(): Bar? = Bar()
|
||||
fun t3(): Bar? = <!UNRESOLVED_REFERENCE!>Bar<!>()
|
||||
|
||||
fun t4(): Baz = Baz()
|
||||
fun t4(): Baz = <!UNRESOLVED_REFERENCE!>Baz<!>()
|
||||
|
||||
fun t5(): Quux = Quux()
|
||||
|
||||
Vendored
+2
-2
@@ -18,14 +18,14 @@ interface I11 {
|
||||
}
|
||||
|
||||
fun f1(x: I10) = x.foo()
|
||||
fun f2(x: I11) = x.foo()
|
||||
fun f2(x: I11) = x.<!UNRESOLVED_REFERENCE!>foo<!>()
|
||||
fun f3(x: J) = x.foo()
|
||||
|
||||
interface BothI1 : I10, I11
|
||||
fun f4(x: BothI1) = x.foo()
|
||||
|
||||
interface BothI2 : I11, I10
|
||||
fun f5(x: BothI2) = x.foo()
|
||||
fun f5(x: BothI2) = x.<!UNRESOLVED_REFERENCE!>foo<!>()
|
||||
|
||||
interface JAndI10 : J, I10
|
||||
fun f6(x: JAndI10) = x.foo()
|
||||
|
||||
Vendored
+9
-9
@@ -34,15 +34,15 @@ val v7: String
|
||||
get() = ""
|
||||
|
||||
fun test() {
|
||||
v1
|
||||
v2
|
||||
v3
|
||||
<!UNRESOLVED_REFERENCE!>v1<!>
|
||||
<!UNRESOLVED_REFERENCE!>v2<!>
|
||||
<!UNRESOLVED_REFERENCE!>v3<!>
|
||||
v3 = ""
|
||||
v4
|
||||
v4 = ""
|
||||
v5
|
||||
v5 = ""
|
||||
v6
|
||||
v6 = ""
|
||||
v7
|
||||
<!UNRESOLVED_REFERENCE!>v4<!> = ""
|
||||
<!UNRESOLVED_REFERENCE!>v5<!>
|
||||
<!UNRESOLVED_REFERENCE!>v5<!> = ""
|
||||
<!UNRESOLVED_REFERENCE!>v6<!>
|
||||
<!UNRESOLVED_REFERENCE!>v6<!> = ""
|
||||
<!UNRESOLVED_REFERENCE!>v7<!>
|
||||
}
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// !API_VERSION: 1.0
|
||||
|
||||
@SinceKotlin("1.1")
|
||||
fun f() {}
|
||||
|
||||
@SinceKotlin("1.1")
|
||||
var p = Unit
|
||||
|
||||
@SinceKotlin("1.1.2")
|
||||
fun z() {}
|
||||
|
||||
|
||||
fun t1() = f()
|
||||
|
||||
fun t2() = p
|
||||
|
||||
fun t3() { p = Unit }
|
||||
|
||||
fun t4() { z() }
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !API_VERSION: 1.0
|
||||
|
||||
@SinceKotlin("1.1")
|
||||
|
||||
Vendored
+2
-2
@@ -13,8 +13,8 @@ open class C2(val x: Int) {
|
||||
typealias C2_Alias = C2
|
||||
|
||||
val test1 = C1_Alias()
|
||||
val test2 = C2_Alias()
|
||||
val test2 = C2_Alias(<!NO_VALUE_FOR_PARAMETER!>)<!>
|
||||
|
||||
class Test3 : C1_Alias()
|
||||
|
||||
class Test4 : C2_Alias()
|
||||
class Test4 : <!NO_VALUE_FOR_PARAMETER!>C2_Alias<!>()
|
||||
|
||||
+3
-3
@@ -31,7 +31,7 @@ fun use1(
|
||||
c1: NewClassExperimentalInThePast,
|
||||
t1: TypeAliasToNewClass
|
||||
) {
|
||||
newPublishedFun()
|
||||
<!UNRESOLVED_REFERENCE!>newPublishedFun<!>()
|
||||
newFunExperimentalInThePast()
|
||||
newValExperimentalInThePast
|
||||
NewClassExperimentalInThePast()
|
||||
@@ -42,7 +42,7 @@ fun use2(
|
||||
c2: NewClassExperimentalInThePast,
|
||||
t2: TypeAliasToNewClass
|
||||
) {
|
||||
newPublishedFun()
|
||||
<!UNRESOLVED_REFERENCE!>newPublishedFun<!>()
|
||||
newFunExperimentalInThePast()
|
||||
newValExperimentalInThePast
|
||||
NewClassExperimentalInThePast()
|
||||
@@ -53,7 +53,7 @@ fun use3(
|
||||
c3: NewClassExperimentalInThePast,
|
||||
t3: TypeAliasToNewClass
|
||||
) {
|
||||
newPublishedFun()
|
||||
<!UNRESOLVED_REFERENCE!>newPublishedFun<!>()
|
||||
newFunExperimentalInThePast()
|
||||
newValExperimentalInThePast
|
||||
NewClassExperimentalInThePast()
|
||||
|
||||
+6
@@ -16871,6 +16871,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/fir/ConstValAccess.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("differentSinceKotlin.kt")
|
||||
public void testDifferentSinceKotlin() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/fir/differentSinceKotlin.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ExtensionAlias.kt")
|
||||
public void testExtensionAlias() throws Exception {
|
||||
|
||||
+6
@@ -17255,6 +17255,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/fir/CustomThrowableMessage.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("differentSinceKotlin.kt")
|
||||
public void testDifferentSinceKotlin() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/fir/differentSinceKotlin.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ExtensionAlias.kt")
|
||||
public void testExtensionAlias() throws Exception {
|
||||
|
||||
+5
@@ -13969,6 +13969,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/fir/ConstValAccess.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("differentSinceKotlin.kt")
|
||||
public void testDifferentSinceKotlin() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/fir/differentSinceKotlin.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExtensionAlias.kt")
|
||||
public void testExtensionAlias() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/fir/ExtensionAlias.kt");
|
||||
|
||||
@@ -161,6 +161,8 @@ object StandardClassIds {
|
||||
|
||||
val RestrictsSuspension = "RestrictsSuspension".coroutinesId()
|
||||
|
||||
val WasExperimental = "WasExperimental".baseId()
|
||||
|
||||
object Java {
|
||||
val Deprecated = "Deprecated".javaLangId()
|
||||
val Repeatable = "Repeatable".javaAnnotationId()
|
||||
|
||||
Reference in New Issue
Block a user