diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index e1a9a0eccf1..698661d6ac2 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -419,6 +419,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/syntheticsVsNormalProperties.kt"); } + @TestMetadata("throwableSubclass.kt") + public void testThrowableSubclass() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/throwableSubclass.kt"); + } + @TestMetadata("treeSet.kt") public void testTreeSet() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/treeSet.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/throwableSubclass.fir.txt b/compiler/fir/analysis-tests/testData/resolve/throwableSubclass.fir.txt new file mode 100644 index 00000000000..d5df7c45fa8 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/throwableSubclass.fir.txt @@ -0,0 +1,67 @@ +FILE: throwableSubclass.kt + public final class Test1 : R|kotlin/Exception| { + public constructor(): R|Test1| { + super() + } + + public final inner class Test2 : R|kotlin/Throwable| { + public constructor(): R|Test1.Test2| { + super() + } + + } + + public final class Test3 : R|kotlin/NullPointerException| { + public constructor(): R|Test1.Test3| { + super() + } + + } + + public final object Test4 : R|kotlin/Throwable| { + private constructor(): R|Test1.Test4| { + super() + } + + } + + } + public final class Test5 : R|kotlin/Any| { + public constructor(): R|Test5| { + super() + } + + public final inner class Test6 : R|kotlin/Exception| { + public constructor(): R|Test5.Test6| { + super() + } + + } + + public final fun foo(): R|kotlin/Unit| { + local final class Test7 : R|kotlin/Throwable| { + public constructor(): R|Test5.Test7| { + super() + } + + } + + } + + } + public final fun topLevelFun(): R|kotlin/Unit| { + local final class Test8 : R|kotlin/Error| { + public constructor(): R|Test8| { + super() + } + + } + + lval obj: R|| = object : R|kotlin/Throwable| { + private constructor(): R|| { + super() + } + + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/throwableSubclass.kt b/compiler/fir/analysis-tests/testData/resolve/throwableSubclass.kt new file mode 100644 index 00000000000..374ffdbdf0d --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/throwableSubclass.kt @@ -0,0 +1,18 @@ +class Test1<T, B> : Exception() { + inner class Test2<S> : Throwable() + class Test3 : NullPointerException() + object Test4 : Throwable() {} +} + +class Test5 { + inner class Test6 : Exception() + + fun foo() { + class Test7 : Throwable() + } +} + +fun topLevelFun() { + class Test8 : Error() + val obj = object : Throwable() {} +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index b266a83769b..92d29a5322b 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -494,6 +494,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/syntheticsVsNormalProperties.kt"); } + @Test + @TestMetadata("throwableSubclass.kt") + public void testThrowableSubclass() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/throwableSubclass.kt"); + } + @Test @TestMetadata("treeSet.kt") public void testTreeSet() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index 883c1ccdc83..931d3a4966f 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -497,6 +497,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/syntheticsVsNormalProperties.kt"); } + @Test + @TestMetadata("throwableSubclass.kt") + public void testThrowableSubclass() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/throwableSubclass.kt"); + } + @Test @TestMetadata("treeSet.kt") public void testTreeSet() throws Exception { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt index 1aafa0e2f4b..0088e1d7b9f 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt @@ -31,6 +31,7 @@ fun main(args: Array) { alias("MemberDeclarationChecker") alias>("FunctionChecker") alias("PropertyChecker") + alias>("ClassChecker") alias("RegularClassChecker") alias("ConstructorChecker") alias("FileChecker") diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt index 0298aabbea9..716247fd568 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt @@ -23,6 +23,8 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() { get() = _functionCheckers override val propertyCheckers: Set get() = _propertyCheckers + override val classCheckers: Set + get() = _classCheckers override val regularClassCheckers: Set get() = _regularClassCheckers override val constructorCheckers: Set @@ -38,6 +40,7 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() { private val _memberDeclarationCheckers: MutableSet = mutableSetOf() private val _functionCheckers: MutableSet = mutableSetOf() private val _propertyCheckers: MutableSet = mutableSetOf() + private val _classCheckers: MutableSet = mutableSetOf() private val _regularClassCheckers: MutableSet = mutableSetOf() private val _constructorCheckers: MutableSet = mutableSetOf() private val _fileCheckers: MutableSet = mutableSetOf() @@ -50,6 +53,7 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() { _memberDeclarationCheckers += checkers.allMemberDeclarationCheckers _functionCheckers += checkers.allFunctionCheckers _propertyCheckers += checkers.allPropertyCheckers + _classCheckers += checkers.allClassCheckers _regularClassCheckers += checkers.allRegularClassCheckers _constructorCheckers += checkers.allConstructorCheckers _fileCheckers += checkers.allFileCheckers diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt index f96ece8dbe5..a479744b463 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt @@ -23,6 +23,7 @@ abstract class DeclarationCheckers { open val memberDeclarationCheckers: Set = emptySet() open val functionCheckers: Set = emptySet() open val propertyCheckers: Set = emptySet() + open val classCheckers: Set = emptySet() open val regularClassCheckers: Set = emptySet() open val constructorCheckers: Set = emptySet() open val fileCheckers: Set = emptySet() @@ -34,7 +35,8 @@ abstract class DeclarationCheckers { @CheckersComponentInternal internal val allMemberDeclarationCheckers: Set get() = memberDeclarationCheckers + allBasicDeclarationCheckers @CheckersComponentInternal internal val allFunctionCheckers: Set get() = functionCheckers + allBasicDeclarationCheckers @CheckersComponentInternal internal val allPropertyCheckers: Set get() = propertyCheckers + allMemberDeclarationCheckers - @CheckersComponentInternal internal val allRegularClassCheckers: Set get() = regularClassCheckers + allMemberDeclarationCheckers + @CheckersComponentInternal internal val allClassCheckers: Set get() = classCheckers + allBasicDeclarationCheckers + @CheckersComponentInternal internal val allRegularClassCheckers: Set get() = regularClassCheckers + allMemberDeclarationCheckers + allClassCheckers @CheckersComponentInternal internal val allConstructorCheckers: Set get() = constructorCheckers + allFunctionCheckers @CheckersComponentInternal internal val allFileCheckers: Set get() = fileCheckers + allBasicDeclarationCheckers } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt index ef4ca66ed49..23e8f7dda22 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt @@ -10,6 +10,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration * DO NOT MODIFY IT MANUALLY */ +import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile @@ -22,6 +23,7 @@ typealias FirBasicDeclarationChecker = FirDeclarationChecker typealias FirMemberDeclarationChecker = FirDeclarationChecker typealias FirFunctionChecker = FirDeclarationChecker> typealias FirPropertyChecker = FirDeclarationChecker +typealias FirClassChecker = FirDeclarationChecker> typealias FirRegularClassChecker = FirDeclarationChecker typealias FirConstructorChecker = FirDeclarationChecker typealias FirFileChecker = FirDeclarationChecker diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt index d6920b5813a..7f449346ea9 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt @@ -38,6 +38,7 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtModifierList +import org.jetbrains.kotlin.psi.KtObjectLiteralExpression import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -318,3 +319,9 @@ fun Modality.toToken(): KtModifierKeywordToken = when (this) { val FirFunctionCall.isIterator get() = this.calleeReference.name.asString() == "" + +internal val throwableClassLikeType = + StandardClassIds.byName("Throwable").constructClassLikeType(emptyArray(), false) + +fun ConeKotlinType.isThrowable(session: FirSession) = + throwableClassLikeType.isSupertypeOf(session.typeCheckerContext, this.fullyExpandedType(session)) \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirThrowableSubclassChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirThrowableSubclassChecker.kt new file mode 100644 index 00000000000..d5b95ac0bd8 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirThrowableSubclassChecker.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2021 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.checkers.declaration + +import org.jetbrains.kotlin.fir.FirSourceElement +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.isThrowable +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.types.ConeClassErrorType + +object FirThrowableSubclassChecker : FirClassChecker() { + override fun check(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.hasThrowableSupertype(context)) + return + + if (declaration.typeParameters.isNotEmpty()) { + reporter.reportGenericThrowableSubclass(declaration.typeParameters.firstOrNull()?.source) + + val source = when { + (declaration as? FirRegularClass)?.isInner == true -> declaration.source + declaration is FirAnonymousObject -> (declaration.declarations.firstOrNull())?.source + else -> null + } + reporter.reportInnerClassOfGenericThrowableSubclass(source) + } else if (declaration.hasGenericOuterDeclaration(context)) { + reporter.reportInnerClassOfGenericThrowableSubclass(declaration.source) + } + } + + private fun FirClass<*>.hasThrowableSupertype(context: CheckerContext) = + superConeTypes.any { it !is ConeClassErrorType && it.isThrowable(context.session) } + + private fun FirClass<*>.hasGenericOuterDeclaration(context: CheckerContext) = + classId.isLocal && context.containingDeclarations.anyIsGeneric() + + private fun Collection.anyIsGeneric() = + any { it is FirTypeParameterRefsOwner && it.typeParameters.isNotEmpty() } + + private fun DiagnosticReporter.reportGenericThrowableSubclass(source: FirSourceElement?) { + source?.let { report(FirErrors.GENERIC_THROWABLE_SUBCLASS.on(it)) } + } + + private fun DiagnosticReporter.reportInnerClassOfGenericThrowableSubclass(source: FirSourceElement?) { + source?.let { report(FirErrors.INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS.on(it)) } + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt index 3a5bff25b17..6775a4a1e2a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer.isSupertypeOf import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.isThrowable +import org.jetbrains.kotlin.fir.analysis.checkers.throwableClassLikeType import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.expressions.FirTryExpression @@ -20,9 +22,6 @@ import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.constructClassLikeType object FirCatchParameterChecker : FirTryExpressionChecker() { - private val throwable = StandardClassIds.byName("Throwable") - .constructClassLikeType(emptyArray(), false) - override fun check(expression: FirTryExpression, context: CheckerContext, reporter: DiagnosticReporter) { for (catchEntry in expression.catches) { val catchParameter = catchEntry.parameter @@ -45,10 +44,7 @@ object FirCatchParameterChecker : FirTryExpressionChecker() { } if (!coneType.isThrowable(context.session)) - catchParameter.source?.let { reporter.report(FirErrors.TYPE_MISMATCH.on(it, throwable, coneType), context) } + catchParameter.source?.let { reporter.report(FirErrors.TYPE_MISMATCH.on(it, throwableClassLikeType, coneType), context) } } } - - private fun ConeKotlinType.isThrowable(session: FirSession) = - throwable.isSupertypeOf(session.typeCheckerContext, this.fullyExpandedType(session)) } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt index a89ec402aa4..68d8ef88dee 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt @@ -25,6 +25,10 @@ class DeclarationCheckersDiagnosticComponent( (checkers.memberDeclarationCheckers + checkers.propertyCheckers).check(property, data, reporter) } + override fun > visitClass(klass: FirClass, data: CheckerContext) { + checkers.classCheckers.check(klass, data, reporter) + } + override fun visitRegularClass(regularClass: FirRegularClass, data: CheckerContext) { checkers.regularClassCheckers.check(regularClass, data, reporter) } @@ -62,7 +66,7 @@ class DeclarationCheckersDiagnosticComponent( } override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: CheckerContext) { - checkers.basicDeclarationCheckers.check(anonymousObject, data, reporter) + (checkers.classCheckers + checkers.basicDeclarationCheckers).check(anonymousObject, data, reporter) } override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: CheckerContext) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 961d15010b7..d62a2cd707d 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -71,6 +71,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_SUPER_INT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_TYPE_PARAMETER_BOUND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GENERIC_THROWABLE_SUBCLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HIDDEN import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_CONST_EXPRESSION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_UNDERSCORE @@ -80,6 +81,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_LATE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_MODIFIERS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFERENCE_ERROR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INSTANCE_ACCESS_BEFORE_SUPER_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INTERFACE_WITH_SUPERCLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER @@ -378,6 +380,14 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { FQ_NAMES_IN_TYPES, FQ_NAMES_IN_TYPES ) + map.put( + GENERIC_THROWABLE_SUBCLASS, + "Subclass of 'Throwable' may not have type parameters" + ) + map.put( + INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS, + "Inner class of generic class extending 'Throwable' is prohibited" + ) // Redeclarations map.put(MANY_COMPANION_OBJECTS, "Only one companion object is allowed per class") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index b6cc52927cd..0ac8ab7e8c9 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -139,6 +139,8 @@ object FirErrors { val CATCH_PARAMETER_WITH_DEFAULT_VALUE by error0() val REIFIED_TYPE_IN_CATCH_CLAUSE by error0() val TYPE_PARAMETER_IN_CATCH_CLAUSE by error0() + val GENERIC_THROWABLE_SUBCLASS by error0() + val INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS by error0(SourceElementPositioningStrategies.DECLARATION_NAME) // Overrides val NOTHING_TO_OVERRIDE by error1(SourceElementPositioningStrategies.OVERRIDE_MODIFIER) diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt index 05cf3e6d768..d2ea9f0135d 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt @@ -35,6 +35,10 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirDestructuringDeclarationChecker, ) + override val classCheckers: Set = setOf( + FirThrowableSubclassChecker, + ) + override val regularClassCheckers: Set = setOf( FirAnnotationClassDeclarationChecker, FirCommonConstructorDelegationIssuesChecker, diff --git a/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt index aa49bfb5632..b85711fc51e 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt @@ -2,11 +2,11 @@ // See KT-9816, KT-9742 // Not allowed in Java -class ZException(val p: T) : Exception() +class ZException<T>(val p: T) : Exception() -class YException(val p: T): java.lang.RuntimeException() +class YException<T>(val p: T): java.lang.RuntimeException() -class XException(val p: T): Throwable() +class XException<T>(val p: T): Throwable() fun bar() { try { diff --git a/compiler/testData/diagnostics/tests/controlStructures/catchInnerClassesOfGenerics.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/catchInnerClassesOfGenerics.fir.kt deleted file mode 100644 index 7f3299674df..00000000000 --- a/compiler/testData/diagnostics/tests/controlStructures/catchInnerClassesOfGenerics.fir.kt +++ /dev/null @@ -1,41 +0,0 @@ -// !LANGUAGE: +ProhibitInnerClassesOfGenericClassExtendingThrowable -// !DIAGNOSTICS: -UNUSED_VARIABLE -// JAVAC_EXPECTED_FILE - -class OuterGeneric { - inner class ErrorInnerExn : Exception() - - inner class InnerA { - inner class ErrorInnerExn2 : Exception() - } - - class OkNestedExn : Exception() - - val errorAnonymousObjectExn = object : Exception() {} - - fun foo() { - class OkLocalExn : Exception() - - val errorAnonymousObjectExn = object : Exception() {} - } - - fun genericFoo() { - class OkLocalExn : Exception() - - class LocalGeneric { - inner class ErrorInnerExnOfLocalGeneric : Exception() - } - } -} - -class Outer { - inner class InnerGeneric { - inner class ErrorInnerExn : Exception() - } -} - -fun genericFoo() { - class ErrorLocalExnInGenericFun : Exception() - - val errorkAnonymousObjectExnInGenericFun = object : Exception() {} -} diff --git a/compiler/testData/diagnostics/tests/controlStructures/catchInnerClassesOfGenerics.kt b/compiler/testData/diagnostics/tests/controlStructures/catchInnerClassesOfGenerics.kt index b07acdf6afa..337224ac30c 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/catchInnerClassesOfGenerics.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/catchInnerClassesOfGenerics.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +ProhibitInnerClassesOfGenericClassExtendingThrowable // !DIAGNOSTICS: -UNUSED_VARIABLE // JAVAC_EXPECTED_FILE diff --git a/compiler/testData/diagnostics/tests/controlStructures/catchInnerClassesOfGenerics_deprecation.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/catchInnerClassesOfGenerics_deprecation.fir.kt index cbe8d725b61..e2ea4ac52a6 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/catchInnerClassesOfGenerics_deprecation.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/catchInnerClassesOfGenerics_deprecation.fir.kt @@ -3,39 +3,39 @@ // JAVAC_EXPECTED_FILE class OuterGeneric { - inner class ErrorInnerExn : Exception() + inner class ErrorInnerExn : Exception() inner class InnerA { - inner class ErrorInnerExn2 : Exception() + inner class ErrorInnerExn2 : Exception() } class OkNestedExn : Exception() - val errorAnonymousObjectExn = object : Exception() {} + val errorAnonymousObjectExn = object : Exception() {} fun foo() { - class OkLocalExn : Exception() + class OkLocalExn : Exception() - val errorAnonymousObjectExn = object : Exception() {} + val errorAnonymousObjectExn = object : Exception() {} } fun genericFoo() { - class OkLocalExn : Exception() + class OkLocalExn : Exception() class LocalGeneric { - inner class ErrorInnerExnOfLocalGeneric : Exception() + inner class ErrorInnerExnOfLocalGeneric : Exception() } } } class Outer { inner class InnerGeneric { - inner class ErrorInnerExn : Exception() + inner class ErrorInnerExn : Exception() } } fun genericFoo() { - class ErrorLocalExnInGenericFun : Exception() + class ErrorLocalExnInGenericFun : Exception() - val errorkAnonymousObjectExnInGenericFun = object : Exception() {} + val errorkAnonymousObjectExnInGenericFun = object : Exception() {} } diff --git a/compiler/testData/diagnostics/tests/controlStructures/catchingLocalClassesCapturingTypeParameters.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/catchingLocalClassesCapturingTypeParameters.fir.kt deleted file mode 100644 index 39925d38fef..00000000000 --- a/compiler/testData/diagnostics/tests/controlStructures/catchingLocalClassesCapturingTypeParameters.fir.kt +++ /dev/null @@ -1,27 +0,0 @@ -// !LANGUAGE: +ProhibitInnerClassesOfGenericClassExtendingThrowable -package test - -var global: Throwable? = null - -fun foo(x: Throwable, z: T, b: (T) -> Unit) { - class A(val y : T) : Exception() - - try { - throw x - } catch (a: A) { - b(a.y) - } catch (e: Throwable) { - global = A(z) - } -} - -fun main() { - foo(RuntimeException(), 1) { throw IllegalStateException() } - foo(global!!, "") { it.length } // (*) -} - -// (*): -//Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String -// at test.TestKt$main$2.invoke(test.kt) -// at test.TestKt.foo(test.kt:12) -// at test.TestKt.main(test.kt:21) \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlStructures/catchingLocalClassesCapturingTypeParameters.kt b/compiler/testData/diagnostics/tests/controlStructures/catchingLocalClassesCapturingTypeParameters.kt index 98948b108d9..f7cdbf4ea93 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/catchingLocalClassesCapturingTypeParameters.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/catchingLocalClassesCapturingTypeParameters.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +ProhibitInnerClassesOfGenericClassExtendingThrowable package test