Uast: implicit receiver for local function calls (KT-25524)
This commit is contained in:
+7
-2
@@ -22,6 +22,8 @@ import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.psi.PsiType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
||||
@@ -110,12 +112,15 @@ class KotlinUFunctionCallExpression(
|
||||
}
|
||||
|
||||
val ktNameReferenceExpression = psi.calleeExpression as? KtNameReferenceExpression ?: return null
|
||||
val variableAsFunctionResolvedCall = resolvedCall as? VariableAsFunctionResolvedCall ?: return null
|
||||
val variableCallDescriptor =
|
||||
(resolvedCall as? VariableAsFunctionResolvedCall)?.variableCall?.resultingDescriptor
|
||||
?: (resolvedCall?.resultingDescriptor as? FunctionDescriptor)?.takeIf { it.visibility == Visibilities.LOCAL }
|
||||
?: return null
|
||||
|
||||
// an implicit receiver for variables calls (KT-25524)
|
||||
return object : KotlinAbstractUExpression(this), UReferenceExpression {
|
||||
|
||||
private val resolvedDeclaration = variableAsFunctionResolvedCall.variableCall.resultingDescriptor.toSource()
|
||||
private val resolvedDeclaration = variableCallDescriptor.toSource()
|
||||
|
||||
override val psi: KtNameReferenceExpression get() = ktNameReferenceExpression
|
||||
|
||||
|
||||
+9
-7
@@ -18,15 +18,14 @@ package org.jetbrains.uast.kotlin
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.psi.PsiType
|
||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtCallElement
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
@@ -94,12 +93,15 @@ class KotlinUFunctionCallExpression(
|
||||
}
|
||||
|
||||
val ktNameReferenceExpression = psi.calleeExpression as? KtNameReferenceExpression ?: return null
|
||||
val variableAsFunctionResolvedCall = resolvedCall as? VariableAsFunctionResolvedCall ?: return null
|
||||
val variableCallDescriptor =
|
||||
(resolvedCall as? VariableAsFunctionResolvedCall)?.variableCall?.resultingDescriptor
|
||||
?: (resolvedCall?.resultingDescriptor as? FunctionDescriptor)?.takeIf { it.visibility == Visibilities.LOCAL }
|
||||
?: return null
|
||||
|
||||
// an implicit receiver for variables calls (KT-25524)
|
||||
return object : KotlinAbstractUExpression(this), UReferenceExpression {
|
||||
|
||||
private val resolvedDeclaration = variableAsFunctionResolvedCall.variableCall.resultingDescriptor.toSource()
|
||||
private val resolvedDeclaration = variableCallDescriptor.toSource()
|
||||
|
||||
override val psi: KtNameReferenceExpression get() = ktNameReferenceExpression
|
||||
|
||||
|
||||
+4
@@ -6,4 +6,8 @@ fun foo() {
|
||||
|
||||
fun doSelectItem(selectItemFunction: () -> Unit) {
|
||||
selectItemFunction()
|
||||
val baz = fun() {
|
||||
Local()
|
||||
}
|
||||
baz()
|
||||
}
|
||||
+10
@@ -26,3 +26,13 @@ UFile (package = )
|
||||
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
|
||||
UIdentifier (Identifier (selectItemFunction))
|
||||
USimpleNameReferenceExpression (identifier = invoke)
|
||||
UDeclarationsExpression
|
||||
ULocalVariable (name = baz)
|
||||
ULambdaExpression
|
||||
UBlockExpression
|
||||
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
|
||||
UIdentifier (Identifier (Local))
|
||||
USimpleNameReferenceExpression (identifier = <anonymous class>)
|
||||
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
|
||||
UIdentifier (Identifier (baz))
|
||||
USimpleNameReferenceExpression (identifier = invoke)
|
||||
|
||||
+5
-1
@@ -2,11 +2,15 @@ import java.util.stream.Stream
|
||||
|
||||
public final class LambdasKt {
|
||||
public static final fun foo() : void {
|
||||
Stream.empty().filter({
|
||||
Stream.empty().filter({
|
||||
it.isEmpty()
|
||||
})
|
||||
}
|
||||
public static final fun doSelectItem(@org.jetbrains.annotations.NotNull selectItemFunction: kotlin.jvm.functions.Function0<kotlin.Unit>) : void {
|
||||
invoke()
|
||||
var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {
|
||||
<anonymous class>()
|
||||
}
|
||||
invoke()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,6 +407,54 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@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())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun <T, R> Iterable<T>.assertedFind(value: R, transform: (T) -> R): T =
|
||||
|
||||
@@ -252,4 +252,52 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@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())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -371,6 +371,54 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@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())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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() }}")
|
||||
|
||||
Reference in New Issue
Block a user