FIR: introduce CatchParameterChecker

This commit is contained in:
eugenpolytechnic
2021-01-29 23:57:19 +03:00
committed by Mikhail Glukhikh
parent d8549d6292
commit 5c0231b727
16 changed files with 123 additions and 10 deletions
@@ -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");
@@ -0,0 +1,20 @@
FILE: catchParameter.kt
public final fun <T> test(): R|kotlin/Unit| {
try {
}
catch (e: R|kotlin/NullPointerException| = R|java/lang/NullPointerException.NullPointerException|()) {
}
try {
}
catch (e: R|T|) {
}
}
public final inline fun <reified T> anotherTest(): R|kotlin/Unit| {
try {
}
catch (e: R|T|) {
}
}
@@ -0,0 +1,13 @@
fun <T> test() {
try {
} catch (<!CATCH_PARAMETER_WITH_DEFAULT_VALUE!>e: NullPointerException = NullPointerException()<!>) {
}
try {} catch (<!TYPE_PARAMETER_IN_CATCH_CLAUSE!>e: T<!>) {}
}
inline fun <reified T> anotherTest() {
try {} catch (<!REIFIED_TYPE_IN_CATCH_CLAUSE!>e: T<!>) {}
}
@@ -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 {
@@ -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 {
@@ -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<String>) {
@@ -21,6 +22,7 @@ fun main(args: Array<String>) {
alias<FirQualifiedAccessExpression>("QualifiedAccessChecker")
alias<FirFunctionCall>("FunctionCallChecker")
alias<FirVariableAssignment>("VariableAssignmentChecker")
alias<FirTryExpression>("TryExpressionChecker")
}
val declarationPackage = "org.jetbrains.kotlin.fir.analysis.checkers.declaration"
@@ -21,11 +21,14 @@ internal class ComposedExpressionCheckers : ExpressionCheckers() {
get() = _functionCallCheckers
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
get() = _variableAssignmentCheckers
override val tryExpressionCheckers: Set<FirTryExpressionChecker>
get() = _tryExpressionCheckers
private val _basicExpressionCheckers: MutableSet<FirBasicExpressionChecker> = mutableSetOf()
private val _qualifiedAccessCheckers: MutableSet<FirQualifiedAccessChecker> = mutableSetOf()
private val _functionCallCheckers: MutableSet<FirFunctionCallChecker> = mutableSetOf()
private val _variableAssignmentCheckers: MutableSet<FirVariableAssignmentChecker> = mutableSetOf()
private val _tryExpressionCheckers: MutableSet<FirTryExpressionChecker> = 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
}
}
@@ -21,9 +21,11 @@ abstract class ExpressionCheckers {
open val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker> = emptySet()
open val functionCallCheckers: Set<FirFunctionCallChecker> = emptySet()
open val variableAssignmentCheckers: Set<FirVariableAssignmentChecker> = emptySet()
open val tryExpressionCheckers: Set<FirTryExpressionChecker> = emptySet()
@CheckersComponentInternal internal val allBasicExpressionCheckers: Set<FirBasicExpressionChecker> get() = basicExpressionCheckers
@CheckersComponentInternal internal val allQualifiedAccessCheckers: Set<FirQualifiedAccessChecker> get() = qualifiedAccessCheckers + allBasicExpressionCheckers
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> get() = functionCallCheckers + allQualifiedAccessCheckers
@CheckersComponentInternal internal val allVariableAssignmentCheckers: Set<FirVariableAssignmentChecker> get() = variableAssignmentCheckers + allBasicExpressionCheckers
@CheckersComponentInternal internal val allTryExpressionCheckers: Set<FirTryExpressionChecker> get() = tryExpressionCheckers + allBasicExpressionCheckers
}
@@ -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<FirStatement>
typealias FirQualifiedAccessChecker = FirExpressionChecker<FirQualifiedAccessExpression>
typealias FirFunctionCallChecker = FirExpressionChecker<FirFunctionCall>
typealias FirVariableAssignmentChecker = FirExpressionChecker<FirVariableAssignment>
typealias FirTryExpressionChecker = FirExpressionChecker<FirTryExpression>
@@ -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) })
}
}
}
}
}
@@ -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) {
@@ -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")
@@ -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<FirSourceElement, PsiElement, String, FirMemberDeclaration>()
val PROPERTY_TYPE_MISMATCH_ON_OVERRIDE by error2<FirSourceElement, PsiElement, String, FirMemberDeclaration>()
val VAR_TYPE_MISMATCH_ON_OVERRIDE by error2<FirSourceElement, PsiElement, String, FirMemberDeclaration>()
val CATCH_PARAMETER_WITH_DEFAULT_VALUE by error0<FirSourceElement, PsiElement>()
val REIFIED_TYPE_IN_CATCH_CLAUSE by error0<FirSourceElement, PsiElement>()
val TYPE_PARAMETER_IN_CATCH_CLAUSE by error0<FirSourceElement, PsiElement>()
// Redeclarations
val MANY_COMPANION_OBJECTS by error0<FirSourceElement, PsiElement>()
@@ -24,4 +24,8 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirSealedClassConstructorCallChecker,
)
override val functionCallCheckers: Set<FirFunctionCallChecker> = setOf()
override val tryExpressionCheckers: Set<FirTryExpressionChecker> = setOf(
FirCatchParameterChecker
)
}
@@ -17,10 +17,10 @@ fun bar() {
inline fun <reified E : Exception, R> tryCatch(lazy: () -> R, failure: (E) -> R): R =
try {
lazy()
} catch (e: E) {
} catch (<!REIFIED_TYPE_IN_CATCH_CLAUSE!>e: E<!>) {
failure(e)
}
fun <T : Throwable> tryCatch() {
try { } catch (e: T) { }
}
try { } catch (<!TYPE_PARAMETER_IN_CATCH_CLAUSE!>e: T<!>) { }
}
@@ -1,3 +1,3 @@
fun test() {
try { } catch (e: Exception = Exception()) { }
}
try { } catch (<!CATCH_PARAMETER_WITH_DEFAULT_VALUE!>e: Exception = Exception()<!>) { }
}