[FE 1.0] Report DUPLICATE_LABEL_IN_WHEN on proper branches
^KT-50385 Fixed
This commit is contained in:
committed by
teamcity
parent
d9a3dd09ea
commit
eb753eac83
+6
@@ -32929,6 +32929,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
runTest("compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exhaustiveWhenWithConstVal.kt")
|
||||
public void testExhaustiveWhenWithConstVal() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/exhaustiveWhenWithConstVal.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ExhaustiveWithNullabilityCheck.kt")
|
||||
public void testExhaustiveWithNullabilityCheck() throws Exception {
|
||||
|
||||
+6
@@ -32929,6 +32929,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exhaustiveWhenWithConstVal.kt")
|
||||
public void testExhaustiveWhenWithConstVal() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/exhaustiveWhenWithConstVal.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ExhaustiveWithNullabilityCheck.kt")
|
||||
public void testExhaustiveWithNullabilityCheck() throws Exception {
|
||||
|
||||
+6
@@ -32929,6 +32929,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exhaustiveWhenWithConstVal.kt")
|
||||
public void testExhaustiveWhenWithConstVal() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/exhaustiveWhenWithConstVal.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ExhaustiveWithNullabilityCheck.kt")
|
||||
public void testExhaustiveWithNullabilityCheck() throws Exception {
|
||||
|
||||
@@ -361,7 +361,30 @@ object WhenChecker {
|
||||
if (expression.subjectExpression == null) return
|
||||
|
||||
val checkedTypes = HashSet<Pair<KotlinType, Boolean>>()
|
||||
val checkedConstants = HashSet<CompileTimeConstant<*>>()
|
||||
/*
|
||||
* `true` in map means that constant can be removed and nothing breaks
|
||||
* `false` means opposite
|
||||
*
|
||||
* Example:
|
||||
* const val myF = false
|
||||
* const val myT = true
|
||||
*
|
||||
* fun test_1(someBoolean: Boolean) {
|
||||
* val s = when (someBoolean) {
|
||||
* myT -> 1
|
||||
* myF -> 2
|
||||
* true -> 3 // DUPLICATE_LABEL_IN_WHEN
|
||||
* false -> 4 // DUPLICATE_LABEL_IN_WHEN
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* In this case myT and myF actually are `true` and `false` correspondingly, but
|
||||
* const vals are not treated by exhaustive checkers, so removal `true` or `false`
|
||||
* branches will break code, so we need to report DUPLICATE_LABEL_IN_WHEN on `myT` and
|
||||
* `myF`, not on `true` and `false`
|
||||
*/
|
||||
val checkedConstants = mutableMapOf<CompileTimeConstant<*>, Boolean>()
|
||||
val notTrivialBranches = mutableMapOf<CompileTimeConstant<*>, KtExpression>()
|
||||
for (entry in expression.entries) {
|
||||
if (entry.isElse) continue
|
||||
|
||||
@@ -372,10 +395,37 @@ object WhenChecker {
|
||||
val constant = ConstantExpressionEvaluator.getConstant(
|
||||
constantExpression, trace.bindingContext
|
||||
) ?: continue@conditions
|
||||
if (checkedConstants.contains(constant)) {
|
||||
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(constantExpression))
|
||||
} else {
|
||||
checkedConstants.add(constant)
|
||||
|
||||
fun report(reportOn: KtExpression) {
|
||||
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(reportOn))
|
||||
}
|
||||
|
||||
when (checkedConstants[constant]) {
|
||||
true -> {
|
||||
// already found trivial constant in previous branches
|
||||
report(constantExpression)
|
||||
}
|
||||
false -> {
|
||||
// already found bad constant in previous branches
|
||||
val isTrivial = constant.isTrivial()
|
||||
if (isTrivial) {
|
||||
// this constant is trivial -> report on first non trivial constant
|
||||
val reportOn = notTrivialBranches.remove(constant)!!
|
||||
report(reportOn)
|
||||
checkedConstants[constant] = true
|
||||
} else {
|
||||
// this constant is also not trivial -> report on it
|
||||
report(constantExpression)
|
||||
}
|
||||
}
|
||||
null -> {
|
||||
// met constant for a first time
|
||||
val isTrivial = constant.isTrivial()
|
||||
checkedConstants[constant] = isTrivial
|
||||
if (!isTrivial) {
|
||||
notTrivialBranches[constant] = constantExpression
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -394,7 +444,10 @@ object WhenChecker {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun CompileTimeConstant<*>.isTrivial(): Boolean {
|
||||
return !usesVariableAsConstant
|
||||
}
|
||||
|
||||
fun checkDeprecatedWhenSyntax(trace: BindingTrace, expression: KtWhenExpression) {
|
||||
|
||||
+2
-2
@@ -40,8 +40,8 @@ fun test() {
|
||||
val s = "";
|
||||
|
||||
when (x) {
|
||||
<!INCOMPATIBLE_TYPES!>s<!> -> 1
|
||||
<!DUPLICATE_LABEL_IN_WHEN, INCOMPATIBLE_TYPES!>""<!> -> 1
|
||||
<!DUPLICATE_LABEL_IN_WHEN, INCOMPATIBLE_TYPES!>s<!> -> 1
|
||||
<!INCOMPATIBLE_TYPES!>""<!> -> 1
|
||||
x -> 1
|
||||
1 -> 1
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// ISSUE: KT-50385
|
||||
|
||||
const val myF = false
|
||||
const val myT = true
|
||||
|
||||
fun test_1(someBoolean: Boolean) {
|
||||
val s = when (someBoolean) {
|
||||
myT /* true */ -> 1
|
||||
myF /* false */ -> 2
|
||||
true -> 3
|
||||
false -> 4
|
||||
}
|
||||
}
|
||||
|
||||
fun test_2(someBoolean: Boolean) {
|
||||
val s = when (someBoolean) {
|
||||
myT /* true */ -> 1
|
||||
true -> 2
|
||||
false -> 3
|
||||
}
|
||||
}
|
||||
|
||||
fun test_3(someBoolean: Boolean) {
|
||||
val s = <!NO_ELSE_IN_WHEN!>when<!> (someBoolean) {
|
||||
myT /* true */ -> 1
|
||||
false -> 2
|
||||
}
|
||||
}
|
||||
|
||||
fun test_4(someBoolean: Boolean) {
|
||||
val s = <!NO_ELSE_IN_WHEN!>when<!> (someBoolean) {
|
||||
myT /* true */ -> 1
|
||||
myT /* true */ -> 2
|
||||
false -> 3
|
||||
}
|
||||
}
|
||||
|
||||
fun test_5(someBoolean: Boolean) {
|
||||
val s = <!NO_ELSE_IN_WHEN!>when<!> (someBoolean) {
|
||||
myT /* true */ -> 1
|
||||
myT /* true */ -> 2
|
||||
myT /* true */ -> 3
|
||||
false -> 4
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// ISSUE: KT-50385
|
||||
|
||||
const val myF = false
|
||||
const val myT = true
|
||||
|
||||
fun test_1(someBoolean: Boolean) {
|
||||
val s = when (someBoolean) {
|
||||
<!DUPLICATE_LABEL_IN_WHEN!>myT<!> /* true */ -> 1
|
||||
<!DUPLICATE_LABEL_IN_WHEN!>myF<!> /* false */ -> 2
|
||||
true -> 3
|
||||
false -> 4
|
||||
}
|
||||
}
|
||||
|
||||
fun test_2(someBoolean: Boolean) {
|
||||
val s = when (someBoolean) {
|
||||
<!DUPLICATE_LABEL_IN_WHEN!>myT<!> /* true */ -> 1
|
||||
true -> 2
|
||||
false -> 3
|
||||
}
|
||||
}
|
||||
|
||||
fun test_3(someBoolean: Boolean) {
|
||||
val s = <!NO_ELSE_IN_WHEN!>when<!> (someBoolean) {
|
||||
myT /* true */ -> 1
|
||||
false -> 2
|
||||
}
|
||||
}
|
||||
|
||||
fun test_4(someBoolean: Boolean) {
|
||||
val s = <!NO_ELSE_IN_WHEN!>when<!> (someBoolean) {
|
||||
myT /* true */ -> 1
|
||||
<!DUPLICATE_LABEL_IN_WHEN!>myT<!> /* true */ -> 2
|
||||
false -> 3
|
||||
}
|
||||
}
|
||||
|
||||
fun test_5(someBoolean: Boolean) {
|
||||
val s = <!NO_ELSE_IN_WHEN!>when<!> (someBoolean) {
|
||||
myT /* true */ -> 1
|
||||
<!DUPLICATE_LABEL_IN_WHEN!>myT<!> /* true */ -> 2
|
||||
<!DUPLICATE_LABEL_IN_WHEN!>myT<!> /* true */ -> 3
|
||||
false -> 4
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package
|
||||
|
||||
public const val myF: kotlin.Boolean = false
|
||||
public const val myT: kotlin.Boolean = true
|
||||
public fun test_1(/*0*/ someBoolean: kotlin.Boolean): kotlin.Unit
|
||||
public fun test_2(/*0*/ someBoolean: kotlin.Boolean): kotlin.Unit
|
||||
public fun test_3(/*0*/ someBoolean: kotlin.Boolean): kotlin.Unit
|
||||
public fun test_4(/*0*/ someBoolean: kotlin.Boolean): kotlin.Unit
|
||||
public fun test_5(/*0*/ someBoolean: kotlin.Boolean): kotlin.Unit
|
||||
|
||||
Generated
+6
@@ -33025,6 +33025,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/when/ExhaustiveVarOverConditionalInit.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exhaustiveWhenWithConstVal.kt")
|
||||
public void testExhaustiveWhenWithConstVal() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/exhaustiveWhenWithConstVal.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ExhaustiveWithNullabilityCheck.kt")
|
||||
public void testExhaustiveWithNullabilityCheck() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user