From b007306740f358c024a69712420f5bc42ff3cbc7 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Wed, 23 Nov 2016 17:29:07 +0300 Subject: [PATCH] Make breakpoints work inside nameless function bodies in inline calls --- .../debugger/DebuggerClassNameProvider.kt | 32 +++++++++++++------ .../outs/stopInNamelessFunInInlineCall.out | 8 +++++ .../stepOver/stopInNamelessFunInInlineCall.kt | 19 +++++++++++ .../debugger/KotlinSteppingTestGenerated.java | 6 ++++ 4 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 idea/testData/debugger/tinyApp/outs/stopInNamelessFunInInlineCall.out create mode 100644 idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInNamelessFunInInlineCall.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt index cb389b2584d..24ac1fbdb04 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/DebuggerClassNameProvider.kt @@ -181,15 +181,27 @@ class DebuggerClassNameProvider(val myDebugProcess: DebugProcess, val scopes: Li private fun inlineCallClassPatterns(typeMapper: KotlinTypeMapper, element: KtElement): List { val context = typeMapper.bindingContext - val (inlineCall, functionLiteral) = runReadAction { - element.parents.filterIsInstance().map { - val lambdaExpression = it.parent as? KtLambdaExpression ?: return@map null - val ktCallExpression = - lambdaExpression.typedParent()?.typedParent()?.typedParent() ?: - lambdaExpression.typedParent()?.typedParent() ?: - return@map null + val (inlineCall, ktAnonymousClassElementProducer) = runReadAction { + element.parents.map { + val ktCallExpression: KtCallExpression = when(it) { + is KtFunctionLiteral -> { + val lambdaExpression = it.parent as? KtLambdaExpression + // call(param, { }) + lambdaExpression?.typedParent()?.typedParent()?.typedParent() ?: - ktCallExpression to it + // call { } + lambdaExpression?.typedParent()?.typedParent() + } + + is KtNamedFunction -> { + // call(fun () {}) + it.typedParent()?.typedParent()?.typedParent() + } + + else -> null + } ?: return@map null + + ktCallExpression to (it as KtElement) }.lastOrNull { it != null && isInlineCall(context, it.component1()) } @@ -200,7 +212,9 @@ class DebuggerClassNameProvider(val myDebugProcess: DebugProcess, val scopes: Li val resolvedCall = runReadAction { inlineCall.getResolvedCall(context) } ?: return emptyList() val inlineFunctionName = resolvedCall.resultingDescriptor.name - val originalInternalClassName = CodegenBinding.asmTypeForAnonymousClass(typeMapper.bindingContext, functionLiteral).internalName + val originalInternalClassName = CodegenBinding.asmTypeForAnonymousClass( + typeMapper.bindingContext, ktAnonymousClassElementProducer).internalName + val ownerDescriptorName = lexicalScope.ownerDescriptor.name val mangledInternalClassName = originalInternalClassName.funPrefix() + (if (ownerDescriptorName.isSpecial) "\$\$special\$" else "$") + diff --git a/idea/testData/debugger/tinyApp/outs/stopInNamelessFunInInlineCall.out b/idea/testData/debugger/tinyApp/outs/stopInNamelessFunInInlineCall.out new file mode 100644 index 00000000000..7faba711ed4 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/stopInNamelessFunInInlineCall.out @@ -0,0 +1,8 @@ +LineBreakpoint created at stopInNamelessFunInInlineCall.kt:9 +!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! stopInNamelessFunInInlineCall.StopInNamelessFunInInlineCallKt +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +stopInNamelessFunInInlineCall.kt:9 +stopInNamelessFunInInlineCall.kt:10 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInNamelessFunInInlineCall.kt b/idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInNamelessFunInInlineCall.kt new file mode 100644 index 00000000000..8907059b512 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInNamelessFunInInlineCall.kt @@ -0,0 +1,19 @@ +package stopInNamelessFunInInlineCall + +fun main(args: Array) { + val a = 1 + + inlineFun(fun (): Unit { + { + //Breakpoint! + foo(a) + foo(a) + }() + }) +} + +inline fun inlineFun(f: () -> Any) { + f() +} + +fun foo(a: Any) {} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java index b98d24a06ff..e94efc782bc 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java @@ -764,6 +764,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest { doStepOverTest(fileName); } + @TestMetadata("stopInNamelessFunInInlineCall.kt") + public void testStopInNamelessFunInInlineCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInNamelessFunInInlineCall.kt"); + doStepOverTest(fileName); + } + @TestMetadata("stopInNonInlinedLambdaInInlineCallWithClosure.kt") public void testStopInNonInlinedLambdaInInlineCallWithClosure() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInNonInlinedLambdaInInlineCallWithClosure.kt");