[FIR] Report NON_EXHAUSTIVE_WHEN_STATEMENT/NO_ELSE_IN_WHEN for when's on logical types
^KT-47709 In Progress
This commit is contained in:
committed by
teamcityserver
parent
ef635f6a96
commit
a6edd852ff
+4
@@ -976,6 +976,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val NO_ELSE_IN_WHEN by error<KtWhenExpression>(PositioningStrategy.WHEN_EXPRESSION) {
|
||||
parameter<List<WhenMissingCase>>("missingWhenCases")
|
||||
}
|
||||
val NON_EXHAUSTIVE_WHEN_STATEMENT by warning<KtWhenExpression>(PositioningStrategy.WHEN_EXPRESSION) {
|
||||
parameter<String>("type")
|
||||
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 ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error<KtElement> {
|
||||
|
||||
@@ -516,6 +516,7 @@ object FirErrors {
|
||||
// When expressions
|
||||
val EXPECTED_CONDITION by error0<KtWhenCondition>()
|
||||
val NO_ELSE_IN_WHEN by error1<KtWhenExpression, List<WhenMissingCase>>(SourceElementPositioningStrategies.WHEN_EXPRESSION)
|
||||
val NON_EXHAUSTIVE_WHEN_STATEMENT by warning2<KtWhenExpression, String, 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)
|
||||
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error1<KtElement, String>()
|
||||
|
||||
+51
-4
@@ -6,29 +6,76 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
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
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isBooleanOrNullableBoolean
|
||||
|
||||
object FirExhaustiveWhenChecker : FirWhenExpressionChecker() {
|
||||
override fun check(expression: FirWhenExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (expression.usedAsExpression && !expression.isExhaustive) {
|
||||
val source = expression.source ?: return
|
||||
reportNotExhaustive(expression, context, reporter)
|
||||
reportElseMisplaced(expression, reporter, context)
|
||||
}
|
||||
|
||||
private fun reportNotExhaustive(whenExpression: FirWhenExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (whenExpression.isExhaustive) return
|
||||
|
||||
val source = whenExpression.source ?: return
|
||||
|
||||
if (whenExpression.usedAsExpression) {
|
||||
if (source.isIfExpression) {
|
||||
reporter.reportOn(source, FirErrors.INVALID_IF_AS_EXPRESSION, context)
|
||||
return
|
||||
} else if (source.isWhenExpression) {
|
||||
val missingCases = (expression.exhaustivenessStatus as ExhaustivenessStatus.NotExhaustive).reasons
|
||||
reporter.reportOn(source, FirErrors.NO_ELSE_IN_WHEN, missingCases, context)
|
||||
reporter.reportOn(source, FirErrors.NO_ELSE_IN_WHEN, whenExpression.missingCases, context)
|
||||
}
|
||||
} else {
|
||||
val subjectType = whenExpression.subject?.typeRef?.coneType ?: return
|
||||
val subjectClassSymbol = subjectType.fullyExpandedType(context.session).toRegularClassSymbol(context.session) ?: return
|
||||
val kind = when {
|
||||
subjectClassSymbol.modality == Modality.SEALED -> AlgebraicTypeKind.Sealed
|
||||
subjectClassSymbol.classKind == ClassKind.ENUM_CLASS -> AlgebraicTypeKind.Enum
|
||||
subjectType.isBooleanOrNullableBoolean -> AlgebraicTypeKind.Boolean
|
||||
else -> return
|
||||
}
|
||||
|
||||
if (context.session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitNonExhaustiveWhenOnAlgebraicTypes)) {
|
||||
reporter.reportOn(source, FirErrors.NO_ELSE_IN_WHEN, whenExpression.missingCases, context)
|
||||
} else {
|
||||
reporter.reportOn(source, FirErrors.NON_EXHAUSTIVE_WHEN_STATEMENT, kind.displayName, whenExpression.missingCases, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val FirWhenExpression.missingCases: List<WhenMissingCase>
|
||||
get() = (exhaustivenessStatus as ExhaustivenessStatus.NotExhaustive).reasons
|
||||
|
||||
private enum class AlgebraicTypeKind(val displayName: String) {
|
||||
Sealed("sealed class/interface"),
|
||||
Enum("enum"),
|
||||
Boolean("Boolean")
|
||||
}
|
||||
|
||||
private fun reportElseMisplaced(
|
||||
expression: FirWhenExpression,
|
||||
reporter: DiagnosticReporter,
|
||||
context: CheckerContext
|
||||
) {
|
||||
val branchesCount = expression.branches.size
|
||||
for (indexedValue in expression.branches.withIndex()) {
|
||||
val branch = indexedValue.value
|
||||
|
||||
+7
@@ -249,6 +249,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEWER_VERSION_IN_
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NONE_APPLICABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_EXHAUSTIVE_WHEN_STATEMENT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_FINAL_MEMBER_IN_FINAL_CLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_FINAL_MEMBER_IN_OBJECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_LOCAL_RETURN_NOT_ALLOWED
|
||||
@@ -1284,6 +1285,12 @@ class FirDefaultErrorMessages {
|
||||
map.put(EXPECTED_CONDITION, "Expected condition of type Boolean")
|
||||
map.put(NO_ELSE_IN_WHEN, "''when'' expression must be exhaustive, add necessary {0}", WHEN_MISSING_CASES)
|
||||
map.put(INVALID_IF_AS_EXPRESSION, "'if' must have both main and 'else' branches if used as an expression")
|
||||
map.put(
|
||||
NON_EXHAUSTIVE_WHEN_STATEMENT,
|
||||
"Non exhaustive ''when'' statements on {0} will be prohibited in 1.7, add {1}",
|
||||
TO_STRING,
|
||||
WHEN_MISSING_CASES
|
||||
)
|
||||
|
||||
// Context tracking
|
||||
map.put(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION, "Type parameter ''{0}'' is not an expression", SYMBOL)
|
||||
|
||||
Reference in New Issue
Block a user