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 com.intellij.psi.impl.light.LightTypeElement
import org.jetbrains.kotlin.asJava.elements.LightVariableBuilder import org.jetbrains.kotlin.asJava.elements.LightVariableBuilder
import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns 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.UDeclaration
import org.jetbrains.uast.UElement import org.jetbrains.uast.UElement
import org.jetbrains.uast.UastErrorType 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.orAnonymous
import org.jetbrains.uast.kotlin.toPsiType import org.jetbrains.uast.kotlin.toPsiType
class UastKotlinPsiVariable( class UastKotlinPsiVariable private constructor(
manager: PsiManager, manager: PsiManager,
name: String, name: String,
type: PsiType, typeProducer: () -> PsiType,
val ktInitializer: KtExpression?, val ktInitializer: KtExpression?,
val psiParent: PsiElement?, val psiParent: PsiElement?,
val containingElement: UElement, val containingElement: UElement,
val ktElement: KtElement 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 { private val psiTypeElement: PsiTypeElement by lz {
LightTypeElement(manager, type) LightTypeElement(manager, psiType)
} }
private val psiInitializer: PsiExpression? by lz { private val psiInitializer: PsiExpression? by lz {
ktInitializer?.let { KotlinUastPsiExpression(it, containingElement) } ktInitializer?.let { KotlinUastPsiExpression(it, containingElement) }
} }
override fun getType(): PsiType = psiType
override fun getText(): String = ktElement.text
override fun getParent() = psiParent override fun getParent() = psiParent
override fun hasInitializer() = ktInitializer != null override fun hasInitializer() = ktInitializer != null
@@ -61,54 +73,55 @@ class UastKotlinPsiVariable(
fun create( fun create(
declaration: KtVariableDeclaration, declaration: KtVariableDeclaration,
parent: PsiElement?, parent: PsiElement?,
containingElement: UElement, containingElement: UElement,
initializer: KtExpression? = null initializer: KtExpression? = null
): PsiLocalVariable { ): PsiLocalVariable {
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: parent val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: parent
val initializerExpression = initializer ?: declaration.initializer
return UastKotlinPsiVariable( return UastKotlinPsiVariable(
declaration.manager, manager = declaration.manager,
declaration.name.orAnonymous("unnamed"), name = declaration.name.orAnonymous("<unnamed>"),
declaration.typeReference.toPsiType(containingElement), typeProducer = { declaration.getType(containingElement) ?: UastErrorType },
initializer ?: declaration.initializer, ktInitializer = initializerExpression,
psiParent, psiParent = psiParent,
containingElement, containingElement = containingElement,
declaration) ktElement = declaration)
} }
fun create(declaration: KtDestructuringDeclaration, containingElement: UElement): PsiLocalVariable { fun create(declaration: KtDestructuringDeclaration, containingElement: UElement): PsiLocalVariable {
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: declaration.parent val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: declaration.parent
return UastKotlinPsiVariable( return UastKotlinPsiVariable(
declaration.manager, manager = declaration.manager,
"var" + Integer.toHexString(declaration.getHashCode()), name = "var" + Integer.toHexString(declaration.getHashCode()),
declaration.initializer?.getType(containingElement) ?: UastErrorType, typeProducer = { declaration.getType(containingElement) ?: UastErrorType },
declaration.initializer, ktInitializer = declaration.initializer,
psiParent, psiParent = psiParent,
containingElement, containingElement = containingElement,
declaration) ktElement = declaration)
} }
fun create(initializer: KtExpression, containingElement: UElement, parent: PsiElement): PsiLocalVariable { fun create(initializer: KtExpression, containingElement: UElement, parent: PsiElement): PsiLocalVariable {
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: parent val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: parent
return UastKotlinPsiVariable( return UastKotlinPsiVariable(
initializer.manager, manager = initializer.manager,
"var" + Integer.toHexString(initializer.getHashCode()), name = "var" + Integer.toHexString(initializer.getHashCode()),
initializer.getType(containingElement) ?: UastErrorType, typeProducer = { initializer.getType(containingElement) ?: UastErrorType },
initializer, ktInitializer = initializer,
psiParent, psiParent = psiParent,
containingElement, containingElement = containingElement,
initializer) ktElement = initializer)
} }
fun create(name: String, localFunction: KtFunction, containingElement: UElement): PsiLocalVariable { fun create(name: String, localFunction: KtFunction, containingElement: UElement): PsiLocalVariable {
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: localFunction.parent val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: localFunction.parent
return UastKotlinPsiVariable( return UastKotlinPsiVariable(
localFunction.manager, manager = localFunction.manager,
name, name = name,
localFunction.getFunctionType(containingElement) ?: UastErrorType, typeProducer = { localFunction.getFunctionType(containingElement) ?: UastErrorType },
localFunction, ktInitializer = localFunction,
psiParent, psiParent = psiParent,
containingElement, containingElement = containingElement,
localFunction) ktElement = localFunction)
} }
} }
} }
@@ -122,18 +135,25 @@ private fun KtFunction.getFunctionType(parent: UElement): PsiType? {
val returnType = descriptor.returnType ?: return null val returnType = descriptor.returnType ?: return null
return createFunctionType( return createFunctionType(
descriptor.builtIns, builtIns = descriptor.builtIns,
descriptor.annotations, annotations = descriptor.annotations,
descriptor.extensionReceiverParameter?.type, receiverType = descriptor.extensionReceiverParameter?.type,
descriptor.valueParameters.map { it.type }, parameterTypes = descriptor.valueParameters.map { it.type },
descriptor.valueParameters.map { it.name }, parameterNames = descriptor.valueParameters.map { it.name },
returnType returnType = returnType
).toPsiType(parent, this, boxed = false) ).toPsiType(parent, this, boxed = false)
} }
private fun KtExpression.getType(parent: UElement): PsiType? = private fun KtExpression.getType(parent: UElement): PsiType? =
analyze()[BindingContext.EXPRESSION_TYPE_INFO, this]?.type?.toPsiType(parent, this, boxed = false) 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 { private fun PsiElement.getHashCode(): Int {
var result = 42 var result = 42
result = 41 * result + containingFile.name.hashCode() 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 {...}] UClass (name = InKt) [public final class InKt {...}]
UAnnotationMethod (name = foo) [public static final fun foo() : boolean {...}] UAnnotationMethod (name = foo) [public static final fun foo() : boolean {...}]
UBlockExpression [{...}] = Nothing UBlockExpression [{...}] = Nothing
UDeclarationsExpression [var x: <ErrorType> = 1] = Undetermined UDeclarationsExpression [var x: int = 1] = Undetermined
ULocalVariable (name = x) [var x: <ErrorType> = 1] ULocalVariable (name = x) [var x: int = 1]
ULiteralExpression (value = 1) [1] = 1 ULiteralExpression (value = 1) [1] = 1
UDeclarationsExpression [var y: <ErrorType> = 10] = Undetermined UDeclarationsExpression [var y: int = 10] = Undetermined
ULocalVariable (name = y) [var y: <ErrorType> = 10] ULocalVariable (name = y) [var y: int = 10]
ULiteralExpression (value = 10) [10] = 10 ULiteralExpression (value = 10) [10] = 10
UReturnExpression [return x in 0 .. 5 && y !in 4 .. 9] = Nothing 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)) 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 () { var bar: <ErrorType> = fun () {
<init>() <init>()
} }
var baz: <ErrorType> = fun () { var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {
<init>() <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) { 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> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] : PsiType:<ErrorType>
UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))]
USimpleNameReferenceExpression (identifier = <init>) [<init>] : PsiType:<ErrorType> USimpleNameReferenceExpression (identifier = <init>) [<init>] : PsiType:<ErrorType>
UDeclarationsExpression [var baz: <ErrorType> = fun () {...}] UDeclarationsExpression [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}]
ULocalVariable (name = baz) [var baz: <ErrorType> = fun () {...}] ULocalVariable (name = baz) [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}]
ULambdaExpression [fun () {...}] ULambdaExpression [fun () {...}]
UBlockExpression [{...}] : PsiType:<ErrorType> UBlockExpression [{...}] : PsiType:<ErrorType>
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] : 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>()() UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] = external <init>()()
UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))]
USimpleNameReferenceExpression (identifier = <init>) [<init>] = external <init>()() USimpleNameReferenceExpression (identifier = <init>) [<init>] = external <init>()()
UDeclarationsExpression [var baz: <ErrorType> = fun () {...}] = Undetermined UDeclarationsExpression [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}] = Undetermined
ULocalVariable (name = baz) [var baz: <ErrorType> = fun () {...}] ULocalVariable (name = baz) [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}]
ULambdaExpression [fun () {...}] = Undetermined ULambdaExpression [fun () {...}] = Undetermined
UBlockExpression [{...}] = external <init>()() UBlockExpression [{...}] = external <init>()()
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] = 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 private static final var sdCardPath$delegate: kotlin.Lazy
public static final fun getSdCardPath() : java.lang.String = UastEmptyExpression public static final fun getSdCardPath() : java.lang.String = UastEmptyExpression
public static final fun localPropertyTest() : void { 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 testInnerClasses() = doTest("InnerClasses")
@Test fun testSimpleScript() = doTest("SimpleScript") @Test fun testSimpleScript() = doTest("SimpleScript")
@Test fun testParameterPropertyWithAnnotation() = doTest("ParameterPropertyWithAnnotation")
@Test fun testParametersWithDefaultValues() = doTest("ParametersWithDefaultValues")
} }