J2K: WhenChecker converted to Kotlin
This commit is contained in:
@@ -14,205 +14,187 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.cfg;
|
package org.jetbrains.kotlin.cfg
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement;
|
|
||||||
import com.intellij.psi.tree.TokenSet;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind;
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality;
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import com.intellij.psi.tree.TokenSet
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils;
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.types.FlexibleTypesKt;
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.types.TypeUtils;
|
import org.jetbrains.kotlin.psi.psiUtil.checkReservedPrefixWord
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
|
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumClass;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumClass
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
|
||||||
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
||||||
|
|
||||||
public final class WhenChecker {
|
object WhenChecker {
|
||||||
private WhenChecker() {
|
|
||||||
|
@JvmStatic
|
||||||
|
fun mustHaveElse(expression: KtWhenExpression, trace: BindingTrace): Boolean {
|
||||||
|
return expression.isUsedAsExpression(trace.bindingContext) && !isWhenExhaustive(expression, trace)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean mustHaveElse(@NotNull KtWhenExpression expression, @NotNull BindingTrace trace) {
|
@JvmStatic
|
||||||
return !BindingContextUtilsKt.isUsedAsStatement(expression, trace.getBindingContext()) && !isWhenExhaustive(expression, trace);
|
fun isWhenByEnum(expression: KtWhenExpression, context: BindingContext): Boolean {
|
||||||
|
return getClassDescriptorOfTypeIfEnum(whenSubjectType(expression, context)) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWhenByEnum(@NotNull KtWhenExpression expression, @NotNull BindingContext context) {
|
@JvmStatic
|
||||||
return getClassDescriptorOfTypeIfEnum(whenSubjectType(expression, context)) != null;
|
fun getClassDescriptorOfTypeIfEnum(type: KotlinType?): ClassDescriptor? {
|
||||||
|
if (type == null) return null
|
||||||
|
val classDescriptor = TypeUtils.getClassDescriptor(type) ?: return null
|
||||||
|
if (classDescriptor.kind != ClassKind.ENUM_CLASS) return null
|
||||||
|
|
||||||
|
return classDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private fun whenSubjectType(expression: KtWhenExpression, context: BindingContext): KotlinType? =
|
||||||
public static ClassDescriptor getClassDescriptorOfTypeIfEnum(@Nullable KotlinType type) {
|
expression.subjectExpression?.let { context.getType(it) } ?: null
|
||||||
if (type == null) return null;
|
|
||||||
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(type);
|
|
||||||
if (classDescriptor == null) return null;
|
|
||||||
if (classDescriptor.getKind() != ClassKind.ENUM_CLASS) return null;
|
|
||||||
|
|
||||||
return classDescriptor;
|
private fun isWhenOnBooleanExhaustive(expression: KtWhenExpression, trace: BindingTrace): Boolean {
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static KotlinType whenSubjectType(@NotNull KtWhenExpression expression, @NotNull BindingContext context) {
|
|
||||||
KtExpression subjectExpression = expression.getSubjectExpression();
|
|
||||||
return subjectExpression == null ? null : context.getType(subjectExpression);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isWhenOnBooleanExhaustive(@NotNull KtWhenExpression expression, @NotNull BindingTrace trace) {
|
|
||||||
// It's assumed (and not checked) that expression is of the boolean type
|
// It's assumed (and not checked) that expression is of the boolean type
|
||||||
boolean containsFalse = false;
|
var containsFalse = false
|
||||||
boolean containsTrue = false;
|
var containsTrue = false
|
||||||
for (KtWhenEntry whenEntry: expression.getEntries()) {
|
for (whenEntry in expression.entries) {
|
||||||
for (KtWhenCondition whenCondition : whenEntry.getConditions()) {
|
for (whenCondition in whenEntry.conditions) {
|
||||||
if (whenCondition instanceof KtWhenConditionWithExpression) {
|
if (whenCondition is KtWhenConditionWithExpression) {
|
||||||
KtExpression whenExpression = ((KtWhenConditionWithExpression) whenCondition).getExpression();
|
val whenExpression = whenCondition.expression
|
||||||
if (CompileTimeConstantUtils.canBeReducedToBooleanConstant(whenExpression, trace, true)) containsTrue = true;
|
if (CompileTimeConstantUtils.canBeReducedToBooleanConstant(whenExpression, trace, true)) containsTrue = true
|
||||||
if (CompileTimeConstantUtils.canBeReducedToBooleanConstant(whenExpression, trace, false)) containsFalse = true;
|
if (CompileTimeConstantUtils.canBeReducedToBooleanConstant(whenExpression, trace, false)) containsFalse = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return containsFalse && containsTrue;
|
return containsFalse && containsTrue
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWhenOnEnumExhaustive(
|
@JvmStatic
|
||||||
@NotNull KtWhenExpression expression,
|
fun isWhenOnEnumExhaustive(
|
||||||
@NotNull BindingTrace trace,
|
expression: KtWhenExpression,
|
||||||
@NotNull ClassDescriptor enumClassDescriptor
|
trace: BindingTrace,
|
||||||
) {
|
enumClassDescriptor: ClassDescriptor): Boolean {
|
||||||
assert isEnumClass(enumClassDescriptor) :
|
assert(isEnumClass(enumClassDescriptor)) { "isWhenOnEnumExhaustive should be called with an enum class descriptor" }
|
||||||
"isWhenOnEnumExhaustive should be called with an enum class descriptor";
|
val entryDescriptors =
|
||||||
Set<ClassDescriptor> entryDescriptors = new HashSet<ClassDescriptor>();
|
DescriptorUtils.getAllDescriptors(enumClassDescriptor.unsubstitutedInnerClassesScope)
|
||||||
for (DeclarationDescriptor descriptor : DescriptorUtils.getAllDescriptors(enumClassDescriptor.getUnsubstitutedInnerClassesScope())) {
|
.filter { isEnumEntry(it) }
|
||||||
if (isEnumEntry(descriptor)) {
|
.filterIsInstance<ClassDescriptor>()
|
||||||
entryDescriptors.add((ClassDescriptor) descriptor);
|
.toSet()
|
||||||
}
|
return !entryDescriptors.isEmpty() && containsAllClassCases(expression, entryDescriptors, trace)
|
||||||
}
|
|
||||||
return !entryDescriptors.isEmpty() && containsAllClassCases(expression, entryDescriptors, trace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void collectNestedSubclasses(
|
private fun collectNestedSubclasses(
|
||||||
@NotNull ClassDescriptor baseDescriptor,
|
baseDescriptor: ClassDescriptor,
|
||||||
@NotNull ClassDescriptor currentDescriptor,
|
currentDescriptor: ClassDescriptor,
|
||||||
@NotNull Set<ClassDescriptor> subclasses
|
subclasses: MutableSet<ClassDescriptor>) {
|
||||||
) {
|
for (descriptor in DescriptorUtils.getAllDescriptors(currentDescriptor.unsubstitutedInnerClassesScope)) {
|
||||||
for (DeclarationDescriptor descriptor : DescriptorUtils.getAllDescriptors(currentDescriptor.getUnsubstitutedInnerClassesScope())) {
|
if (descriptor is ClassDescriptor) {
|
||||||
if (descriptor instanceof ClassDescriptor) {
|
if (DescriptorUtils.isDirectSubclass(descriptor, baseDescriptor)) {
|
||||||
ClassDescriptor memberClassDescriptor = (ClassDescriptor) descriptor;
|
subclasses.add(descriptor)
|
||||||
if (DescriptorUtils.isDirectSubclass(memberClassDescriptor, baseDescriptor)) {
|
|
||||||
subclasses.add(memberClassDescriptor);
|
|
||||||
}
|
}
|
||||||
collectNestedSubclasses(baseDescriptor, memberClassDescriptor, subclasses);
|
collectNestedSubclasses(baseDescriptor, descriptor, subclasses)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isWhenOnSealedClassExhaustive(
|
private fun isWhenOnSealedClassExhaustive(
|
||||||
@NotNull KtWhenExpression expression,
|
expression: KtWhenExpression,
|
||||||
@NotNull BindingTrace trace,
|
trace: BindingTrace,
|
||||||
@NotNull ClassDescriptor classDescriptor
|
classDescriptor: ClassDescriptor): Boolean {
|
||||||
) {
|
assert(classDescriptor.modality === Modality.SEALED) { "isWhenOnSealedClassExhaustive should be called with a sealed class descriptor" }
|
||||||
assert classDescriptor.getModality() == Modality.SEALED :
|
val memberClassDescriptors = HashSet<ClassDescriptor>()
|
||||||
"isWhenOnSealedClassExhaustive should be called with a sealed class descriptor";
|
collectNestedSubclasses(classDescriptor, classDescriptor, memberClassDescriptors)
|
||||||
Set<ClassDescriptor> memberClassDescriptors = new HashSet<ClassDescriptor>();
|
|
||||||
collectNestedSubclasses(classDescriptor, classDescriptor, memberClassDescriptors);
|
|
||||||
// When on a sealed class without derived members is considered non-exhaustive (see test WhenOnEmptySealed)
|
// When on a sealed class without derived members is considered non-exhaustive (see test WhenOnEmptySealed)
|
||||||
return !memberClassDescriptors.isEmpty() && containsAllClassCases(expression, memberClassDescriptors, trace);
|
return !memberClassDescriptors.isEmpty() && containsAllClassCases(expression, memberClassDescriptors, trace)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It's assumed that function is called for a final type. In this case the only possible smart cast is to not nullable type.
|
* It's assumed that function is called for a final type. In this case the only possible smart cast is to not nullable type.
|
||||||
* @return true if type is nullable, and cannot be smart casted
|
* @return true if type is nullable, and cannot be smart casted
|
||||||
*/
|
*/
|
||||||
private static boolean isNullableTypeWithoutPossibleSmartCast(
|
private fun isNullableTypeWithoutPossibleSmartCast(
|
||||||
@Nullable KtExpression expression,
|
expression: KtExpression?,
|
||||||
@NotNull KotlinType type,
|
type: KotlinType,
|
||||||
@NotNull BindingContext context
|
context: BindingContext): Boolean {
|
||||||
) {
|
if (expression == null) return false // Normally should not happen
|
||||||
if (expression == null) return false; // Normally should not happen
|
if (!TypeUtils.isNullableType(type)) return false
|
||||||
if (!TypeUtils.isNullableType(type)) return false;
|
|
||||||
// We cannot read data flow information here due to lack of inputs (module descriptor is necessary)
|
// We cannot read data flow information here due to lack of inputs (module descriptor is necessary)
|
||||||
if (context.get(BindingContext.SMARTCAST, expression) != null) {
|
if (context.get(BindingContext.SMARTCAST, expression) != null) {
|
||||||
// We have smart cast from enum or boolean to something
|
// We have smart cast from enum or boolean to something
|
||||||
// Not very nice but we *can* decide it was smart cast to not-null
|
// Not very nice but we *can* decide it was smart cast to not-null
|
||||||
// because both enum and boolean are final
|
// because both enum and boolean are final
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWhenExhaustive(@NotNull KtWhenExpression expression, @NotNull BindingTrace trace) {
|
@JvmStatic
|
||||||
KotlinType type = whenSubjectType(expression, trace.getBindingContext());
|
fun isWhenExhaustive(expression: KtWhenExpression, trace: BindingTrace): Boolean {
|
||||||
if (type == null) return false;
|
val type = whenSubjectType(expression, trace.bindingContext) ?: return false
|
||||||
ClassDescriptor enumClassDescriptor = getClassDescriptorOfTypeIfEnum(type);
|
val enumClassDescriptor = getClassDescriptorOfTypeIfEnum(type)
|
||||||
|
|
||||||
boolean exhaustive;
|
val exhaustive: Boolean
|
||||||
if (enumClassDescriptor == null) {
|
if (enumClassDescriptor == null) {
|
||||||
if (KotlinBuiltIns.isBoolean(TypeUtils.makeNotNullable(type))) {
|
if (KotlinBuiltIns.isBoolean(TypeUtils.makeNotNullable(type))) {
|
||||||
exhaustive = isWhenOnBooleanExhaustive(expression, trace);
|
exhaustive = isWhenOnBooleanExhaustive(expression, trace)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(type);
|
val classDescriptor = TypeUtils.getClassDescriptor(type)
|
||||||
exhaustive = (classDescriptor != null
|
exhaustive = (classDescriptor != null &&
|
||||||
&& classDescriptor.getModality() == Modality.SEALED
|
classDescriptor.modality === Modality.SEALED &&
|
||||||
&& isWhenOnSealedClassExhaustive(expression, trace, classDescriptor));
|
isWhenOnSealedClassExhaustive(expression, trace, classDescriptor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
exhaustive = isWhenOnEnumExhaustive(expression, trace, enumClassDescriptor);
|
exhaustive = isWhenOnEnumExhaustive(expression, trace, enumClassDescriptor)
|
||||||
}
|
}
|
||||||
if (exhaustive) {
|
if (exhaustive) {
|
||||||
if (// Flexible (nullable) enum types are also counted as exhaustive
|
// Flexible (nullable) enum types are also counted as exhaustive
|
||||||
(enumClassDescriptor != null && FlexibleTypesKt.isFlexible(type))
|
if ((enumClassDescriptor != null && type.isFlexible()) ||
|
||||||
|| containsNullCase(expression, trace)
|
containsNullCase(expression, trace) ||
|
||||||
|| !isNullableTypeWithoutPossibleSmartCast(expression.getSubjectExpression(), type, trace.getBindingContext())) {
|
!isNullableTypeWithoutPossibleSmartCast(expression.subjectExpression, type, trace.bindingContext)) {
|
||||||
|
|
||||||
trace.record(BindingContext.EXHAUSTIVE_WHEN, expression);
|
trace.record(BindingContext.EXHAUSTIVE_WHEN, expression)
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean containsAllClassCases(
|
private fun containsAllClassCases(
|
||||||
@NotNull KtWhenExpression whenExpression,
|
whenExpression: KtWhenExpression,
|
||||||
@NotNull Set<ClassDescriptor> memberDescriptors,
|
memberDescriptors: Set<ClassDescriptor>,
|
||||||
@NotNull BindingTrace trace
|
trace: BindingTrace): Boolean {
|
||||||
) {
|
val checkedDescriptors = HashSet<ClassDescriptor>()
|
||||||
Set<ClassDescriptor> checkedDescriptors = new HashSet<ClassDescriptor>();
|
for (whenEntry in whenExpression.entries) {
|
||||||
for (KtWhenEntry whenEntry : whenExpression.getEntries()) {
|
for (condition in whenEntry.conditions) {
|
||||||
for (KtWhenCondition condition : whenEntry.getConditions()) {
|
var negated = false
|
||||||
boolean negated = false;
|
var checkedDescriptor: ClassDescriptor? = null
|
||||||
ClassDescriptor checkedDescriptor = null;
|
if (condition is KtWhenConditionIsPattern) {
|
||||||
if (condition instanceof KtWhenConditionIsPattern) {
|
val checkedType = trace.get(BindingContext.TYPE, condition.typeReference)
|
||||||
KtWhenConditionIsPattern conditionIsPattern = (KtWhenConditionIsPattern) condition;
|
|
||||||
KotlinType checkedType = trace.get(BindingContext.TYPE, conditionIsPattern.getTypeReference());
|
|
||||||
if (checkedType != null) {
|
if (checkedType != null) {
|
||||||
checkedDescriptor = TypeUtils.getClassDescriptor(checkedType);
|
checkedDescriptor = TypeUtils.getClassDescriptor(checkedType)
|
||||||
}
|
}
|
||||||
negated = conditionIsPattern.isNegated();
|
negated = condition.isNegated
|
||||||
}
|
}
|
||||||
else if (condition instanceof KtWhenConditionWithExpression) {
|
else if (condition is KtWhenConditionWithExpression) {
|
||||||
KtWhenConditionWithExpression conditionWithExpression = (KtWhenConditionWithExpression) condition;
|
if (condition.expression != null) {
|
||||||
if (conditionWithExpression.getExpression() != null) {
|
val reference = getReference(condition.expression)
|
||||||
KtSimpleNameExpression reference = getReference(conditionWithExpression.getExpression());
|
|
||||||
if (reference != null) {
|
if (reference != null) {
|
||||||
DeclarationDescriptor target = trace.get(BindingContext.REFERENCE_TARGET, reference);
|
val target = trace.get(BindingContext.REFERENCE_TARGET, reference)
|
||||||
if (target instanceof ClassDescriptor) {
|
if (target is ClassDescriptor) {
|
||||||
checkedDescriptor = (ClassDescriptor) target;
|
checkedDescriptor = target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,72 +202,72 @@ public final class WhenChecker {
|
|||||||
|
|
||||||
// Checks are important only for nested subclasses of the sealed class
|
// Checks are important only for nested subclasses of the sealed class
|
||||||
// In additional, check without "is" is important only for objects
|
// In additional, check without "is" is important only for objects
|
||||||
if (checkedDescriptor == null
|
if (checkedDescriptor == null ||
|
||||||
|| !memberDescriptors.contains(checkedDescriptor)
|
!memberDescriptors.contains(checkedDescriptor) ||
|
||||||
|| (condition instanceof KtWhenConditionWithExpression
|
(condition is KtWhenConditionWithExpression &&
|
||||||
&& !DescriptorUtils.isObject(checkedDescriptor)
|
!DescriptorUtils.isObject(checkedDescriptor) &&
|
||||||
&& !DescriptorUtils.isEnumEntry(checkedDescriptor))) {
|
!DescriptorUtils.isEnumEntry(checkedDescriptor))) {
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
if (negated) {
|
if (negated) {
|
||||||
if (checkedDescriptors.contains(checkedDescriptor)) return true; // all members are already there
|
if (checkedDescriptors.contains(checkedDescriptor)) return true // all members are already there
|
||||||
checkedDescriptors.addAll(memberDescriptors);
|
checkedDescriptors.addAll(memberDescriptors)
|
||||||
checkedDescriptors.remove(checkedDescriptor);
|
checkedDescriptors.remove(checkedDescriptor)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
checkedDescriptors.add(checkedDescriptor);
|
checkedDescriptors.add(checkedDescriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return checkedDescriptors.containsAll(memberDescriptors);
|
return checkedDescriptors.containsAll(memberDescriptors)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean containsNullCase(@NotNull KtWhenExpression expression, @NotNull BindingTrace trace) {
|
@JvmStatic
|
||||||
for (KtWhenEntry entry : expression.getEntries()) {
|
fun containsNullCase(expression: KtWhenExpression, trace: BindingTrace): Boolean {
|
||||||
for (KtWhenCondition condition : entry.getConditions()) {
|
for (entry in expression.entries) {
|
||||||
if (condition instanceof KtWhenConditionWithExpression) {
|
for (condition in entry.conditions) {
|
||||||
KtWhenConditionWithExpression conditionWithExpression = (KtWhenConditionWithExpression) condition;
|
if (condition is KtWhenConditionWithExpression) {
|
||||||
if (conditionWithExpression.getExpression() != null) {
|
condition.expression?.let {
|
||||||
KotlinType type = trace.getBindingContext().getType(conditionWithExpression.getExpression());
|
val type = trace.bindingContext.getType(it)
|
||||||
if (type != null && KotlinBuiltIns.isNothingOrNullableNothing(type)) {
|
if (type != null && KotlinBuiltIns.isNothingOrNullableNothing(type)) {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private fun getReference(expression: KtExpression?): KtSimpleNameExpression? {
|
||||||
private static KtSimpleNameExpression getReference(@Nullable KtExpression expression) {
|
if (expression is KtSimpleNameExpression) {
|
||||||
if (expression == null) {
|
return expression
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
if (expression instanceof KtSimpleNameExpression) {
|
if (expression is KtQualifiedExpression) {
|
||||||
return (KtSimpleNameExpression) expression;
|
return getReference(expression.selectorExpression)
|
||||||
}
|
}
|
||||||
if (expression instanceof KtQualifiedExpression) {
|
return null
|
||||||
return getReference(((KtQualifiedExpression) expression).getSelectorExpression());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkDeprecatedWhenSyntax(@NotNull BindingTrace trace, @NotNull KtWhenExpression expression) {
|
@JvmStatic
|
||||||
if (expression.getSubjectExpression() != null) return;
|
fun checkDeprecatedWhenSyntax(trace: BindingTrace, expression: KtWhenExpression) {
|
||||||
|
if (expression.subjectExpression != null) return
|
||||||
|
|
||||||
for (KtWhenEntry entry : expression.getEntries()) {
|
for (entry in expression.entries) {
|
||||||
if (entry.isElse()) continue;
|
if (entry.isElse) continue
|
||||||
for (PsiElement child = entry.getFirstChild(); child != null; child = child.getNextSibling()) {
|
var child: PsiElement? = entry.firstChild
|
||||||
if (child.getNode().getElementType() == KtTokens.COMMA) {
|
while (child != null) {
|
||||||
trace.report(Errors.COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT.on(child));
|
if (child.node.elementType === KtTokens.COMMA) {
|
||||||
|
trace.report(Errors.COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT.on(child))
|
||||||
}
|
}
|
||||||
if (child.getNode().getElementType() == KtTokens.ARROW) break;
|
if (child.node.elementType === KtTokens.ARROW) break
|
||||||
|
child = child.nextSibling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkReservedPrefix(@NotNull BindingTrace trace, @NotNull KtWhenExpression expression) {
|
@JvmStatic
|
||||||
KtPsiUtilKt.checkReservedPrefixWord(trace, expression.getWhenKeyword(), "sealed", TokenSet.EMPTY, "sealed when");
|
fun checkReservedPrefix(trace: BindingTrace, expression: KtWhenExpression) {
|
||||||
|
checkReservedPrefixWord(trace, expression.whenKeyword, "sealed", TokenSet.EMPTY, "sealed when")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user