Unify WhenMissingCase from FIR and FE1.0
This commit is contained in:
@@ -22,7 +22,9 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.checkReservedPrefixWord
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -40,19 +42,9 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import java.util.*
|
||||
|
||||
sealed class WhenMissingCase {
|
||||
abstract val branchConditionText: String
|
||||
}
|
||||
|
||||
// Always must be first in the list
|
||||
object UnknownMissingCase : WhenMissingCase() {
|
||||
override fun toString() = "unknown"
|
||||
|
||||
override val branchConditionText = "else"
|
||||
}
|
||||
|
||||
val List<WhenMissingCase>.hasUnknown: Boolean
|
||||
get() = firstOrNull() == UnknownMissingCase
|
||||
get() = firstOrNull() == WhenMissingCase.Unknown
|
||||
|
||||
private interface WhenExhaustivenessChecker {
|
||||
fun getMissingCases(
|
||||
@@ -65,12 +57,6 @@ private interface WhenExhaustivenessChecker {
|
||||
fun isApplicable(subjectType: KotlinType): Boolean = false
|
||||
}
|
||||
|
||||
object NullMissingCase : WhenMissingCase() {
|
||||
override fun toString() = branchConditionText
|
||||
|
||||
override val branchConditionText = "null"
|
||||
}
|
||||
|
||||
// It's not a regular exhaustiveness checker, invoke it only inside other checkers
|
||||
private object WhenOnNullableExhaustivenessChecker /* : WhenExhaustivenessChecker*/ {
|
||||
fun getMissingCases(expression: KtWhenExpression, context: BindingContext, nullable: Boolean) =
|
||||
@@ -89,15 +75,10 @@ private object WhenOnNullableExhaustivenessChecker /* : WhenExhaustivenessChecke
|
||||
}
|
||||
}
|
||||
}
|
||||
return listOf(NullMissingCase)
|
||||
return listOf(WhenMissingCase.NullIsMissing)
|
||||
}
|
||||
}
|
||||
|
||||
class BooleanMissingCase(val b: Boolean) : WhenMissingCase() {
|
||||
override fun toString() = branchConditionText
|
||||
|
||||
override val branchConditionText = b.toString()
|
||||
}
|
||||
|
||||
private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
|
||||
override fun getMissingCases(
|
||||
@@ -118,8 +99,8 @@ private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
|
||||
}
|
||||
}
|
||||
}
|
||||
return (if (!containsTrue) listOf(BooleanMissingCase(true)) else listOf()) +
|
||||
(if (!containsFalse) listOf(BooleanMissingCase(false)) else listOf()) +
|
||||
return (if (!containsTrue) listOf(WhenMissingCase.BooleanIsMissing.True) else listOf()) +
|
||||
(if (!containsFalse) listOf(WhenMissingCase.BooleanIsMissing.False) else listOf()) +
|
||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
||||
}
|
||||
|
||||
@@ -128,15 +109,6 @@ private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
|
||||
}
|
||||
}
|
||||
|
||||
class ClassMissingCase(val descriptor: ClassDescriptor) : WhenMissingCase() {
|
||||
val classIsSingleton get() = descriptor.kind.isSingleton
|
||||
|
||||
val classFqName get() = DescriptorUtils.getFqNameFromTopLevelClass(descriptor)
|
||||
|
||||
override fun toString() = descriptor.name.identifier.let { if (classIsSingleton) it else "is $it" }
|
||||
|
||||
override val branchConditionText = classFqName.asString().let { if (classIsSingleton) it else "is $it" }
|
||||
}
|
||||
|
||||
internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChecker {
|
||||
private fun getReference(expression: KtExpression?): KtSimpleNameExpression? =
|
||||
@@ -195,7 +167,7 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
||||
context: BindingContext
|
||||
): List<WhenMissingCase> {
|
||||
// when on empty enum / sealed is considered non-exhaustive, see test whenOnEmptySealed
|
||||
if (subclasses.isEmpty()) return listOf(UnknownMissingCase)
|
||||
if (subclasses.isEmpty()) return listOf(WhenMissingCase.Unknown)
|
||||
|
||||
val checkedDescriptors = linkedSetOf<ClassDescriptor>()
|
||||
for (whenEntry in whenExpression.entries) {
|
||||
@@ -219,7 +191,20 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
||||
}
|
||||
}
|
||||
}
|
||||
return (subclasses - checkedDescriptors).map(::ClassMissingCase)
|
||||
return (subclasses - checkedDescriptors).map(::createWhenMissingCaseForClassOrEnum)
|
||||
}
|
||||
|
||||
private fun createWhenMissingCaseForClassOrEnum(classDescriptor: ClassDescriptor): WhenMissingCase {
|
||||
val classId = DescriptorUtils.getClassIdForNonLocalClass(classDescriptor)
|
||||
return if (classDescriptor.kind != ClassKind.ENUM_ENTRY) {
|
||||
WhenMissingCase.IsTypeCheckIsMissing(
|
||||
classId = DescriptorUtils.getClassIdForNonLocalClass(classDescriptor),
|
||||
isSingleton = classDescriptor.kind.isSingleton
|
||||
)
|
||||
} else {
|
||||
val enumClassId = classId.outerClassId ?: error("Enum should have class id")
|
||||
WhenMissingCase.EnumCheckIsMissing(CallableId(enumClassId, classId.shortClassName))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,10 +314,10 @@ object WhenChecker {
|
||||
) = WhenOnSealedExhaustivenessChecker.getMissingCases(expression, context, sealedClassDescriptor, false)
|
||||
|
||||
fun getMissingCases(expression: KtWhenExpression, context: BindingContext): List<WhenMissingCase> {
|
||||
val type = whenSubjectType(expression, context) ?: return listOf(UnknownMissingCase)
|
||||
val type = whenSubjectType(expression, context) ?: return listOf(WhenMissingCase.Unknown)
|
||||
val nullable = type.isMarkedNullable
|
||||
val checkers = exhaustivenessCheckers.filter { it.isApplicable(type) }
|
||||
if (checkers.isEmpty()) return listOf(UnknownMissingCase)
|
||||
if (checkers.isEmpty()) return listOf(WhenMissingCase.Unknown)
|
||||
return checkers.map { it.getMissingCases(expression, context, TypeUtils.getClassDescriptor(type), nullable) }.flatten()
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement;
|
||||
import kotlin.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.cfg.WhenMissingCase;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.config.LanguageVersion;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
|
||||
@@ -23,10 +23,10 @@ import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analyzer.moduleInfo
|
||||
import org.jetbrains.kotlin.analyzer.unwrapPlatform
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.cfg.WhenMissingCase
|
||||
import org.jetbrains.kotlin.cfg.hasUnknown
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.newTable
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.newText
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
Reference in New Issue
Block a user