diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt index 3895667a083..b7cf757770c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt @@ -179,14 +179,4 @@ object FirDiagnosticRenderers { } val FUNCTIONAL_TYPE_KINDS = KtDiagnosticRenderers.COLLECTION(FUNCTIONAL_TYPE_KIND) - - @OptIn(SymbolInternals::class) - val SYMBOL_WITH_ANNOTATIONS = Renderer { s: FirBasedSymbol<*> -> - FirRenderer( - typeRenderer = ConeTypeRenderer(), - idRenderer = ConeIdShortRenderer(), - classMemberRenderer = null, - bodyRenderer = null, - ).renderElementAsString(s.fir, trim = true) - } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index 90c93dce102..92f452ceb99 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -1886,11 +1886,11 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { ) map.put( ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, - "All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.\n" + - "Expected: {0}\n" + - "Actual: {1}", - FirDiagnosticRenderers.SYMBOL_WITH_ANNOTATIONS, FirDiagnosticRenderers.SYMBOL_WITH_ANNOTATIONS, - TO_STRING + "{2}.\n" + + "All annotations from expect `{0}` must be present with the same arguments on actual `{1}`, otherwise they might behave incorrectly.", + FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.SYMBOL_RENDERER, + FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.SYMBOL_RENDERER, + FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.INCOMPATIBILITY, ) // Destructuring declaration diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.kt new file mode 100644 index 00000000000..7a9e67a338d --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.kt @@ -0,0 +1,54 @@ +/* + * 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.analysis.diagnostics + +import org.jetbrains.kotlin.diagnostics.rendering.Renderer +import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.renderer.ConeIdShortRenderer +import org.jetbrains.kotlin.fir.renderer.ConeTypeRenderer +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 + +internal object FirExpectActualAnnotationIncompatibilityDiagnosticRenderers { + @OptIn(SymbolInternals::class) + val SYMBOL_RENDERER = Renderer> { + FirRenderer( + typeRenderer = ConeTypeRenderer(), + idRenderer = ConeIdShortRenderer(), + classMemberRenderer = null, + bodyRenderer = null, + annotationRenderer = null, + modifierRenderer = null, + contractRenderer = null, + ).renderElementAsString(it.fir, trim = true) + } + + val INCOMPATIBILITY = Renderer { incompatibilityType: ExpectActualAnnotationsIncompatibilityType -> + val sb = StringBuilder("Annotation `") + .append(renderAnnotation(incompatibilityType.expectAnnotation)) + .append("` ") + when (incompatibilityType) { + is ExpectActualAnnotationsIncompatibilityType.MissingOnActual -> { + sb.append("is missing on actual declaration") + } + is ExpectActualAnnotationsIncompatibilityType.DifferentOnActual -> { + sb.append("has different arguments on actual declaration: `") + .append(renderAnnotation(incompatibilityType.actualAnnotation)) + .append("`") + } + } + sb.toString() + } + + private fun renderAnnotation(ann: FirAnnotation): String { + return FirRenderer( + typeRenderer = ConeTypeRenderer(), + idRenderer = ConeIdShortRenderer(), + ).renderElementAsString(ann, trim = true) + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index fdcf1b052b2..a3a07b644e6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -404,10 +404,11 @@ public class DefaultErrorMessages { "`actual typealias` to annotation which affects code compilation can lead to incorrect behavior. Instead, use ''{0}'' annotation directly.", TO_STRING); MAP.put(ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, - "All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.\n" + - " Expected: {0}\n" + - " Actual: {1}", - DESCRIPTOR_WITH_ANNOTATIONS, DESCRIPTOR_WITH_ANNOTATIONS, TO_STRING); + "{2}.\n" + + "All annotations from expect `{0}` must be present with the same arguments on actual `{1}`, otherwise they might behave incorrectly.", + ExpectActualAnnotationIncompatibilityDiagnosticRenderers.DESCRIPTOR_RENDERER, + ExpectActualAnnotationIncompatibilityDiagnosticRenderers.DESCRIPTOR_RENDERER, + ExpectActualAnnotationIncompatibilityDiagnosticRenderers.INCOMPATIBILITY); MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties"); MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/ExpectActualAnnotationIncompatibilityDiagnosticRenderer.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/ExpectActualAnnotationIncompatibilityDiagnosticRenderer.kt new file mode 100644 index 00000000000..74dbcb17958 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/ExpectActualAnnotationIncompatibilityDiagnosticRenderer.kt @@ -0,0 +1,42 @@ +/* + * 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.diagnostics.rendering + +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.renderer.AnnotationArgumentsRenderingPolicy +import org.jetbrains.kotlin.renderer.ClassifierNamePolicy +import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualAnnotationsIncompatibilityType + +internal object ExpectActualAnnotationIncompatibilityDiagnosticRenderers { + private val descriptorRender = DescriptorRenderer.withOptions { + annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY + modifiers = emptySet() + withDefinedIn = true + classifierNamePolicy = ClassifierNamePolicy.SHORT + } + + @JvmField + val DESCRIPTOR_RENDERER = descriptorRender.asRenderer() + + @JvmField + val INCOMPATIBILITY = Renderer { incompatibilityType: ExpectActualAnnotationsIncompatibilityType -> + val sb = StringBuilder("Annotation `") + .append(descriptorRender.renderAnnotation(incompatibilityType.expectAnnotation)) + .append("` ") + when (incompatibilityType) { + is ExpectActualAnnotationsIncompatibilityType.MissingOnActual -> { + sb.append("is missing on actual declaration") + } + is ExpectActualAnnotationsIncompatibilityType.DifferentOnActual -> { + sb.append("has different arguments on actual declaration: `") + .append(descriptorRender.renderAnnotation(incompatibilityType.actualAnnotation)) + .append("`") + } + } + sb.toString() + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt index 4eaa097945b..4c09656155b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt @@ -711,13 +711,6 @@ object Renderers { @JvmField val COMPACT_WITH_MODIFIERS = DescriptorRenderer.COMPACT_WITH_MODIFIERS.asRenderer() - @JvmField - val DESCRIPTOR_WITH_ANNOTATIONS = DescriptorRenderer.withOptions { - annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY - modifiers = modifiers.plus(DescriptorRendererModifier.ANNOTATIONS) - withDefinedIn = true - }.asRenderer() - @JvmField val DEPRECATION_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions { withoutTypeParameters = false diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendErrors.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendErrors.kt index 5345646e6d3..f3c1bb3c8c5 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendErrors.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendErrors.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.backend.common import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.backend.common.BackendDiagnosticRenderers.EXPECT_ACTUAL_ANNOTATION_INCOMPATIBILITY import org.jetbrains.kotlin.backend.common.BackendDiagnosticRenderers.INCOMPATIBILITY import org.jetbrains.kotlin.backend.common.BackendDiagnosticRenderers.SYMBOL_OWNER_DECLARATION_FQ_NAME import org.jetbrains.kotlin.descriptors.ModuleDescriptor @@ -18,6 +19,7 @@ import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.types.classFqName import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualAnnotationsIncompatibilityType import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility @@ -64,10 +66,11 @@ object KtDefaultCommonBackendErrorMessages : BaseDiagnosticRendererFactory() { ) map.put( CommonBackendErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, - "All annotations from expect declaration `{0}` must be present with the same arguments on actual declaration `{1}` otherwise they have no effect", + "{2}.\n" + + "All annotations from expect `{0}` must be present with the same arguments on actual `{1}`, otherwise they might behave incorrectly.", SYMBOL_OWNER_DECLARATION_FQ_NAME, SYMBOL_OWNER_DECLARATION_FQ_NAME, - STRING, + EXPECT_ACTUAL_ANNOTATION_INCOMPATIBILITY, ) map.put( CommonBackendErrors.EVALUATION_ERROR, @@ -84,4 +87,13 @@ object BackendDiagnosticRenderers { val SYMBOL_OWNER_DECLARATION_FQ_NAME = Renderer { (it.owner as? IrDeclarationWithName)?.fqNameWhenAvailable?.asString() ?: "unknown name" } + val EXPECT_ACTUAL_ANNOTATION_INCOMPATIBILITY = + Renderer { incompatibilityType: ExpectActualAnnotationsIncompatibilityType -> + val expectAnnotationFqName = incompatibilityType.expectAnnotation.type.classFqName ?: "" + val reason = when (incompatibilityType) { + is ExpectActualAnnotationsIncompatibilityType.MissingOnActual -> "is missing on actual declaration" + is ExpectActualAnnotationsIncompatibilityType.DifferentOnActual -> "has different arguments on actual declaration" + } + "Annotation `$expectAnnotationFqName` $reason" + } } diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt index 66159473d3e..e0342f49327 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.diag.txt @@ -1,19 +1,20 @@ // -- Module: -- // -- Module: -- -/jvm.kt:23:14: warning: all annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. - Expected: @Ann public final expect class OnClass defined in root package in file common.kt - Actual: public final actual class OnClass defined in root package in file jvm.kt +/jvm.kt:27: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:26:16: warning: all annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. - Expected: @Ann public final expect fun onMember(): Unit defined in OnMember - Actual: public final actual fun onMember(): Unit defined in OnMember +/jvm.kt:30: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:33:18: warning: all annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. - Expected: @Ann public final expect class ViaTypealias defined in root package in file common.kt - Actual: public final class ViaTypealiasImpl defined in root package in file jvm.kt +/jvm.kt:37: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:40: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() {} + ^ 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 fc833b2f956..50ce2a25516 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.diag.txt @@ -1,11 +1,11 @@ -/jvm.kt:(82,89): warning: All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. -Expected: @Ann() public final expect class OnClass : Any -Actual: public final actual class OnClass : Any +/jvm.kt:(86,93): 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:(130,138): warning: All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. -Expected: @Ann() public final expect fun onMember(): Unit -Actual: public final actual fun onMember(): Unit +/jvm.kt:(134,142): 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:(209,221): warning: All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect. -Expected: @Ann() public final expect class ViaTypealias : Any -Actual: public final class ViaTypealiasImpl : Any +/jvm.kt:(213,225): 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:(279,295): 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. diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt index 8a763049448..80c468a02d5 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.fir.kt @@ -17,6 +17,10 @@ expect class ViaTypealias { fun foo() } +annotation class WithArg(val s: String) + +@WithArg("str") +expect fun withDifferentArg() // MODULE: m1-jvm()()(m1-common) // FILE: jvm.kt @@ -31,3 +35,6 @@ class ViaTypealiasImpl { } actual typealias ViaTypealias = ViaTypealiasImpl + +@WithArg("other str") +actual fun withDifferentArg() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt index 7d505921da2..4d6fc140d06 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt @@ -17,6 +17,10 @@ expect class ViaTypealias { fun foo() } +annotation class WithArg(val s: String) + +@WithArg("str") +expect fun withDifferentArg() // MODULE: m1-jvm()()(m1-common) // FILE: jvm.kt @@ -31,3 +35,6 @@ class ViaTypealiasImpl { } actual typealias ViaTypealias = ViaTypealiasImpl + +@WithArg("other str") +actual fun withDifferentArg() {}