Files
kotlin-fork/plugins/uast-kotlin/tests/KotlinUastResolveApiTest.kt
T
2020-04-09 16:38:11 +03:00

307 lines
11 KiB
Kotlin

/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.uast.test.kotlin
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiType
import com.intellij.psi.PsiVariable
import com.intellij.testFramework.LightProjectDescriptor
import junit.framework.TestCase
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.KotlinUFunctionCallExpression
import org.jetbrains.uast.test.env.kotlin.findElementByText
import org.jetbrains.uast.test.env.kotlin.findElementByTextFromPsi
import org.jetbrains.uast.test.env.kotlin.findUElementByTextFromPsi
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class KotlinUastResolveApiTest : KotlinLightCodeInsightFixtureTestCase() {
override fun getProjectDescriptor(): LightProjectDescriptor =
KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
fun testResolveStringFromUast() {
val file = myFixture.addFileToProject(
"s.kt", """fun foo(){
val s = "abc"
s.toUpperCase()
}
""${'"'}"""
)
val refs = file.findUElementByTextFromPsi<UQualifiedReferenceExpression>("s.toUpperCase()")
TestCase.assertNotNull((refs.receiver.getExpressionType() as PsiClassType).resolve())
}
fun testMultiResolve() {
val file = myFixture.configureByText(
"s.kt", """
fun foo(): Int = TODO()
fun foo(a: Int): Int = TODO()
fun foo(a: Int, b: Int): Int = TODO()
fun main(args: Array<String>) {
foo(1<caret>
}"""
)
val main = file.toUElement()!!.findElementByTextFromPsi<UElement>("main").getContainingUMethod()!!
val functionCall =
main.findElementByText<UElement>("foo").uastParent as KotlinUFunctionCallExpression
val resolvedDeclaration = functionCall.multiResolve()
val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "<null>" }
assertContainsElements(
resolvedDeclarationsStrings,
"fun foo(): Int = TODO()",
"fun foo(a: Int): Int = TODO()",
"fun foo(a: Int, b: Int): Int = TODO()"
)
TestCase.assertEquals(PsiType.INT, functionCall.getExpressionType())
val firstArgument = main.findElementByText<UElement>("1")
val firstParameter = functionCall.getArgumentForParameter(0)
TestCase.assertEquals(firstArgument, firstParameter)
}
fun testMultiResolveJava() {
val file = myFixture.configureByText(
"s.kt", """
fun main(args: Array<String>) {
System.out.print(""
}
"""
)
val main = file.toUElement()!!.findElementByTextFromPsi<UElement>("main").getContainingUMethod()!!
val functionCall = main.findElementByText<UElement>("print").uastParent as KotlinUFunctionCallExpression
val resolvedDeclaration = functionCall.multiResolve()
val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "<null>" }
assertContainsElements(
resolvedDeclarationsStrings,
"public void print(char c) { /* compiled code */ }",
"public void print(int i) { /* compiled code */ }",
"public void print(long l) { /* compiled code */ }",
"public void print(float f) { /* compiled code */ }",
"public void print(double d) { /* compiled code */ }",
"public void print(char[] s) { /* compiled code */ }",
"public void print(java.lang.String s) { /* compiled code */ }",
"public void print(java.lang.Object obj) { /* compiled code */ }"
)
TestCase.assertEquals(PsiType.VOID, functionCall.getExpressionType())
val firstArgument = main.findElementByText<UElement>("\"\"")
val firstParameter = functionCall.getArgumentForParameter(0)
TestCase.assertEquals(firstArgument, firstParameter)
}
fun testMultiResolveJavaAmbiguous() {
myFixture.addClass(
"""
public class JavaClass {
public void setParameter(String name, int value){}
public void setParameter(String name, double value){}
public void setParameter(String name, String value){}
}
"""
)
val file = myFixture.configureByText(
"s.kt", """
fun main(args: Array<String>) {
JavaClass().setParameter(""
}
"""
)
val main = file.toUElement()!!.findElementByTextFromPsi<UElement>("main").getContainingUMethod()!!
val functionCall = main.findElementByText<UElement>("setParameter").uastParent as KotlinUFunctionCallExpression
val resolvedDeclaration = functionCall.multiResolve()
val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "<null>" }
assertContainsElements(
resolvedDeclarationsStrings,
"public void setParameter(String name, int value){}",
"public void setParameter(String name, double value){}",
"public void setParameter(String name, String value){}"
)
TestCase.assertEquals(PsiType.VOID, functionCall.getExpressionType())
val firstArgument = main.findElementByText<UElement>("\"\"")
val firstParameter = functionCall.getArgumentForParameter(0)
TestCase.assertEquals(firstArgument, firstParameter)
}
fun testMultiResolveInClass() {
val file = myFixture.configureByText(
"s.kt", """
class MyClass {
fun foo(): Int = TODO()
fun foo(a: Int): Int = TODO()
fun foo(a: Int, b: Int): Int = TODO()
}
fun foo(string: String) = TODO()
fun main(args: Array<String>) {
MyClass().foo(
}
"""
)
val functionCall =
file.toUElement()!!.findElementByTextFromPsi<UElement>("main").getContainingUMethod()!!
.findElementByText<UElement>("foo").uastParent as KotlinUFunctionCallExpression
val resolvedDeclaration = functionCall.multiResolve()
val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "<null>" }
assertContainsElements(
resolvedDeclarationsStrings,
"fun foo(): Int = TODO()",
"fun foo(a: Int): Int = TODO()",
"fun foo(a: Int, b: Int): Int = TODO()"
)
assertDoesntContain(resolvedDeclarationsStrings, "fun foo(string: String) = TODO()")
TestCase.assertEquals(PsiType.INT, functionCall.getExpressionType())
}
fun testMultiConstructorResolve() {
val file = myFixture.configureByText(
"s.kt", """
class MyClass(int: Int) {
constructor(int: Int, int1: Int) : this(int + int1)
fun foo(): Int = TODO()
}
fun MyClass(string: String): MyClass = MyClass(1)
fun main(args: Array<String>) {
MyClass(
}
"""
)
val functionCall =
file.toUElement()!!.findElementByTextFromPsi<UElement>("main").getContainingUMethod()!!
.findElementByText<UElement>("MyClass").uastParent as KotlinUFunctionCallExpression
val resolvedDeclaration = functionCall.multiResolve()
val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "<null>" }
assertContainsElements(
resolvedDeclarationsStrings,
"(int: Int)",
"constructor(int: Int, int1: Int) : this(int + int1)",
"fun MyClass(string: String): MyClass = MyClass(1)"
)
assertDoesntContain(resolvedDeclarationsStrings, "fun foo(): Int = TODO()")
TestCase.assertEquals(PsiType.getTypeByName("MyClass", project, file.resolveScope), functionCall.getExpressionType())
}
fun testMultiInvokableObjectResolve() {
val file = myFixture.configureByText(
"s.kt", """
object Foo {
operator fun invoke(i: Int): Int = TODO()
operator fun invoke(i1: Int, i2: Int): Int = TODO()
operator fun invoke(i1: Int, i2: Int, i3: Int): Int = TODO()
}
fun main(args: Array<String>) {
Foo(
}
"""
)
val functionCall =
file.toUElement()!!.findElementByTextFromPsi<UElement>("main").getContainingUMethod()!!
.findElementByText<UElement>("Foo").uastParent as KotlinUFunctionCallExpression
val resolvedDeclaration = functionCall.multiResolve()
val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "<null>" }
assertContainsElements(
resolvedDeclarationsStrings,
"operator fun invoke(i: Int): Int = TODO()",
"operator fun invoke(i1: Int, i2: Int): Int = TODO()",
"operator fun invoke(i1: Int, i2: Int, i3: Int): Int = TODO()"
)
TestCase.assertEquals(PsiType.INT, functionCall.getExpressionType())
}
fun testMultiResolveJvmOverloads() {
val file = myFixture.configureByText(
"s.kt", """
class MyClass {
@JvmOverloads
fun foo(i1: Int = 1, i2: Int = 2): Int = TODO()
}
fun main(args: Array<String>) {
MyClass().foo(
}"""
)
val functionCall =
file.toUElement()!!.findElementByTextFromPsi<UElement>("main").getContainingUMethod()!!
.findElementByText<UElement>("foo").uastParent as KotlinUFunctionCallExpression
val resolvedDeclaration = functionCall.multiResolve()
val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "<null>" }
assertContainsElements(
resolvedDeclarationsStrings,
"@JvmOverloads\n fun foo(i1: Int = 1, i2: Int = 2): Int = TODO()"
)
TestCase.assertEquals(PsiType.INT, functionCall.getExpressionType())
}
fun testLocalResolve() {
myFixture.configureByText(
"MyClass.kt", """
fun foo() {
fun bar() {}
ba<caret>r()
}
"""
)
val uCallExpression = myFixture.file.findElementAt(myFixture.caretOffset).toUElement().getUCallExpression().orFail("cant convert to UCallExpression")
val resolved = uCallExpression.resolve().orFail("cant resolve from $uCallExpression")
TestCase.assertEquals("bar", resolved.name)
}
}