Uast: handling resolve to deserialized methods (KT-24679)
This commit is contained in:
+3
-3
@@ -1,16 +1,16 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.kotlin.idea.caches.lightClasses
|
||||
package org.jetbrains.kotlin.type
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.Type.*
|
||||
|
||||
internal object MapPsiToAsmDesc {
|
||||
object MapPsiToAsmDesc {
|
||||
fun typeDesc(type: PsiType): String = when (type) {
|
||||
PsiType.VOID -> primitive(VOID_TYPE)
|
||||
|
||||
+1
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.type.MapPsiToAsmDesc
|
||||
|
||||
interface LightMemberOriginForCompiledElement : LightMemberOrigin {
|
||||
override val originKind: JvmDeclarationOriginKind
|
||||
|
||||
+2
-21
@@ -16,14 +16,10 @@
|
||||
|
||||
package org.jetbrains.uast.kotlin
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiType
|
||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
||||
@@ -39,21 +35,6 @@ class KotlinUFunctionCallExpression(
|
||||
givenParent: UElement?,
|
||||
private val _resolvedCall: ResolvedCall<*>?
|
||||
) : KotlinAbstractUExpression(givenParent), UCallExpressionEx, KotlinUElementWithType {
|
||||
companion object {
|
||||
fun resolveSource(descriptor: DeclarationDescriptor, source: PsiElement?): PsiMethod? {
|
||||
if (descriptor is ConstructorDescriptor && descriptor.isPrimary
|
||||
&& source is KtClassOrObject && source.primaryConstructor == null
|
||||
&& source.secondaryConstructors.isEmpty()) {
|
||||
return source.toLightClass()?.constructors?.firstOrNull()
|
||||
}
|
||||
|
||||
return when (source) {
|
||||
is KtFunction -> LightClassUtil.getLightClassMethod(source)
|
||||
is PsiMethod -> source
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(psi: KtCallElement, uastParent: UElement?) : this(psi, uastParent, null)
|
||||
|
||||
@@ -124,8 +105,8 @@ class KotlinUFunctionCallExpression(
|
||||
|
||||
override fun resolve(): PsiMethod? {
|
||||
val descriptor = resolvedCall?.resultingDescriptor ?: return null
|
||||
val source = descriptor.toSource() ?: return null
|
||||
return resolveSource(descriptor, source)
|
||||
val source = descriptor.toSource()
|
||||
return resolveSource(psi, descriptor, source)
|
||||
}
|
||||
|
||||
override fun accept(visitor: UastVisitor) {
|
||||
|
||||
+2
-17
@@ -40,21 +40,6 @@ class KotlinUFunctionCallExpression(
|
||||
givenParent: UElement?,
|
||||
private val _resolvedCall: ResolvedCall<*>?
|
||||
) : KotlinAbstractUExpression(givenParent), UCallExpression, KotlinUElementWithType {
|
||||
companion object {
|
||||
fun resolveSource(descriptor: DeclarationDescriptor, source: PsiElement?): PsiMethod? {
|
||||
if (descriptor is ConstructorDescriptor && descriptor.isPrimary
|
||||
&& source is KtClassOrObject && source.primaryConstructor == null
|
||||
&& source.secondaryConstructors.isEmpty()) {
|
||||
return source.toLightClass()?.constructors?.firstOrNull()
|
||||
}
|
||||
|
||||
return when (source) {
|
||||
is KtFunction -> LightClassUtil.getLightClassMethod(source)
|
||||
is PsiMethod -> source
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(psi: KtCallElement, uastParent: UElement?) : this(psi, uastParent, null)
|
||||
|
||||
@@ -106,8 +91,8 @@ class KotlinUFunctionCallExpression(
|
||||
|
||||
override fun resolve(): PsiMethod? {
|
||||
val descriptor = resolvedCall?.resultingDescriptor ?: return null
|
||||
val source = descriptor.toSource() ?: return null
|
||||
return resolveSource(descriptor, source)
|
||||
val source = descriptor.toSource()
|
||||
return resolveSource(psi, descriptor, source)
|
||||
}
|
||||
|
||||
override fun accept(visitor: UastVisitor) {
|
||||
|
||||
+1
-1
@@ -159,7 +159,7 @@ open class KotlinUSimpleReferenceExpression(
|
||||
|
||||
override fun resolve(): PsiMethod? {
|
||||
val source = accessorDescriptor.toSource()
|
||||
return KotlinUFunctionCallExpression.resolveSource(accessorDescriptor, source)
|
||||
return resolveSource(psi, accessorDescriptor, source)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ open class KotlinUSimpleReferenceExpression(
|
||||
|
||||
override fun resolve(): PsiMethod? {
|
||||
val source = accessorDescriptor.toSource()
|
||||
return KotlinUFunctionCallExpression.resolveSource(accessorDescriptor, source)
|
||||
return resolveSource(psi, accessorDescriptor, source)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -157,7 +157,7 @@ open class KotlinUSimpleReferenceExpression(
|
||||
|
||||
override fun resolve(): PsiMethod? {
|
||||
val source = accessorDescriptor.toSource()
|
||||
return KotlinUFunctionCallExpression.resolveSource(accessorDescriptor, source)
|
||||
return resolveSource(psi, accessorDescriptor, source)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+114
-28
@@ -19,27 +19,27 @@ package org.jetbrains.uast.kotlin
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiPrimitiveType
|
||||
import com.intellij.psi.PsiType
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.cache.TypeInfo
|
||||
import com.intellij.psi.impl.compiled.ClsTypeElementImpl
|
||||
import com.intellij.psi.impl.compiled.SignatureParsing
|
||||
import com.intellij.psi.impl.compiled.StubBuildingVisitor
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.util.PsiTypesUtil
|
||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.asJava.toLightElements
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
|
||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMemberSignature
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
@@ -47,10 +47,10 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeApproximator
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.type.MapPsiToAsmDesc
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.isInterface
|
||||
import org.jetbrains.uast.*
|
||||
import java.lang.ref.WeakReference
|
||||
@@ -64,9 +64,9 @@ internal inline fun String?.orAnonymous(kind: String = ""): String = this ?: "<a
|
||||
internal fun DeclarationDescriptor.toSource(): PsiElement? {
|
||||
return try {
|
||||
DescriptorToSourceUtils.getEffectiveReferencedDescriptors(this)
|
||||
.asSequence()
|
||||
.mapNotNull { DescriptorToSourceUtils.getSourceFromDescriptor(it) }
|
||||
.firstOrNull()
|
||||
.asSequence()
|
||||
.mapNotNull { DescriptorToSourceUtils.getSourceFromDescriptor(it) }
|
||||
.firstOrNull()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
Logger.getInstance("DeclarationDescriptor.toSource").error(e)
|
||||
@@ -74,18 +74,104 @@ internal fun DeclarationDescriptor.toSource(): PsiElement? {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun resolveSource(context: KtElement, descriptor: DeclarationDescriptor, source: PsiElement?): PsiMethod? {
|
||||
|
||||
if (descriptor is ConstructorDescriptor && descriptor.isPrimary
|
||||
&& source is KtClassOrObject && source.primaryConstructor == null
|
||||
&& source.secondaryConstructors.isEmpty()
|
||||
) {
|
||||
return source.toLightClass()?.constructors?.firstOrNull()
|
||||
}
|
||||
|
||||
return when (source) {
|
||||
is KtFunction -> LightClassUtil.getLightClassMethod(source)
|
||||
is PsiMethod -> source
|
||||
null -> resolveDeserialized(context, descriptor)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveDeserialized(context: KtElement, descriptor: DeclarationDescriptor): PsiMethod? {
|
||||
if (descriptor !is DeserializedCallableMemberDescriptor) return null
|
||||
|
||||
val containingDeclaration = descriptor.containingDeclaration
|
||||
val psiClass = when (containingDeclaration) {
|
||||
is LazyJavaPackageFragment -> {
|
||||
val binaryPackageSourceElement = containingDeclaration.source as? KotlinJvmBinaryPackageSourceElement ?: return null
|
||||
val containingBinaryClass = binaryPackageSourceElement.getContainingBinaryClass(descriptor) ?: return null
|
||||
val containingClassQualifiedName = containingBinaryClass.classId.asSingleFqName().asString()
|
||||
JavaPsiFacade.getInstance(context.project).findClass(containingClassQualifiedName, context.resolveScope) ?: return null
|
||||
}
|
||||
is DeserializedClassDescriptor -> {
|
||||
val declaredPsiType = containingDeclaration.defaultType.toPsiType(null, context, false)
|
||||
(declaredPsiType as? PsiClassType)?.resolve() ?: return null
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
|
||||
val proto = descriptor.proto
|
||||
val nameResolver = descriptor.nameResolver
|
||||
val typeTable = descriptor.typeTable
|
||||
|
||||
return when (proto) {
|
||||
is ProtoBuf.Function -> {
|
||||
val signature = JvmProtoBufUtil.getJvmMethodSignature(proto, nameResolver, typeTable)
|
||||
?: getMethodSignatureFromDescriptor(context, descriptor)
|
||||
?: return null
|
||||
|
||||
psiClass.methods.firstOrNull { it.name == signature.name && it.matchesDesc(signature.desc) }
|
||||
}
|
||||
is ProtoBuf.Constructor -> {
|
||||
val signature = JvmProtoBufUtil.getJvmConstructorSignature(proto, nameResolver, typeTable)
|
||||
?: getMethodSignatureFromDescriptor(context, descriptor)
|
||||
?: return null
|
||||
|
||||
psiClass.constructors.firstOrNull { it.matchesDesc(signature.desc) }
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiMethod.matchesDesc(desc: String) = desc == buildString {
|
||||
parameterList.parameters.joinTo(this, separator = "", prefix = "(", postfix = ")") { MapPsiToAsmDesc.typeDesc(it.type) }
|
||||
append(MapPsiToAsmDesc.typeDesc(returnType ?: PsiType.VOID))
|
||||
}
|
||||
|
||||
private fun getMethodSignatureFromDescriptor(context: KtElement, descriptor: CallableDescriptor): JvmMemberSignature? {
|
||||
fun PsiType.raw() = (this as? PsiClassType)?.rawType() ?: PsiPrimitiveType.getUnboxedType(this) ?: this
|
||||
fun KotlinType.toPsiType() = toPsiType(null, context, false).raw()
|
||||
|
||||
val originalDescriptor = descriptor.original
|
||||
val receiverType = originalDescriptor.extensionReceiverParameter?.type?.toPsiType()
|
||||
val parameterTypes = listOfNotNull(receiverType) + originalDescriptor.valueParameters.map { it.type.toPsiType() }
|
||||
val returnType = originalDescriptor.returnType?.toPsiType() ?: PsiType.VOID
|
||||
|
||||
val desc = parameterTypes.joinToString("", prefix = "(", postfix = ")") { MapPsiToAsmDesc.typeDesc(it) } +
|
||||
MapPsiToAsmDesc.typeDesc(returnType)
|
||||
|
||||
return JvmMemberSignature.Method(descriptor.name.asString(), desc)
|
||||
}
|
||||
|
||||
internal fun <T> lz(initializer: () -> T) = lazy(LazyThreadSafetyMode.SYNCHRONIZED, initializer)
|
||||
|
||||
internal fun KotlinType.toPsiType(source: UElement, element: KtElement, boxed: Boolean): PsiType {
|
||||
internal fun KotlinType.toPsiType(source: UElement, element: KtElement, boxed: Boolean): PsiType =
|
||||
toPsiType(source.getParentOfType<UDeclaration>(false)?.psi, element, boxed)
|
||||
|
||||
internal fun KotlinType.toPsiType(lightDeclaration: PsiModifierListOwner?, context: KtElement, boxed: Boolean): PsiType {
|
||||
if (this.isError) return UastErrorType
|
||||
|
||||
(constructor.declarationDescriptor as? TypeAliasDescriptor)?.let { typeAlias ->
|
||||
return typeAlias.expandedType.toPsiType(source, element, boxed)
|
||||
return typeAlias.expandedType.toPsiType(lightDeclaration, context, boxed)
|
||||
}
|
||||
|
||||
(constructor.declarationDescriptor as? TypeParameterDescriptor)?.let { typeParameter ->
|
||||
return CommonSupertypes.commonSupertype(typeParameter.upperBounds).toPsiType(lightDeclaration, context, boxed)
|
||||
}
|
||||
|
||||
if (arguments.isEmpty()) {
|
||||
val typeFqName = this.constructor.declarationDescriptor?.fqNameSafe?.asString()
|
||||
fun PsiPrimitiveType.orBoxed() = if (boxed) getBoxedType(element) else this
|
||||
fun PsiPrimitiveType.orBoxed() = if (boxed) getBoxedType(context) else this
|
||||
val psiType = when (typeFqName) {
|
||||
"kotlin.Int" -> PsiType.INT.orBoxed()
|
||||
"kotlin.Long" -> PsiType.LONG.orBoxed()
|
||||
@@ -95,11 +181,11 @@ internal fun KotlinType.toPsiType(source: UElement, element: KtElement, boxed: B
|
||||
"kotlin.Char" -> PsiType.CHAR.orBoxed()
|
||||
"kotlin.Double" -> PsiType.DOUBLE.orBoxed()
|
||||
"kotlin.Float" -> PsiType.FLOAT.orBoxed()
|
||||
"kotlin.String" -> PsiType.getJavaLangString(element.manager, GlobalSearchScope.projectScope(element.project))
|
||||
"kotlin.String" -> PsiType.getJavaLangString(context.manager, GlobalSearchScope.projectScope(context.project))
|
||||
else -> {
|
||||
val typeConstructor = this.constructor
|
||||
if (typeConstructor is IntegerValueTypeConstructor) {
|
||||
TypeUtils.getDefaultPrimitiveNumberType(typeConstructor).toPsiType(source, element, boxed)
|
||||
TypeUtils.getDefaultPrimitiveNumberType(typeConstructor).toPsiType(lightDeclaration, context, boxed)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
@@ -110,13 +196,13 @@ internal fun KotlinType.toPsiType(source: UElement, element: KtElement, boxed: B
|
||||
|
||||
if (this.containsLocalTypes()) return UastErrorType
|
||||
|
||||
val project = element.project
|
||||
val project = context.project
|
||||
val typeMapper = ServiceManager.getService(project, KotlinUastBindingContextProviderService::class.java)
|
||||
.getTypeMapper(element) ?: return UastErrorType
|
||||
.getTypeMapper(context) ?: return UastErrorType
|
||||
|
||||
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE)
|
||||
val typeMappingMode = if (boxed) TypeMappingMode.GENERIC_ARGUMENT else TypeMappingMode.DEFAULT
|
||||
val approximatedType = TypeApproximator().approximateDeclarationType(this, true, element.languageVersionSettings)
|
||||
val approximatedType = TypeApproximator().approximateDeclarationType(this, true, context.languageVersionSettings)
|
||||
typeMapper.mapType(approximatedType, signatureWriter, typeMappingMode)
|
||||
|
||||
val signature = StringCharacterIterator(signatureWriter.toString())
|
||||
@@ -125,7 +211,7 @@ internal fun KotlinType.toPsiType(source: UElement, element: KtElement, boxed: B
|
||||
val typeInfo = TypeInfo.fromString(javaType, false)
|
||||
val typeText = TypeInfo.createTypeText(typeInfo) ?: return UastErrorType
|
||||
|
||||
return ClsTypeElementImpl(source.getParentOfType<UDeclaration>(false)?.psi ?: element, typeText, '\u0000').type
|
||||
return ClsTypeElementImpl(lightDeclaration ?: context, typeText, '\u0000').type
|
||||
}
|
||||
|
||||
private fun KotlinType.containsLocalTypes(): Boolean {
|
||||
@@ -168,8 +254,8 @@ internal fun PsiElement.getMaybeLightElement(context: UElement): PsiElement? {
|
||||
}
|
||||
|
||||
internal fun KtElement.resolveCallToDeclaration(
|
||||
context: KotlinAbstractUElement,
|
||||
resultingDescriptor: DeclarationDescriptor? = null
|
||||
context: KotlinAbstractUElement,
|
||||
resultingDescriptor: DeclarationDescriptor? = null
|
||||
): PsiElement? {
|
||||
val descriptor = resultingDescriptor ?: run {
|
||||
val resolvedCall = getResolvedCall(analyze()) ?: return null
|
||||
@@ -191,7 +277,7 @@ internal fun KtExpression.unwrapBlockOrParenthesis(): KtExpression {
|
||||
internal fun KtElement.analyze(): BindingContext {
|
||||
if(containingFile !is KtFile) return BindingContext.EMPTY // EA-114080, EA-113475
|
||||
return ServiceManager.getService(project, KotlinUastBindingContextProviderService::class.java)
|
||||
?.getBindingContext(this) ?: BindingContext.EMPTY
|
||||
?.getBindingContext(this) ?: BindingContext.EMPTY
|
||||
}
|
||||
|
||||
internal inline fun <reified T : UDeclaration, reified P : PsiElement> unwrap(element: P): P {
|
||||
@@ -205,7 +291,7 @@ internal fun KtExpression.getExpectedType(): KotlinType? = analyze()[BindingCont
|
||||
internal fun KtTypeReference.getType(): KotlinType? = analyze()[BindingContext.TYPE, this]
|
||||
|
||||
internal fun KotlinType.getFunctionalInterfaceType(source: UElement, element: KtElement): PsiType? =
|
||||
takeIf { it.isInterface() && !it.isBuiltinFunctionalTypeOrSubtype }?.toPsiType(source, element, false)
|
||||
takeIf { it.isInterface() && !it.isBuiltinFunctionalTypeOrSubtype }?.toPsiType(source, element, false)
|
||||
|
||||
internal fun KotlinULambdaExpression.getFunctionalInterfaceType(): PsiType? {
|
||||
val parent = psi.parent
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
class A {
|
||||
fun foo() {}
|
||||
inline fun inlineFoo() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
A().foo()
|
||||
A().inlineFoo()
|
||||
listOf(A()).forEach { println(it) } // inline from stdlib
|
||||
listOf("").joinToString() // not inline from stdlib
|
||||
listOf("").size // property from stdlib
|
||||
listOf("").last() // overloaded extension from stdlib
|
||||
mutableMapOf(1 to "1").entries.first().setValue("123") // call on nested method in stdlib
|
||||
val intRange = 0L..3L
|
||||
intRange.contains(2 as Int) // extension-fun with @JvmName("longRangeContains")
|
||||
IntRange(1, 2) // constructor from stdlib
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin
|
||||
import org.jetbrains.uast.test.env.findElementByText
|
||||
@@ -340,6 +341,25 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
|
||||
assertArguments(listOf("\"foo\"", "1"), "object : Parent(b = 1, a = \"foo\")\n")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResolvedDeserializedMethod() = doTest("Resolve") { _, file ->
|
||||
val barMethod = file.findElementByTextFromPsi<UElement>("bar").getParentOfType<UMethod>()!!
|
||||
|
||||
fun UElement.assertResolveCall(callText: String, methodName: String = callText.substringBefore("(")) {
|
||||
this.findElementByTextFromPsi<UCallExpression>(callText).let {
|
||||
val resolve = it.resolve().sure { "resolving '$callText'" }
|
||||
assertEquals(methodName, resolve.name)
|
||||
}
|
||||
}
|
||||
barMethod.assertResolveCall("foo()")
|
||||
barMethod.assertResolveCall("inlineFoo()")
|
||||
barMethod.assertResolveCall("forEach { println(it) }", "forEach")
|
||||
barMethod.assertResolveCall("joinToString()")
|
||||
barMethod.assertResolveCall("last()")
|
||||
barMethod.assertResolveCall("setValue(\"123\")")
|
||||
barMethod.assertResolveCall("contains(2 as Int)", "longRangeContains")
|
||||
barMethod.assertResolveCall("IntRange(1, 2)")
|
||||
}
|
||||
}
|
||||
|
||||
fun <T, R> Iterable<T>.assertedFind(value: R, transform: (T) -> R): T =
|
||||
|
||||
@@ -5,8 +5,10 @@ import com.intellij.testFramework.UsefulTestCase
|
||||
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin
|
||||
import org.jetbrains.uast.test.env.findElementByText
|
||||
@@ -194,4 +196,22 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
|
||||
Assert.assertTrue((originalTypeParameters.declarations.single() as UParameter).type.isValid)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResolvedDeserializedMethod() = doTest("Resolve") { _, file ->
|
||||
val barMethod = file.psi.findElementAt(file.psi.text.indexOf("bar")).sure { "sourceElement" }
|
||||
.parentsWithSelf.mapNotNull { it.toUElementOfType<UMethod>() }.firstOrNull().sure { "parent UMethod" }
|
||||
|
||||
fun UElement.assertResolveCall(callText: String, methodName: String = callText.substringBefore("(")) {
|
||||
this.findElementByTextFromPsi<UCallExpression>(callText).let {
|
||||
val resolve = it.resolve().sure { "resolving '$callText'" }
|
||||
assertEquals(methodName, resolve.name)
|
||||
}
|
||||
}
|
||||
barMethod.assertResolveCall("foo()")
|
||||
barMethod.assertResolveCall("inlineFoo()")
|
||||
barMethod.assertResolveCall("forEach { println(it) }", "forEach")
|
||||
barMethod.assertResolveCall("joinToString()")
|
||||
barMethod.assertResolveCall("last()")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,10 @@ import com.intellij.testFramework.UsefulTestCase
|
||||
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getValueParameterList
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin
|
||||
import org.jetbrains.uast.test.env.findElementByText
|
||||
@@ -306,7 +307,23 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResolvedDeserializedMethod() = doTest("Resolve") { _, file ->
|
||||
val barMethod = file.findElementByTextFromPsi<UElement>("bar").sourcePsiElement.sure { "sourceElement" }
|
||||
.parentsWithSelf.mapNotNull { it.toUElementOfType<UMethod>() }.firstOrNull().sure { "parent UMethod" }
|
||||
|
||||
fun UElement.assertResolveCall(callText: String, methodName: String = callText.substringBefore("(")) {
|
||||
this.findElementByTextFromPsi<UCallExpression>(callText).let {
|
||||
val resolve = it.resolve().sure { "resolving '$callText'" }
|
||||
assertEquals(methodName, resolve.name)
|
||||
}
|
||||
}
|
||||
barMethod.assertResolveCall("foo()")
|
||||
barMethod.assertResolveCall("inlineFoo()")
|
||||
barMethod.assertResolveCall("forEach { println(it) }", "forEach")
|
||||
barMethod.assertResolveCall("joinToString()")
|
||||
barMethod.assertResolveCall("last()")
|
||||
}
|
||||
}
|
||||
|
||||
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