From 060b6e6b158f159640bcefafc60a870386d579a4 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Wed, 2 Sep 2015 12:22:06 +0300 Subject: [PATCH] Debugger: support stepping out inline function --- .../stepping/KotlinSteppingCommandProvider.kt | 121 ++++++++++++++++-- .../kotlin/idea/util/DebuggerUtils.java | 13 ++ .../tinyApp/outs/stepOutInlineFunction.out | 8 ++ .../outs/stepOutInlineFunctionStdlib.out | 9 ++ .../outs/stepOutInlinedLambdaArgument.out | 9 ++ .../stepOutSeveralInlineArgumentDeepest.out | 10 ++ .../outs/stepOutSeveralInlineFunctions.out | 8 ++ .../stepOutSeveralInlineFunctionsDeepest.out | 8 ++ .../custom/stepOutInlineFunctionStdlib.kt | 15 +++ .../stepping/stepOut/stepOutInlineFunction.kt | 19 +++ .../stepOut/stepOutInlinedLambdaArgument.kt | 20 +++ .../stepOutSeveralInlineArgumentDeepest.kt | 27 ++++ .../stepOut/stepOutSeveralInlineFunctions.kt | 25 ++++ .../stepOutSeveralInlineFunctionsDeepest.kt | 25 ++++ .../idea/debugger/KotlinDebuggerTestBase.kt | 4 +- .../debugger/KotlinSteppingTestGenerated.java | 36 ++++++ 16 files changed, 348 insertions(+), 9 deletions(-) create mode 100644 idea/testData/debugger/tinyApp/outs/stepOutInlineFunction.out create mode 100644 idea/testData/debugger/tinyApp/outs/stepOutInlineFunctionStdlib.out create mode 100644 idea/testData/debugger/tinyApp/outs/stepOutInlinedLambdaArgument.out create mode 100644 idea/testData/debugger/tinyApp/outs/stepOutSeveralInlineArgumentDeepest.out create mode 100644 idea/testData/debugger/tinyApp/outs/stepOutSeveralInlineFunctions.out create mode 100644 idea/testData/debugger/tinyApp/outs/stepOutSeveralInlineFunctionsDeepest.out create mode 100644 idea/testData/debugger/tinyApp/src/stepping/custom/stepOutInlineFunctionStdlib.kt create mode 100644 idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlineFunction.kt create mode 100644 idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlinedLambdaArgument.kt create mode 100644 idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineArgumentDeepest.kt create mode 100644 idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctions.kt create mode 100644 idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctionsDeepest.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt index 1b2766a0180..ef4e2f56d36 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt @@ -24,14 +24,20 @@ import com.intellij.debugger.engine.events.DebuggerCommandImpl import com.intellij.debugger.impl.JvmSteppingCommandProvider import com.intellij.util.concurrency.Semaphore import com.intellij.xdebugger.impl.XSourcePositionImpl +import com.sun.jdi.Location import com.sun.jdi.ReferenceType import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils import org.jetbrains.kotlin.idea.core.refactoring.getLineCount import org.jetbrains.kotlin.idea.core.refactoring.getLineStartOffset +import org.jetbrains.kotlin.idea.util.DebuggerUtils import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode @@ -44,16 +50,13 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() { ): DebugProcessImpl.ResumeCommand? { if (suspendContext == null) return null - if (!isKotlinStrataPresent(suspendContext)) return null - - val result: Pair>? = computeInManagerThread(suspendContext) { + val result: Pair? = computeInManagerThread(suspendContext) { val sp = runReadAction { ContextUtil.getSourcePosition(it) } ?: return@computeInManagerThread null - val cl = it.debugProcess.positionManager.getAllClasses(sp) + val cl = it.frameProxy?.location()?.declaringType() ?: return@computeInManagerThread null sp to cl } - val (sourcePosition, allClasses) = result ?: return null - val computedReferenceType = allClasses.firstOrNull() ?: return null + val (sourcePosition, computedReferenceType) = result ?: return null val file = sourcePosition.file as? JetFile ?: return null @@ -80,7 +83,107 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() { return null } - private fun isKotlinStrataPresent(suspendContext: SuspendContextImpl): Boolean { + override fun getStepOutCommand(suspendContext: SuspendContextImpl?, stepSize: Int): DebugProcessImpl.ResumeCommand? { + if (suspendContext == null) return null + + val location = computeInManagerThread(suspendContext) { + it.frameProxy?.location() + } ?: return null + + val sourcePosition = suspendContext.debugProcess.positionManager.getSourcePosition(location) ?: return null + val computedReferenceType = location.declaringType() ?: return null + + val locations = computedReferenceType.allLineLocations() + + val file = sourcePosition.file as? JetFile ?: return null + val lineStartOffset = file.getLineStartOffset(sourcePosition.line) ?: return null + val nextLineLocations = locations.dropWhile { it.lineNumber() != location.lineNumber() }.filter { it.method() == location.method() } + + val inlineFunction = getInlineFunctionsIfAny(file, lineStartOffset) + if (inlineFunction != null) { + val xPosition = suspendContext.getXPositionForStepOutFromInlineFunction(nextLineLocations, inlineFunction) ?: return null + return suspendContext.debugProcess.createRunToCursorCommand(suspendContext, xPosition, true) + } + + val inlinedArgument = getInlineArgumentIfAny(file, lineStartOffset) + if (inlinedArgument != null) { + val xPosition = suspendContext.getXPositionForStepOutFromInlinedArgument(nextLineLocations, inlinedArgument) ?: return null + return suspendContext.debugProcess.createRunToCursorCommand(suspendContext, xPosition, true) + } + + return null + } + + private fun SuspendContextImpl.getXPositionForStepOutFromInlineFunction( + locations: List, + inlineFunctionsToSkip: List + ): XSourcePositionImpl? { + return getNextPositionWithFilter(locations) { + file, offset -> + if (inlineFunctionsToSkip.any { it.textRange.contains(offset) }) { + return@getNextPositionWithFilter true + } + + val inlinedArgument = getInlineArgumentIfAny(file, offset) + inlinedArgument != null && inlinedArgument.textRange.contains(offset) + } + } + + private fun SuspendContextImpl.getXPositionForStepOutFromInlinedArgument( + locations: List, + inlinedArgumentToSkip: JetFunctionLiteral + ): XSourcePositionImpl? { + return getNextPositionWithFilter(locations) { + file, offset -> + inlinedArgumentToSkip.textRange.contains(offset) + } + } + + private fun SuspendContextImpl.getNextPositionWithFilter( + locations: List, + skip: (JetFile, Int) -> Boolean + ): XSourcePositionImpl? { + for (location in locations) { + val file = this.debugProcess.positionManager.getSourcePosition(location)?.file as? JetFile ?: continue + val currentLine = location.lineNumber() - 1 + val lineStartOffset = file.getLineStartOffset(currentLine) ?: continue + if (skip(file, lineStartOffset)) continue + + val elementAt = file.findElementAt(lineStartOffset) ?: continue + return XSourcePositionImpl.createByElement(elementAt) + } + + return null + } + + private fun getInlineFunctionsIfAny(file: JetFile, offset: Int): List? { + val elementAt = file.findElementAt(offset) ?: return null + val containingFunction = elementAt.getParentOfType(false) ?: return null + + val descriptor = containingFunction.resolveToDescriptor() + if (!InlineUtil.isInline(descriptor)) return null + + val inlineFunctionsCalls = DebuggerUtils.analyzeElementWithInline( + containingFunction.getResolutionFacade(), + containingFunction.analyzeFully(), + containingFunction, + false + ).filterIsInstance() + + return inlineFunctionsCalls + } + + private fun getInlineArgumentIfAny(file: JetFile, offset: Int): JetFunctionLiteral? { + val elementAt = file.findElementAt(offset) ?: return null + val functionLiteralExpression = elementAt.getParentOfType(false) ?: return null + + val context = functionLiteralExpression.analyze(BodyResolveMode.PARTIAL) + if (!InlineUtil.isInlinedArgument(functionLiteralExpression.functionLiteral, context, false)) return null + + return functionLiteralExpression.functionLiteral + } + + private fun isKotlinStrataAvailable(suspendContext: SuspendContextImpl): Boolean { val availableStrata = suspendContext.frameProxy?.location()?.declaringType()?.availableStrata() ?: return false return availableStrata.contains("Kotlin") } @@ -93,7 +196,9 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() { val worker = object : DebuggerCommandImpl() { override fun action() { try { - result = action(suspendContext) + if (isKotlinStrataAvailable(suspendContext)) { + result = action(suspendContext) + } } finally { semaphore.up() diff --git a/idea/src/org/jetbrains/kotlin/idea/util/DebuggerUtils.java b/idea/src/org/jetbrains/kotlin/idea/util/DebuggerUtils.java index 4daea016d71..a4781313d6d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/util/DebuggerUtils.java +++ b/idea/src/org/jetbrains/kotlin/idea/util/DebuggerUtils.java @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.idea.resolve.ResolutionFacade; import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils; import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde; import org.jetbrains.kotlin.idea.debugger.DebuggerPackage; +import org.jetbrains.kotlin.idea.resolve.ResolvePackage; import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; import org.jetbrains.kotlin.psi.*; @@ -177,6 +178,18 @@ public class DebuggerUtils { return new Pair>(context, new ArrayList(toProcess)); } + @NotNull + public static Collection analyzeElementWithInline( + @NotNull ResolutionFacade resolutionFacade, + @NotNull BindingContext bindingContext, + @NotNull JetNamedFunction function, + boolean analyzeInlineFunctions + ) { + Set analyzedElements = new HashSet(); + analyzeElementWithInline(resolutionFacade, bindingContext, function, 1, analyzedElements, !analyzeInlineFunctions); + return analyzedElements; + } + @NotNull private static BindingContext analyzeElementWithInline( @NotNull ResolutionFacade resolutionFacade, diff --git a/idea/testData/debugger/tinyApp/outs/stepOutInlineFunction.out b/idea/testData/debugger/tinyApp/outs/stepOutInlineFunction.out new file mode 100644 index 00000000000..6dae41c9b83 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/stepOutInlineFunction.out @@ -0,0 +1,8 @@ +LineBreakpoint created at stepOutInlineFunction.kt:12 +!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! stepOutInlineFunction.StepOutInlineFunctionPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +stepOutInlineFunction.kt:12 +stepOutInlineFunction.kt:7 +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/outs/stepOutInlineFunctionStdlib.out b/idea/testData/debugger/tinyApp/outs/stepOutInlineFunctionStdlib.out new file mode 100644 index 00000000000..b5140b5e5a5 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/stepOutInlineFunctionStdlib.out @@ -0,0 +1,9 @@ +LineBreakpoint created at stepOutInlineFunctionStdlib.kt:6 +!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! stepOutInlineFunctionStdlib.StepOutInlineFunctionStdlibPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +stepOutInlineFunctionStdlib.kt:6 +_Elements.!EXT! +stepOutInlineFunctionStdlib.kt:9 +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/outs/stepOutInlinedLambdaArgument.out b/idea/testData/debugger/tinyApp/outs/stepOutInlinedLambdaArgument.out new file mode 100644 index 00000000000..a54cf8acda5 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/stepOutInlinedLambdaArgument.out @@ -0,0 +1,9 @@ +LineBreakpoint created at stepOutInlinedLambdaArgument.kt:6 +!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! stepOutInlinedLambdaArgument.StepOutInlinedLambdaArgumentPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +stepOutInlinedLambdaArgument.kt:6 +stepOutInlinedLambdaArgument.kt:15 +stepOutInlinedLambdaArgument.kt:9 +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/outs/stepOutSeveralInlineArgumentDeepest.out b/idea/testData/debugger/tinyApp/outs/stepOutSeveralInlineArgumentDeepest.out new file mode 100644 index 00000000000..dfb8f27d94f --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/stepOutSeveralInlineArgumentDeepest.out @@ -0,0 +1,10 @@ +LineBreakpoint created at stepOutSeveralInlineArgumentDeepest.kt:6 +!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! stepOutSeveralInlineArgumentDeepest.StepOutSeveralInlineArgumentDeepestPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +stepOutSeveralInlineArgumentDeepest.kt:6 +stepOutSeveralInlineArgumentDeepest.kt:22 +stepOutSeveralInlineArgumentDeepest.kt:16 +stepOutSeveralInlineArgumentDeepest.kt:8 +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/outs/stepOutSeveralInlineFunctions.out b/idea/testData/debugger/tinyApp/outs/stepOutSeveralInlineFunctions.out new file mode 100644 index 00000000000..96e0f2b31db --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/stepOutSeveralInlineFunctions.out @@ -0,0 +1,8 @@ +LineBreakpoint created at stepOutSeveralInlineFunctions.kt:12 +!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! stepOutSeveralInlineFunctions.StepOutSeveralInlineFunctionsPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +stepOutSeveralInlineFunctions.kt:12 +stepOutSeveralInlineFunctions.kt:7 +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/outs/stepOutSeveralInlineFunctionsDeepest.out b/idea/testData/debugger/tinyApp/outs/stepOutSeveralInlineFunctionsDeepest.out new file mode 100644 index 00000000000..8de2ecf25a4 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/stepOutSeveralInlineFunctionsDeepest.out @@ -0,0 +1,8 @@ +LineBreakpoint created at stepOutSeveralInlineFunctionsDeepest.kt:20 +!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! stepOutSeveralInlineFunctionsDeepest.StepOutSeveralInlineFunctionsDeepestPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +stepOutSeveralInlineFunctionsDeepest.kt:20 +stepOutSeveralInlineFunctionsDeepest.kt:15 +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/custom/stepOutInlineFunctionStdlib.kt b/idea/testData/debugger/tinyApp/src/stepping/custom/stepOutInlineFunctionStdlib.kt new file mode 100644 index 00000000000..1cba38ae7a1 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/custom/stepOutInlineFunctionStdlib.kt @@ -0,0 +1,15 @@ +package stepOutInlineFunctionStdlib + +fun main(args: Array) { + val a = listOf(1, 2, 3) + //Breakpoint! + a.firstOrNull { + it > 1 + } +} + +fun test(i: Int) = 1 + +// TRACING_FILTERS_ENABLED: false +// STEP_INTO: 1 +// STEP_OUT: 1 diff --git a/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlineFunction.kt b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlineFunction.kt new file mode 100644 index 00000000000..f3419e70115 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlineFunction.kt @@ -0,0 +1,19 @@ +package stepOutInlineFunction + +fun main(args: Array) { + foo { + test(2) + } + test(3) +} + +inline fun foo(f: () -> Unit) { + //Breakpoint! + val a = 1 + f() + val b = 2 +} + +fun test(i: Int) = 1 + +// STEP_OUT: 2 \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlinedLambdaArgument.kt b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlinedLambdaArgument.kt new file mode 100644 index 00000000000..2fcacae96bc --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlinedLambdaArgument.kt @@ -0,0 +1,20 @@ +package stepOutInlinedLambdaArgument + +fun main(args: Array) { + foo { + //Breakpoint! + test(1) + test(2) + } + test(3) +} + +inline fun foo(f: () -> Unit) { + val a = 1 + f() + val b = 2 +} + +fun test(i: Int) = 1 + +// STEP_OUT: 2 \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineArgumentDeepest.kt b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineArgumentDeepest.kt new file mode 100644 index 00000000000..c6e40a1fa71 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineArgumentDeepest.kt @@ -0,0 +1,27 @@ +package stepOutSeveralInlineArgumentDeepest + +fun main(args: Array) { + f1 { + //Breakpoint! + test(2) + } + test(3) +} + +inline fun f1(f: () -> Unit) { + val a = 1 + f2 { + f() + } + val b = 2 +} + +inline fun f2(f: () -> Unit) { + val a = 1 + f() + val b = 2 +} + +fun test(i: Int) = 1 + +// STEP_OUT: 4 \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctions.kt b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctions.kt new file mode 100644 index 00000000000..72ddbf19c57 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctions.kt @@ -0,0 +1,25 @@ +package stepOutSeveralInlineFunctions + +fun main(args: Array) { + f1 { + test(2) + } + test(3) +} + +inline fun f1(f: () -> Unit) { + //Breakpoint! + val a = 1 + f2 { + f() + } + val b = 2 +} + +inline fun f2(f: () -> Unit) { + val a = 1 + f() + val b = 2 +} + +fun test(i: Int) = 1 \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctionsDeepest.kt b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctionsDeepest.kt new file mode 100644 index 00000000000..6a74726ea3d --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctionsDeepest.kt @@ -0,0 +1,25 @@ +package stepOutSeveralInlineFunctionsDeepest + +fun main(args: Array) { + f1 { + test(2) + } + test(3) +} + +inline fun f1(f: () -> Unit) { + val a = 1 + f2 { + f() + } + val b = 2 +} + +inline fun f2(f: () -> Unit) { + //Breakpoint! + val a = 1 + f() + val b = 2 +} + +fun test(i: Int) = 1 \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestBase.kt b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestBase.kt index 062ea8565d1..c16ba900828 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestBase.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestBase.kt @@ -136,7 +136,9 @@ abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() { } protected fun SuspendContextImpl.stepOut() { - dp.getManagerThread()!!.schedule(dp.createStepOutCommand(this)) + val stepOutCommand = runReadAction { KotlinSteppingCommandProvider().getStepOutCommand(this, StepRequest.STEP_LINE) } + ?: dp.createStepOutCommand(this) + dp.getManagerThread()!!.schedule(stepOutCommand) } protected fun SuspendContextImpl.stepOver() { diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java index 6322f0355e3..5d48fd2fe35 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java @@ -297,6 +297,36 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest { String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/inapplicableFieldWatchpoints.kt"); doStepOutTest(fileName); } + + @TestMetadata("stepOutInlineFunction.kt") + public void testStepOutInlineFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlineFunction.kt"); + doStepOutTest(fileName); + } + + @TestMetadata("stepOutInlinedLambdaArgument.kt") + public void testStepOutInlinedLambdaArgument() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlinedLambdaArgument.kt"); + doStepOutTest(fileName); + } + + @TestMetadata("stepOutSeveralInlineArgumentDeepest.kt") + public void testStepOutSeveralInlineArgumentDeepest() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineArgumentDeepest.kt"); + doStepOutTest(fileName); + } + + @TestMetadata("stepOutSeveralInlineFunctions.kt") + public void testStepOutSeveralInlineFunctions() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctions.kt"); + doStepOutTest(fileName); + } + + @TestMetadata("stepOutSeveralInlineFunctionsDeepest.kt") + public void testStepOutSeveralInlineFunctionsDeepest() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctionsDeepest.kt"); + doStepOutTest(fileName); + } } @TestMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver") @@ -444,5 +474,11 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest { String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/stepIntoStdlibInlineFun2step.kt"); doCustomTest(fileName); } + + @TestMetadata("stepOutInlineFunctionStdlib.kt") + public void testStepOutInlineFunctionStdlib() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/stepOutInlineFunctionStdlib.kt"); + doCustomTest(fileName); + } } }