Warning generation on non-exhaustive whens over enums + a set of tests + fixed test #KT-6227 Fixed

This commit is contained in:
Mikhail Glukhikh
2015-05-28 15:28:13 +03:00
parent 969993bd09
commit de12771c0f
13 changed files with 318 additions and 5 deletions
@@ -759,10 +759,19 @@ public class JetFlowInformationProvider {
? ((InstructionWithValue) instruction).getOutputValue()
: null;
for (JetElement element : instruction.getOwner().getValueElements(value)) {
if (element instanceof JetWhenExpression) {
JetWhenExpression whenExpression = (JetWhenExpression) element;
if (whenExpression.getElseExpression() == null && WhenChecker.mustHaveElse(whenExpression, trace)) {
trace.report(NO_ELSE_IN_WHEN.on(whenExpression));
if (!(element instanceof JetWhenExpression)) continue;
JetWhenExpression whenExpression = (JetWhenExpression) element;
if (whenExpression.getElseExpression() != null) continue;
if (WhenChecker.mustHaveElse(whenExpression, trace)) {
trace.report(NO_ELSE_IN_WHEN.on(whenExpression));
}
else if (whenExpression.getSubjectExpression() != null) {
ClassDescriptor enumClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfEnum(
trace.getType(whenExpression.getSubjectExpression()));
if (enumClassDescriptor != null
&& !WhenChecker.isWhenOnEnumExhaustive(whenExpression, trace, enumClassDescriptor)) {
trace.report(NON_EXHAUSTIVE_WHEN.on(whenExpression));
}
}
}
@@ -619,6 +619,7 @@ public interface Errors {
DiagnosticFactory0<JetWhenCondition> EXPECTED_CONDITION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetWhenEntry> ELSE_MISPLACED_IN_WHEN = DiagnosticFactory0.create(ERROR, ELSE_ENTRY);
DiagnosticFactory0<JetWhenExpression> NO_ELSE_IN_WHEN = DiagnosticFactory0.create(ERROR, WHEN_EXPRESSION);
DiagnosticFactory0<JetWhenExpression> NON_EXHAUSTIVE_WHEN = DiagnosticFactory0.create(WARNING, WHEN_EXPRESSION);
// Type mismatch
@@ -387,6 +387,7 @@ public class DefaultErrorMessages {
MAP.put(ELSE_MISPLACED_IN_WHEN, "'else' entry must be the last one in a when-expression");
MAP.put(NO_ELSE_IN_WHEN, "'when' expression must contain 'else' branch");
MAP.put(NON_EXHAUSTIVE_WHEN, "'when' expression contains only some variants and no 'else' branch");
MAP.put(TYPE_MISMATCH_IN_RANGE, "Type mismatch: incompatible types of range and element checked in it");
MAP.put(CYCLIC_INHERITANCE_HIERARCHY, "There's a cycle in the inheritance hierarchy for this type");
+1 -1
View File
@@ -1,7 +1,7 @@
//FILE: foo.kt
fun main(args: Array<String>) {
val c: Type
when (<!UNINITIALIZED_VARIABLE, UNUSED_EXPRESSION!>c<!>) {
<!NON_EXHAUSTIVE_WHEN!>when<!> (<!UNINITIALIZED_VARIABLE, UNUSED_EXPRESSION!>c<!>) {
}
}
@@ -0,0 +1,11 @@
// Base for KT-6227
enum class X { A, B, C, D }
fun foo(arg: X): String {
var res = "XXX"
<!NON_EXHAUSTIVE_WHEN!>when<!> (arg) {
X.A -> res = "A"
X.B -> res = "B"
}
return res
}
@@ -0,0 +1,57 @@
package
internal fun foo(/*0*/ arg: X): kotlin.String
internal final enum class X : kotlin.Enum<X> {
public enum entry A : X {
private constructor A()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry B : X {
private constructor B()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry C : X {
private constructor C()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry D : X {
private constructor D()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
private constructor X()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): X
public final /*synthesized*/ fun values(): kotlin.Array<X>
}
@@ -0,0 +1,12 @@
// Base for KT-6227
enum class X { A, B, C, D }
fun foo(arg: X): String {
val res: String
when (arg) {
X.A -> res = "A"
X.B -> res = "B"
else -> res = "CD"
}
return res
}
@@ -0,0 +1,57 @@
package
internal fun foo(/*0*/ arg: X): kotlin.String
internal final enum class X : kotlin.Enum<X> {
public enum entry A : X {
private constructor A()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry B : X {
private constructor B()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry C : X {
private constructor C()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry D : X {
private constructor D()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
private constructor X()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): X
public final /*synthesized*/ fun values(): kotlin.Array<X>
}
@@ -0,0 +1,13 @@
// Base for KT-6227
enum class X { A, B, C, D }
fun foo(arg: X): String {
val res: String
when (arg) {
X.A -> res = "A"
X.B -> res = "B"
X.C -> res = "C"
X.D -> res = "D"
}
return res
}
@@ -0,0 +1,57 @@
package
internal fun foo(/*0*/ arg: X): kotlin.String
internal final enum class X : kotlin.Enum<X> {
public enum entry A : X {
private constructor A()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry B : X {
private constructor B()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry C : X {
private constructor C()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry D : X {
private constructor D()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
private constructor X()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): X
public final /*synthesized*/ fun values(): kotlin.Array<X>
}
@@ -0,0 +1,14 @@
// Base for KT-6227
enum class X { A, B, C, D }
fun foo(arg: X?): String {
var res = "XXX"
// Should we report something here? Probably not, null is not an enum entry
when (arg) {
X.A -> res = "A"
X.B -> res = "B"
X.C -> res = "C"
X.D -> res = "D"
}
return res
}
@@ -0,0 +1,57 @@
package
internal fun foo(/*0*/ arg: X?): kotlin.String
internal final enum class X : kotlin.Enum<X> {
public enum entry A : X {
private constructor A()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry B : X {
private constructor B()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry C : X {
private constructor C()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry D : X {
private constructor D()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
private constructor X()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): X
public final /*synthesized*/ fun values(): kotlin.Array<X>
}
@@ -13728,6 +13728,30 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("NonExhaustiveWarning.kt")
public void testNonExhaustiveWarning() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/NonExhaustiveWarning.kt");
doTest(fileName);
}
@TestMetadata("NonExhaustiveWarningElse.kt")
public void testNonExhaustiveWarningElse() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/NonExhaustiveWarningElse.kt");
doTest(fileName);
}
@TestMetadata("NonExhaustiveWarningFalse.kt")
public void testNonExhaustiveWarningFalse() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/NonExhaustiveWarningFalse.kt");
doTest(fileName);
}
@TestMetadata("NonExhaustiveWarningNull.kt")
public void testNonExhaustiveWarningNull() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/NonExhaustiveWarningNull.kt");
doTest(fileName);
}
@TestMetadata("PropertyNotInitialized.kt")
public void testPropertyNotInitialized() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/PropertyNotInitialized.kt");