Uast: making local lambda resolve and methods multiresolve work via resolveToDeclaration and resolveToPsiMethod

also fixes KT-36275
This commit is contained in:
Nicolay Mitropolsky
2020-04-02 15:34:42 +03:00
parent 89863bd2a3
commit f5df64674f
5 changed files with 20 additions and 33 deletions
@@ -530,7 +530,7 @@ internal object KotlinConverter {
is UastKotlinPsiParameterBase<*> -> el<UParameter> {
original.ktOrigin.safeAs<KtTypeReference>()?.let { convertReceiverParameter(it) }
}
is UastKotlinPsiVariable -> el<UVariable>(buildKt(original.ktElement, ::KotlinUVariable))
is UastKotlinPsiVariable -> el<ULocalVariable>(buildKt(original.ktElement, ::KotlinULocalVariable))
is KtEnumEntry -> el<UEnumConstant> {
convertEnumEntry(original, givenParent)
@@ -16,23 +16,16 @@
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 com.intellij.psi.*
import com.intellij.psi.util.PsiTypesUtil
import org.jetbrains.kotlin.asJava.toLightClass
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.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.uast.*
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
@@ -151,21 +144,17 @@ class KotlinUFunctionCallExpression(
}
val ktNameReferenceExpression = sourcePsi.calleeExpression as? KtNameReferenceExpression ?: return null
val variableCallDescriptor =
(resolvedCall as? VariableAsFunctionResolvedCall)?.variableCall?.resultingDescriptor
?: (resolvedCall?.resultingDescriptor as? FunctionDescriptor)?.takeIf { it.visibility == Visibilities.LOCAL }
?: return null
val localCallableDeclaration = resolveToDeclaration(ktNameReferenceExpression) as? PsiVariable ?: return null
if (localCallableDeclaration !is PsiLocalVariable && localCallableDeclaration !is PsiParameter) return null
// an implicit receiver for variables calls (KT-25524)
return object : KotlinAbstractUExpression(this), UReferenceExpression {
private val resolvedDeclaration = variableCallDescriptor.toSource()
override val sourcePsi: KtNameReferenceExpression get() = ktNameReferenceExpression
override val psi: KtNameReferenceExpression get() = ktNameReferenceExpression
override val resolvedName: String? get() = localCallableDeclaration.name
override val resolvedName: String? get() = (resolvedDeclaration as? PsiNamedElement)?.name
override fun resolve(): PsiElement? = resolvedDeclaration
override fun resolve(): PsiElement? = localCallableDeclaration
}
@@ -177,9 +166,10 @@ class KotlinUFunctionCallExpression(
val methodName = methodName ?: calleeExpression.text ?: return emptyList()
val variants = getReferenceVariants(calleeExpression, methodName)
return variants.flatMap {
when (val source = it.toSource()) {
is KtClass -> source.toLightClass()?.constructors?.asSequence().orEmpty()
else -> resolveToPsiMethod(sourcePsi, it, source)?.let { sequenceOf(it) }.orEmpty()
when (it) {
is PsiClass -> it.constructors.asSequence()
is PsiMethod -> sequenceOf(it)
else -> emptySequence()
}
}.map { TypedResolveResult(it) }.asIterable()
})
@@ -89,7 +89,7 @@ internal val KOTLIN_CACHED_UELEMENT_KEY = Key.create<WeakReference<UElement>>("c
@Suppress("NOTHING_TO_INLINE")
internal inline fun String?.orAnonymous(kind: String = ""): String = this ?: "<anonymous" + (if (kind.isNotBlank()) " $kind" else "") + ">"
internal fun DeclarationDescriptor.toSource(): PsiElement? {
private fun DeclarationDescriptor.toSource(): PsiElement? {
return try {
DescriptorToSourceUtils.getEffectiveReferencedDescriptors(this)
.asSequence()
@@ -11,28 +11,25 @@ import com.intellij.psi.PsiPolyVariantReference
import com.intellij.psi.PsiSubstitutor
import com.intellij.psi.ResolveResult
import com.intellij.psi.infos.CandidateInfo
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UMultiResolvable
import org.jetbrains.uast.UResolvable
import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
import org.jetbrains.uast.kotlin.resolveToDeclaration
internal fun getReferenceVariants(ktElement: KtElement, nameHint: String): Sequence<DeclarationDescriptor> =
ServiceManager.getService(ktElement.project, KotlinUastResolveProviderService::class.java).getReferenceVariants(ktElement, nameHint)
internal fun getReferenceVariants(ktElement: KtExpression, nameHint: String): Sequence<PsiElement> =
ServiceManager.getService(ktElement.project, KotlinUastResolveProviderService::class.java)
.getReferenceVariants(ktElement, nameHint)
.mapNotNull { resolveToDeclaration(ktElement, it) }
internal fun UElement.getResolveResultVariants(ktExpression: KtExpression?): Iterable<ResolveResult> {
internal fun getResolveResultVariants(ktExpression: KtExpression?): Iterable<ResolveResult> {
ktExpression ?: return emptyList()
val referenceVariants = getReferenceVariants(ktExpression, ktExpression.name ?: ktExpression.text)
fun asCandidateInfo(descriptor: DeclarationDescriptor): CandidateInfo? =
resolveToDeclaration(ktExpression, descriptor)?.let { CandidateInfo(it, PsiSubstitutor.EMPTY) }
return referenceVariants.mapNotNull(::asCandidateInfo).asIterable()
return referenceVariants.mapNotNull {CandidateInfo(it, PsiSubstitutor.EMPTY) }.asIterable()
}
@@ -573,8 +573,8 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
val receiver = localFunction.receiver ?: kfail("receiver expected")
assertEquals("UReferenceExpression", receiver.asLogString())
val uVariable = (receiver as UReferenceExpression).resolve().toUElement() ?: kfail("uelement expected")
assertEquals("ULambdaExpression", uVariable.asLogString())
assertEquals(uVariable, localFunctionResolved.toUElement())
assertEquals("ULocalVariable (name = bar)", uVariable.asLogString())
assertEquals((uVariable as ULocalVariable).uastInitializer, localFunctionResolved.toUElement())
}
}