From 107879a78a7b54143ca27098b9d4c6e6f42c8bc8 Mon Sep 17 00:00:00 2001 From: Vyacheslav Gerasimov Date: Mon, 3 Apr 2017 20:45:03 +0300 Subject: [PATCH] Implement getTypeElement for UastKotlinPsiVariable #KT-16849 Fixed --- .../uast/kotlin/psi/UastKotlinPsiVariable.kt | 65 +++++++++++++------ plugins/uast-kotlin/testData/Elvis.kt | 8 ++- plugins/uast-kotlin/testData/Elvis.log.txt | 25 ++++--- plugins/uast-kotlin/testData/Elvis.render.txt | 13 ++-- .../uast-kotlin/testData/LocalDeclarations.kt | 2 + .../testData/LocalDeclarations.log.txt | 5 ++ .../testData/LocalDeclarations.render.txt | 3 + .../testData/LocalDeclarations.types.txt | 5 ++ .../testData/LocalDeclarations.values.txt | 5 ++ 9 files changed, 91 insertions(+), 40 deletions(-) diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt index 2a574725f59..77cf13e027d 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt @@ -1,17 +1,20 @@ package org.jetbrains.uast.kotlin.psi -import com.intellij.lang.Language import com.intellij.psi.* +import com.intellij.psi.impl.light.LightTypeElement import org.jetbrains.kotlin.asJava.elements.LightVariableBuilder +import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.uast.UDeclaration import org.jetbrains.uast.UElement import org.jetbrains.uast.UastErrorType import org.jetbrains.uast.getParentOfType import org.jetbrains.uast.kotlin.analyze +import org.jetbrains.uast.kotlin.lz import org.jetbrains.uast.kotlin.orAnonymous import org.jetbrains.uast.kotlin.toPsiType @@ -19,28 +22,38 @@ class UastKotlinPsiVariable( manager: PsiManager, name: String, type: PsiType, - language: Language, val ktInitializer: KtExpression?, val psiParent: PsiElement?, val containingElement: UElement, val ktElement: KtElement -) : LightVariableBuilder(manager, name, type, language), PsiLocalVariable { +) : LightVariableBuilder(manager, name, type, KotlinLanguage.INSTANCE), PsiLocalVariable { + + private val psiTypeElement: PsiTypeElement by lz { + LightTypeElement(manager, type) + } + + private val psiInitializer: PsiExpression? by lz { + ktInitializer?.let { KotlinUastPsiExpression(it, containingElement) } + } + override fun getParent() = psiParent override fun hasInitializer() = ktInitializer != null - override fun getInitializer(): PsiExpression? = ktInitializer?.let { KotlinUastPsiExpression(it, containingElement) } - + + override fun getInitializer(): PsiExpression? = psiInitializer + + override fun getTypeElement() = psiTypeElement + + override fun setInitializer(initializer: PsiExpression?) = throw NotImplementedError() + + override fun getContainingFile(): PsiFile? = ktElement.containingFile + override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || other::class.java != this::class.java) return false return ktElement == (other as? UastKotlinPsiVariable)?.ktElement } - override fun getTypeElement() = throw NotImplementedError() - override fun setInitializer(initializer: PsiExpression?) = throw NotImplementedError() - - override fun getContainingFile(): PsiFile? = ktElement.containingFile - override fun hashCode() = ktElement.hashCode() companion object { @@ -55,7 +68,6 @@ class UastKotlinPsiVariable( declaration.manager, declaration.name.orAnonymous("unnamed"), declaration.typeReference.toPsiType(containingElement), - KotlinLanguage.INSTANCE, initializer ?: declaration.initializer, psiParent, containingElement, @@ -67,8 +79,7 @@ class UastKotlinPsiVariable( return UastKotlinPsiVariable( declaration.manager, "var" + Integer.toHexString(declaration.getHashCode()), - UastErrorType, //TODO, - KotlinLanguage.INSTANCE, + declaration.initializer?.getType(containingElement) ?: UastErrorType, declaration.initializer, psiParent, containingElement, @@ -80,8 +91,7 @@ class UastKotlinPsiVariable( return UastKotlinPsiVariable( initializer.manager, "var" + Integer.toHexString(initializer.getHashCode()), - UastErrorType, //TODO, - KotlinLanguage.INSTANCE, + initializer.getType(containingElement) ?: UastErrorType, initializer, psiParent, containingElement, @@ -93,8 +103,7 @@ class UastKotlinPsiVariable( return UastKotlinPsiVariable( localFunction.manager, name, - UastErrorType, // TODO, - KotlinLanguage.INSTANCE, + localFunction.getFunctionType(containingElement) ?: UastErrorType, localFunction, psiParent, containingElement, @@ -104,12 +113,26 @@ class UastKotlinPsiVariable( } private class KotlinUastPsiExpression(val ktExpression: KtExpression, val parent: UElement) : PsiElement by ktExpression, PsiExpression { - override fun getType(): PsiType? { - val ktType = ktExpression.analyze()[BindingContext.EXPRESSION_TYPE_INFO, ktExpression]?.type ?: return null - return ktType.toPsiType(parent, ktExpression, boxed = false) - } + override fun getType(): PsiType? = ktExpression.getType(parent) } +private fun KtFunction.getFunctionType(parent: UElement): PsiType? { + val descriptor = analyze()[BindingContext.FUNCTION, this] ?: return null + val returnType = descriptor.returnType ?: return null + + return createFunctionType( + descriptor.builtIns, + descriptor.annotations, + descriptor.extensionReceiverParameter?.type, + descriptor.valueParameters.map { it.type }, + descriptor.valueParameters.map { it.name }, + returnType + ).toPsiType(parent, this, boxed = false) +} + +private fun KtExpression.getType(parent: UElement): PsiType? = + analyze()[BindingContext.EXPRESSION_TYPE_INFO, this]?.type?.toPsiType(parent, this, boxed = false) + private fun PsiElement.getHashCode(): Int { var result = 42 result = 41 * result + containingFile.name.hashCode() diff --git a/plugins/uast-kotlin/testData/Elvis.kt b/plugins/uast-kotlin/testData/Elvis.kt index c2e32cefc8a..17c55b2ec7f 100644 --- a/plugins/uast-kotlin/testData/Elvis.kt +++ b/plugins/uast-kotlin/testData/Elvis.kt @@ -1,6 +1,8 @@ -fun foo(bar: String): Any? = null +fun foo(bar: String): String? = null -fun baz(): Any? { - return foo("Lorem ipsum") ?: foo("dolor sit amet") ?: foo("consectetuer adipiscing elit") +fun bar() = 42 + +fun baz(): String? { + return foo("Lorem ipsum") ?: foo("dolor sit amet") ?: bar().toString() } \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/Elvis.log.txt b/plugins/uast-kotlin/testData/Elvis.log.txt index 59e5fb4442e..ae0dd88b8df 100644 --- a/plugins/uast-kotlin/testData/Elvis.log.txt +++ b/plugins/uast-kotlin/testData/Elvis.log.txt @@ -4,34 +4,39 @@ UFile (package = ) UParameter (name = bar) UAnnotation (fqName = org.jetbrains.annotations.NotNull) ULiteralExpression (value = null) + UAnnotationMethod (name = bar) + ULiteralExpression (value = 42) UAnnotationMethod (name = baz) UBlockExpression UReturnExpression UExpressionList (elvis) UDeclarationsExpression - ULocalVariable (name = var243c4e1a) + ULocalVariable (name = var243c51a0) UExpressionList (elvis) UDeclarationsExpression - ULocalVariable (name = varc4aef1e3) + ULocalVariable (name = varc4aef569) UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) UIdentifier (Identifier (foo)) USimpleNameReferenceExpression (identifier = foo) ULiteralExpression (value = "Lorem ipsum") UIfExpression UBinaryExpression (operator = !=) - USimpleNameReferenceExpression (identifier = varc4aef1e3) + USimpleNameReferenceExpression (identifier = varc4aef569) ULiteralExpression (value = null) - USimpleNameReferenceExpression (identifier = varc4aef1e3) + USimpleNameReferenceExpression (identifier = varc4aef569) UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) UIdentifier (Identifier (foo)) USimpleNameReferenceExpression (identifier = foo) ULiteralExpression (value = "dolor sit amet") UIfExpression UBinaryExpression (operator = !=) - USimpleNameReferenceExpression (identifier = var243c4e1a) + USimpleNameReferenceExpression (identifier = var243c51a0) ULiteralExpression (value = null) - USimpleNameReferenceExpression (identifier = var243c4e1a) - UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) - UIdentifier (Identifier (foo)) - USimpleNameReferenceExpression (identifier = foo) - ULiteralExpression (value = "consectetuer adipiscing elit") + USimpleNameReferenceExpression (identifier = var243c51a0) + UQualifiedReferenceExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (bar)) + USimpleNameReferenceExpression (identifier = bar) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString) diff --git a/plugins/uast-kotlin/testData/Elvis.render.txt b/plugins/uast-kotlin/testData/Elvis.render.txt index 466d2c1385e..558f74c7731 100644 --- a/plugins/uast-kotlin/testData/Elvis.render.txt +++ b/plugins/uast-kotlin/testData/Elvis.render.txt @@ -1,12 +1,13 @@ public final class ElvisKt { - public static final fun foo(bar: java.lang.String) : java.lang.Object = null - public static final fun baz() : java.lang.Object { + public static final fun foo(bar: java.lang.String) : java.lang.String = null + public static final fun bar() : int = 42 + public static final fun baz() : java.lang.String { return elvis { - var var243c4e1a: = elvis { - var varc4aef1e3: = foo("Lorem ipsum") - if (varc4aef1e3 != null) varc4aef1e3 else foo("dolor sit amet") + var var243c51a0: java.lang.String = elvis { + var varc4aef569: java.lang.String = foo("Lorem ipsum") + if (varc4aef569 != null) varc4aef569 else foo("dolor sit amet") } - if (var243c4e1a != null) var243c4e1a else foo("consectetuer adipiscing elit") + if (var243c51a0 != null) var243c51a0 else bar().toString() } } } diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.kt b/plugins/uast-kotlin/testData/LocalDeclarations.kt index 8b4531f0209..ff45265e296 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.kt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.kt @@ -6,5 +6,7 @@ fun foo(): Boolean { Local() } + fun Int.someLocalFun(text: String) = 42 + return bar() == Local() } \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.log.txt b/plugins/uast-kotlin/testData/LocalDeclarations.log.txt index 87775b574ab..9dadf83072a 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.log.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.log.txt @@ -18,6 +18,11 @@ UFile (package = ) UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) UIdentifier (Identifier (Local)) USimpleNameReferenceExpression (identifier = ) + UDeclarationsExpression + UVariable (name = someLocalFun) + ULambdaExpression + UParameter (name = text) + ULiteralExpression (value = 42) UReturnExpression UBinaryExpression (operator = ==) UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.render.txt b/plugins/uast-kotlin/testData/LocalDeclarations.render.txt index e7e1c8e6be2..2238de1dfae 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.render.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.render.txt @@ -9,6 +9,9 @@ public final class LocalDeclarationsKt { var baz: = fun () { () } + var someLocalFun: kotlin.jvm.functions.Function2 = fun (var text: java.lang.String) { + 42 + } return bar() == () } } diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.types.txt b/plugins/uast-kotlin/testData/LocalDeclarations.types.txt index 631652d4a77..83d11248efa 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.types.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.types.txt @@ -18,6 +18,11 @@ UFile (package = ) [public final class LocalDeclarationsKt {...] UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] : PsiType: UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] USimpleNameReferenceExpression (identifier = ) [] : PsiType: + UDeclarationsExpression [var someLocalFun: kotlin.jvm.functions.Function2 = fun (var text: java.lang.String) {...}] + UVariable (name = someLocalFun) [var someLocalFun: kotlin.jvm.functions.Function2 = fun (var text: java.lang.String) {...}] + ULambdaExpression [fun (var text: java.lang.String) {...}] + UParameter (name = text) [var text: java.lang.String] + ULiteralExpression (value = 42) [42] : PsiType:int UReturnExpression [return bar() == ()] : PsiType:Void UBinaryExpression (operator = ==) [bar() == ()] : PsiType:boolean UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) [bar()] : PsiType: diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.values.txt b/plugins/uast-kotlin/testData/LocalDeclarations.values.txt index f7cc9eaac37..37d52bcf6c1 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.values.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.values.txt @@ -18,6 +18,11 @@ UFile (package = ) [public final class LocalDeclarationsKt {...] UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] = external ()() UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] USimpleNameReferenceExpression (identifier = ) [] = external () + UDeclarationsExpression [var someLocalFun: kotlin.jvm.functions.Function2 = fun (var text: java.lang.String) {...}] = Undetermined + UVariable (name = someLocalFun) [var someLocalFun: kotlin.jvm.functions.Function2 = fun (var text: java.lang.String) {...}] + ULambdaExpression [fun (var text: java.lang.String) {...}] = Undetermined + UParameter (name = text) [var text: java.lang.String] + ULiteralExpression (value = 42) [42] = 42 UReturnExpression [return bar() == ()] = Nothing UBinaryExpression (operator = ==) [bar() == ()] = Undetermined UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) [bar()] = external bar()()