show detailed smart cast info in "Show expression type" (KT-8803)

This commit is contained in:
Dmitry Jemerov
2016-08-26 16:34:25 +02:00
parent 2141cd268c
commit 256fd04e95
5 changed files with 51 additions and 5 deletions
@@ -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<KtExpression>() {
private val typeRenderer = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions {
@@ -59,11 +61,22 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
}
}
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
}
+1 -1
View File
@@ -4,5 +4,5 @@ fun foo(x: Any) {
}
}
// TYPE: x -> <html>String (smart cast)</html>
// TYPE: x -> <html>String (smart cast from Any)</html>
// TYPE: x.length -> <html>Int</html>
@@ -0,0 +1,13 @@
interface A
interface B : A
fun fn(value: Any) {
if (value is B) {
if (<caret>value is A) { // here
}
}
}
// TYPE: value -> <html>B (smart cast from Any)</html>
// TYPE: value is A -> <html>Boolean</html>
@@ -0,0 +1,14 @@
interface A
interface B
fun fn(value: Any) {
if (value is B) {
if (value is A) {
println(valu<caret>e)
}
}
}
// TYPE: value -> <html>A & B (smart cast from Any)</html>
// TYPE: println(value) -> <html>Unit</html>
@@ -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");