diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt index d30321e40f6..5387623a7da 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getType -import org.jetbrains.kotlin.types.KotlinType class KotlinExpressionTypeProvider : ExpressionTypeProvider() { override fun getExpressionsAt(elementAt: PsiElement): List = @@ -39,27 +38,27 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider() { } override fun getInformationHint(element: KtExpression): String { - val type = typeByExpression(element) ?: return "Type is unknown" - return renderTypeHint(type) + val bindingContext = element.analyze() + + return "${renderExpressionType(element, bindingContext)}" + } + + private fun renderExpressionType(element: KtExpression, bindingContext: BindingContext): String { + if (element is KtCallableDeclaration) { + val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? CallableDescriptor + if (descriptor != null) { + return descriptor.returnType?.let { DescriptorRenderer.HTML.renderType(it) } ?: "Type is unknown" + } + } + + val expressionType = element.getType(bindingContext) ?: return "Type is unknown" + val result = DescriptorRenderer.HTML.renderType(expressionType) + val smartCast = bindingContext[BindingContext.SMARTCAST, element] + if (smartCast != null) { + return result + " (smart cast)" + } + return result } override fun getErrorHint(): String = "No expression found" - - companion object { - fun renderTypeHint(type: KotlinType) = "" + DescriptorRenderer.HTML.renderType(type) + "" - - fun typeByExpression(expression: KtExpression): KotlinType? { - val bindingContext = expression.analyze() - - if (expression is KtCallableDeclaration) { - val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, expression] as? CallableDescriptor - if (descriptor != null) { - return descriptor.returnType - } - } - - return expression.getType(bindingContext) - } - } } - diff --git a/idea/testData/codeInsight/expressionType/SmartCast.kt b/idea/testData/codeInsight/expressionType/SmartCast.kt new file mode 100644 index 00000000000..6f5404f67b4 --- /dev/null +++ b/idea/testData/codeInsight/expressionType/SmartCast.kt @@ -0,0 +1,9 @@ +fun foo(x: Any) { + if (x is String) { + x.length + } +} + +// TYPE: if (x is String) { x.length } -> kotlin.Unit +// TYPE: x -> kotlin.String (smart cast) +// TYPE: x.length -> kotlin.Int diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractExpressionTypeTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractExpressionTypeTest.kt index bdafaeb50e4..8779779de1c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractExpressionTypeTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractExpressionTypeTest.kt @@ -29,7 +29,8 @@ abstract class AbstractExpressionTypeTest : KotlinLightCodeInsightFixtureTestCas protected fun doTest(path: String) { myFixture.configureByFile(path) val expressionTypeProvider = KotlinExpressionTypeProvider() - val expressions = expressionTypeProvider.getExpressionsAt(myFixture.elementAtCaret) + val elementAtCaret = myFixture.file.findElementAt(myFixture.editor.caretModel.offset)!! + val expressions = expressionTypeProvider.getExpressionsAt(elementAtCaret) val types = expressions.map { "${it.text.replace('\n', ' ')} -> ${expressionTypeProvider.getInformationHint(it)}" } val expectedTypes = InTextDirectivesUtils.findLinesWithPrefixesRemoved(myFixture.file.text, "// TYPE: ") UsefulTestCase.assertOrderedEquals(types, expectedTypes)