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