FIR checker: ILLEGAL_DECLARATION_IN_WHEN_SUBJECT
This commit is contained in:
committed by
Mikhail Glukhikh
parent
31573a98e8
commit
768ddea18f
+3
@@ -873,6 +873,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
}
|
}
|
||||||
val INVALID_IF_AS_EXPRESSION by error<KtIfExpression>(PositioningStrategy.IF_EXPRESSION)
|
val INVALID_IF_AS_EXPRESSION by error<KtIfExpression>(PositioningStrategy.IF_EXPRESSION)
|
||||||
val ELSE_MISPLACED_IN_WHEN by error<KtWhenEntry>(PositioningStrategy.ELSE_ENTRY)
|
val ELSE_MISPLACED_IN_WHEN by error<KtWhenEntry>(PositioningStrategy.ELSE_ENTRY)
|
||||||
|
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error<KtElement> {
|
||||||
|
parameter<String>("illegalReason")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val CONTEXT_TRACKING by object : DiagnosticGroup("Context tracking") {
|
val CONTEXT_TRACKING by object : DiagnosticGroup("Context tracking") {
|
||||||
|
|||||||
@@ -480,6 +480,7 @@ object FirErrors {
|
|||||||
val NO_ELSE_IN_WHEN by error1<KtWhenExpression, List<WhenMissingCase>>(SourceElementPositioningStrategies.WHEN_EXPRESSION)
|
val NO_ELSE_IN_WHEN by error1<KtWhenExpression, List<WhenMissingCase>>(SourceElementPositioningStrategies.WHEN_EXPRESSION)
|
||||||
val INVALID_IF_AS_EXPRESSION by error0<KtIfExpression>(SourceElementPositioningStrategies.IF_EXPRESSION)
|
val INVALID_IF_AS_EXPRESSION by error0<KtIfExpression>(SourceElementPositioningStrategies.IF_EXPRESSION)
|
||||||
val ELSE_MISPLACED_IN_WHEN by error0<KtWhenEntry>(SourceElementPositioningStrategies.ELSE_ENTRY)
|
val ELSE_MISPLACED_IN_WHEN by error0<KtWhenEntry>(SourceElementPositioningStrategies.ELSE_ENTRY)
|
||||||
|
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error1<KtElement, String>()
|
||||||
|
|
||||||
// Context tracking
|
// Context tracking
|
||||||
val TYPE_PARAMETER_IS_NOT_AN_EXPRESSION by error1<KtSimpleNameExpression, FirTypeParameterSymbol>()
|
val TYPE_PARAMETER_IS_NOT_AN_EXPRESSION by error1<KtSimpleNameExpression, FirTypeParameterSymbol>()
|
||||||
|
|||||||
+1
@@ -61,6 +61,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
|||||||
get() = setOf(
|
get() = setOf(
|
||||||
FirExhaustiveWhenChecker,
|
FirExhaustiveWhenChecker,
|
||||||
FirWhenConditionChecker,
|
FirWhenConditionChecker,
|
||||||
|
FirWhenSubjectChecker,
|
||||||
)
|
)
|
||||||
|
|
||||||
override val loopExpressionCheckers: Set<FirLoopExpressionChecker>
|
override val loopExpressionCheckers: Set<FirLoopExpressionChecker>
|
||||||
|
|||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.KtNodeTypes
|
||||||
|
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.analysis.diagnostics.reportOn
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.getChild
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
|
||||||
|
object FirWhenSubjectChecker : FirWhenExpressionChecker() {
|
||||||
|
override fun check(expression: FirWhenExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
val subject = expression.subject
|
||||||
|
val subjectVariable = expression.subjectVariable
|
||||||
|
val source = (subjectVariable ?: subject)?.source ?: return
|
||||||
|
when {
|
||||||
|
subject?.source?.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION -> {
|
||||||
|
reporter.reportOn(source, FirErrors.ILLEGAL_DECLARATION_IN_WHEN_SUBJECT, "destructuring declaration", context)
|
||||||
|
}
|
||||||
|
subjectVariable?.source?.getChild(KtTokens.VAR_KEYWORD) != null -> {
|
||||||
|
reporter.reportOn(source, FirErrors.ILLEGAL_DECLARATION_IN_WHEN_SUBJECT, "var", context)
|
||||||
|
}
|
||||||
|
subjectVariable?.source?.getChild(KtNodeTypes.PROPERTY_DELEGATE) != null -> {
|
||||||
|
reporter.reportOn(source, FirErrors.ILLEGAL_DECLARATION_IN_WHEN_SUBJECT, "delegated property", context)
|
||||||
|
}
|
||||||
|
subjectVariable != null && subjectVariable.initializer == null -> {
|
||||||
|
reporter.reportOn(source, FirErrors.ILLEGAL_DECLARATION_IN_WHEN_SUBJECT, "variable without initializer", context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-3
@@ -11,18 +11,18 @@ fun testSimpleValInWhenSubject() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun testValWithoutInitializerWhenSubject() {
|
fun testValWithoutInitializerWhenSubject() {
|
||||||
when (val y: Any) {
|
when (<!ILLEGAL_DECLARATION_IN_WHEN_SUBJECT!>val y: Any<!>) {
|
||||||
is String -> <!UNINITIALIZED_VARIABLE!>y<!>.<!UNRESOLVED_REFERENCE!>length<!>
|
is String -> <!UNINITIALIZED_VARIABLE!>y<!>.<!UNRESOLVED_REFERENCE!>length<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testVarInWhenSubject() {
|
fun testVarInWhenSubject() {
|
||||||
when (var y = foo()) {
|
when (<!ILLEGAL_DECLARATION_IN_WHEN_SUBJECT!>var y = foo()<!>) {
|
||||||
is String -> y.length
|
is String -> y.length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testDelegatedValInWhenSubject() {
|
fun testDelegatedValInWhenSubject() {
|
||||||
when (val y by lazy { 42 }) {
|
when (<!ILLEGAL_DECLARATION_IN_WHEN_SUBJECT!>val y by lazy { 42 }<!>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -2379,7 +2379,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
}
|
}
|
||||||
add(FirErrors.EXPECTED_CONDITION) { firDiagnostic ->
|
add(FirErrors.EXPECTED_CONDITION) { firDiagnostic ->
|
||||||
ExpectedConditionImpl(
|
ExpectedConditionImpl(
|
||||||
firDiagnostic as FirPsiDiagnostic<*>,
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2404,6 +2404,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.ILLEGAL_DECLARATION_IN_WHEN_SUBJECT) { firDiagnostic ->
|
||||||
|
IllegalDeclarationInWhenSubjectImpl(
|
||||||
|
firDiagnostic.a,
|
||||||
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION) { firDiagnostic ->
|
add(FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION) { firDiagnostic ->
|
||||||
TypeParameterIsNotAnExpressionImpl(
|
TypeParameterIsNotAnExpressionImpl(
|
||||||
firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir),
|
firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir),
|
||||||
|
|||||||
+5
@@ -1693,6 +1693,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = ElseMisplacedInWhen::class
|
override val diagnosticClass get() = ElseMisplacedInWhen::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class IllegalDeclarationInWhenSubject : KtFirDiagnostic<KtElement>() {
|
||||||
|
override val diagnosticClass get() = IllegalDeclarationInWhenSubject::class
|
||||||
|
abstract val illegalReason: String
|
||||||
|
}
|
||||||
|
|
||||||
abstract class TypeParameterIsNotAnExpression : KtFirDiagnostic<KtSimpleNameExpression>() {
|
abstract class TypeParameterIsNotAnExpression : KtFirDiagnostic<KtSimpleNameExpression>() {
|
||||||
override val diagnosticClass get() = TypeParameterIsNotAnExpression::class
|
override val diagnosticClass get() = TypeParameterIsNotAnExpression::class
|
||||||
abstract val typeParameter: KtTypeParameterSymbol
|
abstract val typeParameter: KtTypeParameterSymbol
|
||||||
|
|||||||
+10
-2
@@ -2710,10 +2710,10 @@ internal class UselessIsCheckImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class ExpectedConditionImpl(
|
internal class ExpectedConditionImpl(
|
||||||
firDiagnostic: FirPsiDiagnostic<*>,
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
) : KtFirDiagnostic.ExpectedCondition(), KtAbstractFirDiagnostic<KtWhenCondition> {
|
) : KtFirDiagnostic.ExpectedCondition(), KtAbstractFirDiagnostic<KtWhenCondition> {
|
||||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class NoElseInWhenImpl(
|
internal class NoElseInWhenImpl(
|
||||||
@@ -2738,6 +2738,14 @@ internal class ElseMisplacedInWhenImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class IllegalDeclarationInWhenSubjectImpl(
|
||||||
|
override val illegalReason: String,
|
||||||
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.IllegalDeclarationInWhenSubject(), KtAbstractFirDiagnostic<KtElement> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
internal class TypeParameterIsNotAnExpressionImpl(
|
internal class TypeParameterIsNotAnExpressionImpl(
|
||||||
override val typeParameter: KtTypeParameterSymbol,
|
override val typeParameter: KtTypeParameterSymbol,
|
||||||
firDiagnostic: FirPsiDiagnostic,
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
|
|||||||
Reference in New Issue
Block a user