| /* |
| * 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.* |
| 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.kotlin.utils.addToStdlib.cast |
| 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()") |
| val receiver = refs.receiver |
| TestCase.assertEquals(CommonClassNames.JAVA_LANG_STRING, (receiver.getExpressionType() as PsiClassType).resolve()!!.qualifiedName!!) |
| val resolve = receiver.cast<UReferenceExpression>().resolve() |
| |
| val variable = file.findUElementByTextFromPsi<UVariable>("val s = \"abc\"") |
| TestCase.assertEquals(resolve, variable.javaPsi) |
| TestCase.assertTrue( |
| "resolved expression $resolve should be equivalent to ${variable.sourcePsi}", |
| PsiManager.getInstance(project).areElementsEquivalent(resolve, variable.sourcePsi) |
| ) |
| } |
| |
| 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("1" |
| } |
| """ |
| ) |
| |
| 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>("1") |
| 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("1" |
| } |
| """ |
| ) |
| |
| 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>("1") |
| 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) |
| } |
| |
| |
| fun testResolveCompiledAnnotation() { |
| myFixture.configureByText( |
| "MyClass.kt", """ |
| @Deprecated(message = "deprecated") |
| fun foo() {} |
| """ |
| ) |
| |
| val compiledAnnotationParameter = myFixture.file.toUElement()!!.findElementByTextFromPsi<USimpleNameReferenceExpression>("message") |
| val resolved = compiledAnnotationParameter.resolve() as PsiMethod |
| TestCase.assertEquals("message", resolved.name) |
| } |
| |
| fun testAssigningArrayElementType() { |
| myFixture.configureByText( |
| "MyClass.kt", """ |
| fun foo() { |
| val arr = arrayOfNulls<List<*>>(10) |
| arr[0] = emptyList<Any>() |
| |
| val lst = mutableListOf<List<*>>() |
| lst[0] = emptyList<Any>() |
| } |
| """ |
| ) |
| |
| val uFile = myFixture.file.toUElement()!! |
| |
| TestCase.assertEquals( |
| "PsiType:List<?>", |
| uFile.findElementByTextFromPsi<UExpression>("arr[0]").getExpressionType().toString() |
| ) |
| TestCase.assertEquals( |
| "PsiType:List<?>", |
| uFile.findElementByTextFromPsi<UExpression>("lst[0]").getExpressionType().toString() |
| ) |
| } |
| } |
| |