diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt index bbcc37bcf47..5008520540e 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.stubs.KotlinUserTypeStub import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes import org.jetbrains.kotlin.psi.stubs.impl.* +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.serialization.Flags import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.ProtoBuf.Type @@ -100,7 +101,7 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) { createTypeAnnotationStubs(parent, type, notExtensionAnnotations) val isExtension = extensionAnnotations.isNotEmpty() - createFunctionTypeStub(nullableTypeParent(parent, type), type, isExtension) + createFunctionTypeStub(nullableTypeParent(parent, type), type, isExtension, Flags.SUSPEND_TYPE.get(type.flags)) return } @@ -158,7 +159,7 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) { Projection.STAR -> KtProjectionKind.STAR } - private fun createFunctionTypeStub(parent: StubElement, type: Type, isExtensionFunctionType: Boolean) { + private fun createFunctionTypeStub(parent: StubElement, type: Type, isExtensionFunctionType: Boolean, isSuspend: Boolean) { val typeArgumentList = type.argumentList val functionType = KotlinPlaceHolderStubImpl(parent, KtStubElementTypes.FUNCTION_TYPE) if (isExtensionFunctionType) { @@ -171,15 +172,35 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) { val parameterList = KotlinPlaceHolderStubImpl(functionType, KtStubElementTypes.VALUE_PARAMETER_LIST) val typeArgumentsWithoutReceiverAndReturnType = typeArgumentList.subList(if (isExtensionFunctionType) 1 else 0, typeArgumentList.size - 1) - typeArgumentsWithoutReceiverAndReturnType.forEach { argument -> + var suspendParameterType: Type? = null + + for ((index, argument) in typeArgumentsWithoutReceiverAndReturnType.withIndex()) { + if (isSuspend && index == typeArgumentsWithoutReceiverAndReturnType.size - 1) { + val parameterType = argument.type(c.typeTable)!! + if (parameterType.hasClassName() && parameterType.argumentCount == 1) { + val classId = c.nameResolver.getClassId(parameterType.className) + val fqName = classId.asSingleFqName() + if (fqName == DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME) { + suspendParameterType = parameterType + continue + } + } + } val parameter = KotlinParameterStubImpl( parameterList, fqName = null, name = null, isMutable = false, hasValOrVar = false, hasDefaultValue = false ) + createTypeReferenceStub(parameter, argument.type(c.typeTable)!!) } - val returnType = typeArgumentList.last().type(c.typeTable)!! - createTypeReferenceStub(functionType, returnType) + + if (suspendParameterType == null) { + val returnType = typeArgumentList.last().type(c.typeTable)!! + createTypeReferenceStub(functionType, returnType) + } + else { + createTypeReferenceStub(functionType, suspendParameterType.getArgument(0).type) + } } fun createValueParameterListStub( diff --git a/idea/testData/decompiler/stubBuilder/SuspendLambda/SuspendLambda.kt b/idea/testData/decompiler/stubBuilder/SuspendLambda/SuspendLambda.kt new file mode 100644 index 00000000000..77809f3e0e7 --- /dev/null +++ b/idea/testData/decompiler/stubBuilder/SuspendLambda/SuspendLambda.kt @@ -0,0 +1,14 @@ +package test + +class SuspendLambda { + fun (suspend () -> T).createCoroutine(completion: Continuation) {} + + fun testCoroutine(f: suspend (Int) -> T?) {} + + fun testCoroutineWithAnnotation(f: suspend (Int) -> @A T?) {} +} + +@Target(AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER) +annotation class A + +class Continuation {} \ No newline at end of file diff --git a/idea/testData/decompiler/stubBuilder/SuspendLambda/SuspendLambda.txt b/idea/testData/decompiler/stubBuilder/SuspendLambda/SuspendLambda.txt new file mode 100644 index 00000000000..638d6b3e553 --- /dev/null +++ b/idea/testData/decompiler/stubBuilder/SuspendLambda/SuspendLambda.txt @@ -0,0 +1,96 @@ +PsiJetFileStubImpl[package=test] + PACKAGE_DIRECTIVE + REFERENCE_EXPRESSION[referencedName=test] + IMPORT_LIST + CLASS[fqName=test.SuspendLambda, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=SuspendLambda, superNames=[]] + MODIFIER_LIST[public final] + PRIMARY_CONSTRUCTOR + MODIFIER_LIST[public] + VALUE_PARAMETER_LIST + CLASS_BODY + FUN[fqName=test.SuspendLambda.testCoroutine, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=true, isExtension=false, isTopLevel=false, name=testCoroutine] + MODIFIER_LIST[public final] + TYPE_PARAMETER_LIST + TYPE_PARAMETER[fqName=null, isInVariance=false, isOutVariance=false, name=T] + VALUE_PARAMETER_LIST + VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=f] + TYPE_REFERENCE + MODIFIER_LIST[suspend] + FUNCTION_TYPE + 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 + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=T] + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=kotlin] + REFERENCE_EXPRESSION[referencedName=Unit] + FUN[fqName=test.SuspendLambda.testCoroutineWithAnnotation, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=true, isExtension=false, isTopLevel=false, name=testCoroutineWithAnnotation] + MODIFIER_LIST[public final] + TYPE_PARAMETER_LIST + TYPE_PARAMETER[fqName=null, isInVariance=false, isOutVariance=false, name=T] + VALUE_PARAMETER_LIST + VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=f] + TYPE_REFERENCE + MODIFIER_LIST[suspend] + FUNCTION_TYPE + 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 + MODIFIER_LIST[] + ANNOTATION_ENTRY[hasValueArguments=false, shortName=A] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=test] + REFERENCE_EXPRESSION[referencedName=A] + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=T] + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=kotlin] + REFERENCE_EXPRESSION[referencedName=Unit] + FUN[fqName=test.SuspendLambda.createCoroutine, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=true, isExtension=true, isTopLevel=false, name=createCoroutine] + MODIFIER_LIST[public final] + TYPE_PARAMETER_LIST + TYPE_PARAMETER[fqName=null, isInVariance=false, isOutVariance=false, name=T] + TYPE_REFERENCE + MODIFIER_LIST[suspend] + FUNCTION_TYPE + VALUE_PARAMETER_LIST + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=T] + VALUE_PARAMETER_LIST + VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=completion] + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=test] + REFERENCE_EXPRESSION[referencedName=Continuation] + TYPE_ARGUMENT_LIST + TYPE_PROJECTION[projectionKind=NONE] + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=T] + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=kotlin] + REFERENCE_EXPRESSION[referencedName=Unit] diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderTestGenerated.java index b84aa7e45a3..88112adca7b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderTestGenerated.java @@ -186,6 +186,12 @@ public class ClsStubBuilderTestGenerated extends AbstractClsStubBuilderTest { doTest(fileName); } + @TestMetadata("SuspendLambda") + public void testSuspendLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/stubBuilder/SuspendLambda/"); + doTest(fileName); + } + @TestMetadata("TopLevelMembersAnnotatedKt") public void testTopLevelMembersAnnotatedKt() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/stubBuilder/TopLevelMembersAnnotatedKt/");