From 5c95f69aef7fb1df61cbb0b6315ab37a519937b2 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 2 Aug 2023 14:37:11 +0200 Subject: [PATCH] [FE, IR] Check annotations compatibility on expect and actual value parameters Comment was added to make it clear why whole declarations reported in diagnostic instead of value parameter symbols (same will be done with other targets in subsequent commits). ^KT-60671 --- ...DiagnosticsWithLightTreeTestGenerated.java | 6 +++++ ...endMPPDiagnosticsWithPsiTestGenerated.java | 6 +++++ ...tractExpectActualAnnotationMatchChecker.kt | 27 +++++++++++++++++++ .../checkDiagnosticFullText.diag.txt | 14 ++++++---- .../checkDiagnosticFullText.fir.diag.txt | 13 +++++---- .../checkDiagnosticFullText.fir.kt | 4 +++ .../checkDiagnosticFullText.kt | 4 +++ .../annotationMatching/valueParameters.fir.kt | 18 +++++++++++++ .../annotationMatching/valueParameters.kt | 18 +++++++++++++ .../test/runners/DiagnosticTestGenerated.java | 6 +++++ 10 files changed, 106 insertions(+), 10 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/valueParameters.fir.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/annotationMatching/valueParameters.kt diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java index 1f33cef8761..6be983aec34 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java @@ -926,6 +926,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt"); } + @Test + @TestMetadata("valueParameters.kt") + public void testValueParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/valueParameters.kt"); + } + @Test @TestMetadata("withAnnotationActualTypealias.kt") public void testWithAnnotationActualTypealias() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java index 148f4d8a9ad..22c34459a89 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java @@ -926,6 +926,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt"); } + @Test + @TestMetadata("valueParameters.kt") + public void testValueParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/valueParameters.kt"); + } + @Test @TestMetadata("withAnnotationActualTypealias.kt") public void testWithAnnotationActualTypealias() throws Exception { diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualAnnotationMatchChecker.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualAnnotationMatchChecker.kt index 9a981acd7b1..da63de306a7 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualAnnotationMatchChecker.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualAnnotationMatchChecker.kt @@ -28,6 +28,14 @@ object AbstractExpectActualAnnotationMatchChecker { ) class Incompatibility( + /** + * [expectSymbol] and [actualSymbol] are declaration symbols where annotation been mismatched. + * They are needed for writing whole declarations in diagnostic text. + * They are not the same as symbols passed to checker as arguments in [areAnnotationsCompatible] in following cases: + * 1. If [actualSymbol] is typealias, it will be expanded. + * 2. If problem is in class member, [expectSymbol] will be mismatched member, not the original class. + * 3. If annotation mismatched on function value parameter, symbols will be whole functions, not value parameter symbols. + */ val expectSymbol: DeclarationSymbolMarker, val actualSymbol: DeclarationSymbolMarker, val type: IncompatibilityType, @@ -63,6 +71,7 @@ object AbstractExpectActualAnnotationMatchChecker { actualSymbol: CallableSymbolMarker, ): Incompatibility? { commonForClassAndCallableChecks(expectSymbol, actualSymbol)?.let { return it } + areAnnotationsOnValueParametersCompatible(expectSymbol, actualSymbol)?.let { return it } return null } @@ -100,6 +109,24 @@ object AbstractExpectActualAnnotationMatchChecker { return null } + context (ExpectActualMatchingContext<*>) + private fun areAnnotationsOnValueParametersCompatible( + expectSymbol: CallableSymbolMarker, + actualSymbol: CallableSymbolMarker, + ): Incompatibility? { + val expectParams = expectSymbol.valueParameters + val actualParams = actualSymbol.valueParameters + + if (expectParams.size != actualParams.size) return null + + return expectParams.zip(actualParams).firstNotNullOfOrNull { (expectParam, actualParam) -> + areAnnotationsSetOnDeclarationsCompatible(expectParam, actualParam)?.let { + // Write containing declarations into diagnostic + Incompatibility(expectSymbol, actualSymbol, it.type) + } + } + } + context (ExpectActualMatchingContext<*>) private fun areAnnotationsSetOnDeclarationsCompatible( expectSymbol: DeclarationSymbolMarker, diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt index 29e0266a9a2..97ee54f26b9 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt @@ -1,24 +1,28 @@ // -- Module: -- // -- Module: -- -/jvm.kt:29:14: warning: annotation `@Ann` is missing on actual declaration. +/jvm.kt:31: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:32:16: warning: annotation `@Ann` is missing on actual declaration. +/jvm.kt:34: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:37:18: warning: annotation `@Ann` is missing on actual declaration. +/jvm.kt:39: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:42:18: warning: annotation `@Ann` is missing on actual declaration. +/jvm.kt:44: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:45:12: warning: annotation `@WithArg(s = "str")` has different arguments on actual declaration: `@WithArg(s = "other str")`. +/jvm.kt:47: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:49: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) {} + ^ diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt index f3fe0e8065d..f03b1674954 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt @@ -1,14 +1,17 @@ -/jvm.kt:(88,95): warning: Annotation `@Ann()` is missing on actual declaration. +/jvm.kt:(90,97): 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:(136,144): warning: Annotation `@Ann()` is missing on actual declaration. +/jvm.kt:(138,146): 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:(194,206): warning: Annotation `@Ann()` is missing on actual declaration. +/jvm.kt:(196,208): 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:(299,322): warning: Annotation `@Ann()` is missing on actual declaration. +/jvm.kt:(301,324): 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:(387,403): warning: Annotation `@WithArg(s = String(str))` has different arguments on actual declaration: `@WithArg(s = String(other str))`. +/jvm.kt:(389,405): 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:(423,435): 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. diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt index 8da9e0b3283..a455012e5fd 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt @@ -24,6 +24,8 @@ annotation class WithArg(val s: String) @WithArg("str") expect fun withDifferentArg() +expect fun inValueParam(@Ann arg: String) + // MODULE: m1-jvm()()(m1-common) // FILE: jvm.kt actual class OnClass @@ -43,3 +45,5 @@ class MemberScopeViaTypealiasImpl { @WithArg("other str") actual fun withDifferentArg() {} + +actual fun inValueParam(arg: String) {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt index 912ff475112..a9219fe1e95 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt @@ -24,6 +24,8 @@ annotation class WithArg(val s: String) @WithArg("str") expect fun withDifferentArg() +expect fun inValueParam(@Ann arg: String) + // MODULE: m1-jvm()()(m1-common) // FILE: jvm.kt actual class OnClass @@ -43,3 +45,5 @@ actual typealias MemberScopeViaTypealias< @WithArg("other str") actual fun withDifferentArg() {} + +actual fun inValueParam(arg: String) {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/valueParameters.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/valueParameters.fir.kt new file mode 100644 index 00000000000..4746b2a2413 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/valueParameters.fir.kt @@ -0,0 +1,18 @@ +// MODULE: m1-common +// FILE: common.kt +@Target(AnnotationTarget.VALUE_PARAMETER) +annotation class Ann + +expect fun inMethod(@Ann arg: String) + +expect class InConstructor(@Ann arg: String) + +expect fun withIncopatibility(@Ann p1: String, @Ann p2: String) + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual fun inMethod(arg: String) {} + +actual class InConstructor actual constructor(arg: String) {} + +actual fun withIncopatibility(p1: String) {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/valueParameters.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/valueParameters.kt new file mode 100644 index 00000000000..cc74b97805f --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/valueParameters.kt @@ -0,0 +1,18 @@ +// MODULE: m1-common +// FILE: common.kt +@Target(AnnotationTarget.VALUE_PARAMETER) +annotation class Ann + +expect fun inMethod(@Ann arg: String) + +expect class InConstructor(@Ann arg: String) + +expect fun withIncopatibility(@Ann p1: String, @Ann p2: String) + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual fun inMethod(arg: String) {} + +actual class InConstructor actual constructor(arg: String) {} + +actual fun withIncopatibility(p1: String) {} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index a5271203cdd..327dc132c44 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -23921,6 +23921,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt"); } + @Test + @TestMetadata("valueParameters.kt") + public void testValueParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/valueParameters.kt"); + } + @Test @TestMetadata("withAnnotationActualTypealias.kt") public void testWithAnnotationActualTypealias() throws Exception {