diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/MapPsiToAsmDesc.kt b/compiler/util/src/org/jetbrains/kotlin/type/MapPsiToAsmDesc.kt similarity index 94% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/MapPsiToAsmDesc.kt rename to compiler/util/src/org/jetbrains/kotlin/type/MapPsiToAsmDesc.kt index 88527646b84..0a693b4e3f0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/MapPsiToAsmDesc.kt +++ b/compiler/util/src/org/jetbrains/kotlin/type/MapPsiToAsmDesc.kt @@ -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) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/LightMemberOriginForCompiledElement.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/LightMemberOriginForCompiledElement.kt index c5713facaf9..6437d092cb2 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/LightMemberOriginForCompiledElement.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/LightMemberOriginForCompiledElement.kt @@ -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 diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt index db86b21c68b..68c19f28b66 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt @@ -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) { diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.173 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.173 index b2dfc81fcab..04a5f9b3192 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.173 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.173 @@ -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) { diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt index 35f7f36e08d..90248bf9e06 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt @@ -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) } } diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.172 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.172 index 5756815f8b2..90022da8f0d 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.172 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.172 @@ -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) } } diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.173 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.173 index dbfcfa8cbc2..c3af9a0fd5f 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.173 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.173 @@ -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) } } diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt index d3ce1ebbb00..81bf53db1f7 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt @@ -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 ?: " 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 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(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(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 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 diff --git a/plugins/uast-kotlin/testData/Resolve.kt b/plugins/uast-kotlin/testData/Resolve.kt new file mode 100644 index 00000000000..4100a17ba41 --- /dev/null +++ b/plugins/uast-kotlin/testData/Resolve.kt @@ -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 +} diff --git a/plugins/uast-kotlin/tests/KotlinUastApiTest.kt b/plugins/uast-kotlin/tests/KotlinUastApiTest.kt index 4a508dde279..8783d6455d4 100644 --- a/plugins/uast-kotlin/tests/KotlinUastApiTest.kt +++ b/plugins/uast-kotlin/tests/KotlinUastApiTest.kt @@ -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("bar").getParentOfType()!! + + fun UElement.assertResolveCall(callText: String, methodName: String = callText.substringBefore("(")) { + this.findElementByTextFromPsi(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 Iterable.assertedFind(value: R, transform: (T) -> R): T = diff --git a/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.172 b/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.172 index 11ab3106f14..908a756d096 100644 --- a/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.172 +++ b/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.172 @@ -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() }.firstOrNull().sure { "parent UMethod" } + + fun UElement.assertResolveCall(callText: String, methodName: String = callText.substringBefore("(")) { + this.findElementByTextFromPsi(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()") + } } diff --git a/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.173 b/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.173 index 4e673d38b1a..18eb64a27c9 100644 --- a/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.173 +++ b/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.173 @@ -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("bar").sourcePsiElement.sure { "sourceElement" } + .parentsWithSelf.mapNotNull { it.toUElementOfType() }.firstOrNull().sure { "parent UMethod" } + fun UElement.assertResolveCall(callText: String, methodName: String = callText.substringBefore("(")) { + this.findElementByTextFromPsi(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 Iterable.assertedFind(value: R, transform: (T) -> R): T = find { transform(it) == value } ?: throw AssertionError("'$value' not found, only ${this.joinToString { transform(it).toString() }}")