diff --git a/compiler/testData/diagnostics/nativeTests/throws.kt b/compiler/testData/diagnostics/nativeTests/throws.kt index b5cc8972322..70f94105ab2 100644 --- a/compiler/testData/diagnostics/nativeTests/throws.kt +++ b/compiler/testData/diagnostics/nativeTests/throws.kt @@ -11,16 +11,36 @@ class Exception3 : Throwable() @Throws fun foo() {} +interface Base0 { + fun foo() +} + +class ThrowsOnOverride : Base0 { + @Throws(Exception1::class) override fun foo() {} +} + interface Base1 { @Throws(Exception1::class) fun foo() } -class HasThrowsOnOverride : Base1 { - @Throws(Exception1::class) override fun foo() {} +class InheritsThrowsAndNoThrows : Base0, Base1 { + override fun foo() {} +} + +class OverridesThrowsAndNoThrows : Base0, Base1 { + @Throws(Exception1::class) override fun foo() {} +} + +class SameThrowsOnOverride : Base1 { + @Throws(Exception1::class) override fun foo() {} +} + +class DifferentThrowsOnOverride : Base1 { + @Throws(Exception2::class) override fun foo() {} } class HasThrowsWithEmptyListOnOverride : Base1 { - @Throws override fun foo() {} + @Throws override fun foo() {} } interface Base2 { @@ -31,8 +51,28 @@ open class InheritsDifferentThrows1 : Base1, Base2 { override fun foo() {} } +open class OverridesDifferentThrows1_1 : Base1, Base2 { + @Throws(Exception1::class) override fun foo() {} +} + +open class OverridesDifferentThrows1_2 : Base1, Base2 { + @Throws(Exception2::class) override fun foo() {} +} + +open class OverridesDifferentThrows1_3 : Base1, Base2 { + @Throws(Exception1::class, Exception2::class) override fun foo() {} +} + class InheritsDifferentThrowsThroughSameClass1 : InheritsDifferentThrows1() { - override fun foo() {} + override fun foo() {} +} + +class OverridesDifferentThrowsThroughSameClass1 : InheritsDifferentThrows1() { + @Throws(Exception1::class) override fun foo() {} +} + +class OverridesDifferentThrowsThroughSameClass2 : InheritsDifferentThrows1() { + @Throws(Exception2::class) override fun foo() {} } interface Base3 { @@ -43,6 +83,30 @@ class InheritsDifferentThrows2 : InheritsDifferentThrows1(), Base3 { override fun foo() {} } +class OverridesDifferentThrows2 : InheritsDifferentThrows1(), Base3 { + @Throws(Exception3::class) override fun foo() {} +} + +open class OverridesDifferentThrows3 : Base1, Base2 { + @Throws(Exception3::class) override fun foo() {} +} + +class InheritsDifferentThrows3 : OverridesDifferentThrows3() { + override fun foo() {} +} + +class OverrideDifferentThrows4 : OverridesDifferentThrows3() { + override fun foo() {} +} + +class OverrideDifferentThrows5 : OverridesDifferentThrows3() { + @Throws(Exception3::class) override fun foo() {} +} + +class OverrideDifferentThrows6 : OverridesDifferentThrows3() { + @Throws(Exception1::class) override fun foo() {} +} + interface Base4 { @Throws(Exception1::class) fun foo() } @@ -51,6 +115,18 @@ class InheritsSameThrows : Base1, Base4 { override fun foo() {} } +class OverridesSameThrows : Base1, Base4 { + @Throws(Exception1::class) override fun foo() {} +} + +class OverrideDifferentThrows7 : Base1, Base4 { + @Throws(Exception2::class) override fun foo() {} +} + +class OverrideDifferentThrows8 : Base1, Base3 { + @Throws(Exception2::class) override fun foo() {} +} + interface Base5 { @Throws(Exception1::class, Exception2::class) fun foo() } @@ -63,6 +139,18 @@ class InheritsSameThrowsMultiple : Base5, Base6 { override fun foo() {} } +class OverridesSameThrowsMultiple1 : Base5, Base6 { + @Throws(Exception1::class, Exception2::class) override fun foo() {} +} + +class OverridesSameThrowsMultiple2 : Base5, Base6 { + @Throws(Exception2::class, Exception1::class) override fun foo() {} +} + +class OverridesDifferentThrowsMultiple : Base5, Base6 { + @Throws(Exception1::class) override fun foo() {} +} + fun withLocalClass() { class LocalException : Throwable() @@ -73,4 +161,32 @@ fun withLocalClass() { class InheritsDifferentThrowsLocal : Base1, Base7() { override fun foo() {} } + + class OverridesDifferentThrowsLocal : Base1, Base7() { + @Throws(Exception1::class, LocalException::class) override fun foo() {} + } +} + +interface ThrowsOnFakeOverride : Base1 + +class InheritThrowsOnFakeOverride : ThrowsOnFakeOverride { + override fun foo() {} +} + +class OverrideDifferentThrowsOnFakeOverride : ThrowsOnFakeOverride { + @Throws(Exception2::class) override fun foo() {} +} + +interface IncompatibleThrowsOnFakeOverride : Base1, Base2 + +class OverrideIncompatibleThrowsOnFakeOverride1 : IncompatibleThrowsOnFakeOverride { + @Throws(Exception1::class) override fun foo() {} +} + +class OverrideIncompatibleThrowsOnFakeOverride2 : IncompatibleThrowsOnFakeOverride { + @Throws(Exception2::class) override fun foo() {} +} + +class InheritIncompatibleThrowsOnFakeOverride : IncompatibleThrowsOnFakeOverride { + override fun foo() {} } diff --git a/compiler/testData/diagnostics/nativeTests/throws.txt b/compiler/testData/diagnostics/nativeTests/throws.txt index 8ec6afac55d..d7ec2a99aa8 100644 --- a/compiler/testData/diagnostics/nativeTests/throws.txt +++ b/compiler/testData/diagnostics/nativeTests/throws.txt @@ -3,6 +3,13 @@ package @kotlin.native.Throws(exceptionClasses = {}) public fun foo(): kotlin.Unit public fun withLocalClass(): kotlin.Unit +public interface Base0 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + public interface Base1 { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public abstract fun foo(): kotlin.Unit @@ -45,6 +52,14 @@ public interface Base6 { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } +public final class DifferentThrowsOnOverride : Base1 { + public constructor DifferentThrowsOnOverride() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception2::class}) public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + public final class Exception1 : kotlin.Throwable { public constructor Exception1() public open override /*1*/ /*fake_override*/ val cause: kotlin.Throwable? @@ -72,14 +87,6 @@ public final class Exception3 : kotlin.Throwable { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } -public final class HasThrowsOnOverride : Base1 { - public constructor HasThrowsOnOverride() - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public open override /*1*/ fun foo(): kotlin.Unit - public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String -} - public final class HasThrowsWithEmptyListOnOverride : Base1 { public constructor HasThrowsWithEmptyListOnOverride() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @@ -88,6 +95,29 @@ public final class HasThrowsWithEmptyListOnOverride : Base1 { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } +public interface IncompatibleThrowsOnFakeOverride : Base1, Base2 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class InheritIncompatibleThrowsOnFakeOverride : IncompatibleThrowsOnFakeOverride { + public constructor InheritIncompatibleThrowsOnFakeOverride() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class InheritThrowsOnFakeOverride : ThrowsOnFakeOverride { + public constructor InheritThrowsOnFakeOverride() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + public open class InheritsDifferentThrows1 : Base1, Base2 { public constructor InheritsDifferentThrows1() public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @@ -104,6 +134,14 @@ public final class InheritsDifferentThrows2 : InheritsDifferentThrows1, Base3 { public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String } +public final class InheritsDifferentThrows3 : OverridesDifferentThrows3 { + public constructor InheritsDifferentThrows3() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + public final class InheritsDifferentThrowsThroughSameClass1 : InheritsDifferentThrows1 { public constructor InheritsDifferentThrowsThroughSameClass1() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @@ -128,6 +166,197 @@ public final class InheritsSameThrowsMultiple : Base5, Base6 { public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String } +public final class InheritsThrowsAndNoThrows : Base0, Base1 { + public constructor InheritsThrowsAndNoThrows() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverrideDifferentThrows4 : OverridesDifferentThrows3 { + public constructor OverrideDifferentThrows4() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverrideDifferentThrows5 : OverridesDifferentThrows3 { + public constructor OverrideDifferentThrows5() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception3::class}) public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverrideDifferentThrows6 : OverridesDifferentThrows3 { + public constructor OverrideDifferentThrows6() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverrideDifferentThrows7 : Base1, Base4 { + public constructor OverrideDifferentThrows7() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception2::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverrideDifferentThrows8 : Base1, Base3 { + public constructor OverrideDifferentThrows8() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception2::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverrideDifferentThrowsOnFakeOverride : ThrowsOnFakeOverride { + public constructor OverrideDifferentThrowsOnFakeOverride() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception2::class}) public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverrideIncompatibleThrowsOnFakeOverride1 : IncompatibleThrowsOnFakeOverride { + public constructor OverrideIncompatibleThrowsOnFakeOverride1() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverrideIncompatibleThrowsOnFakeOverride2 : IncompatibleThrowsOnFakeOverride { + public constructor OverrideIncompatibleThrowsOnFakeOverride2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception2::class}) public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class OverridesDifferentThrows1_1 : Base1, Base2 { + public constructor OverridesDifferentThrows1_1() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class OverridesDifferentThrows1_2 : Base1, Base2 { + public constructor OverridesDifferentThrows1_2() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception2::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class OverridesDifferentThrows1_3 : Base1, Base2 { + public constructor OverridesDifferentThrows1_3() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class, Exception2::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverridesDifferentThrows2 : InheritsDifferentThrows1, Base3 { + public constructor OverridesDifferentThrows2() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception3::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class OverridesDifferentThrows3 : Base1, Base2 { + public constructor OverridesDifferentThrows3() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception3::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverridesDifferentThrowsMultiple : Base5, Base6 { + public constructor OverridesDifferentThrowsMultiple() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverridesDifferentThrowsThroughSameClass1 : InheritsDifferentThrows1 { + public constructor OverridesDifferentThrowsThroughSameClass1() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverridesDifferentThrowsThroughSameClass2 : InheritsDifferentThrows1 { + public constructor OverridesDifferentThrowsThroughSameClass2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception2::class}) public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverridesSameThrows : Base1, Base4 { + public constructor OverridesSameThrows() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverridesSameThrowsMultiple1 : Base5, Base6 { + public constructor OverridesSameThrowsMultiple1() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class, Exception2::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverridesSameThrowsMultiple2 : Base5, Base6 { + public constructor OverridesSameThrowsMultiple2() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception2::class, Exception1::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OverridesThrowsAndNoThrows : Base0, Base1 { + public constructor OverridesThrowsAndNoThrows() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class SameThrowsOnOverride : Base1 { + public constructor SameThrowsOnOverride() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface ThrowsOnFakeOverride : Base1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public abstract override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class ThrowsOnOverride : Base0 { + public constructor ThrowsOnOverride() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.native.Throws(exceptionClasses = {Exception1::class}) public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + package kotlin { package kotlin.native { diff --git a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/DefaultErrorMessagesNative.kt b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/DefaultErrorMessagesNative.kt index ea27dbd2a7c..b9f4ef561ef 100644 --- a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/DefaultErrorMessagesNative.kt +++ b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/DefaultErrorMessagesNative.kt @@ -12,7 +12,10 @@ import org.jetbrains.kotlin.diagnostics.rendering.Renderers private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy { DiagnosticFactoryToRendererMap("Native").apply { put(ErrorsNative.THROWS_LIST_EMPTY, "@Throws must have non-empty class list") - put(ErrorsNative.THROWS_ON_OVERRIDE, "@Throws is prohibited for overridden members") + put( + ErrorsNative.INCOMPATIBLE_THROWS_OVERRIDE, "Member overrides different @Throws filter from {0}", + Renderers.NAME + ) put( ErrorsNative.INCOMPATIBLE_THROWS_INHERITED, "Member inherits different @Throws filters from {0}", Renderers.commaSeparated(Renderers.NAME) diff --git a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/ErrorsNative.kt b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/ErrorsNative.kt index 37cb2ecd181..1c0b8f000ca 100644 --- a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/ErrorsNative.kt +++ b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/ErrorsNative.kt @@ -17,7 +17,7 @@ object ErrorsNative { @JvmField val THROWS_LIST_EMPTY = DiagnosticFactory0.create(Severity.ERROR) @JvmField - val THROWS_ON_OVERRIDE = DiagnosticFactory0.create(Severity.ERROR) + val INCOMPATIBLE_THROWS_OVERRIDE = DiagnosticFactory1.create(Severity.ERROR) @JvmField val INCOMPATIBLE_THROWS_INHERITED = DiagnosticFactory1.create>(Severity.ERROR) diff --git a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeThrowsChecker.kt b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeThrowsChecker.kt index 203b208be37..54062b9acea 100644 --- a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeThrowsChecker.kt +++ b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeThrowsChecker.kt @@ -11,48 +11,81 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument -import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors +import org.jetbrains.kotlin.utils.DFS object NativeThrowsChecker : DeclarationChecker { private val throwsFqName = FqName("kotlin.native.Throws") override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { - checkForIncompatibleMultipleInheritance(declaration, descriptor, context) + val throwsAnnotation = descriptor.annotations.findAnnotation(throwsFqName) + val reportLocation = throwsAnnotation?.let { DescriptorToSourceUtils.getSourceFromAnnotation(it) } ?: declaration - val throwsAnnotation = descriptor.annotations.findAnnotation(throwsFqName) ?: return - val element = DescriptorToSourceUtils.getSourceFromAnnotation(throwsAnnotation) ?: declaration + if (!checkInheritance(declaration, descriptor, context, throwsAnnotation, reportLocation)) return - if (descriptor is CallableMemberDescriptor && descriptor.overriddenDescriptors.isNotEmpty()) { - context.trace.report(ErrorsNative.THROWS_ON_OVERRIDE.on(element)) - return - } - - if (throwsAnnotation.getVariadicArguments().isEmpty()) { - context.trace.report(ErrorsNative.THROWS_LIST_EMPTY.on(element)) + if (throwsAnnotation != null && throwsAnnotation.getVariadicArguments().isEmpty()) { + context.trace.report(ErrorsNative.THROWS_LIST_EMPTY.on(reportLocation)) } } - private fun checkForIncompatibleMultipleInheritance( + private fun checkInheritance( declaration: KtDeclaration, descriptor: DeclarationDescriptor, - context: DeclarationCheckerContext - ) { - if (descriptor !is CallableMemberDescriptor) return + context: DeclarationCheckerContext, + throwsAnnotation: AnnotationDescriptor?, + reportLocation: KtElement + ): Boolean { + if (descriptor !is CallableMemberDescriptor || descriptor.overriddenDescriptors.isEmpty()) return true - if (descriptor.overriddenDescriptors.size < 2) return // No multiple inheritance here. + val inherited = findInheritedThrows(descriptor).entries.distinctBy { it.value } - val incompatible = descriptor.findOriginalTopMostOverriddenDescriptors() - .distinctBy { it.annotations.findAnnotation(throwsFqName)?.getVariadicArguments()?.toSet() } + if (inherited.size >= 2) { + context.trace.report(ErrorsNative.INCOMPATIBLE_THROWS_INHERITED.on(declaration, inherited.map { it.key.containingDeclaration })) + return false + } - if (incompatible.size < 2) return + if (throwsAnnotation == null) return true - context.trace.report(ErrorsNative.INCOMPATIBLE_THROWS_INHERITED.on(declaration, incompatible.map { it.containingDeclaration })) + val (overriddenMember, overriddenThrows) = inherited.firstOrNull() + ?: return true // Should not happen though. + + if (decodeThrowsFilter(throwsAnnotation) != overriddenThrows) { + context.trace.report(ErrorsNative.INCOMPATIBLE_THROWS_OVERRIDE.on(reportLocation, overriddenMember.containingDeclaration)) + return false + } + + return true + } + + private fun findInheritedThrows(descriptor: CallableMemberDescriptor): Map { + val result = mutableMapOf() + + DFS.dfs( + descriptor.overriddenDescriptors, + { current -> current.overriddenDescriptors }, + object : DFS.AbstractNodeHandler() { + override fun beforeChildren(current: CallableMemberDescriptor): Boolean { + val throwsAnnotation = current.annotations.findAnnotation(throwsFqName).takeIf { current.kind.isReal } + return if (throwsAnnotation == null && current.overriddenDescriptors.isNotEmpty()) { + // Visit overridden members: + true + } else { + // Take current and ignore overridden: + result[current.original] = decodeThrowsFilter(throwsAnnotation) + false + } + } + + override fun result() {} + }) + + return result } private fun AnnotationDescriptor.getVariadicArguments(): List> { @@ -60,4 +93,9 @@ object NativeThrowsChecker : DeclarationChecker { return argument.value } + private fun decodeThrowsFilter(throwsAnnotation: AnnotationDescriptor?) = + ThrowsFilter(throwsAnnotation?.getVariadicArguments()?.toSet()) + + private data class ThrowsFilter(val classes: Set>?) + }