[FE, IR] Check annotations compatibility on expect and actual getters and setters

^KT-60671
This commit is contained in:
Roman Efremov
2023-08-04 15:28:52 +02:00
committed by Space Team
parent 8fb2935ef6
commit e79851910e
15 changed files with 175 additions and 15 deletions
@@ -854,6 +854,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt");
}
@Test
@TestMetadata("gettersAndSetters.kt")
public void testGettersAndSetters() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/gettersAndSetters.kt");
}
@Test
@TestMetadata("intrinsicConstEvaluation.kt")
public void testIntrinsicConstEvaluation() throws Exception {
@@ -854,6 +854,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt");
}
@Test
@TestMetadata("gettersAndSetters.kt")
public void testGettersAndSetters() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/gettersAndSetters.kt");
}
@Test
@TestMetadata("intrinsicConstEvaluation.kt")
public void testIntrinsicConstEvaluation() throws Exception {
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.renderer.FirRenderer
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualAnnotationsIncompatibilityType
import org.jetbrains.kotlin.utils.Printer
internal object FirExpectActualAnnotationIncompatibilityDiagnosticRenderers {
@OptIn(SymbolInternals::class)
@@ -26,6 +27,8 @@ internal object FirExpectActualAnnotationIncompatibilityDiagnosticRenderers {
modifierRenderer = null,
contractRenderer = null,
).renderElementAsString(it.fir, trim = true)
// Write property accessors on the same line as the property
.run { replace(Printer.LINE_SEPARATOR, "") }
}
val INCOMPATIBILITY = Renderer { incompatibilityType: ExpectActualAnnotationsIncompatibilityType<FirAnnotation> ->
@@ -142,6 +142,9 @@ class FirExpectActualMatchingContextImpl private constructor(
override val PropertySymbolMarker.isConst: Boolean
get() = asSymbol().resolvedStatus.isConst
override val PropertySymbolMarker.getter: FunctionSymbolMarker?
get() = asSymbol().getterSymbol
override val PropertySymbolMarker.setter: FunctionSymbolMarker?
get() = asSymbol().setterSymbol
@@ -231,6 +231,9 @@ internal abstract class IrExpectActualMatchingContext(
override val PropertySymbolMarker.isConst: Boolean
get() = asIr().isConst
override val PropertySymbolMarker.getter: FunctionSymbolMarker?
get() = asIr().getter?.symbol
override val PropertySymbolMarker.setter: FunctionSymbolMarker?
get() = asIr().setter?.symbol
@@ -80,6 +80,29 @@ object AbstractExpectActualAnnotationMatchChecker {
commonForClassAndCallableChecks(expectSymbol, actualSymbol)?.let { return it }
areAnnotationsOnValueParametersCompatible(expectSymbol, actualSymbol)?.let { return it }
if (expectSymbol is PropertySymbolMarker && actualSymbol is PropertySymbolMarker) {
arePropertyGetterAndSetterAnnotationsCompatible(expectSymbol, actualSymbol)?.let { return it }
}
return null
}
context (ExpectActualMatchingContext<*>)
private fun arePropertyGetterAndSetterAnnotationsCompatible(
expectSymbol: PropertySymbolMarker,
actualSymbol: PropertySymbolMarker,
): Incompatibility? {
listOf(
expectSymbol.getter to actualSymbol.getter,
expectSymbol.setter to actualSymbol.setter,
).forEach { (expectAccessor, actualAccessor) ->
if (expectAccessor != null && actualAccessor != null) {
areAnnotationsSetOnDeclarationsCompatible(expectAccessor, actualAccessor)?.let {
// Write containing declarations into diagnostic
return Incompatibility(expectSymbol, actualSymbol, actualAccessor.getSourceElement(), it.type)
}
}
}
return null
}
@@ -165,7 +188,7 @@ object AbstractExpectActualAnnotationMatchChecker {
expectSymbol: DeclarationSymbolMarker,
actualSymbol: DeclarationSymbolMarker,
): Incompatibility? {
// TODO(Roman.Efremov, KT-58551): check other annotation targets (constructors, types, value parameters, etc)
// TODO(Roman.Efremov, KT-60671): check annotations set on types
val skipSourceAnnotations = actualSymbol.hasSourceAnnotationsErased
val actualAnnotationsByName = actualSymbol.annotations.groupBy { it.classId }
@@ -99,6 +99,7 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
val PropertySymbolMarker.isLateinit: Boolean
val PropertySymbolMarker.isConst: Boolean
val PropertySymbolMarker.getter: FunctionSymbolMarker?
val PropertySymbolMarker.setter: FunctionSymbolMarker?
fun createExpectActualTypeParameterSubstitutor(
@@ -136,6 +136,10 @@ class ClassicExpectActualMatchingContext(
get() = asDescriptor().isLateInit
override val PropertySymbolMarker.isConst: Boolean
get() = asDescriptor().isConst
override val PropertySymbolMarker.getter: FunctionSymbolMarker?
get() = asDescriptor().getter
override val PropertySymbolMarker.setter: FunctionSymbolMarker?
get() = asDescriptor().setter
@@ -1,32 +1,36 @@
// -- Module: <m1-common> --
// -- Module: <m1-jvm> --
/jvm.kt:39:14: warning: annotation `@Ann` is missing on actual declaration.
/jvm.kt:44:14: warning: annotation `@Ann` is missing on actual declaration.
All annotations from expect `class OnClass defined in root package in file common.kt` must be present with the same arguments on actual `class OnClass defined in root package in file jvm.kt`, otherwise they might behave incorrectly.
actual class OnClass
^
/jvm.kt:42:16: warning: annotation `@Ann` is missing on actual declaration.
/jvm.kt:47:16: warning: annotation `@Ann` is missing on actual declaration.
All annotations from expect `fun onMember(): Unit defined in OnMember` must be present with the same arguments on actual `fun onMember(): Unit defined in OnMember`, otherwise they might behave incorrectly.
actual fun onMember() {}
^
/jvm.kt:47:18: warning: annotation `@Ann` is missing on actual declaration.
/jvm.kt:52:18: warning: annotation `@Ann` is missing on actual declaration.
All annotations from expect `class ViaTypealias defined in root package in file common.kt` must be present with the same arguments on actual `class ViaTypealiasImpl defined in root package in file jvm.kt`, otherwise they might behave incorrectly.
actual typealias ViaTypealias = ViaTypealiasImpl
^
/jvm.kt:52:18: warning: annotation `@Ann` is missing on actual declaration.
/jvm.kt:57:18: warning: annotation `@Ann` is missing on actual declaration.
All annotations from expect `fun foo(): Unit defined in MemberScopeViaTypealias` must be present with the same arguments on actual `fun foo(): Unit defined in MemberScopeViaTypealiasImpl`, otherwise they might behave incorrectly.
actual typealias MemberScopeViaTypealias = MemberScopeViaTypealiasImpl
^
/jvm.kt:55:12: warning: annotation `@WithArg(s = "str")` has different arguments on actual declaration: `@WithArg(s = "other str")`.
/jvm.kt:60:12: warning: annotation `@WithArg(s = "str")` has different arguments on actual declaration: `@WithArg(s = "other str")`.
All annotations from expect `fun withDifferentArg(): Unit defined in root package in file common.kt` must be present with the same arguments on actual `fun withDifferentArg(): Unit defined in root package in file jvm.kt`, otherwise they might behave incorrectly.
actual fun withDifferentArg() {}
^
/jvm.kt:57:12: warning: annotation `@Ann` is missing on actual declaration.
/jvm.kt:62:12: warning: annotation `@Ann` is missing on actual declaration.
All annotations from expect `fun inValueParam(arg: String): Unit defined in root package in file common.kt` must be present with the same arguments on actual `fun inValueParam(arg: String): Unit defined in root package in file jvm.kt`, otherwise they might behave incorrectly.
actual fun inValueParam(arg: String) {}
^
/jvm.kt:59:16: warning: annotation `@Ann` is missing on actual declaration.
/jvm.kt:64:16: warning: annotation `@Ann` is missing on actual declaration.
All annotations from expect `fun <T> inTypeParam(): Unit defined in root package in file common.kt` must be present with the same arguments on actual `fun <T> inTypeParam(): Unit defined in root package in file jvm.kt`, otherwise they might behave incorrectly.
actual fun <T> inTypeParam() {}
^
/jvm.kt:66:12: warning: annotation `@Ann` is missing on actual declaration.
All annotations from expect `val onGetter: String defined in root package in file common.kt` must be present with the same arguments on actual `val onGetter: String defined in root package in file jvm.kt`, otherwise they might behave incorrectly.
actual val onGetter: String = ""
^
@@ -1,20 +1,23 @@
/jvm.kt:(98,105): warning: Annotation `@Ann()` is missing on actual declaration.
/jvm.kt:(103,110): warning: Annotation `@Ann()` is missing on actual declaration.
All annotations from expect 'class OnClass : Any' must be present with the same arguments on actual 'class OnClass : Any', otherwise they might behave incorrectly.
/jvm.kt:(146,154): warning: Annotation `@Ann()` is missing on actual declaration.
/jvm.kt:(151,159): warning: Annotation `@Ann()` is missing on actual declaration.
All annotations from expect 'fun onMember(): Unit' must be present with the same arguments on actual 'fun onMember(): Unit', otherwise they might behave incorrectly.
/jvm.kt:(204,216): warning: Annotation `@Ann()` is missing on actual declaration.
/jvm.kt:(209,221): warning: Annotation `@Ann()` is missing on actual declaration.
All annotations from expect 'class ViaTypealias : Any' must be present with the same arguments on actual 'class ViaTypealiasImpl : Any', otherwise they might behave incorrectly.
/jvm.kt:(309,332): warning: Annotation `@Ann()` is missing on actual declaration.
/jvm.kt:(314,337): warning: Annotation `@Ann()` is missing on actual declaration.
All annotations from expect 'fun foo(): Unit' must be present with the same arguments on actual 'fun foo(): Unit', otherwise they might behave incorrectly.
/jvm.kt:(397,413): warning: Annotation `@WithArg(s = String(str))` has different arguments on actual declaration: `@WithArg(s = String(other str))`.
/jvm.kt:(402,418): warning: Annotation `@WithArg(s = String(str))` has different arguments on actual declaration: `@WithArg(s = String(other str))`.
All annotations from expect 'fun withDifferentArg(): Unit' must be present with the same arguments on actual 'fun withDifferentArg(): Unit', otherwise they might behave incorrectly.
/jvm.kt:(431,443): warning: Annotation `@Ann()` is missing on actual declaration.
/jvm.kt:(436,448): warning: Annotation `@Ann()` is missing on actual declaration.
All annotations from expect 'fun inValueParam(arg: String): Unit' must be present with the same arguments on actual 'fun inValueParam(arg: String): Unit', otherwise they might behave incorrectly.
/jvm.kt:(476,487): warning: Annotation `@Ann()` is missing on actual declaration.
/jvm.kt:(481,492): warning: Annotation `@Ann()` is missing on actual declaration.
All annotations from expect 'fun <T> inTypeParam(): Unit' must be present with the same arguments on actual 'fun <T> inTypeParam(): Unit', otherwise they might behave incorrectly.
/jvm.kt:(510,518): warning: Annotation `@PROPERTY_GETTER:Ann()` is missing on actual declaration.
All annotations from expect 'val onGetter: String get(): String' must be present with the same arguments on actual 'val onGetter: String get(): String', otherwise they might behave incorrectly.
@@ -6,6 +6,8 @@
AnnotationTarget.CLASS,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.TYPE_PARAMETER,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
)
annotation class Ann
@@ -34,6 +36,9 @@ expect fun inValueParam(@Ann arg: String)
expect fun <@Ann T> inTypeParam()
@get:Ann
expect val onGetter: String
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual class <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>OnClass<!><!>
@@ -57,3 +62,5 @@ actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>withDifferentArg<!>() {}<!>
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>inValueParam<!>(arg: String) {}<!>
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual fun <T> <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>inTypeParam<!>() {}<!>
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual val <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onGetter<!>: String = ""<!>
@@ -6,6 +6,8 @@
AnnotationTarget.CLASS,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.TYPE_PARAMETER,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
)
annotation class Ann
@@ -34,6 +36,9 @@ expect fun inValueParam(@Ann arg: String)
expect fun <@Ann T> inTypeParam()
@get:Ann
expect val onGetter: String
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
actual class <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>OnClass<!>
@@ -57,3 +62,5 @@ actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>withDifferentArg<!>() {}
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>inValueParam<!>(arg: String) {}
actual fun <T> <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>inTypeParam<!>() {}
actual val <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onGetter<!>: String = ""
@@ -0,0 +1,42 @@
// MODULE: m1-common
// FILE: common.kt
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
annotation class Ann
expect val onGetter: String
@Ann get
expect val onGetterImplicit: String
@Ann get
@get:Ann
expect val onGetterWithExplicitTarget: String
@get:Ann
expect val explicitTargetMatchesWithoutTarget: String
@get:Ann
expect val setOnPropertyWithoutTargetNotMatch: String
expect var onSetter: String
@Ann set
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual val <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onGetter<!>: String
get() = ""<!>
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual val <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onGetterImplicit<!>: String = ""<!>
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual val <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onGetterWithExplicitTarget<!>: String
get() = ""<!>
actual val explicitTargetMatchesWithoutTarget: String
@Ann get() = ""
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>@Ann
actual val <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>setOnPropertyWithoutTargetNotMatch<!>: String = ""<!>
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual var <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onSetter<!>: String
get() = ""
set(_) {}<!>
@@ -0,0 +1,42 @@
// MODULE: m1-common
// FILE: common.kt
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
annotation class Ann
expect val onGetter: String
@Ann get
expect val onGetterImplicit: String
@Ann get
@get:Ann
expect val onGetterWithExplicitTarget: String
@get:Ann
expect val explicitTargetMatchesWithoutTarget: String
@get:Ann
expect val setOnPropertyWithoutTargetNotMatch: String
expect var onSetter: String
@Ann set
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
actual val <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onGetter<!>: String
get() = ""
actual val <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onGetterImplicit<!>: String = ""
actual val <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onGetterWithExplicitTarget<!>: String
get() = ""
actual val explicitTargetMatchesWithoutTarget: String
@Ann get() = ""
@Ann
actual val <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>setOnPropertyWithoutTargetNotMatch<!>: String = ""
actual var <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onSetter<!>: String
get() = ""
set(_) {}
@@ -23849,6 +23849,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt");
}
@Test
@TestMetadata("gettersAndSetters.kt")
public void testGettersAndSetters() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/gettersAndSetters.kt");
}
@Test
@TestMetadata("intrinsicConstEvaluation.kt")
public void testIntrinsicConstEvaluation() throws Exception {