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 18e275d1142..bc3dcee379d 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 @@ -54,6 +54,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/cast.kt"); } + @TestMetadata("catchParameter.kt") + public void testCatchParameter() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt"); + } + @TestMetadata("companion.kt") public void testCompanion() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/companion.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt b/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt new file mode 100644 index 00000000000..1e253b1f2dd --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt @@ -0,0 +1,20 @@ +FILE: catchParameter.kt + public final fun test(): R|kotlin/Unit| { + try { + } + catch (e: R|kotlin/NullPointerException| = R|java/lang/NullPointerException.NullPointerException|()) { + } + + try { + } + catch (e: R|T|) { + } + + } + public final inline fun anotherTest(): R|kotlin/Unit| { + try { + } + catch (e: R|T|) { + } + + } \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt b/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt new file mode 100644 index 00000000000..0a0f2b86410 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt @@ -0,0 +1,13 @@ +fun test() { + try { + + } catch (e: NullPointerException = NullPointerException()) { + + } + + try {} catch (e: T) {} +} + +inline fun anotherTest() { + try {} catch (e: T) {} +} \ No newline at end of file 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 0a8480423e5..3ee6cbb889b 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 @@ -56,6 +56,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/cast.kt"); } + @Test + @TestMetadata("catchParameter.kt") + public void testCatchParameter() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt"); + } + @Test @TestMetadata("companion.kt") public void testCompanion() 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 5715994f8f3..2248bdb9a1b 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 @@ -59,6 +59,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/cast.kt"); } + @Test + @TestMetadata("catchParameter.kt") + public void testCatchParameter() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt"); + } + @Test @TestMetadata("companion.kt") public void testCompanion() 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 41ec1d4a3a1..1aafa0e2f4b 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 @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment +import org.jetbrains.kotlin.fir.expressions.FirTryExpression import java.io.File fun main(args: Array) { @@ -21,6 +22,7 @@ fun main(args: Array) { alias("QualifiedAccessChecker") alias("FunctionCallChecker") alias("VariableAssignmentChecker") + alias("TryExpressionChecker") } val declarationPackage = "org.jetbrains.kotlin.fir.analysis.checkers.declaration" diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt index 842faa079dc..f4e8d19e20a 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt @@ -21,11 +21,14 @@ internal class ComposedExpressionCheckers : ExpressionCheckers() { get() = _functionCallCheckers override val variableAssignmentCheckers: Set get() = _variableAssignmentCheckers + override val tryExpressionCheckers: Set + get() = _tryExpressionCheckers private val _basicExpressionCheckers: MutableSet = mutableSetOf() private val _qualifiedAccessCheckers: MutableSet = mutableSetOf() private val _functionCallCheckers: MutableSet = mutableSetOf() private val _variableAssignmentCheckers: MutableSet = mutableSetOf() + private val _tryExpressionCheckers: MutableSet = mutableSetOf() @CheckersComponentInternal internal fun register(checkers: ExpressionCheckers) { @@ -33,5 +36,6 @@ internal class ComposedExpressionCheckers : ExpressionCheckers() { _qualifiedAccessCheckers += checkers.allQualifiedAccessCheckers _functionCallCheckers += checkers.allFunctionCallCheckers _variableAssignmentCheckers += checkers.allVariableAssignmentCheckers + _tryExpressionCheckers += checkers.allTryExpressionCheckers } } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt index 73101389aa4..72e167d29e2 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt @@ -21,9 +21,11 @@ abstract class ExpressionCheckers { open val qualifiedAccessCheckers: Set = emptySet() open val functionCallCheckers: Set = emptySet() open val variableAssignmentCheckers: Set = emptySet() + open val tryExpressionCheckers: Set = emptySet() @CheckersComponentInternal internal val allBasicExpressionCheckers: Set get() = basicExpressionCheckers @CheckersComponentInternal internal val allQualifiedAccessCheckers: Set get() = qualifiedAccessCheckers + allBasicExpressionCheckers @CheckersComponentInternal internal val allFunctionCallCheckers: Set get() = functionCallCheckers + allQualifiedAccessCheckers @CheckersComponentInternal internal val allVariableAssignmentCheckers: Set get() = variableAssignmentCheckers + allBasicExpressionCheckers + @CheckersComponentInternal internal val allTryExpressionCheckers: Set get() = tryExpressionCheckers + allBasicExpressionCheckers } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt index 5ff7f6070cd..3f7f70d9f3d 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt @@ -13,9 +13,11 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.expressions.FirTryExpression import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment typealias FirBasicExpressionChecker = FirExpressionChecker typealias FirQualifiedAccessChecker = FirExpressionChecker typealias FirFunctionCallChecker = FirExpressionChecker typealias FirVariableAssignmentChecker = FirExpressionChecker +typealias FirTryExpressionChecker = FirExpressionChecker 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 new file mode 100644 index 00000000000..4205522572c --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt @@ -0,0 +1,35 @@ +/* + * 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.expression + +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.expressions.FirTryExpression +import org.jetbrains.kotlin.fir.types.ConeTypeParameterType +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef + +object FirCatchParameterChecker : FirTryExpressionChecker() { + override fun check(expression: FirTryExpression, context: CheckerContext, reporter: DiagnosticReporter) { + for (catchEntry in expression.catches) { + val catchParameter = catchEntry.parameter + + if (catchParameter.defaultValue != null) + reporter.report(catchParameter.source?.let { FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE.on(it) }) + + val typeRef = catchParameter.returnTypeRef + if (typeRef is FirResolvedTypeRef && typeRef.type is ConeTypeParameterType) { + val isReified = (typeRef.type as ConeTypeParameterType).lookupTag.typeParameterSymbol.fir.isReified + + if (isReified) { + reporter.report(catchParameter.source?.let { FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE.on(it) }) + } else { + reporter.report(catchParameter.source?.let { FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE.on(it) }) + } + } + } + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt index 8f737d23862..ba5376b9c2a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt @@ -73,7 +73,7 @@ class ExpressionCheckersDiagnosticComponent(collector: AbstractDiagnosticCollect } override fun visitTryExpression(tryExpression: FirTryExpression, data: CheckerContext) { - checkers.basicExpressionCheckers.check(tryExpression, data, reporter) + checkers.tryExpressionCheckers.check(tryExpression, data, reporter) } override fun visitClassReferenceExpression(classReferenceExpression: FirClassReferenceExpression, 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 4da06ddfe13..edae7bea6ab 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 @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGN_OPERATOR_A import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BREAK_OR_CONTINUE_OUTSIDE_A_LOOP import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CAN_BE_VAL +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CLASS_IN_SUPERTYPE_FOR_ENUM import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTION_AMBIGUITY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTION_MISSING @@ -118,6 +119,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_RETURN_ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SETTER_PARAMETER_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SINGLE_EXPRESSION_STRING_TEMPLATE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_VISIBILITY_MODIFIER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_MODIFIER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_NOT_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH_ON_OVERRIDE @@ -135,6 +137,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_MISMATCH import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_ENUM import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_OBJECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_SUPERTYPE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_VARIABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_LABEL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_REFERENCE @@ -337,6 +340,18 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { TO_STRING, DECLARATION_NAME ) // # + map.put( + CATCH_PARAMETER_WITH_DEFAULT_VALUE, + "Catch clause parameter may not have a default value" + ) + map.put( + REIFIED_TYPE_IN_CATCH_CLAUSE, + "Reified type is forbidden for catch parameter" + ) + map.put( + TYPE_PARAMETER_IN_CATCH_CLAUSE, + "Type parameter is forbidden for catch parameter" + ) // 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 83ee92ce381..6b9c5751864 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 @@ -12,16 +12,12 @@ import org.jetbrains.kotlin.fir.FirEffectiveVisibility import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration -import org.jetbrains.kotlin.fir.expressions.FirExpression -import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.types.KotlinType object FirErrors { // Miscellaneous @@ -139,6 +135,9 @@ object FirErrors { val RETURN_TYPE_MISMATCH_ON_OVERRIDE by error2() val PROPERTY_TYPE_MISMATCH_ON_OVERRIDE by error2() val VAR_TYPE_MISMATCH_ON_OVERRIDE by error2() + val CATCH_PARAMETER_WITH_DEFAULT_VALUE by error0() + val REIFIED_TYPE_IN_CATCH_CLAUSE by error0() + val TYPE_PARAMETER_IN_CATCH_CLAUSE by error0() // Redeclarations val MANY_COMPANION_OBJECTS by error0() diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt index f93b89239f3..4ffda04a3ec 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt @@ -24,4 +24,8 @@ object CommonExpressionCheckers : ExpressionCheckers() { FirSealedClassConstructorCallChecker, ) override val functionCallCheckers: Set = setOf() + + override val tryExpressionCheckers: Set = setOf( + FirCatchParameterChecker + ) } diff --git a/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt index 44d55d0b17a..aa49bfb5632 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt @@ -17,10 +17,10 @@ fun bar() { inline fun tryCatch(lazy: () -> R, failure: (E) -> R): R = try { lazy() - } catch (e: E) { + } catch (e: E) { failure(e) } fun tryCatch() { - try { } catch (e: T) { } -} \ No newline at end of file + try { } catch (e: T) { } +} diff --git a/compiler/testData/diagnostics/tests/controlStructures/catchWithDefault.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/catchWithDefault.fir.kt index 8e568f28604..bac12215b6a 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/catchWithDefault.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/catchWithDefault.fir.kt @@ -1,3 +1,3 @@ fun test() { - try { } catch (e: Exception = Exception()) { } -} \ No newline at end of file + try { } catch (e: Exception = Exception()) { } +}