Make breakpoints work inside nameless function bodies in inline calls

This commit is contained in:
Nikolay Krasko
2016-11-23 17:29:07 +03:00
parent 89ac89f0c6
commit b007306740
4 changed files with 56 additions and 9 deletions
@@ -181,15 +181,27 @@ class DebuggerClassNameProvider(val myDebugProcess: DebugProcess, val scopes: Li
private fun inlineCallClassPatterns(typeMapper: KotlinTypeMapper, element: KtElement): List<String> {
val context = typeMapper.bindingContext
val (inlineCall, functionLiteral) = runReadAction {
element.parents.filterIsInstance<KtFunctionLiteral>().map {
val lambdaExpression = it.parent as? KtLambdaExpression ?: return@map null
val ktCallExpression =
lambdaExpression.typedParent<KtValueArgument>()?.typedParent<KtValueArgumentList>()?.typedParent<KtCallExpression>() ?:
lambdaExpression.typedParent<KtLambdaArgument>()?.typedParent<KtCallExpression>() ?:
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, { <it> })
lambdaExpression?.typedParent<KtValueArgument>()?.typedParent<KtValueArgumentList>()?.typedParent<KtCallExpression>() ?:
ktCallExpression to it
// call { <it> }
lambdaExpression?.typedParent<KtLambdaArgument>()?.typedParent<KtCallExpression>()
}
is KtNamedFunction -> {
// call(fun () {})
it.typedParent<KtValueArgument>()?.typedParent<KtValueArgumentList>()?.typedParent<KtCallExpression>()
}
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 "$") +
@@ -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
@@ -0,0 +1,19 @@
package stopInNamelessFunInInlineCall
fun main(args: Array<String>) {
val a = 1
inlineFun(fun (): Unit {
{
//Breakpoint!
foo(a)
foo(a)
}()
})
}
inline fun inlineFun(f: () -> Any) {
f()
}
fun foo(a: Any) {}
@@ -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");