[kotlin-dfa] KTIJ-35248 False positive: Constant conditions: "Condition is always false" with contract and Number subclass

Box types when processing contracts

GitOrigin-RevId: c09b52b2c2e5d5067ff95923df19372664882437
This commit is contained in:
Tagir Valeev
2025-09-26 13:54:39 +00:00
committed by intellij-monorepo-bot
parent 148ece4eea
commit d83277bb7b
5 changed files with 25 additions and 3 deletions
@@ -131,7 +131,7 @@ class KotlinFunctionCallInstruction(
?.cond(RelationType.equivalence(!isNegated), factory.fromDfType(DfTypes.NULL))
is KaContractIsInstancePredicateExpression -> argument.findDfaValue(callDescriptor, arguments)
?.cond(if (isNegated) RelationType.IS_NOT else RelationType.IS, factory.fromDfType(type.toDfType()))
?.cond(if (isNegated) RelationType.IS_NOT else RelationType.IS, factory.fromDfType(type.toDfReferenceType()))
else -> null
}
@@ -364,8 +364,7 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
if (kotlinType is KaErrorType || kotlinType is KaTypeParameterType) return DfType.TOP
val result = if (kotlinType.isMarkedNullable) kotlinType.toDfType()
else {
// makeNullable to convert primitive to boxed
val dfType = kotlinType.withNullability(true).toDfType().meet(DfTypes.NOT_NULL_OBJECT)
val dfType = kotlinType.toDfReferenceType()
if (dfType is DfReferenceType) dfType.dropSpecialField() else dfType
}
return if (result is DfReferenceType)
@@ -51,6 +51,14 @@ internal fun KaType?.toDfType(): DfType {
return toDfTypeNotNullable()
}
/**
* Convert KaType to DfReferenceType (primitive types are boxed)
*/
context(_: KaSession)
internal fun KaType?.toDfReferenceType(): DfType {
return this?.withNullability(true).toDfType().meet(DfTypes.NOT_NULL_OBJECT)
}
context(_: KaSession)
private fun KaType.toDfTypeNotNullable(): DfType {
return when (this) {
@@ -46,6 +46,7 @@ class K2DataFlowInspectionTest : AbstractK2InspectionTest() {
fun testConstantDivisionByZero() = doTest()
fun testConstantWithDifferentType() = doTest()
fun testContextParameter() = doTest()
fun testContractForNumber() = doTest()
fun testCustomObjectComparisonK2() = doTest()
fun testDestructuringInLoop() = doTest()
fun testDoubleComparison() = doTest()
@@ -0,0 +1,14 @@
// WITH_STDLIB
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
fun foo(number: Number) {
if (myPredicate(number))
println(number)
}
@OptIn(ExperimentalContracts::class)
fun myPredicate(n: Number): Boolean {
contract { returns(true) implies (n is Int) }
return n is Int
}