UAST: Fix getType and getText for UastKotlinPsiVariable

This commit is contained in:
Vyacheslav Gerasimov
2017-09-13 20:16:47 +03:00
parent 14742a6048
commit bba2d27e82
12 changed files with 141 additions and 50 deletions
@@ -4,12 +4,13 @@ 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.descriptors.CallableDescriptor
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.kotlin.utils.ifEmpty
import org.jetbrains.kotlin.types.isError
import org.jetbrains.uast.UDeclaration
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UastErrorType
@@ -19,24 +20,35 @@ import org.jetbrains.uast.kotlin.lz
import org.jetbrains.uast.kotlin.orAnonymous
import org.jetbrains.uast.kotlin.toPsiType
class UastKotlinPsiVariable(
class UastKotlinPsiVariable private constructor(
manager: PsiManager,
name: String,
type: PsiType,
typeProducer: () -> PsiType,
val ktInitializer: KtExpression?,
val psiParent: PsiElement?,
val containingElement: UElement,
val ktElement: KtElement
) : LightVariableBuilder(manager, name, type, KotlinLanguage.INSTANCE), PsiLocalVariable {
) : LightVariableBuilder(
manager,
name,
UastErrorType, // Type is calculated lazily
KotlinLanguage.INSTANCE
), PsiLocalVariable {
private val psiType: PsiType by lz(typeProducer)
private val psiTypeElement: PsiTypeElement by lz {
LightTypeElement(manager, type)
LightTypeElement(manager, psiType)
}
private val psiInitializer: PsiExpression? by lz {
ktInitializer?.let { KotlinUastPsiExpression(it, containingElement) }
}
override fun getType(): PsiType = psiType
override fun getText(): String = ktElement.text
override fun getParent() = psiParent
override fun hasInitializer() = ktInitializer != null
@@ -61,54 +73,55 @@ class UastKotlinPsiVariable(
fun create(
declaration: KtVariableDeclaration,
parent: PsiElement?,
containingElement: UElement,
containingElement: UElement,
initializer: KtExpression? = null
): PsiLocalVariable {
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: parent
val initializerExpression = initializer ?: declaration.initializer
return UastKotlinPsiVariable(
declaration.manager,
declaration.name.orAnonymous("unnamed"),
declaration.typeReference.toPsiType(containingElement),
initializer ?: declaration.initializer,
psiParent,
containingElement,
declaration)
manager = declaration.manager,
name = declaration.name.orAnonymous("<unnamed>"),
typeProducer = { declaration.getType(containingElement) ?: UastErrorType },
ktInitializer = initializerExpression,
psiParent = psiParent,
containingElement = containingElement,
ktElement = declaration)
}
fun create(declaration: KtDestructuringDeclaration, containingElement: UElement): PsiLocalVariable {
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: declaration.parent
return UastKotlinPsiVariable(
declaration.manager,
"var" + Integer.toHexString(declaration.getHashCode()),
declaration.initializer?.getType(containingElement) ?: UastErrorType,
declaration.initializer,
psiParent,
containingElement,
declaration)
manager = declaration.manager,
name = "var" + Integer.toHexString(declaration.getHashCode()),
typeProducer = { declaration.getType(containingElement) ?: UastErrorType },
ktInitializer = declaration.initializer,
psiParent = psiParent,
containingElement = containingElement,
ktElement = declaration)
}
fun create(initializer: KtExpression, containingElement: UElement, parent: PsiElement): PsiLocalVariable {
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: parent
return UastKotlinPsiVariable(
initializer.manager,
"var" + Integer.toHexString(initializer.getHashCode()),
initializer.getType(containingElement) ?: UastErrorType,
initializer,
psiParent,
containingElement,
initializer)
manager = initializer.manager,
name = "var" + Integer.toHexString(initializer.getHashCode()),
typeProducer = { initializer.getType(containingElement) ?: UastErrorType },
ktInitializer = initializer,
psiParent = psiParent,
containingElement = containingElement,
ktElement = initializer)
}
fun create(name: String, localFunction: KtFunction, containingElement: UElement): PsiLocalVariable {
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: localFunction.parent
return UastKotlinPsiVariable(
localFunction.manager,
name,
localFunction.getFunctionType(containingElement) ?: UastErrorType,
localFunction,
psiParent,
containingElement,
localFunction)
manager = localFunction.manager,
name = name,
typeProducer = { localFunction.getFunctionType(containingElement) ?: UastErrorType },
ktInitializer = localFunction,
psiParent = psiParent,
containingElement = containingElement,
ktElement = localFunction)
}
}
}
@@ -122,18 +135,25 @@ private fun KtFunction.getFunctionType(parent: UElement): PsiType? {
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
builtIns = descriptor.builtIns,
annotations = descriptor.annotations,
receiverType = descriptor.extensionReceiverParameter?.type,
parameterTypes = descriptor.valueParameters.map { it.type },
parameterNames = descriptor.valueParameters.map { it.name },
returnType = 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 KtDeclaration.getType(parent: UElement): PsiType? {
return (analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? CallableDescriptor)
?.returnType
?.takeIf { !it.isError }
?.toPsiType(parent, this, false)
}
private fun PsiElement.getHashCode(): Int {
var result = 42
result = 41 * result + containingFile.name.hashCode()
+4 -4
View File
@@ -2,11 +2,11 @@ UFile (package = ) [public final class InKt {...]
UClass (name = InKt) [public final class InKt {...}]
UAnnotationMethod (name = foo) [public static final fun foo() : boolean {...}]
UBlockExpression [{...}] = Nothing
UDeclarationsExpression [var x: <ErrorType> = 1] = Undetermined
ULocalVariable (name = x) [var x: <ErrorType> = 1]
UDeclarationsExpression [var x: int = 1] = Undetermined
ULocalVariable (name = x) [var x: int = 1]
ULiteralExpression (value = 1) [1] = 1
UDeclarationsExpression [var y: <ErrorType> = 10] = Undetermined
ULocalVariable (name = y) [var y: <ErrorType> = 10]
UDeclarationsExpression [var y: int = 10] = Undetermined
ULocalVariable (name = y) [var y: int = 10]
ULiteralExpression (value = 10) [10] = 10
UReturnExpression [return x in 0 .. 5 && y !in 4 .. 9] = Nothing
UBinaryExpression (operator = &&) [x in 0 .. 5 && y !in 4 .. 9] = true (depending on: (var x = 1), (var y = 10))
+1 -1
View File
@@ -6,7 +6,7 @@ public final class LocalDeclarationsKt {
var bar: <ErrorType> = fun () {
<init>()
}
var baz: <ErrorType> = fun () {
var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {
<init>()
}
var someLocalFun: kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.String,? extends java.lang.Integer> = fun (var text: java.lang.String) {
+2 -2
View File
@@ -11,8 +11,8 @@ UFile (package = ) [public final class LocalDeclarationsKt {...]
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] : PsiType:<ErrorType>
UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))]
USimpleNameReferenceExpression (identifier = <init>) [<init>] : PsiType:<ErrorType>
UDeclarationsExpression [var baz: <ErrorType> = fun () {...}]
ULocalVariable (name = baz) [var baz: <ErrorType> = fun () {...}]
UDeclarationsExpression [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}]
ULocalVariable (name = baz) [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}]
ULambdaExpression [fun () {...}]
UBlockExpression [{...}] : PsiType:<ErrorType>
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] : PsiType:<ErrorType>
+2 -2
View File
@@ -11,8 +11,8 @@ UFile (package = ) [public final class LocalDeclarationsKt {...]
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] = external <init>()()
UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))]
USimpleNameReferenceExpression (identifier = <init>) [<init>] = external <init>()()
UDeclarationsExpression [var baz: <ErrorType> = fun () {...}] = Undetermined
ULocalVariable (name = baz) [var baz: <ErrorType> = fun () {...}]
UDeclarationsExpression [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}] = Undetermined
ULocalVariable (name = baz) [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}]
ULambdaExpression [fun () {...}] = Undetermined
UBlockExpression [{...}] = external <init>()()
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] = external <init>()()
@@ -0,0 +1,27 @@
UFile (package = )
UClass (name = MyAnnotation)
UClass (name = Test1)
UField (name = bar)
UAnnotation (fqName = null)
UAnnotationMethod (name = getBar)
UAnnotationMethod (name = setBar)
UParameter (name = p)
UAnnotation (fqName = null)
UAnnotationMethod (name = Test1)
UParameter (name = bar)
UAnnotation (fqName = MyAnnotation)
UAnnotation (fqName = null)
UClass (name = Test2)
UField (name = bar)
UAnnotation (fqName = MyAnnotation)
UAnnotation (fqName = null)
UAnnotationMethod (name = getBar)
UAnnotation (fqName = MyAnnotation)
UAnnotationMethod (name = setBar)
UAnnotation (fqName = MyAnnotation)
UParameter (name = p)
UAnnotation (fqName = MyAnnotation)
UAnnotation (fqName = null)
UAnnotationMethod (name = Test2)
UParameter (name = bar)
UAnnotation (fqName = null)
@@ -0,0 +1,18 @@
public abstract annotation MyAnnotation {
}
public final class Test1 {
private var bar: int
public final fun getBar() : int = UastEmptyExpression
public final fun setBar(p: int) : void = UastEmptyExpression
public fun Test1(bar: int) = UastEmptyExpression
}
public final class Test2 {
private var bar: int
@MyAnnotation
public final fun getBar() : int = UastEmptyExpression
@MyAnnotation
public final fun setBar(p: int) : void = UastEmptyExpression
public fun Test2(bar: int) = UastEmptyExpression
}
@@ -0,0 +1,4 @@
fun foo(a: Int, b: String, c: Int = 0, flag: Boolean = false) {
}
@@ -0,0 +1,14 @@
UFile (package = )
UClass (name = ParametersWithDefaultValuesKt)
UAnnotationMethod (name = foo)
UParameter (name = a)
UAnnotation (fqName = null)
UParameter (name = b)
UAnnotation (fqName = org.jetbrains.annotations.NotNull)
UParameter (name = c)
UAnnotation (fqName = null)
ULiteralExpression (value = 0)
UParameter (name = flag)
UAnnotation (fqName = null)
ULiteralExpression (value = false)
UBlockExpression
@@ -0,0 +1,4 @@
public final class ParametersWithDefaultValuesKt {
public static final fun foo(a: int, b: java.lang.String, c: int, flag: boolean) : void {
}
}
+1 -1
View File
@@ -2,6 +2,6 @@ public final class PropertyDelegateKt {
private static final var sdCardPath$delegate: kotlin.Lazy
public static final fun getSdCardPath() : java.lang.String = UastEmptyExpression
public static final fun localPropertyTest() : void {
var sdCardPathLocal: <ErrorType>
var sdCardPathLocal: java.lang.String
}
}
@@ -34,4 +34,8 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() {
@Test fun testInnerClasses() = doTest("InnerClasses")
@Test fun testSimpleScript() = doTest("SimpleScript")
@Test fun testParameterPropertyWithAnnotation() = doTest("ParameterPropertyWithAnnotation")
@Test fun testParametersWithDefaultValues() = doTest("ParametersWithDefaultValues")
}