191: Uast: implementation of UMethod.returnTypeReference (KT-29012)

This commit is contained in:
Nicolay Mitropolsky
2019-01-15 18:51:50 +03:00
parent 630b39d6b0
commit 9559346199
2 changed files with 622 additions and 0 deletions
@@ -0,0 +1,144 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.uast.kotlin.declarations
import com.intellij.psi.*
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.elements.isGetter
import org.jetbrains.kotlin.asJava.elements.isSetter
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.uast.*
import org.jetbrains.uast.java.internal.JavaUElementWithComments
import org.jetbrains.uast.kotlin.*
open class KotlinUMethod(
psi: KtLightMethod,
givenParent: UElement?
) : KotlinAbstractUElement(givenParent), UAnnotationMethod, UMethodTypeSpecific, UAnchorOwner, JavaUElementWithComments, PsiMethod by psi {
override val comments: List<UComment>
get() = super<KotlinAbstractUElement>.comments
override val psi: KtLightMethod = unwrap<UMethod, KtLightMethod>(psi)
override val javaPsi = psi
override val sourcePsi = psi.kotlinOrigin
override fun getSourceElement() = sourcePsi ?: this
override val uastDefaultValue by lz {
val annotationParameter = psi.kotlinOrigin as? KtParameter ?: return@lz null
val defaultValue = annotationParameter.defaultValue ?: return@lz null
getLanguagePlugin().convertElement(defaultValue, this) as? UExpression
}
private val kotlinOrigin = (psi.originalElement as KtLightElement<*, *>).kotlinOrigin
override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile)
override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?)
override val annotations by lz {
psi.annotations
.mapNotNull { (it as? KtLightElement<*, *>)?.kotlinOrigin as? KtAnnotationEntry }
.map { KotlinUAnnotation(it, this) }
}
private val receiver by lz { (sourcePsi as? KtCallableDeclaration)?.receiverTypeReference }
override val uastParameters by lz {
val lightParams = psi.parameterList.parameters
val receiver = receiver ?: return@lz lightParams.map {
KotlinUParameter(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, this)
}
val receiverLight = lightParams.firstOrNull() ?: return@lz emptyList<UParameter>()
val uParameters = SmartList<UParameter>(KotlinReceiverUParameter(receiverLight, receiver, this))
lightParams.drop(1).mapTo(uParameters) { KotlinUParameter(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, this) }
uParameters
}
override val uastAnchor by lazy {
KotlinUIdentifier(
nameIdentifier,
sourcePsi.let { sourcePsi ->
when (sourcePsi) {
is PsiNameIdentifierOwner -> sourcePsi.nameIdentifier
is KtObjectDeclaration -> sourcePsi.getObjectKeyword()
else -> sourcePsi?.navigationElement
}
},
this
)
}
override val uastBody by lz {
val bodyExpression = when (kotlinOrigin) {
is KtFunction -> kotlinOrigin.bodyExpression
is KtProperty -> when {
psi.isGetter -> kotlinOrigin.getter?.bodyExpression
psi.isSetter -> kotlinOrigin.setter?.bodyExpression
else -> null
}
else -> null
} ?: return@lz null
when (bodyExpression) {
!is KtBlockExpression -> {
KotlinUBlockExpression.KotlinLazyUBlockExpression(this, { block ->
val implicitReturn = KotlinUImplicitReturnExpression(block)
val uBody = getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression
?: return@KotlinLazyUBlockExpression emptyList()
listOf(implicitReturn.apply { returnExpression = uBody })
})
}
else -> getLanguagePlugin().convertElement(bodyExpression, this) as? UExpression
}
}
override val isOverride: Boolean
get() = (kotlinOrigin as? KtCallableDeclaration)?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false
override fun getBody(): PsiCodeBlock? = super<UAnnotationMethod>.getBody()
override fun getOriginalElement(): PsiElement? = super<UAnnotationMethod>.getOriginalElement()
override val returnTypeReference: UTypeReferenceExpression? by lz {
(sourcePsi as? KtCallableDeclaration)?.typeReference?.let {
LazyKotlinUTypeReferenceExpression(it, this) { javaPsi.returnType ?: UastErrorType }
}
}
override fun equals(other: Any?) = other is KotlinUMethod && psi == other.psi
companion object {
fun create(psi: KtLightMethod, containingElement: UElement?) =
if (psi.kotlinOrigin is KtConstructor<*>) {
KotlinConstructorUMethod(
psi.kotlinOrigin?.containingClassOrObject,
psi, containingElement
)
}
else
KotlinUMethod(psi, containingElement)
}
}
@@ -0,0 +1,478 @@
package org.jetbrains.uast.test.kotlin
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiModifier
import com.intellij.testFramework.UsefulTestCase
import org.jetbrains.kotlin.asJava.toLightAnnotation
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin
import org.jetbrains.uast.test.env.kotlin.findElementByText
import org.jetbrains.uast.test.env.kotlin.findElementByTextFromPsi
import org.jetbrains.uast.visitor.AbstractUastVisitor
import org.junit.Assert
import org.junit.Test
class KotlinUastApiTest : AbstractKotlinUastTest() {
override fun check(testName: String, file: UFile) {
}
@Test fun testAnnotationParameters() {
doTest("AnnotationParameters") { _, file ->
val annotation = file.findElementByText<UAnnotation>("@IntRange(from = 10, to = 0)")
assertEquals(annotation.findAttributeValue("from")?.evaluate(), 10)
val toAttribute = annotation.findAttributeValue("to")!!
assertEquals(toAttribute.evaluate(), 0)
KtUsefulTestCase.assertInstanceOf(annotation.psi.toUElement(), UAnnotation::class.java)
KtUsefulTestCase.assertInstanceOf(
annotation.psi.cast<KtAnnotationEntry>().toLightAnnotation().toUElement(),
UAnnotation::class.java
)
KtUsefulTestCase.assertInstanceOf(toAttribute.uastParent, UNamedExpression::class.java)
KtUsefulTestCase.assertInstanceOf(toAttribute.psi.toUElement()?.uastParent, UNamedExpression::class.java)
}
}
@Test fun testConvertStringTemplate() {
doTest("StringTemplateInClass") { _, file ->
val literalExpression = file.findElementByText<ULiteralExpression>("lorem")
val psi = literalExpression.psi!!
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
val literalExpressionAgain = psi.toUElement()
Assert.assertTrue(literalExpressionAgain is ULiteralExpression)
}
}
@Test fun testConvertStringTemplateWithExpectedType() {
doTest("StringTemplateWithVar") { _, file ->
val index = file.psi.text.indexOf("foo")
val stringTemplate = file.psi.findElementAt(index)!!.getParentOfType<KtStringTemplateExpression>(false)
val uLiteral = stringTemplate.toUElementOfType<ULiteralExpression>()
assertNull(uLiteral)
}
}
@Test fun testNameContainingFile() {
doTest("NameContainingFile") { _, file ->
val foo = file.findElementByText<UClass>("class Foo")
assertEquals(file.psi, foo.nameIdentifier!!.containingFile)
val bar = file.findElementByText<UMethod>("fun bar() {}")
assertEquals(file.psi, bar.nameIdentifier!!.containingFile)
val xyzzy = file.findElementByText<UVariable>("val xyzzy: Int = 0")
assertEquals(file.psi, xyzzy.nameIdentifier!!.containingFile)
}
}
@Test fun testInterfaceMethodWithBody() {
doTest("DefaultImpls") { _, file ->
val bar = file.findElementByText<UMethod>("fun bar() = \"Hello!\"")
assertFalse(bar.containingFile.text!!, bar.psi.modifierList.hasExplicitModifier(PsiModifier.DEFAULT))
assertTrue(bar.containingFile.text!!, bar.psi.modifierList.hasModifierProperty(PsiModifier.DEFAULT))
}
}
@Test fun testSAM() {
doTest("SAM") { _, file ->
assertNull(file.findElementByText<ULambdaExpression>("{ /* Not SAM */ }").functionalInterfaceType)
assertEquals("java.lang.Runnable",
file.findElementByText<ULambdaExpression>("{/* Variable */}").functionalInterfaceType?.canonicalText)
assertEquals("java.lang.Runnable",
file.findElementByText<ULambdaExpression>("{/* Assignment */}").functionalInterfaceType?.canonicalText)
assertEquals("java.lang.Runnable",
file.findElementByText<ULambdaExpression>("{/* Type Cast */}").functionalInterfaceType?.canonicalText)
assertEquals("java.lang.Runnable",
file.findElementByText<ULambdaExpression>("{/* Argument */}").functionalInterfaceType?.canonicalText)
assertEquals("java.lang.Runnable",
file.findElementByText<ULambdaExpression>("{/* Return */}").functionalInterfaceType?.canonicalText)
assertEquals(
"java.lang.Runnable",
file.findElementByText<ULambdaExpression>("{ /* SAM */ }").functionalInterfaceType?.canonicalText
)
}
}
@Test fun testParameterPropertyWithAnnotation() {
doTest("ParameterPropertyWithAnnotation") { _, file ->
val test1 = file.classes.find { it.name == "Test1" }!!
val constructor1 = test1.methods.find { it.name == "Test1" }!!
assertTrue(constructor1.uastParameters.first().annotations.any { it.qualifiedName == "MyAnnotation" })
val getter1 = test1.methods.find { it.name == "getBar" }!!
assertFalse(getter1.annotations.any { it.qualifiedName == "MyAnnotation" })
val setter1 = test1.methods.find { it.name == "setBar" }!!
assertFalse(setter1.annotations.any { it.qualifiedName == "MyAnnotation" })
assertFalse(setter1.uastParameters.first().annotations.any { it.qualifiedName == "MyAnnotation" })
val test2 = file.classes.find { it.name == "Test2" }!!
val constructor2 = test2.methods.find { it.name == "Test2" }!!
assertFalse(constructor2.uastParameters.first().annotations.any { it.qualifiedName?.startsWith("MyAnnotation") ?: false })
val getter2 = test2.methods.find { it.name == "getBar" }!!
getter2.annotations.single { it.qualifiedName == "MyAnnotation" }
val setter2 = test2.methods.find { it.name == "setBar" }!!
setter2.annotations.single { it.qualifiedName == "MyAnnotation2" }
setter2.uastParameters.first().annotations.single { it.qualifiedName == "MyAnnotation3" }
test2.fields.find { it.name == "bar" }!!.annotations.single { it.qualifiedName == "MyAnnotation5" }
}
}
@Test fun testConvertTypeInAnnotation() {
doTest("TypeInAnnotation") { _, file ->
val index = file.psi.text.indexOf("Test")
val element = file.psi.findElementAt(index)!!.getParentOfType<KtUserType>(false)!!
assertNotNull(element.getUastParentOfType(UAnnotation::class.java))
}
}
@Test fun testElvisType() {
doTest("ElvisType") { _, file ->
val elvisExpression = file.findElementByText<UExpression>("text ?: return")
assertEquals("String", elvisExpression.getExpressionType()!!.presentableText)
}
}
@Test fun testFindAttributeDefaultValue() {
doTest("AnnotationParameters") { _, file ->
val witDefaultValue = file.findElementByText<UAnnotation>("@WithDefaultValue")
assertEquals(42, witDefaultValue.findAttributeValue("value")!!.evaluate())
assertEquals(42, witDefaultValue.findAttributeValue(null)!!.evaluate())
}
}
@Test fun testIfCondition() {
doTest("IfStatement") { _, file ->
val psiFile = file.psi
val element = psiFile.findElementAt(psiFile.text.indexOf("\"abc\""))!!
val binaryExpression = element.getParentOfType<KtBinaryExpression>(false)!!
val uBinaryExpression = KotlinUastLanguagePlugin().convertElementWithParent(binaryExpression, null)!!
UsefulTestCase.assertInstanceOf(uBinaryExpression.uastParent, UIfExpression::class.java)
}
}
@Test
fun testWhenStringLiteral() {
doTest("WhenStringLiteral") { _, file ->
file.findElementByTextFromPsi<ULiteralExpression>("abc").let { literalExpression ->
val psi = literalExpression.psi!!
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
UsefulTestCase.assertInstanceOf(literalExpression.uastParent, USwitchClauseExpressionWithBody::class.java)
}
file.findElementByTextFromPsi<ULiteralExpression>("def").let { literalExpression ->
val psi = literalExpression.psi!!
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
UsefulTestCase.assertInstanceOf(literalExpression.uastParent, USwitchClauseExpressionWithBody::class.java)
}
file.findElementByTextFromPsi<ULiteralExpression>("def1").let { literalExpression ->
val psi = literalExpression.psi!!
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
UsefulTestCase.assertInstanceOf(literalExpression.uastParent, UBlockExpression::class.java)
}
}
}
@Test
fun testWhenAndDestructing() {
doTest("WhenAndDestructing") { _, file ->
file.findElementByTextFromPsi<UExpression>("val (bindingContext, statementFilter) = arr").let { e ->
val uBlockExpression = e.getParentOfType<UBlockExpression>()
Assert.assertNotNull(uBlockExpression)
val uMethod = uBlockExpression!!.getParentOfType<UMethod>()
Assert.assertNotNull(uMethod)
}
}
}
@Test
fun testBrokenMethodTypeResolve() {
doTest("BrokenMethod") { _, file ->
file.accept(object : AbstractUastVisitor() {
override fun visitCallExpression(node: UCallExpression): Boolean {
node.returnType
return false
}
})
}
}
@Test
fun testSimpleAnnotated() {
doTest("SimpleAnnotated") { _, file ->
file.findElementByTextFromPsi<UField>("@kotlin.SinceKotlin(\"1.0\")\n val property: String = \"Mary\"").let { field ->
val annotation = field.annotations.assertedFind("kotlin.SinceKotlin") { it.qualifiedName }
Assert.assertEquals("1.0", annotation.findDeclaredAttributeValue("version")?.evaluateString())
Assert.assertEquals("SinceKotlin", annotation.cast<UAnchorOwner>().uastAnchor?.sourcePsi?.text)
}
}
}
fun UFile.checkUastSuperTypes(refText: String, superTypes: List<String>) {
findElementByTextFromPsi<UClass>(refText, false).let {
assertEquals("base classes", superTypes, it.uastSuperTypes.map { it.getQualifiedName() })
}
}
@Test
fun testSuperTypes() {
doTest("SuperCalls") { _, file ->
file.checkUastSuperTypes("B", listOf("A"))
file.checkUastSuperTypes("O", listOf("A"))
file.checkUastSuperTypes("innerObject ", listOf("A"))
file.checkUastSuperTypes("InnerClass", listOf("A"))
file.checkUastSuperTypes("object : A(\"textForAnon\")", listOf("A"))
}
}
@Test
fun testAnonymousSuperTypes() {
doTest("Anonymous") { _, file ->
file.checkUastSuperTypes("object : Runnable { override fun run() {} }", listOf("java.lang.Runnable"))
file.checkUastSuperTypes(
"object : Runnable, Closeable { override fun close() {} override fun run() {} }",
listOf("java.lang.Runnable", "java.io.Closeable")
)
file.checkUastSuperTypes(
"object : InputStream(), Runnable { override fun read(): Int = 0; override fun run() {} }",
listOf("java.io.InputStream", "java.lang.Runnable")
)
}
}
@Test
fun testLiteralArraysTypes() {
doTest("AnnotationParameters") { _, file ->
file.findElementByTextFromPsi<UCallExpression>("intArrayOf(1, 2, 3)").let { field ->
Assert.assertEquals("PsiType:int[]", field.returnType.toString())
}
file.findElementByTextFromPsi<UCallExpression>("[1, 2, 3]").let { field ->
Assert.assertEquals("PsiType:int[]", field.returnType.toString())
Assert.assertEquals("PsiType:int", field.typeArguments.single().toString())
}
file.findElementByTextFromPsi<UCallExpression>("[\"a\", \"b\", \"c\"]").let { field ->
Assert.assertEquals("PsiType:String[]", field.returnType.toString())
Assert.assertEquals("PsiType:String", field.typeArguments.single().toString())
}
}
}
@Test
fun testTypeAliases() {
doTest("TypeAliases") { _, file ->
val g = (file.psi as KtFile).declarations.single { it.name == "G" } as KtTypeAlias
val originalType = g.getTypeReference()!!.typeElement as KtFunctionType
val originalTypeParameters = originalType.parameterList.toUElement() as UDeclarationsExpression
Assert.assertTrue((originalTypeParameters.declarations.single() as UParameter).type.isValid)
}
}
@Test
fun testNestedAnnotation() = doTest("AnnotationComplex") { _, file ->
file.findElementByTextFromPsi<UElement>("@AnnotationArray(value = Annotation())")
.findElementByTextFromPsi<UElement>("Annotation()")
.sourcePsiElement
.let { referenceExpression ->
val convertedUAnnotation = referenceExpression
.cast<KtReferenceExpression>()
.toUElementOfType<UAnnotation>()
?: throw AssertionError("haven't got annotation from $referenceExpression(${referenceExpression?.javaClass})")
checkDescriptorsLeak(convertedUAnnotation)
assertEquals("Annotation", convertedUAnnotation.qualifiedName)
val lightAnnotation = convertedUAnnotation.getAsJavaPsiElement(PsiAnnotation::class.java)
?: throw AssertionError("can't get lightAnnotation from $convertedUAnnotation")
assertEquals("Annotation", lightAnnotation.qualifiedName)
assertEquals("Annotation", (convertedUAnnotation as UAnchorOwner).uastAnchor?.sourcePsi?.text)
}
}
@Test
fun testParametersDisorder() = doTest("ParametersDisorder") { _, file ->
fun assertArguments(argumentsInPositionalOrder: List<String?>?, refText: String) =
file.findElementByTextFromPsi<UCallExpression>(refText).let { call ->
if (call !is UCallExpressionEx) throw AssertionError("${call.javaClass} is not a UCallExpressionEx")
Assert.assertEquals(
argumentsInPositionalOrder,
call.resolve()?.let { psiMethod ->
(0 until psiMethod.parameterList.parametersCount).map {
call.getArgumentForParameter(it)?.asRenderString()
}
}
)
}
assertArguments(listOf("2", "2.2"), "global(b = 2.2F, a = 2)")
assertArguments(listOf(null, "\"bbb\""), "withDefault(d = \"bbb\")")
assertArguments(listOf("1.3", "3.4"), "atan2(1.3, 3.4)")
assertArguments(null, "unresolvedMethod(\"param1\", \"param2\")")
assertArguments(listOf("\"%i %i %i\"", "varargs 1 : 2 : 3"), "format(\"%i %i %i\", 1, 2, 3)")
assertArguments(listOf("\"%i %i %i\"", "varargs arrayOf(1, 2, 3)"), "format(\"%i %i %i\", arrayOf(1, 2, 3))")
assertArguments(
listOf("\"%i %i %i\"", "varargs arrayOf(1, 2, 3) : arrayOf(4, 5, 6)"),
"format(\"%i %i %i\", arrayOf(1, 2, 3), arrayOf(4, 5, 6))"
)
assertArguments(listOf("\"%i %i %i\"", "\"\".chunked(2).toTypedArray()"), "format(\"%i %i %i\", *\"\".chunked(2).toTypedArray())")
assertArguments(listOf("\"def\"", "8", "7.0"), "with2Receivers(8, 7.0F)")
assertArguments(listOf("\"foo\"", "1"), "object : Parent(b = 1, a = \"foo\")\n")
}
@Test
fun testResolvedDeserializedMethod() = doTest("Resolve") { _, file ->
val barMethod = file.findElementByTextFromPsi<UElement>("bar").getParentOfType<UMethod>()!!
fun UElement.assertResolveCall(callText: String, methodName: String = callText.substringBefore("(")) {
this.findElementByTextFromPsi<UCallExpression>(callText).let {
val resolve = it.resolve().sure { "resolving '$callText'" }
assertEquals(methodName, resolve.name)
}
}
barMethod.assertResolveCall("foo()")
barMethod.assertResolveCall("inlineFoo()")
barMethod.assertResolveCall("forEach { println(it) }", "forEach")
barMethod.assertResolveCall("joinToString()")
barMethod.assertResolveCall("last()")
barMethod.assertResolveCall("setValue(\"123\")")
barMethod.assertResolveCall("contains(2 as Int)", "longRangeContains")
barMethod.assertResolveCall("IntRange(1, 2)")
}
@Test
fun testUtilsStreamLambda() {
doTest("Lambdas") { _, file ->
val lambda = file.findElementByTextFromPsi<ULambdaExpression>("{ it.isEmpty() }")
assertEquals(
"java.util.function.Predicate<? super java.lang.String>",
lambda.functionalInterfaceType?.canonicalText
)
assertEquals(
"kotlin.jvm.functions.Function1<? super java.lang.String,? extends java.lang.Boolean>",
lambda.getExpressionType()?.canonicalText
)
val uCallExpression = lambda.uastParent.assertedCast<UCallExpression> { "UCallExpression expected" }
assertTrue(uCallExpression.valueArguments.contains(lambda))
}
}
@Test
fun testLambdaParamCall() {
doTest("Lambdas") { _, file ->
val lambdaCall = file.findElementByTextFromPsi<UCallExpression>("selectItemFunction()")
assertEquals(
"UIdentifier (Identifier (selectItemFunction))",
lambdaCall.methodIdentifier?.asLogString()
)
assertEquals(
"selectItemFunction",
lambdaCall.methodIdentifier?.name
)
assertEquals(
"invoke",
lambdaCall.methodName
)
val receiver = lambdaCall.receiver ?: kotlin.test.fail("receiver expected")
assertEquals("UReferenceExpression", receiver.asLogString())
val uParameter = (receiver as UReferenceExpression).resolve().toUElement() ?: kotlin.test.fail("uelement expected")
assertEquals("UParameter (name = selectItemFunction)", uParameter.asLogString())
}
}
@Test
fun testLocalLambdaCall() {
doTest("Lambdas") { _, file ->
val lambdaCall = file.findElementByTextFromPsi<UCallExpression>("baz()")
assertEquals(
"UIdentifier (Identifier (baz))",
lambdaCall.methodIdentifier?.asLogString()
)
assertEquals(
"baz",
lambdaCall.methodIdentifier?.name
)
assertEquals(
"invoke",
lambdaCall.methodName
)
val receiver = lambdaCall.receiver ?: kotlin.test.fail("receiver expected")
assertEquals("UReferenceExpression", receiver.asLogString())
val uParameter = (receiver as UReferenceExpression).resolve().toUElement() ?: kotlin.test.fail("uelement expected")
assertEquals("ULocalVariable (name = baz)", uParameter.asLogString())
}
}
@Test
fun testLocalDeclarationCall() {
doTest("LocalDeclarations") { _, file ->
val localFunction = file.findElementByTextFromPsi<UElement>("bar() == Local()").
findElementByText<UCallExpression>("bar()")
assertEquals(
"UIdentifier (Identifier (bar))",
localFunction.methodIdentifier?.asLogString()
)
assertEquals(
"bar",
localFunction.methodIdentifier?.name
)
assertEquals(
"bar",
localFunction.methodName
)
assertNull(localFunction.resolve())
val receiver = localFunction.receiver ?: kotlin.test.fail("receiver expected")
assertEquals("UReferenceExpression", receiver.asLogString())
val uParameter = (receiver as UReferenceExpression).resolve().toUElement() ?: kotlin.test.fail("uelement expected")
assertEquals("ULambdaExpression", uParameter.asLogString())
}
}
@Test
fun testMethodReturnTypeReference() {
doTest("Elvis") { _, file ->
assertEquals(
"UTypeReferenceExpression (name = java.lang.String)",
file.findElementByTextFromPsi<UMethod>("fun foo(bar: String): String? = null").returnTypeReference?.asLogString()
)
assertEquals(
null,
file.findElementByTextFromPsi<UMethod>("fun bar() = 42").returnTypeReference?.asLogString()
)
}
}
}
fun <T, R> Iterable<T>.assertedFind(value: R, transform: (T) -> R): T =
find { transform(it) == value } ?: throw AssertionError("'$value' not found, only ${this.joinToString { transform(it).toString() }}")