show detailed smart cast info in "Show expression type" (KT-8803)
This commit is contained in:
@@ -20,12 +20,14 @@ import com.intellij.lang.ExpressionTypeProvider
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
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.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.renderer.RenderingFormat
|
import org.jetbrains.kotlin.renderer.RenderingFormat
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||||
|
|
||||||
class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
|
class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
|
||||||
private val typeRenderer = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions {
|
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 expressionTypeInfo = bindingContext[BindingContext.EXPRESSION_TYPE_INFO, element] ?: return "Type is unknown"
|
||||||
val result = typeRenderer.renderType(expressionType)
|
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]
|
val smartCast = bindingContext[BindingContext.SMARTCAST, element]
|
||||||
if (smartCast != null) {
|
if (smartCast != null && element is KtReferenceExpression) {
|
||||||
return result + " (smart cast)"
|
val declaredType = (bindingContext[BindingContext.REFERENCE_TARGET, element] as? CallableDescriptor)?.returnType
|
||||||
|
if (declaredType != null) {
|
||||||
|
return result + " (smart cast from " + typeRenderer.renderType(declaredType) + ")"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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>
|
// 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);
|
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")
|
@TestMetadata("VariableDeclaration.kt")
|
||||||
public void testVariableDeclaration() throws Exception {
|
public void testVariableDeclaration() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/expressionType/VariableDeclaration.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/expressionType/VariableDeclaration.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user