Introduce action to add missing when branches on sealed class

Made via diagnostics NON_EXHAUSTIVE_WHEN_FOR_SEALED_CLASS
with INFO severity and quick-fix
So #KT-17580 Fixed
This commit is contained in:
fitermay
2017-05-10 22:56:06 -04:00
committed by Mikhail Glukhikh
parent 1072495001
commit e30b9758f4
12 changed files with 124 additions and 3 deletions
@@ -808,6 +808,13 @@ class ControlFlowInformationProvider private constructor(
trace.report(NON_EXHAUSTIVE_WHEN.on(element, enumMissingCases))
}
}
val sealedClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfSealed(subjectType)
if (sealedClassDescriptor != null) {
val sealedMissingCases = WhenChecker.getSealedMissingCases(element, context, sealedClassDescriptor)
if (!sealedMissingCases.isEmpty()) {
trace.report(NON_EXHAUSTIVE_WHEN_ON_SEALED_CLASS.on(element, sealedMissingCases))
}
}
}
}
}
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumClass
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.types.KotlinType
@@ -275,6 +274,11 @@ object WhenChecker {
return classDescriptor
}
@JvmStatic
fun getClassDescriptorOfTypeIfSealed(type: KotlinType?): ClassDescriptor?
= type?.let { TypeUtils.getClassDescriptor(it) }?.takeIf { DescriptorUtils.isSealedClass(it) }
@JvmStatic
fun whenSubjectType(expression: KtWhenExpression, context: BindingContext) =
expression.subjectExpression?.let { context.get(SMARTCAST, it)?.defaultType ?: context.getType(it) }
@@ -286,6 +290,13 @@ object WhenChecker {
enumClassDescriptor: ClassDescriptor
) = WhenOnEnumExhaustivenessChecker.getMissingCases(expression, context, enumClassDescriptor, false)
@JvmStatic
fun getSealedMissingCases(
expression: KtWhenExpression,
context: BindingContext,
sealedClassDescriptor: ClassDescriptor
) = WhenOnSealedExhaustivenessChecker.getMissingCases(expression, context, sealedClassDescriptor, false)
fun getMissingCases(expression: KtWhenExpression, context: BindingContext): List<WhenMissingCase> {
val type = whenSubjectType(expression, context) ?: return listOf(UnknownMissingCase)
val nullable = type.isMarkedNullable
@@ -50,6 +50,7 @@ import java.util.Map;
import static org.jetbrains.kotlin.diagnostics.PositioningStrategies.*;
import static org.jetbrains.kotlin.diagnostics.Severity.ERROR;
import static org.jetbrains.kotlin.diagnostics.Severity.INFO;
import static org.jetbrains.kotlin.diagnostics.Severity.WARNING;
/**
@@ -849,6 +850,9 @@ public interface Errors {
DiagnosticFactory0<KtWhenEntry> REDUNDANT_ELSE_IN_WHEN = DiagnosticFactory0.create(WARNING, ELSE_ENTRY);
DiagnosticFactory1<KtWhenExpression, List<WhenMissingCase>> NO_ELSE_IN_WHEN = DiagnosticFactory1.create(ERROR, WHEN_EXPRESSION);
DiagnosticFactory1<KtWhenExpression, List<WhenMissingCase>> NON_EXHAUSTIVE_WHEN = DiagnosticFactory1.create(WARNING, WHEN_EXPRESSION);
DiagnosticFactory1<KtWhenExpression, List<WhenMissingCase>>
NON_EXHAUSTIVE_WHEN_ON_SEALED_CLASS = DiagnosticFactory1.create(INFO, WHEN_EXPRESSION);
DiagnosticFactory0<PsiElement> COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> DUPLICATE_LABEL_IN_WHEN = DiagnosticFactory0.create(WARNING);
@@ -520,6 +520,7 @@ public class DefaultErrorMessages {
MAP.put(NO_ELSE_IN_WHEN, "''when'' expression must be exhaustive, add necessary {0}", RENDER_WHEN_MISSING_CASES);
MAP.put(NON_EXHAUSTIVE_WHEN, "''when'' expression on enum is recommended to be exhaustive, add {0}", RENDER_WHEN_MISSING_CASES);
MAP.put(NON_EXHAUSTIVE_WHEN_ON_SEALED_CLASS, "''when'' expression on sealed classes is recommended to be exhaustive, add {0}", RENDER_WHEN_MISSING_CASES);
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");