mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 11:50:54 +07:00
[kotlin-dfa] Limited boxing support
GitOrigin-RevId: 5a6824c2921e4ebf4c68437b5e7f3c31e88cc692
This commit is contained in:
committed by
intellij-monorepo-bot
parent
112174f6b2
commit
0111a86d02
@@ -2,6 +2,7 @@
|
||||
package org.jetbrains.kotlin.idea.inspections.dfa
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.java.inst.*
|
||||
import com.intellij.codeInspection.dataFlow.jvm.SpecialField
|
||||
import com.intellij.codeInspection.dataFlow.lang.ir.*
|
||||
import com.intellij.codeInspection.dataFlow.lang.ir.ControlFlow.DeferredOffset
|
||||
import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeBinOp
|
||||
@@ -96,7 +97,7 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
|
||||
processExpression(operand)
|
||||
val anchor = KotlinExpressionAnchor(expr)
|
||||
if (operand != null) {
|
||||
val dfType = operand.getKotlinType().toDfType()
|
||||
val dfType = operand.getKotlinType().toDfType(expr)
|
||||
val descriptor = KtLocalVariableDescriptor.create(operand)
|
||||
val ref = expr.operationReference.text
|
||||
if (dfType is DfIntegralType) {
|
||||
@@ -197,6 +198,9 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
|
||||
val descriptor = KtLocalVariableDescriptor.create(expr)
|
||||
if (descriptor != null) {
|
||||
addInstruction(JvmPushInstruction(descriptor.createValue(factory, null), KotlinExpressionAnchor(expr)))
|
||||
val exprType = expr.getKotlinType()
|
||||
val declaredType = descriptor.variable.type()
|
||||
addImplicitConversion(expr, declaredType, exprType)
|
||||
return
|
||||
}
|
||||
broken = true
|
||||
@@ -217,7 +221,7 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
|
||||
processBinaryRelationExpression(expr, relation, token == KtTokens.EXCLEQ || token == KtTokens.EQEQ)
|
||||
return
|
||||
}
|
||||
val leftType = expr.left?.getKotlinType()?.toDfType() ?: DfType.TOP
|
||||
val leftType = expr.left?.getKotlinType()?.toDfType(expr) ?: DfType.TOP
|
||||
if (leftType is DfIntegralType) {
|
||||
val mathOp = mathOpFromToken(expr.operationReference)
|
||||
if (mathOp != null) {
|
||||
@@ -332,6 +336,13 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
|
||||
if (actualType == expectedType) return
|
||||
val actualPsiType = actualType.toPsiType(expression)
|
||||
val expectedPsiType = expectedType.toPsiType(expression)
|
||||
if (actualType.isMarkedNullable && !expectedType.isMarkedNullable && expectedPsiType is PsiPrimitiveType) {
|
||||
addInstruction(UnwrapDerivedVariableInstruction(SpecialField.UNBOX))
|
||||
}
|
||||
else if (!actualType.isMarkedNullable && expectedType.isMarkedNullable && actualPsiType is PsiPrimitiveType) {
|
||||
addInstruction(WrapDerivedVariableInstruction(
|
||||
expectedType.toDfType(expression).meet(DfTypes.NOT_NULL_OBJECT), SpecialField.UNBOX))
|
||||
}
|
||||
if (actualPsiType is PsiPrimitiveType && expectedPsiType is PsiPrimitiveType) {
|
||||
addInstruction(PrimitiveConversionInstruction(expectedPsiType, null))
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.kotlin.idea.inspections.dfa
|
||||
|
||||
import com.intellij.codeInsight.Nullability
|
||||
import com.intellij.codeInspection.dataFlow.DfaNullability
|
||||
import com.intellij.codeInspection.dataFlow.jvm.SpecialField
|
||||
import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeBinOp
|
||||
import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet
|
||||
import com.intellij.codeInspection.dataFlow.types.DfPrimitiveType
|
||||
import com.intellij.codeInspection.dataFlow.types.DfReferenceType
|
||||
import com.intellij.codeInspection.dataFlow.types.DfType
|
||||
import com.intellij.codeInspection.dataFlow.types.DfTypes
|
||||
import com.intellij.codeInspection.dataFlow.value.RelationType
|
||||
@@ -22,9 +27,21 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
|
||||
internal fun KotlinType?.toDfType() : DfType {
|
||||
internal fun KotlinType?.toDfType(context: PsiElement) : DfType {
|
||||
if (this == null) return DfType.TOP
|
||||
if (isMarkedNullable) {
|
||||
var notNullableType = makeNotNullable().toDfType(context)
|
||||
if (notNullableType is DfPrimitiveType) {
|
||||
notNullableType = SpecialField.UNBOX.asDfType(notNullableType)
|
||||
.meet(DfTypes.typedObject(toPsiType(context), Nullability.UNKNOWN))
|
||||
}
|
||||
return if (notNullableType is DfReferenceType) {
|
||||
notNullableType.dropNullability().meet(DfaNullability.NULLABLE.asDfType())
|
||||
} else {
|
||||
notNullableType
|
||||
}
|
||||
}
|
||||
return when {
|
||||
this == null -> DfType.TOP
|
||||
isBoolean() -> DfTypes.BOOLEAN
|
||||
isByte() -> DfTypes.intRange(LongRangeSet.range(Byte.MIN_VALUE.toLong(), Byte.MAX_VALUE.toLong()))
|
||||
isChar() -> DfTypes.intRange(LongRangeSet.range(Character.MIN_VALUE.toLong(), Character.MAX_VALUE.toLong()))
|
||||
@@ -33,7 +50,7 @@ internal fun KotlinType?.toDfType() : DfType {
|
||||
isLong() -> DfTypes.LONG
|
||||
isFloat() -> DfTypes.FLOAT
|
||||
isDouble() -> DfTypes.DOUBLE
|
||||
else -> DfType.TOP
|
||||
else -> DfTypes.typedObject(toPsiType(context), Nullability.NOT_NULL)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.psi.*
|
||||
class KtLocalVariableDescriptor(val variable : KtCallableDeclaration) : VariableDescriptor {
|
||||
override fun isStable(): Boolean = true
|
||||
|
||||
override fun getDfType(qualifier: DfaVariableValue?): DfType = variable.type().toDfType()
|
||||
override fun getDfType(qualifier: DfaVariableValue?): DfType = variable.type().toDfType(variable)
|
||||
|
||||
override fun createValue(factory: DfaValueFactory, qualifier: DfaValue?): DfaValue {
|
||||
assert(qualifier == null) { "Local variable descriptor should not be qualified, got qualifier '$qualifier'" }
|
||||
|
||||
@@ -4466,6 +4466,21 @@ public abstract class LocalInspectionTestGenerated extends AbstractLocalInspecti
|
||||
runTest("testData/inspectionsLocal/dfa/booleanNot.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("boxing.kt")
|
||||
public void testBoxing() throws Exception {
|
||||
runTest("testData/inspectionsLocal/dfa/boxing.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("boxing2.kt")
|
||||
public void testBoxing2() throws Exception {
|
||||
runTest("testData/inspectionsLocal/dfa/boxing2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("boxing3.kt")
|
||||
public void testBoxing3() throws Exception {
|
||||
runTest("testData/inspectionsLocal/dfa/boxing3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("declaration.kt")
|
||||
public void testDeclaration() throws Exception {
|
||||
runTest("testData/inspectionsLocal/dfa/declaration.kt");
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// PROBLEM: none
|
||||
fun test(x : Int?) {
|
||||
if (x != null && <caret>x > 5) {}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// PROBLEM: Condition is always false
|
||||
// FIX: none
|
||||
fun test(x : Int?) {
|
||||
if (x != null && x > 5 && <caret>x < 3) {}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// PROBLEM: Condition is always false
|
||||
// FIX: none
|
||||
fun test(y : Int) {
|
||||
var x : Int?
|
||||
x = y
|
||||
if (<caret>x == null) {}
|
||||
}
|
||||
Reference in New Issue
Block a user