FIR: introduce CatchParameterChecker
This commit is contained in:
committed by
Mikhail Glukhikh
parent
d8549d6292
commit
5c0231b727
+5
@@ -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<!>) {}
|
||||
}
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+2
@@ -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"
|
||||
|
||||
+4
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -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
|
||||
}
|
||||
|
||||
+2
@@ -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>
|
||||
|
||||
+35
@@ -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) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+15
@@ -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")
|
||||
|
||||
+3
-4
@@ -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>()
|
||||
|
||||
+4
@@ -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<!>) { }
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
fun test() {
|
||||
try { } catch (e: Exception = Exception()) { }
|
||||
}
|
||||
try { } catch (<!CATCH_PARAMETER_WITH_DEFAULT_VALUE!>e: Exception = Exception()<!>) { }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user