[FIR] Implement ELSE_MISPLACED_IN_WHEN diagnostics, fix tests

This commit is contained in:
Ivan Kochurkin
2021-04-14 22:56:25 +03:00
committed by TeamCityServer
parent 7f4da93cc3
commit 00bc04b3df
17 changed files with 67 additions and 15 deletions
@@ -39,6 +39,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
OPEN_MODIFIER,
WHEN_EXPRESSION,
IF_EXPRESSION,
ELSE_ENTRY,
VARIANCE_MODIFIER,
LATEINIT_MODIFIER,
INLINE_OR_VALUE_MODIFIER,
@@ -642,6 +642,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
parameter<List<WhenMissingCase>>("missingWhenCases")
}
val INVALID_IF_AS_EXPRESSION by error<KtIfExpression>(PositioningStrategy.IF_EXPRESSION)
val ELSE_MISPLACED_IN_WHEN by error<KtWhenEntry>(PositioningStrategy.ELSE_ENTRY)
}
val CONTEXT_TRACKING by object : DiagnosticGroup("Context tracking") {
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeParameterList
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
@@ -377,6 +378,7 @@ object FirErrors {
// When expressions
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 ELSE_MISPLACED_IN_WHEN by error0<KtWhenEntry>(SourceElementPositioningStrategies.ELSE_ENTRY)
// Context tracking
val TYPE_PARAMETER_IS_NOT_AN_EXPRESSION by error1<KtSimpleNameExpression, FirTypeParameterSymbol>()
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.ExhaustivenessStatus
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
import org.jetbrains.kotlin.fir.expressions.isExhaustive
object FirExhaustiveWhenChecker : FirWhenExpressionChecker() {
@@ -27,6 +28,14 @@ object FirExhaustiveWhenChecker : FirWhenExpressionChecker() {
reporter.reportOn(source, FirErrors.NO_ELSE_IN_WHEN, missingCases, context)
}
}
val branchesCount = expression.branches.size
for (indexedValue in expression.branches.withIndex()) {
val branch = indexedValue.value
if (branch.condition is FirElseIfTrueCondition && indexedValue.index < branchesCount - 1) {
reporter.reportOn(branch.source, FirErrors.ELSE_MISPLACED_IN_WHEN, context)
}
}
}
private val FirSourceElement.isIfExpression: Boolean
@@ -501,6 +501,17 @@ object LightTreePositioningStrategies {
}
}
val ELSE_ENTRY = object : LightTreePositioningStrategy() {
override fun mark(
node: LighterASTNode,
startOffset: Int,
endOffset: Int,
tree: FlyweightCapableTreeStructure<LighterASTNode>
): List<TextRange> {
return markElement(tree.elseKeyword(node) ?: node, startOffset, endOffset, tree, node)
}
}
val ARRAY_ACCESS = object : LightTreePositioningStrategy() {
override fun mark(
node: LighterASTNode,
@@ -577,6 +588,9 @@ private fun FlyweightCapableTreeStructure<LighterASTNode>.whenKeyword(node: Ligh
private fun FlyweightCapableTreeStructure<LighterASTNode>.ifKeyword(node: LighterASTNode): LighterASTNode? =
findChildByType(node, KtTokens.IF_KEYWORD)
private fun FlyweightCapableTreeStructure<LighterASTNode>.elseKeyword(node: LighterASTNode): LighterASTNode? =
findChildByType(node, KtTokens.ELSE_KEYWORD)
private fun FlyweightCapableTreeStructure<LighterASTNode>.returnKeyword(node: LighterASTNode): LighterASTNode? =
findChildByType(node, KtTokens.RETURN_KEYWORD)
@@ -163,6 +163,11 @@ object SourceElementPositioningStrategies {
PositioningStrategies.IF_EXPRESSION
)
val ELSE_ENTRY = SourceElementPositioningStrategy(
LightTreePositioningStrategies.ELSE_ENTRY,
PositioningStrategies.ELSE_ENTRY
)
val ARRAY_ACCESS = SourceElementPositioningStrategy(
LightTreePositioningStrategies.ARRAY_ACCESS,
PositioningStrategies.ARRAY_ACCESS
@@ -6,7 +6,7 @@ fun foo() : Int {
var z = 0
when(d) {
5, 3 -> z++
else -> { z = -1000 }
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> { z = -1000 }
return z -> 34
}
}
@@ -23,4 +23,4 @@ fun fff(): Int {
return 34
}
fun bar(): Int = 8
fun bar(): Int = 8
@@ -31,7 +31,7 @@ fun t5(x: Int) = <!NO_ELSE_IN_WHEN!>when<!> (x) {
}
fun foo3(x: Int) = when(x) {
else -> 1
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> 1
2 -> 2
}
@@ -56,6 +56,6 @@ fun fourth(arg: Color) = when (arg) {
fun fifth(arg: Any?) = when (arg) {
is Any -> "Any"
else -> ""
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> ""
else -> null
}
+1 -1
View File
@@ -50,7 +50,7 @@ fun test() {
val z = 1
when (z) {
else -> 1
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> 1
1 -> 2
}
@@ -18,7 +18,7 @@ fun case1() {
val z = JavaEnum.Val_3
val when1 = when (z) {
JavaEnum.Val_1 -> { false }
else -> {true}
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> {true}
JavaEnum.Val_2 -> { false }
}
}
@@ -28,7 +28,7 @@ fun case1() {
fun case2() {
val z = JavaEnum.Val_3
val when1 = when (z) {
else -> {true}
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> {true}
JavaEnum.Val_1 -> { false }
JavaEnum.Val_2 -> { false }
}
@@ -37,7 +37,7 @@ fun case2() {
fun case3() {
val z = JavaEnum.Val_3
val when1 = when (z) {
else -> {true}
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> {true}
JavaEnum.Val_1 -> { false }
JavaEnum.Val_2 -> { false }
else -> { true }
@@ -3,21 +3,21 @@
// TESTCASE NUMBER: 1
fun case_1(value_1: Int): String = when (value_1) {
else -> ""
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> ""
1 -> ""
}
// TESTCASE NUMBER: 2
fun case_2(value_1: Int): String = when (value_1) {
1 -> ""
else -> ""
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> ""
2 -> ""
}
// TESTCASE NUMBER: 3
fun case_3(value_1: Int): String {
when (value_1) {
else -> return ""
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> return ""
else -> return ""
}
@@ -3,21 +3,21 @@
// TESTCASE NUMBER: 1
fun case_1(value_1: Int): String = when {
else -> ""
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> ""
value_1 == 1 -> ""
}
// TESTCASE NUMBER: 2
fun case_2(value_1: Int): String = when {
value_1 == 1 -> ""
else -> ""
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> ""
value_1 == 2 -> ""
}
// TESTCASE NUMBER: 3
fun case_3(): String {
when {
else -> return ""
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> return ""
else -> return ""
}
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeParameterList
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
/*
@@ -1793,6 +1794,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.ELSE_MISPLACED_IN_WHEN) { firDiagnostic ->
ElseMisplacedInWhenImpl(
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION) { firDiagnostic ->
TypeParameterIsNotAnExpressionImpl(
firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir),
@@ -50,6 +50,7 @@ import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeParameterList
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
@@ -1260,6 +1261,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = InvalidIfAsExpression::class
}
abstract class ElseMisplacedInWhen : KtFirDiagnostic<KtWhenEntry>() {
override val diagnosticClass get() = ElseMisplacedInWhen::class
}
abstract class TypeParameterIsNotAnExpression : KtFirDiagnostic<KtSimpleNameExpression>() {
override val diagnosticClass get() = TypeParameterIsNotAnExpression::class
abstract val typeParameter: KtTypeParameterSymbol
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeParameterList
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
@@ -2041,6 +2042,13 @@ internal class InvalidIfAsExpressionImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ElseMisplacedInWhenImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.ElseMisplacedInWhen(), KtAbstractFirDiagnostic<KtWhenEntry> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class TypeParameterIsNotAnExpressionImpl(
override val typeParameter: KtTypeParameterSymbol,
firDiagnostic: FirPsiDiagnostic<*>,
+1 -1
View File
@@ -35,7 +35,7 @@ fun test() {
val z = 1
when (z) {
else -> 1
<error descr="[ELSE_MISPLACED_IN_WHEN] ">else</error> -> 1
1 -> 2
}