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 bdaa26c942a..88aa1db9c95 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 @@ -76,6 +76,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.uast.* import org.jetbrains.uast.kotlin.expressions.KotlinLocalFunctionUVariable +import org.jetbrains.uast.kotlin.psi.UastDescriptorLightMethod import org.jetbrains.uast.kotlin.psi.UastFakeLightMethod import org.jetbrains.uast.kotlin.psi.UastFakeLightPrimaryConstructor import java.lang.ref.WeakReference @@ -425,7 +426,7 @@ private fun resolveDeserialized( psiClass.getMethodBySignature( JvmProtoBufUtil.getJvmMethodSignature(proto, nameResolver, typeTable) ?: getMethodSignatureFromDescriptor(context, descriptor) - ) + ) ?: UastDescriptorLightMethod(descriptor as SimpleFunctionDescriptor, psiClass, context) // fake Java-invisible methods } is ProtoBuf.Constructor -> { val signature = JvmProtoBufUtil.getJvmConstructorSignature(proto, nameResolver, typeTable) diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastDescriptorLightMethod.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastDescriptorLightMethod.kt new file mode 100644 index 00000000000..283d16196ea --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastDescriptorLightMethod.kt @@ -0,0 +1,126 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.uast.kotlin.psi + +import com.intellij.psi.* +import com.intellij.psi.impl.light.* +import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterListBuilder +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtFunction +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import org.jetbrains.uast.UastErrorType +import org.jetbrains.uast.kotlin.analyze +import org.jetbrains.uast.kotlin.getType +import org.jetbrains.uast.kotlin.toPsiType + +internal class UastDescriptorLightMethod(original: SimpleFunctionDescriptor, containingClass: PsiClass, context: KtElement) : + UastDescriptorLightMethodBase(original, containingClass, context) { + + private val _buildTypeParameterList by lazy { + KotlinLightTypeParameterListBuilder(this).also { paramList -> + for ((i, p) in original.typeParameters.withIndex()) { + paramList.addParameter( + object : LightTypeParameterBuilder( + p.name.identifier, + this, + i + ) { + private val myExtendsList by lazy { + super.getExtendsList().apply { + p.upperBounds.forEach { bound -> + bound.toPsiType(this@UastDescriptorLightMethod, context, false) + .safeAs() + ?.let { addReference(it) } + } + } + } + + override fun getExtendsList(): LightReferenceListBuilder = myExtendsList + } + ) + } + } + } + + override fun getTypeParameterList(): PsiTypeParameterList = _buildTypeParameterList + + private val paramsList: PsiParameterList by lazy { + object : LightParameterListBuilder(containingClass.manager, containingClass.language) { + override fun getParent(): PsiElement = this@UastDescriptorLightMethod + override fun getContainingFile(): PsiFile = parent.containingFile + + init { + val parameterList = this + + original.extensionReceiverParameter?.let { receiver -> + this.addParameter( + UastDescriptorLightParameterBase( + "\$this\$${original.name.identifier}", + receiver.type.toPsiType(this@UastDescriptorLightMethod, context, false), + parameterList, + receiver + ) + ) + } + + for ((i, p) in original.valueParameters.withIndex()) { + this.addParameter( + UastDescriptorLightParameter( + p.name.identifier, + p.type.toPsiType(this@UastDescriptorLightMethod, context, false), + parameterList, + p + ) + ) + } + } + } + } + + override fun getParameterList(): PsiParameterList = paramsList +} + +internal abstract class UastDescriptorLightMethodBase( + internal val original: T, containingClass: PsiClass, protected val context: KtElement +) : LightMethodBuilder( + containingClass.manager, containingClass.language, original.name.identifier, + LightParameterListBuilder(containingClass.manager, containingClass.language), + LightModifierList(containingClass.manager) +) { + + init { + this.containingClass = containingClass + if (original.dispatchReceiverParameter == null) { + addModifier(PsiModifier.STATIC) + } + } + + + override fun getReturnType(): PsiType? { + return original.returnType?.toPsiType(this, context, false) + } + + override fun getParent(): PsiElement? = containingClass + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as UastDescriptorLightMethodBase<*> + + if (original != other.original) return false + + return true + } + + override fun hashCode(): Int = original.hashCode() +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastDescriptorLightParameter.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastDescriptorLightParameter.kt new file mode 100644 index 00000000000..852ccb2f4ec --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastDescriptorLightParameter.kt @@ -0,0 +1,49 @@ +package org.jetbrains.uast.kotlin.psi + +import com.intellij.lang.Language +import com.intellij.psi.* +import com.intellij.psi.impl.light.LightParameter +import org.jetbrains.kotlin.descriptors.ParameterDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.components.isVararg +import org.jetbrains.uast.UDeclaration +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UastErrorType +import org.jetbrains.uast.getParentOfType +import org.jetbrains.uast.kotlin.analyze +import org.jetbrains.uast.kotlin.toPsiType + +internal class UastDescriptorLightParameter( + name: String, + type: PsiType, + parent: PsiElement, + ktParameter: ValueParameterDescriptor, + language: Language = parent.language, +) : UastDescriptorLightParameterBase(name, type, parent, ktParameter, language) + +internal open class UastDescriptorLightParameterBase( + name: String, + type: PsiType, + private val parent: PsiElement, + val ktOrigin: T, + language: Language = parent.language, +) : LightParameter(name, type, parent, language, ktOrigin.isVararg) { + + override fun getParent(): PsiElement = parent + + override fun getContainingFile(): PsiFile? = parent.containingFile + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || other::class.java != this::class.java) return false + return ktOrigin == (other as? UastDescriptorLightParameterBase<*>)?.ktOrigin + } + + override fun hashCode(): Int = ktOrigin.hashCode() +} diff --git a/plugins/uast-kotlin/testData/ReifiedResolve.resolved.txt b/plugins/uast-kotlin/testData/ReifiedResolve.resolved.txt index 8fdca272777..fe1fcb825ca 100644 --- a/plugins/uast-kotlin/testData/ReifiedResolve.resolved.txt +++ b/plugins/uast-kotlin/testData/ReifiedResolve.resolved.txt @@ -16,7 +16,7 @@ UTypeReferenceExpression (name = T) -> USimpleNameReferenceExpression (identifie UTypeReferenceExpression (name = java.lang.String) -> USimpleNameReferenceExpression (identifier = String) -> PsiClass:String: String UTypeReferenceExpression (name = java.lang.String) -> USimpleNameReferenceExpression (identifier = String) -> PsiClass:String: String UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))(resolves to KtUltraLightMethodForSourceDeclaration:bar) -> USimpleNameReferenceExpression (identifier = bar) -> KtUltraLightMethodForSourceDeclaration:bar: bar - ULocalVariable (name = z) -> UQualifiedReferenceExpression -> null: null + ULocalVariable (name = z) -> UQualifiedReferenceExpression -> LightMethodBuilder:filterIsInstance: filterIsInstance UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))(resolves to PsiMethod:listOf) -> USimpleNameReferenceExpression (identifier = listOf) -> PsiMethod:listOf: listOf - UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))(resolves to null) -> USimpleNameReferenceExpression (identifier = filterIsInstance) -> null: null + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))(resolves to LightMethodBuilder:filterIsInstance) -> USimpleNameReferenceExpression (identifier = filterIsInstance) -> LightMethodBuilder:filterIsInstance: filterIsInstance UTypeReferenceExpression (name = java.lang.String) -> USimpleNameReferenceExpression (identifier = String) -> PsiClass:String: String