[java-dfa] GetQualifiedValueInstruction (part of IDEA-361818)

GitOrigin-RevId: d8a75de6784cae450640720a89271f88c9c46cb6
This commit is contained in:
Tagir Valeev
2024-11-08 13:00:01 +00:00
committed by intellij-monorepo-bot
parent bace4cfa96
commit 9a5250258f
12 changed files with 144 additions and 58 deletions
@@ -132,7 +132,7 @@ public class CFGBuilder {
*/
@Contract("_ -> this")
public @NotNull CFGBuilder unwrap(@NotNull DerivedVariableDescriptor descriptor) {
return add(new UnwrapDerivedVariableInstruction(descriptor));
return add(new GetQualifiedValueInstruction(descriptor));
}
/**
@@ -540,7 +540,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
length = SpecialField.COLLECTION_SIZE;
}
if (length != null) {
addInstruction(new UnwrapDerivedVariableInstruction(length));
addInstruction(new GetQualifiedValueInstruction(length));
addInstruction(new ConditionalGotoInstruction(loopEndOffset, DfTypes.intValue(0)));
hasSizeCheck = true;
} else {
@@ -875,7 +875,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
DfaControlTransferValue transferValue = exception != null ? createTransfer(exception) : null;
addInstruction(new DupInstruction());
addInstruction(new UnwrapDerivedVariableInstruction(SpecialField.CONSUMED_STREAM));
addInstruction(new GetQualifiedValueInstruction(SpecialField.CONSUMED_STREAM));
addInstruction(new EnsureInstruction(new ConsumedStreamProblem(reference), RelationType.NE, DfStreamStateType.CONSUMED, transferValue));
addInstruction(new PopInstruction());
}
@@ -1900,7 +1900,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
if (TypeConversionUtil.isPrimitiveAndNotNull(expectedType) &&
TypeConversionUtil.isAssignableFromPrimitiveWrapper(toBound(actualType))) {
addInstruction(new UnwrapDerivedVariableInstruction(SpecialField.UNBOX));
addInstruction(new GetQualifiedValueInstruction(SpecialField.UNBOX));
actualType = PsiPrimitiveType.getUnboxedType(actualType);
}
expectedType = toBound(expectedType);
@@ -2487,22 +2487,49 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
@Override public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) {
startElement(expression);
pushReferenceExpression(expression);
addNullCheck(expression);
finishElement(expression);
}
private void pushReferenceExpression(@NotNull PsiReferenceExpression expression) {
JavaExpressionAnchor anchor = new JavaExpressionAnchor(expression);
PsiVariable var = ObjectUtils.tryCast(expression.resolve(), PsiVariable.class);
// complex assignments (e.g. "|=") are both reading and writing
boolean writing = PsiUtil.isAccessedForWriting(expression) && !PsiUtil.isAccessedForReading(expression);
if (!writing && var != null && !PlainDescriptor.hasInitializationHacks(var)) {
DfaValue constValue = JavaDfaValueFactory.getConstantFromVariable(myFactory, var);
if (constValue != null && !JavaDfaValueFactory.maybeUninitializedConstant(constValue, expression, var)) {
addInstruction(new JvmPushInstruction(constValue, anchor));
return;
}
}
final PsiExpression qualifierExpression = expression.getQualifierExpression();
if (var instanceof PsiField field && !field.hasModifierProperty(PsiModifier.STATIC) && !writing) {
DfaValue effectiveQualifier = JavaDfaValueFactory.getQualifierOrThisValue(myFactory, expression);
if (qualifierExpression == null) {
addInstruction(new JvmPushInstruction(effectiveQualifier == null ? myFactory.getUnknown() : effectiveQualifier, null));
} else {
qualifierExpression.accept(this);
}
VariableDescriptor descriptor = Objects.requireNonNull(JavaDfaValueFactory.getAccessedVariableOrGetter(field));
if (effectiveQualifier instanceof DfaVariableValue qualifierVar &&
JavaDfaHelpers.mayLeakFromType(descriptor.getDfType(qualifierVar)) &&
JavaDfaHelpers.mayLeakFromExpression(expression)) {
addInstruction(new EscapeInstruction(List.of(qualifierVar.getDescriptor())));
}
addInstruction(new GetQualifiedValueInstruction(descriptor, anchor));
return;
}
if (qualifierExpression != null && !(qualifierExpression instanceof PsiReferenceExpression ref && ref.resolve() instanceof PsiClass)) {
qualifierExpression.accept(this);
addInstruction(new PopInstruction());
}
// complex assignments (e.g. "|=") are both reading and writing
boolean writing = PsiUtil.isAccessedForWriting(expression) && !PsiUtil.isAccessedForReading(expression);
DfaValue value = JavaDfaValueFactory.getExpressionDfaValue(myFactory, expression);
addInstruction(new JvmPushInstruction(value == null ? myFactory.getUnknown() : value,
writing ? null : new JavaExpressionAnchor(expression),
writing ? null : anchor,
writing));
addNullCheck(expression);
finishElement(expression);
}
@Override public void visitLiteralExpression(@NotNull PsiLiteralExpression expression) {
@@ -13,6 +13,7 @@ import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.codeInspection.dataFlow.value.DfaWrappedValue;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.ig.psiutils.ExpressionUtils;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -73,4 +74,9 @@ public final class JavaDfaHelpers {
}
return (psiType == null ? DfType.TOP : TypeConstraints.exactSubtype(expression, psiType).asDfType()).meet(DfTypes.NOT_NULL_OBJECT);
}
static boolean mayLeakFromExpression(@NotNull PsiExpression expression) {
PsiElement parent = ExpressionUtils.getPassThroughParent(expression);
return !(parent instanceof PsiInstanceOfExpression) && !(parent instanceof PsiPolyadicExpression);
}
}
@@ -184,9 +184,9 @@ public final class JavaDfaValueFactory {
return qualifierValue;
}
private static boolean maybeUninitializedConstant(DfaValue constValue,
@NotNull PsiReferenceExpression refExpr,
PsiModifierListOwner var) {
static boolean maybeUninitializedConstant(DfaValue constValue,
@NotNull PsiReferenceExpression refExpr,
PsiModifierListOwner var) {
// If static final field is referred from the same or inner/nested class,
// we consider that it might be uninitialized yet as some class initializers may call its methods or
// even instantiate objects of this class and call their methods
@@ -252,7 +252,7 @@ public final class JavaDfaValueFactory {
* @return a value that represents a constant created from variable; null if variable cannot be represented as a constant
*/
@Nullable
private static DfaValue getConstantFromVariable(DfaValueFactory factory, PsiVariable variable) {
static DfaValue getConstantFromVariable(DfaValueFactory factory, PsiVariable variable) {
if (!variable.hasModifierProperty(PsiModifier.FINAL) || ignoreInitializer(variable)) return null;
Object value = variable.computeConstantValue();
PsiType type = variable.getType();
@@ -10,10 +10,7 @@ import com.intellij.codeInspection.dataFlow.JavaMethodContractUtil;
import com.intellij.codeInspection.dataFlow.NullabilityUtil;
import com.intellij.codeInspection.dataFlow.jvm.FieldChecker;
import com.intellij.codeInspection.dataFlow.types.DfTypes;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.codeInspection.dataFlow.value.VariableDescriptor;
import com.intellij.codeInspection.dataFlow.value.*;
import com.intellij.psi.*;
import com.intellij.psi.util.*;
import com.intellij.util.JavaPsiConstructorUtil;
@@ -41,7 +38,7 @@ public final class PlainDescriptor extends PsiVarDescriptor {
@NotNull
@Override
public String toString() {
return String.valueOf(myVariable.getName());
return PsiFormatUtil.formatVariable(myVariable, PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME, PsiSubstitutor.EMPTY);
}
@Override
@@ -75,6 +72,12 @@ public final class PlainDescriptor extends PsiVarDescriptor {
(myVariable instanceof PsiField && myVariable.hasModifierProperty(PsiModifier.STATIC))) {
return factory.getVarFactory().createVariableValue(this);
}
if (qualifier instanceof DfaTypeValue typeValue) {
PsiField field = typeValue.getDfType().getConstantOfType(PsiField.class);
if (field != null) {
qualifier = factory.getVarFactory().createVariableValue(new PlainDescriptor(field));
}
}
return super.createValue(factory, qualifier);
}
@@ -64,11 +64,6 @@ public final class ThisDescriptor extends PsiVarDescriptor {
return true;
}
@Override
public boolean isImplicitReadPossible() {
return true;
}
@Override
public int hashCode() {
return Objects.hashCode(myQualifier.getQualifiedName());
@@ -0,0 +1,26 @@
import java.io.IOException;
import java.io.InputStream;
public class GetTernary {
static class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
void test(boolean b, Point p1, Point p2) {
int x = (b ? p1 : p2).x;
if (x == 1) {
if (b && <warning descr="Condition 'p1.x == 1' is always 'true' when reached">p1.x == 1</warning>) {}
}
if (p1.x == 2 && p2.x == 2) {
int x1 = (b ? p1 : p2).x;
if (<warning descr="Condition 'x1 == 2' is always 'true'">x1 == 2</warning>) {
}
}
}
}
@@ -762,4 +762,5 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
public void testFieldAliasing() { doTest();}
public void testFieldLocalNoAliasing() { doTest();}
public void testIoContracts() { doTest(); }
public void testGetTernary() { doTest(); }
}
@@ -1936,6 +1936,12 @@ c:com.intellij.codeInspection.dataFlow.lang.ir.FlushVariableInstruction
- accept(com.intellij.codeInspection.dataFlow.interpreter.DataFlowInterpreter,com.intellij.codeInspection.dataFlow.memory.DfaMemoryState):com.intellij.codeInspection.dataFlow.lang.ir.DfaInstructionState[]
- bindToFactory(com.intellij.codeInspection.dataFlow.value.DfaValueFactory):com.intellij.codeInspection.dataFlow.lang.ir.Instruction
- getVariable():com.intellij.codeInspection.dataFlow.value.DfaVariableValue
c:com.intellij.codeInspection.dataFlow.lang.ir.GetQualifiedValueInstruction
- com.intellij.codeInspection.dataFlow.lang.ir.EvalInstruction
- <init>(com.intellij.codeInspection.dataFlow.value.VariableDescriptor):V
- <init>(com.intellij.codeInspection.dataFlow.value.VariableDescriptor,com.intellij.codeInspection.dataFlow.lang.DfaAnchor):V
- eval(com.intellij.codeInspection.dataFlow.value.DfaValueFactory,com.intellij.codeInspection.dataFlow.memory.DfaMemoryState,com.intellij.codeInspection.dataFlow.value.DfaValue[]):com.intellij.codeInspection.dataFlow.value.DfaValue
- getRequiredDescriptors(com.intellij.codeInspection.dataFlow.value.DfaValueFactory):java.util.List
c:com.intellij.codeInspection.dataFlow.lang.ir.GotoInstruction
- com.intellij.codeInspection.dataFlow.lang.ir.Instruction
- <init>(com.intellij.codeInspection.dataFlow.lang.ir.ControlFlow$ControlFlowOffset):V
@@ -1997,11 +2003,6 @@ c:com.intellij.codeInspection.dataFlow.lang.ir.SwapInstruction
- com.intellij.codeInspection.dataFlow.lang.ir.Instruction
- <init>():V
- accept(com.intellij.codeInspection.dataFlow.interpreter.DataFlowInterpreter,com.intellij.codeInspection.dataFlow.memory.DfaMemoryState):com.intellij.codeInspection.dataFlow.lang.ir.DfaInstructionState[]
c:com.intellij.codeInspection.dataFlow.lang.ir.UnwrapDerivedVariableInstruction
- com.intellij.codeInspection.dataFlow.lang.ir.EvalInstruction
- <init>(com.intellij.codeInspection.dataFlow.value.DerivedVariableDescriptor):V
- eval(com.intellij.codeInspection.dataFlow.value.DfaValueFactory,com.intellij.codeInspection.dataFlow.memory.DfaMemoryState,com.intellij.codeInspection.dataFlow.value.DfaValue[]):com.intellij.codeInspection.dataFlow.value.DfaValue
- getRequiredDescriptors(com.intellij.codeInspection.dataFlow.value.DfaValueFactory):java.util.List
c:com.intellij.codeInspection.dataFlow.lang.ir.WrapDerivedVariableInstruction
- com.intellij.codeInspection.dataFlow.lang.ir.EvalInstruction
- <init>(com.intellij.codeInspection.dataFlow.types.DfType,com.intellij.codeInspection.dataFlow.value.DerivedVariableDescriptor):V
@@ -1,38 +1,43 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInspection.dataFlow.lang.ir;
import com.intellij.codeInspection.dataFlow.lang.DfaAnchor;
import com.intellij.codeInspection.dataFlow.memory.DfaMemoryState;
import com.intellij.codeInspection.dataFlow.value.DerivedVariableDescriptor;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
import com.intellij.codeInspection.dataFlow.value.VariableDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* Instruction to push a field qualified by the value on the stack
*/
public class UnwrapDerivedVariableInstruction extends EvalInstruction {
private final @NotNull DerivedVariableDescriptor myDerivedVariableDescriptor;
public class GetQualifiedValueInstruction extends EvalInstruction {
private final @NotNull VariableDescriptor myDescriptor;
public UnwrapDerivedVariableInstruction(@NotNull DerivedVariableDescriptor derivedVariable) {
super(null, 1);
myDerivedVariableDescriptor = derivedVariable;
public GetQualifiedValueInstruction(@NotNull VariableDescriptor descriptor) {
this(descriptor, null);
}
public GetQualifiedValueInstruction(@NotNull VariableDescriptor descriptor, @Nullable DfaAnchor anchor) {
super(anchor, 1);
myDescriptor = descriptor;
}
@Override
public @NotNull DfaValue eval(@NotNull DfaValueFactory factory, @NotNull DfaMemoryState state, @NotNull DfaValue @NotNull ... arguments) {
return myDerivedVariableDescriptor.createValue(factory, arguments[0]);
return myDescriptor.createValue(factory, arguments[0]);
}
@Override
public List<VariableDescriptor> getRequiredDescriptors(@NotNull DfaValueFactory factory) {
return List.of(myDerivedVariableDescriptor);
return List.of(myDescriptor);
}
@Override
public String toString() {
return "UNWRAP " + myDerivedVariableDescriptor;
return "GET_FIELD " + myDescriptor;
}
}
@@ -349,7 +349,8 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
if (typeReference != null) {
val castType = typeReference.type
if (castType.toDfType() is DfPrimitiveType) {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.UNBOX))
addInstruction(
GetQualifiedValueInstruction(SpecialField.UNBOX))
}
}
}
@@ -515,9 +516,11 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
val leftConstraint = TypeConstraint.fromDfType(leftDfType)
val rightConstraint = TypeConstraint.fromDfType(rightDfType)
if (leftConstraint.isEnum && rightConstraint.isEnum && leftConstraint.meet(rightConstraint) != TypeConstraints.BOTTOM) {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.ENUM_ORDINAL))
addInstruction(
GetQualifiedValueInstruction(SpecialField.ENUM_ORDINAL))
processExpression(right)
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.ENUM_ORDINAL))
addInstruction(
GetQualifiedValueInstruction(SpecialField.ENUM_ORDINAL))
addInstruction(BooleanBinaryInstruction(relation, forceEqualityByContent, KotlinExpressionAnchor(expr)))
} else if (leftConstraint.isExact(CommonClassNames.JAVA_LANG_STRING) &&
rightConstraint.isExact(CommonClassNames.JAVA_LANG_STRING)
@@ -854,7 +857,7 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
if (expression?.getKotlinType()?.canBeNull() == true) {
addInstruction(CheckNotNullInstruction(NullabilityProblemKind.unboxingNullable.problem(expression, null)!!,
trapTracker.maybeTransferValue("java.lang.NullPointerException")))
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.UNBOX))
addInstruction(GetQualifiedValueInstruction(SpecialField.UNBOX))
}
}
@@ -1357,7 +1360,8 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
if (!pushJavaClassField(receiver, selector, expr)) {
val specialField = (selector.mainReference?.resolveToSymbol() as? KaVariableSymbol)?.toSpecialField()
if (specialField != null) {
addInstruction(UnwrapDerivedVariableInstruction(specialField))
addInstruction(
GetQualifiedValueInstruction(specialField))
if (expr is KtSafeQualifiedExpression) {
addInstruction(WrapDerivedVariableInstruction(expr.getKotlinType().toDfType(), SpecialField.UNBOX))
}
@@ -1571,7 +1575,8 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
if (name == "isEmpty" || name == "isNotEmpty") {
val callableId = target.callableId
if (callableId != null && callableId.packageName.asString() == "kotlin.collections") {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.COLLECTION_SIZE))
addInstruction(GetQualifiedValueInstruction(
SpecialField.COLLECTION_SIZE))
addInstruction(PushValueInstruction(DfTypes.intValue(0)))
addInstruction(
BooleanBinaryInstruction(
@@ -1817,7 +1822,7 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
addInstruction(PushValueInstruction(actualDfType))
}
if (actualDfType !is DfPrimitiveType && expectedDfType is DfPrimitiveType) {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.UNBOX))
addInstruction(GetQualifiedValueInstruction(SpecialField.UNBOX))
} else if (expectedDfType !is DfPrimitiveType && actualDfType is DfPrimitiveType) {
val dfType = actualType.withNullability(KaTypeNullability.NULLABLE).toDfType().meet(DfTypes.NOT_NULL_OBJECT)
addInstruction(WrapDerivedVariableInstruction(expectedType.toDfType().meet(dfType), SpecialField.UNBOX))
@@ -40,7 +40,6 @@ import org.jetbrains.kotlin.contracts.description.ContractProviderKey
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveMainReference
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.caches.resolve.safeAnalyzeNonSourceRootCode
import org.jetbrains.kotlin.idea.codeInsight.hints.RangeKtExpressionType.*
@@ -72,7 +71,6 @@ import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.concurrent.ConcurrentHashMap
class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpression) {
@@ -351,7 +349,9 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
if (typeReference != null) {
val castType = typeReference.getAbbreviatedTypeOrType(typeReference.safeAnalyzeNonSourceRootCode(BodyResolveMode.FULL))
if (castType.toDfType() is DfPrimitiveType) {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.UNBOX))
addInstruction(
GetQualifiedValueInstruction(SpecialField.UNBOX)
)
}
}
}
@@ -390,7 +390,9 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
}
if (curType != null && KotlinBuiltIns.isArrayOrPrimitiveArray(curType)) {
if (indexType.canBeNull()) {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.UNBOX))
addInstruction(
GetQualifiedValueInstruction(SpecialField.UNBOX)
)
}
val transfer = trapTracker.maybeTransferValue("kotlin.IndexOutOfBoundsException")
val elementType = expr.builtIns.getArrayElementType(curType)
@@ -407,7 +409,10 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
when {
KotlinBuiltIns.isString(kotlinType) -> {
if (indexType.canBeNull()) {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.UNBOX))
addInstruction(
GetQualifiedValueInstruction(
SpecialField.UNBOX)
)
}
val transfer = trapTracker.maybeTransferValue("kotlin.IndexOutOfBoundsException")
addInstruction(EnsureIndexInBoundsInstruction(KotlinArrayIndexProblem(SpecialField.STRING_LENGTH, idx), transfer))
@@ -419,7 +424,10 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
}
isList(kotlinType) -> {
if (indexType.canBeNull()) {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.UNBOX))
addInstruction(
GetQualifiedValueInstruction(
SpecialField.UNBOX)
)
}
val transfer = trapTracker.maybeTransferValue("kotlin.IndexOutOfBoundsException")
addInstruction(EnsureIndexInBoundsInstruction(KotlinArrayIndexProblem(SpecialField.COLLECTION_SIZE, idx), transfer))
@@ -632,7 +640,10 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
val containingPackage = if (containingDeclaration is PackageFragmentDescriptor) containingDeclaration.fqName
else (containingDeclaration as? ClassDescriptor)?.containingPackage()
if (containingPackage?.asString() == "kotlin.collections") {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.COLLECTION_SIZE))
addInstruction(
GetQualifiedValueInstruction(
SpecialField.COLLECTION_SIZE)
)
addInstruction(PushValueInstruction(DfTypes.intValue(0)))
addInstruction(
BooleanBinaryInstruction(
@@ -816,7 +827,7 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
if (!pushJavaClassField(receiver, selector, expr)) {
val specialField = findSpecialField(expr)
if (specialField != null) {
addInstruction(UnwrapDerivedVariableInstruction(specialField))
addInstruction(GetQualifiedValueInstruction(specialField))
if (expr is KtSafeQualifiedExpression) {
addInstruction(WrapDerivedVariableInstruction(expr.getKotlinType().toDfType(), SpecialField.UNBOX))
}
@@ -1523,7 +1534,7 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
addInstruction(PushValueInstruction(actualDfType))
}
if (actualDfType !is DfPrimitiveType && expectedDfType is DfPrimitiveType) {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.UNBOX))
addInstruction(GetQualifiedValueInstruction(SpecialField.UNBOX))
}
else if (expectedDfType !is DfPrimitiveType && actualDfType is DfPrimitiveType) {
val dfType = actualType.makeNullable().toDfType().meet(DfTypes.NOT_NULL_OBJECT)
@@ -1562,9 +1573,13 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
val leftConstraint = TypeConstraint.fromDfType(leftDfType)
val rightConstraint = TypeConstraint.fromDfType(rightDfType)
if (leftConstraint.isEnum && rightConstraint.isEnum && leftConstraint.meet(rightConstraint) != TypeConstraints.BOTTOM) {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.ENUM_ORDINAL))
addInstruction(
GetQualifiedValueInstruction(SpecialField.ENUM_ORDINAL)
)
processExpression(right)
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.ENUM_ORDINAL))
addInstruction(
GetQualifiedValueInstruction(SpecialField.ENUM_ORDINAL)
)
addInstruction(BooleanBinaryInstruction(relation, forceEqualityByContent, KotlinExpressionAnchor(expr)))
} else if (leftConstraint.isExact(CommonClassNames.JAVA_LANG_STRING) &&
rightConstraint.isExact(CommonClassNames.JAVA_LANG_STRING)) {
@@ -1685,7 +1700,9 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
addImplicitConversion(dfVarType, balancedType)
addInstruction(BooleanBinaryInstruction(RelationType.EQ, true, KotlinWhenConditionAnchor(condition)))
} else if (exprType?.canBeNull() == true) {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.UNBOX))
addInstruction(
GetQualifiedValueInstruction(SpecialField.UNBOX)
)
}
}
is KtWhenConditionIsPattern -> {
@@ -1736,7 +1753,7 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
val condition = ifExpression.condition
processExpression(condition)
if (condition?.getKotlinType()?.canBeNull() == true) {
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.UNBOX))
addInstruction(GetQualifiedValueInstruction(SpecialField.UNBOX))
}
val skipThenOffset = DeferredOffset()
val thenStatement = ifExpression.then