show type of control statements used as expressions

This commit is contained in:
Dmitry Jemerov
2016-10-04 18:13:26 +02:00
parent 02a5856ffd
commit dbbba45d63
3 changed files with 28 additions and 4 deletions
@@ -29,6 +29,7 @@ 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
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
private val typeRenderer = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.withOptions {
@@ -38,19 +39,28 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
override fun getExpressionsAt(elementAt: PsiElement): List<KtExpression> =
elementAt.parentsWithSelf.filterIsInstance<KtExpression>().filter { it.shouldShowType() }.toList()
private fun KtExpression.shouldShowType() = when(this) {
private fun KtExpression.shouldShowType() = when (this) {
is KtFunctionLiteral -> false
is KtFunction -> !hasBlockBody() && !hasDeclaredReturnType()
is KtProperty -> typeReference == null
is KtPropertyAccessor -> false
is KtDestructuringDeclarationEntry -> true
is KtStatementExpression, is KtDestructuringDeclaration -> false
is KtIfExpression, is KtLoopExpression, is KtWhenExpression, is KtTryExpression -> parent !is KtBlockExpression
is KtIfExpression, is KtWhenExpression, is KtTryExpression -> shouldShowStatementType()
is KtLoopExpression -> false
else -> getQualifiedExpressionForSelector() == null
}
private fun KtExpression.shouldShowStatementType(): Boolean {
if (parent !is KtBlockExpression) return true
if (parent.children.lastOrNull() == this) {
return analyze(BodyResolveMode.PARTIAL)[BindingContext.USED_AS_EXPRESSION, this] ?: false
}
return false
}
override fun getInformationHint(element: KtExpression): String {
val bindingContext = element.analyze()
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
return "<html>${renderExpressionType(element, bindingContext)}</html>"
}
@@ -65,7 +75,7 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
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 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)
@@ -0,0 +1,8 @@
val x = if (flag) {
if (flag2) 1<caret>3 else 7
} else 42
// TYPE: 13 -> <html>Int</html>
// TYPE: if (flag2) 13 else 7 -> <html>Int</html>
// TYPE: if (flag) { if (flag2) 13 else 7 } else 42 -> <html>Int</html>
// TYPE: val x = if (flag) { if (flag2) 13 else 7 } else 42 -> <html>Int</html>
@@ -47,6 +47,12 @@ public class ExpressionTypeTestGenerated extends AbstractExpressionTypeTest {
doTest(fileName);
}
@TestMetadata("IfAsExpressionInsideBlock.kt")
public void testIfAsExpressionInsideBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/expressionType/IfAsExpressionInsideBlock.kt");
doTest(fileName);
}
@TestMetadata("Kt11601.kt")
public void testKt11601() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/expressionType/Kt11601.kt");