diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExhaustiveWhenChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExhaustiveWhenChecker.kt index 163161fd572ee..49ec5d0b03726 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExhaustiveWhenChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExhaustiveWhenChecker.kt @@ -12,8 +12,10 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.WhenMissingCase import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.fullyExpandedClassId import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass import org.jetbrains.kotlin.fir.declarations.utils.isExpect @@ -22,8 +24,12 @@ 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.impl.FirEmptyExpressionBlock +import org.jetbrains.kotlin.fir.moduleData +import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.toRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.isBooleanOrNullableBoolean object FirExhaustiveWhenChecker : FirWhenExpressionChecker(MppCheckerKind.Common) { @@ -125,11 +131,24 @@ object FirExhaustiveWhenChecker : FirWhenExpressionChecker(MppCheckerKind.Common if (whenExpression.exhaustivenessStatus == ExhaustivenessStatus.RedundantlyExhaustive) { for (branch in whenExpression.branches) { if (branch.source == null || branch.condition !is FirElseIfTrueCondition) continue - reporter.reportOn(branch.source, FirErrors.REDUNDANT_ELSE_IN_WHEN) + + val subjectConeType = whenExpression.subjectVariable?.returnTypeRef?.coneType + if (subjectConeType == null || + subjectConeType.isBooleanOrNullableBoolean || // Values are known + subjectConeType.getModuleDataOrNull() == context.session.moduleData // Subject is from the same module + ) { + reporter.reportOn(branch.source, FirErrors.REDUNDANT_ELSE_IN_WHEN) + } } } } + context(context: CheckerContext) + private fun ConeKotlinType.getModuleDataOrNull(): FirModuleData? { + val classId = fullyExpandedClassId(context.session) ?: return null + return context.session.symbolProvider.getClassLikeSymbolByClassId(classId)?.moduleData + } + private val KtSourceElement.isIfExpression: Boolean get() = elementType == KtNodeTypes.IF diff --git a/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.fir.kt b/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.fir.kt deleted file mode 100644 index 20f489c4e6157..0000000000000 --- a/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.fir.kt +++ /dev/null @@ -1,49 +0,0 @@ -// RUN_PIPELINE_TILL: BACKEND -// 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() -} - -/* GENERATED_FIR_TAGS: classDeclaration, enumDeclaration, enumEntry, equalityExpression, functionDeclaration, -integerLiteral, isExpression, nullableType, sealed, smartcast, stringLiteral, whenExpression, whenWithSubject */ diff --git a/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.kt b/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.kt index 4be944ba30960..313b131f27b1e 100644 --- a/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.kt +++ b/compiler/testData/diagnostics/tests/multimodule/redundantElseInWhen.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // RUN_PIPELINE_TILL: BACKEND // MODULE: m1 // FILE: a.kt