[ClsStubs] Add context receivers on function types

This commit is contained in:
Egor Kulikov
2023-04-20 19:26:46 +02:00
committed by teamcity
parent 6b41c5a969
commit c46c922841
6 changed files with 98 additions and 9 deletions
@@ -0,0 +1,12 @@
// JVM_FILE_NAME: ContextReceiversOnFunctionTypeKt
// !LANGUAGE: +ContextReceivers
fun f(g: context(A, B) Int.(Int) -> Int) {}
class A {
val valueA: Int = 10
}
class B {
val valueB: Int = 11
}
@@ -0,0 +1,41 @@
PsiJetFileStubImpl[package=]
PACKAGE_DIRECTIVE
IMPORT_LIST
FUN[fqName=f, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=true, mayHaveContract=false, name=f]
MODIFIER_LIST[public]
VALUE_PARAMETER_LIST
VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=g]
TYPE_REFERENCE
FUNCTION_TYPE
CONTEXT_RECEIVER_LIST
CONTEXT_RECEIVER[label=null]
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION[referencedName=A]
CONTEXT_RECEIVER[label=null]
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION[referencedName=B]
FUNCTION_TYPE_RECEIVER
TYPE_REFERENCE
USER_TYPE
USER_TYPE
REFERENCE_EXPRESSION[referencedName=kotlin]
REFERENCE_EXPRESSION[referencedName=Int]
VALUE_PARAMETER_LIST
VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=null]
TYPE_REFERENCE
USER_TYPE
USER_TYPE
REFERENCE_EXPRESSION[referencedName=kotlin]
REFERENCE_EXPRESSION[referencedName=Int]
TYPE_REFERENCE
USER_TYPE
USER_TYPE
REFERENCE_EXPRESSION[referencedName=kotlin]
REFERENCE_EXPRESSION[referencedName=Int]
TYPE_REFERENCE
USER_TYPE
USER_TYPE
REFERENCE_EXPRESSION[referencedName=kotlin]
REFERENCE_EXPRESSION[referencedName=Unit]
@@ -108,6 +108,12 @@ public class ClsStubBuilderTestGenerated extends AbstractClsStubBuilderTest {
runTest("analysis/decompiled/decompiler-to-file-stubs/testData/clsFileStubBuilder/ContextReceiversOnClass/");
}
@Test
@TestMetadata("ContextReceiversOnFunctionType")
public void testContextReceiversOnFunctionType() throws Exception {
runTest("analysis/decompiled/decompiler-to-file-stubs/testData/clsFileStubBuilder/ContextReceiversOnFunctionType/");
}
@Test
@TestMetadata("ContextReceiversOnTopLevelCallables")
public void testContextReceiversOnTopLevelCallables() throws Exception {
@@ -108,6 +108,12 @@ public class ByDecompiledPsiStubBuilderTestGenerated extends AbstractByDecompile
runTest("analysis/decompiled/decompiler-to-file-stubs/testData/clsFileStubBuilder/ContextReceiversOnClass/");
}
@Test
@TestMetadata("ContextReceiversOnFunctionType")
public void testContextReceiversOnFunctionType() throws Exception {
runTest("analysis/decompiled/decompiler-to-file-stubs/testData/clsFileStubBuilder/ContextReceiversOnFunctionType/");
}
@Test
@TestMetadata("ContextReceiversOnTopLevelCallables")
public void testContextReceiversOnTopLevelCallables() throws Exception {
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.metadata.ProtoBuf.Type
import org.jetbrains.kotlin.metadata.ProtoBuf.Type.Argument.Projection
import org.jetbrains.kotlin.metadata.ProtoBuf.TypeParameter.Variance
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -110,19 +111,29 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) {
it.classId.asSingleFqName() == StandardNames.FqNames.extensionFunctionType
}
val (contextReceiverAnnotations, otherAnnotations) = notExtensionAnnotations.partition {
it.classId.asSingleFqName() == StandardNames.FqNames.contextFunctionTypeParams
}
val isExtension = extensionAnnotations.isNotEmpty()
val isSuspend = Flags.SUSPEND_TYPE.get(type.flags)
val nullableWrapper = if (isSuspend) {
val wrapper = nullableTypeParent(parent, type)
createTypeAnnotationStubs(wrapper, type, notExtensionAnnotations)
createTypeAnnotationStubs(wrapper, type, otherAnnotations)
wrapper
} else {
createTypeAnnotationStubs(parent, type, notExtensionAnnotations)
createTypeAnnotationStubs(parent, type, otherAnnotations)
nullableTypeParent(parent, type)
}
createFunctionTypeStub(nullableWrapper, type, isExtension, isSuspend)
val numContextReceivers = if (contextReceiverAnnotations.isEmpty()) {
0
} else {
val argument = type.getExtension(JvmProtoBuf.typeAnnotation).find { c.nameResolver.getClassId(it.id).asSingleFqName() == StandardNames.FqNames.contextFunctionTypeParams }!!.getArgument(0)
argument.value.intValue.toInt()
}
createFunctionTypeStub(nullableWrapper, type, isExtension, isSuspend, numContextReceivers)
return
}
@@ -225,20 +236,33 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) {
parent: StubElement<out PsiElement>,
type: Type,
isExtensionFunctionType: Boolean,
isSuspend: Boolean
isSuspend: Boolean,
numContextReceivers: Int,
) {
val typeArgumentList = type.argumentList
val functionType = KotlinPlaceHolderStubImpl<KtFunctionType>(parent, KtStubElementTypes.FUNCTION_TYPE)
var processedTypes = 0
if (numContextReceivers != 0) {
ContextReceiversListStubBuilder(c).createContextReceiverStubs(
functionType,
typeArgumentList.subList(
processedTypes,
processedTypes + numContextReceivers
).map { it.type(c.typeTable)!! })
processedTypes += numContextReceivers
}
if (isExtensionFunctionType) {
val functionTypeReceiverStub =
KotlinPlaceHolderStubImpl<KtFunctionTypeReceiver>(functionType, KtStubElementTypes.FUNCTION_TYPE_RECEIVER)
val receiverTypeProto = typeArgumentList.first().type(c.typeTable)!!
val receiverTypeProto = typeArgumentList[processedTypes].type(c.typeTable)!!
createTypeReferenceStub(functionTypeReceiverStub, receiverTypeProto)
processedTypes++
}
val parameterList = KotlinPlaceHolderStubImpl<KtParameterList>(functionType, KtStubElementTypes.VALUE_PARAMETER_LIST)
val typeArgumentsWithoutReceiverAndReturnType =
typeArgumentList.subList(if (isExtensionFunctionType) 1 else 0, typeArgumentList.size - 1)
val typeArgumentsWithoutReceiverAndReturnType = typeArgumentList.subList(processedTypes, typeArgumentList.size - 1)
var suspendParameterType: Type? = null
for ((index, argument) in typeArgumentsWithoutReceiverAndReturnType.withIndex()) {
@@ -23,12 +23,12 @@ object KotlinStubVersions {
// Though only kotlin declarations (no code in the bodies) are stubbed, please do increase this version
// if you are not 100% sure it can be avoided.
// Increasing this version will lead to reindexing of all kotlin source files on the first IDE startup with the new version.
const val SOURCE_STUB_VERSION = 148
const val SOURCE_STUB_VERSION = 149
// Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed
// or changes are made to the core stub building code (org.jetbrains.kotlin.idea.decompiler.stubBuilder).
// Increasing this version will lead to reindexing of all binary files that are potentially kotlin binaries (including all class files).
private const val BINARY_STUB_VERSION = 84
private const val BINARY_STUB_VERSION = 85
// Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile)
// Increasing this version will lead to reindexing of all classfiles.