Uast: making local lambda resolve and methods multiresolve work via resolveToDeclaration and resolveToPsiMethod
also fixes KT-36275
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
+10
-20
@@ -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()
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-1
@@ -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()
|
||||||
|
|||||||
+6
-9
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user