diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt index 5d3008b02ba..44763077ccf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt @@ -54,6 +54,7 @@ import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.hasThisOrNoDispatchRe import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal +import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils.* import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils @@ -797,7 +798,14 @@ class ControlFlowInformationProvider private constructor( val subjectType = trace.getType(subjectExpression) if (elseEntry != null) { if (missingCases.isEmpty() && subjectType != null && !subjectType.isFlexible()) { - trace.report(REDUNDANT_ELSE_IN_WHEN.on(elseEntry)) + val subjectClass = subjectType.constructor.declarationDescriptor as? ClassDescriptor + val pseudocodeElement = instruction.owner.correspondingElement + val pseudocodeDescriptor = trace[DECLARATION_TO_DESCRIPTOR, pseudocodeElement] + if (subjectClass == null || + KotlinBuiltIns.isBooleanOrNullableBoolean(subjectType) || + subjectClass.module == pseudocodeDescriptor?.module) { + trace.report(REDUNDANT_ELSE_IN_WHEN.on(elseEntry)) + } } continue } diff --git a/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.kt b/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.kt new file mode 100644 index 00000000000..6a8a2e774df --- /dev/null +++ b/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.kt @@ -0,0 +1,45 @@ +// MODULE: m1 +// FILE: a.kt + +package test + +enum class E { + FIRST +} + +sealed class S + +class Derived : S() + +// MODULE: m2(m1) +// FILE: b.kt + +package other + +import test.* + +fun foo(e: E) = when (e) { + E.FIRST -> 42 + else -> -42 +} + +fun bar(s: S?) = when (s) { + is Derived -> "Derived" + null -> "" + else -> TODO("What?!?!") +} + +fun baz(b: Boolean?) = when (b) { + true -> 1 + false -> 0 + null -> -1 + // Still warning + else -> TODO() +} + +fun baz(b: Boolean) = when (b) { + true -> 1 + false -> 0 + // Still warning + else -> TODO() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.txt b/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.txt new file mode 100644 index 00000000000..9b6e28bc442 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.txt @@ -0,0 +1,52 @@ +// -- Module: -- +package + +package test { + + public final class Derived : test.S { + public constructor Derived() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final enum class E : kotlin.Enum { + enum entry FIRST + + private constructor E() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: test.E): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): test.E + public final /*synthesized*/ fun values(): kotlin.Array + } + + public sealed class S { + private constructor S() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + + +// -- Module: -- +package + +package other { + public fun bar(/*0*/ s: test.S?): kotlin.String + public fun baz(/*0*/ b: kotlin.Boolean): kotlin.Int + public fun baz(/*0*/ b: kotlin.Boolean?): kotlin.Int + public fun foo(/*0*/ e: test.E): kotlin.Int +} + +package test { +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index a7044036aae..4df866bf52e 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -12955,6 +12955,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("redundantElseInWhen.kt") + public void testRedundantElseInWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.kt"); + doTest(fileName); + } + @TestMetadata("varargConflict.kt") public void testVarargConflict() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multimodule/varargConflict.kt");