diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt index d028c3279f6..55068e11849 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt @@ -20,12 +20,14 @@ import com.intellij.lang.ExpressionTypeProvider import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.RenderingFormat import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getType +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory class KotlinExpressionTypeProvider : ExpressionTypeProvider() { private val typeRenderer = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions { @@ -59,11 +61,22 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider() { } } - val expressionType = element.getType(bindingContext) ?: return "Type is unknown" - val result = typeRenderer.renderType(expressionType) + val expressionTypeInfo = bindingContext[BindingContext.EXPRESSION_TYPE_INFO, element] ?: return "Type is unknown" + val expressionType = element.getType(bindingContext) + val result = expressionType?.let { typeRenderer.renderType(it) } ?: return "Type is unknown" + + val dataFlowValue = DataFlowValueFactory.createDataFlowValue(element, expressionType, bindingContext, element.findModuleDescriptor()) + val types = expressionTypeInfo.dataFlowInfo.getStableTypes(dataFlowValue) + if (!types.isEmpty()) { + return types.joinToString(separator = " & ") { typeRenderer.renderType(it) } + " (smart cast from " + result + ")" + } + val smartCast = bindingContext[BindingContext.SMARTCAST, element] - if (smartCast != null) { - return result + " (smart cast)" + if (smartCast != null && element is KtReferenceExpression) { + val declaredType = (bindingContext[BindingContext.REFERENCE_TARGET, element] as? CallableDescriptor)?.returnType + if (declaredType != null) { + return result + " (smart cast from " + typeRenderer.renderType(declaredType) + ")" + } } return result } diff --git a/idea/testData/codeInsight/expressionType/SmartCast.kt b/idea/testData/codeInsight/expressionType/SmartCast.kt index d6d1a1dbd02..f6328b34a14 100644 --- a/idea/testData/codeInsight/expressionType/SmartCast.kt +++ b/idea/testData/codeInsight/expressionType/SmartCast.kt @@ -4,5 +4,5 @@ fun foo(x: Any) { } } -// TYPE: x -> String (smart cast) +// TYPE: x -> String (smart cast from Any) // TYPE: x.length -> Int diff --git a/idea/testData/codeInsight/expressionType/SoftSmartCast.kt b/idea/testData/codeInsight/expressionType/SoftSmartCast.kt new file mode 100644 index 00000000000..dbcd19d7cc0 --- /dev/null +++ b/idea/testData/codeInsight/expressionType/SoftSmartCast.kt @@ -0,0 +1,13 @@ +interface A +interface B : A + +fun fn(value: Any) { + if (value is B) { + if (value is A) { // here + + } + } +} + +// TYPE: value -> B (smart cast from Any) +// TYPE: value is A -> Boolean diff --git a/idea/testData/codeInsight/expressionType/SoftSmartCastMultipleTypes.kt b/idea/testData/codeInsight/expressionType/SoftSmartCastMultipleTypes.kt new file mode 100644 index 00000000000..479538973bc --- /dev/null +++ b/idea/testData/codeInsight/expressionType/SoftSmartCastMultipleTypes.kt @@ -0,0 +1,14 @@ +interface A +interface B + +fun fn(value: Any) { + if (value is B) { + if (value is A) { + println(value) + + } + } +} + +// TYPE: value -> A & B (smart cast from Any) +// TYPE: println(value) -> Unit diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/ExpressionTypeTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/ExpressionTypeTestGenerated.java index 21c5e6a12f6..28db5cb7c57 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/ExpressionTypeTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/ExpressionTypeTestGenerated.java @@ -89,6 +89,12 @@ public class ExpressionTypeTestGenerated extends AbstractExpressionTypeTest { doTest(fileName); } + @TestMetadata("SoftSmartCastMultipleTypes.kt") + public void testSoftSmartCastMultipleTypes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/expressionType/SoftSmartCastMultipleTypes.kt"); + doTest(fileName); + } + @TestMetadata("VariableDeclaration.kt") public void testVariableDeclaration() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/expressionType/VariableDeclaration.kt");