Step over for suspended calls (KT-18453)

Debugger do the normal step over action and checks if function is
going to suspend. In this case the "run-to-cursor" breakpoint is
installed on function enter to intercept re-enter into function
after suspension.

 #KT-18453 In Progress
This commit is contained in:
Nikolay Krasko
2017-05-29 19:20:15 +03:00
parent 6d7ce6cec1
commit 0e8e8ef546
23 changed files with 603 additions and 13 deletions
@@ -23,6 +23,8 @@ import com.intellij.debugger.settings.DebuggerSettings
import com.sun.jdi.Location
import com.sun.jdi.request.StepRequest
import org.jetbrains.kotlin.idea.debugger.KotlinPositionManager
import org.jetbrains.kotlin.idea.debugger.isOnSuspendReturnOrReenter
import org.jetbrains.kotlin.idea.debugger.isOneLineMethod
import org.jetbrains.kotlin.idea.util.application.runReadAction
class KotlinExtraSteppingFilter : ExtraSteppingFilter {
@@ -54,6 +56,10 @@ class KotlinExtraSteppingFilter : ExtraSteppingFilter {
return false
} ?: return false
if (isOnSuspendReturnOrReenter(location) && !isOneLineMethod(location)) {
return true
}
val settings = DebuggerSettings.getInstance()
if (settings.TRACING_FILTERS_ENABLED) {
val classNames = positionManager.originalClassNameForPosition(sourcePosition).map { it.replace('/', '.') }
@@ -17,12 +17,15 @@
package org.jetbrains.kotlin.idea.debugger
import com.intellij.debugger.engine.DebugProcessImpl
import com.intellij.debugger.engine.DebuggerManagerThreadImpl
import com.intellij.debugger.engine.events.DebuggerCommandImpl
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.jdi.LocalVariableProxyImpl
import com.sun.jdi.*
import com.sun.tools.jdi.LocalVariableImpl
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_ASM_TYPE
import org.jetbrains.kotlin.codegen.coroutines.DO_RESUME_METHOD_NAME
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.load.java.JvmAbi
@@ -54,13 +57,21 @@ fun isInsideInlineArgument(inlineArgument: KtFunction, location: Location, debug
} != null
}
fun <T: Any> DebugProcessImpl.invokeInManagerThread(f: (DebuggerContextImpl) -> T?): T? {
fun <T : Any> DebugProcessImpl.invokeInManagerThread(f: (DebuggerContextImpl) -> T?): T? {
var result: T? = null
managerThread.invokeAndWait(object : DebuggerCommandImpl() {
val command: DebuggerCommandImpl = object : DebuggerCommandImpl() {
override fun action() {
result = runReadAction { f(debuggerContext) }
}
})
}
when {
DebuggerManagerThreadImpl.isManagerThread() ->
managerThread.invoke(command)
else ->
managerThread.invokeAndWait(command)
}
return result
}
@@ -137,3 +148,48 @@ private class MockStackFrame(private val location: Location, private val vm: Vir
override fun getArgumentValues(): List<Value> = emptyList()
override fun virtualMachine() = vm
}
private val DO_RESUME_SIGNATURE = "(Ljava/lang/Object;Ljava/lang/Throwable;)Ljava/lang/Object;"
fun isInSuspendMethod(location: Location): Boolean {
val method = location.method()
val signature = method.signature()
return signature.contains(CONTINUATION_ASM_TYPE.toString()) ||
(method.name() == DO_RESUME_METHOD_NAME && signature == DO_RESUME_SIGNATURE)
}
fun suspendFunctionFirstLineLocation(location: Location): Int? {
if (!isInSuspendMethod(location)) {
return null
}
val lineNumber = location.method().location().lineNumber()
if (lineNumber == -1) {
return null
}
return lineNumber
}
fun isOnSuspendReturnOrReenter(location: Location): Boolean {
val suspendStartLineNumber = suspendFunctionFirstLineLocation(location) ?: return false
return suspendStartLineNumber == location.lineNumber()
}
fun isLastLineLocationInMethod(location: Location): Boolean {
val knownLines = location.method().allLineLocations().map { it.lineNumber() }.filter { it != -1 }
if (knownLines.isEmpty()) {
return false
}
return knownLines.max() == location.lineNumber()
}
fun isOneLineMethod(location: Location): Boolean {
val allLineLocations = location.method().allLineLocations()
val firstLine = allLineLocations.firstOrNull()?.lineNumber()
val lastLine = allLineLocations.lastOrNull()?.lineNumber()
return firstLine != null && firstLine == lastLine
}
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.debugger.stepping;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.RequestHint;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.sun.jdi.request.StepRequest;
import org.jetbrains.annotations.NotNull;
public class DebugProcessImplHelper {
public static DebugProcessImpl.StepOverCommand createStepOverCommandWithCustomFilter(
SuspendContextImpl suspendContext,
boolean ignoreBreakpoints,
KotlinSuspendCallStepOverFilter methodFilter) {
DebugProcessImpl debugProcess = suspendContext.getDebugProcess();
return debugProcess.new StepOverCommand(suspendContext, ignoreBreakpoints, StepRequest.STEP_LINE) {
@NotNull
@Override
protected RequestHint getHint(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl stepThread) {
@SuppressWarnings("MagicConstant")
RequestHint hint = new RequestHintWithMethodFilter(stepThread, suspendContext, StepRequest.STEP_OVER, methodFilter);
hint.setRestoreBreakpoints(ignoreBreakpoints);
hint.setIgnoreFilters(ignoreBreakpoints || debugProcess.getSession().shouldIgnoreSteppingFilters());
return hint;
}
};
}
}
@@ -38,8 +38,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils
import org.jetbrains.kotlin.idea.debugger.ktLocationInfo
import org.jetbrains.kotlin.idea.debugger.*
import org.jetbrains.kotlin.idea.debugger.stepping.DexBytecode.GOTO
import org.jetbrains.kotlin.idea.debugger.stepping.DexBytecode.MOVE
import org.jetbrains.kotlin.idea.debugger.stepping.DexBytecode.RETURN
@@ -89,9 +88,18 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
sourcePosition: SourcePosition): DebugProcessImpl.ResumeCommand? {
val kotlinSourcePosition = KotlinSourcePosition.create(sourcePosition) ?: return null
if (!isSpecialStepOverNeeded(kotlinSourcePosition)) return null
if (isSpecialStepOverNeeded(kotlinSourcePosition)) {
return DebuggerSteppingHelper.createStepOverCommand(suspendContext, ignoreBreakpoints, kotlinSourcePosition)
}
return DebuggerSteppingHelper.createStepOverCommand(suspendContext, ignoreBreakpoints, kotlinSourcePosition)
val file = sourcePosition.elementAt.containingFile
val location = suspendContext.debugProcess.invokeInManagerThread { suspendContext.frameProxy?.location() } ?: return null
if (isInSuspendMethod(location) && !isOnSuspendReturnOrReenter(location) && !isLastLineLocationInMethod(location)) {
return DebugProcessImplHelper.createStepOverCommandWithCustomFilter(
suspendContext, ignoreBreakpoints, KotlinSuspendCallStepOverFilter(sourcePosition.line, file))
}
return null
}
data class KotlinSourcePosition(val file: KtFile, val function: KtNamedFunction,
@@ -204,9 +212,8 @@ private fun getInlineArgumentsCallsIfAny(sourcePosition: SourcePosition, declara
fun isCallOfArgument(ktCallExpression: KtCallExpression): Boolean {
val context = ktCallExpression.analyze(BodyResolveMode.PARTIAL)
val resolvedCall = ktCallExpression.getResolvedCall(context) ?: return false
val resolvedCall = ktCallExpression.getResolvedCall(context) as? VariableAsFunctionResolvedCallImpl ?: return false
if (resolvedCall !is VariableAsFunctionResolvedCallImpl) return false
val candidateDescriptor = resolvedCall.variableCall.candidateDescriptor
return candidateDescriptor in valueParameters
@@ -394,8 +401,8 @@ fun getStepOverAction(
.dropWhile { it != patchedLocation }
.drop(1)
.dropWhile { it.ktLineNumber() == patchedLineNumber }
.takeWhile { location ->
!isLocationSuitable(location) || lambdaArgumentRanges.any { location.ktLineNumber() in it }
.takeWhile { loc ->
!isLocationSuitable(loc) || lambdaArgumentRanges.any { loc.ktLineNumber() in it }
}
.dropWhile { it.ktLineNumber() == patchedLineNumber }
@@ -579,4 +586,4 @@ object DexBytecode {
val GOTO = 0x28
val MOVE = 0x01
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.debugger.stepping
import com.intellij.debugger.DebuggerBundle
import com.intellij.debugger.DebuggerManagerEx
import com.intellij.debugger.engine.DebugProcessImpl
import com.intellij.debugger.engine.MethodFilter
import com.intellij.debugger.engine.RequestHint
import com.intellij.debugger.engine.SuspendContextImpl
import com.intellij.debugger.settings.DebuggerSettings
import com.intellij.psi.PsiFile
import com.intellij.util.Range
import com.intellij.xdebugger.impl.XSourcePositionImpl
import com.sun.jdi.Location
import com.sun.jdi.request.EventRequest
import org.jetbrains.kotlin.idea.debugger.isOnSuspendReturnOrReenter
import org.jetbrains.kotlin.idea.debugger.suspendFunctionFirstLineLocation
import org.jetbrains.kotlin.idea.util.application.runReadAction
class KotlinSuspendCallStepOverFilter(private val line: Int, private val file: PsiFile) : MethodFilter {
override fun getCallingExpressionLines(): Range<Int>? = Range(line, line)
override fun locationMatches(process: DebugProcessImpl, location: Location?): Boolean {
return location != null && isOnSuspendReturnOrReenter(location)
}
override fun onReached(context: SuspendContextImpl, hint: RequestHint): Int {
val location = context.frameProxy?.location() ?: return RequestHint.STOP
val suspendStartLineNumber = suspendFunctionFirstLineLocation(location) ?: return RequestHint.STOP
val debugProcess = context.debugProcess
val breakpointManager = DebuggerManagerEx.getInstanceEx(debugProcess.project).breakpointManager
breakpointManager.applyThreadFilter(debugProcess, null)
createRunToCursorBreakpoint(context, suspendStartLineNumber - 1, file)
return RequestHint.RESUME
}
}
private fun createRunToCursorBreakpoint(context: SuspendContextImpl, line: Int, file: PsiFile) {
val position = XSourcePositionImpl.create(file.virtualFile, line) ?: return
val process = context.debugProcess
process.showStatusText(DebuggerBundle.message("status.run.to.cursor"))
process.cancelRunToCursorBreakpoint()
val runToCursorBreakpoint =
runReadAction {
DebuggerManagerEx.getInstanceEx(process.project).breakpointManager.addRunToCursorBreakpoint(position, false)
} ?:
return
runToCursorBreakpoint.suspendPolicy = when {
context.suspendPolicy == EventRequest.SUSPEND_EVENT_THREAD -> DebuggerSettings.SUSPEND_THREAD
else -> DebuggerSettings.SUSPEND_ALL
}
runToCursorBreakpoint.createRequest(process)
process.setRunToCursorBreakpoint(runToCursorBreakpoint)
}
@@ -0,0 +1,91 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.debugger.stepping
import com.intellij.debugger.engine.BreakpointStepMethodFilter
import com.intellij.debugger.engine.MethodFilter
import com.intellij.debugger.engine.RequestHint
import com.intellij.debugger.engine.SuspendContextImpl
import com.intellij.debugger.engine.evaluation.EvaluateException
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl
import com.intellij.openapi.diagnostic.Logger
import com.sun.jdi.VMDisconnectedException
import com.sun.jdi.request.StepRequest
import org.intellij.lang.annotations.MagicConstant
import java.lang.reflect.Field
internal class RequestHintWithMethodFilter(
stepThread: ThreadReferenceProxyImpl,
suspendContext: SuspendContextImpl,
@MagicConstant(intValues = longArrayOf(
StepRequest.STEP_INTO.toLong(),
StepRequest.STEP_OVER.toLong(),
StepRequest.STEP_OUT.toLong())) depth: Int,
methodFilter: MethodFilter
) : RequestHint(stepThread, suspendContext, methodFilter) {
private var targetMethodMatched = false
init {
// NOTE: Debugger API. Open RequestHint constructor with depth
if (depth != StepRequest.STEP_INTO) {
findFieldWithValue(StepRequest.STEP_INTO, Integer.TYPE)?.setInt(this, depth)
}
}
private fun findFieldWithValue(value: Int, type: Class<*>): Field? {
return RequestHint::class.java.declaredFields.firstOrNull { field ->
if (field.type == type) {
field.isAccessible = true
if (field.getInt(this) == value) {
return@firstOrNull true
}
}
false
}
}
override fun getNextStepDepth(context: SuspendContextImpl): Int {
try {
val frameProxy = context.frameProxy
val filter = methodFilter
if (filter != null && frameProxy != null && filter !is BreakpointStepMethodFilter) {
/*NODE: Debugger API. Base implementation works only for smart step into, and calls filter only if !isTheSameFrame(context). */
if (filter.locationMatches(context.debugProcess, frameProxy.location())) {
targetMethodMatched = true
return filter.onReached(context, this)
}
}
}
catch (ignored: VMDisconnectedException) {
return STOP
}
catch (e: EvaluateException) {
LOG.error(e)
return STOP
}
return super.getNextStepDepth(context)
}
override fun wasStepTargetMethodMatched(): Boolean {
return super.wasStepTargetMethodMatched() || targetMethodMatched
}
}
private val LOG = Logger.getInstance(RequestHintWithMethodFilter::class.java)
@@ -15,4 +15,8 @@ fun main(args: Array<String>) {
builder {
first()
}
}
}
// STEP_INTO: 1
// TODO: Breakpoint on builder {} is now triggered twice. This is because generated line number on suspend function enter.
@@ -2,6 +2,7 @@ LineBreakpoint created at coroutine.kt:15
Run Java
Connected to the target VM
coroutine.kt:15
coroutine.kt:15
coroutine.kt:16
Disconnected from the target VM
@@ -0,0 +1,21 @@
package stepIntoSuspendFunctionSimple
import forTests.builder
private fun foo() {}
suspend fun second() {
}
suspend fun first(): Int {
second()
return 12
}
fun main(args: Array<String>) {
builder {
//Breakpoint!
first()
foo()
}
}
@@ -0,0 +1,8 @@
LineBreakpoint created at stepIntoSuspendFunctionSimple.kt:18
Run Java
Connected to the target VM
stepIntoSuspendFunctionSimple.kt:18
stepIntoSuspendFunctionSimple.kt:10
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,21 @@
package soNonSuspendableSuspendCall
import forTests.builder
private fun foo() {}
suspend fun second() {
}
suspend fun first(): Int {
second()
return 12
}
fun main(args: Array<String>) {
builder {
//Breakpoint!
first()
foo()
}
}
@@ -0,0 +1,8 @@
LineBreakpoint created at soNonSuspendableSuspendCall.kt:18
Run Java
Connected to the target VM
soNonSuspendableSuspendCall.kt:18
soNonSuspendableSuspendCall.kt:19
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,33 @@
package soSuspendableCallInEndOfFun
import forTests.builder
import kotlin.coroutines.experimental.Continuation
import kotlin.coroutines.experimental.suspendCoroutine
private fun foo(a: Any) {}
fun main(args: Array<String>) {
builder {
inFun()
}
foo("Main end")
Thread.sleep(100)
}
suspend fun inFun() {
foo("Start")
//Breakpoint!
run()
}
suspend fun run() {
suspendCoroutine { cont: Continuation<Unit> ->
Thread {
cont.resume(Unit)
Thread.sleep(10)
}.start()
}
}
// STEP_OVER: 4
@@ -0,0 +1,11 @@
LineBreakpoint created at soSuspendableCallInEndOfFun.kt:21
Run Java
Connected to the target VM
soSuspendableCallInEndOfFun.kt:21
soSuspendableCallInEndOfFun.kt:18
soSuspendableCallInEndOfFun.kt:22
soSuspendableCallInEndOfFun.kt:-1
soSuspendableCallInEndOfFun.kt:28
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,29 @@
package soSuspendableCallInEndOfLambda
import forTests.builder
import kotlin.coroutines.experimental.Continuation
import kotlin.coroutines.experimental.suspendCoroutine
private fun foo(a: Any) {}
fun main(args: Array<String>) {
builder {
foo("Start")
//Breakpoint!
run()
}
foo("Main end")
Thread.sleep(100)
}
suspend fun run() {
suspendCoroutine { cont: Continuation<Unit> ->
Thread {
cont.resume(Unit)
Thread.sleep(10)
}.start()
}
}
// STEP_OVER: 2
@@ -0,0 +1,9 @@
LineBreakpoint created at soSuspendableCallInEndOfLambda.kt:13
Run Java
Connected to the target VM
soSuspendableCallInEndOfLambda.kt:13
soSuspendableCallInEndOfLambda.kt:10
soSuspendableCallInEndOfLambda.kt:14
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,33 @@
package soSuspendableCallInFun
import forTests.builder
import kotlin.coroutines.experimental.Continuation
import kotlin.coroutines.experimental.suspendCoroutine
private fun foo(a: Any) {}
fun main(args: Array<String>) {
builder {
inFun()
}
foo("Main end")
Thread.sleep(100)
}
suspend fun inFun() {
//Breakpoint!
run()
foo("End")
}
suspend fun run() {
suspendCoroutine { cont: Continuation<Unit> ->
Thread {
cont.resume(Unit)
Thread.sleep(10)
}.start()
}
}
// STEP_OVER: 2
@@ -0,0 +1,9 @@
LineBreakpoint created at soSuspendableCallInFun.kt:20
Run Java
Connected to the target VM
soSuspendableCallInFun.kt:20
soSuspendableCallInFun.kt:18
soSuspendableCallInFun.kt:21
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,34 @@
package soSuspendableCallInFunFromOtherStepping
import forTests.builder
import kotlin.coroutines.experimental.Continuation
import kotlin.coroutines.experimental.suspendCoroutine
private fun foo(a: Any) {}
fun main(args: Array<String>) {
builder {
inFun()
}
foo("Main end")
Thread.sleep(120)
}
suspend fun inFun() {
//Breakpoint!
foo("Start")
run()
foo("End")
}
suspend fun run() {
return suspendCoroutine { cont: Continuation<Unit> ->
Thread {
cont.resume(Unit)
Thread.sleep(10)
}.start()
}
}
// STEP_OVER: 3
@@ -0,0 +1,10 @@
LineBreakpoint created at soSuspendableCallInFunFromOtherStepping.kt:20
Run Java
Connected to the target VM
soSuspendableCallInFunFromOtherStepping.kt:20
soSuspendableCallInFunFromOtherStepping.kt:21
soSuspendableCallInFunFromOtherStepping.kt:18
soSuspendableCallInFunFromOtherStepping.kt:22
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,29 @@
package soSuspendableCallInLambda
import forTests.builder
import kotlin.coroutines.experimental.Continuation
import kotlin.coroutines.experimental.suspendCoroutine
private fun foo(a: Any) {}
fun main(args: Array<String>) {
builder {
//Breakpoint!
run()
foo("End")
}
foo("Main end")
Thread.sleep(100)
}
suspend fun run() {
suspendCoroutine { cont: Continuation<Unit> ->
Thread {
cont.resume(Unit)
Thread.sleep(10)
}.start()
}
}
// STEP_OVER: 2
@@ -0,0 +1,9 @@
LineBreakpoint created at soSuspendableCallInLambda.kt:12
Run Java
Connected to the target VM
soSuspendableCallInLambda.kt:12
soSuspendableCallInLambda.kt:10
soSuspendableCallInLambda.kt:13
Disconnected from the target VM
Process finished with exit code 0
@@ -314,6 +314,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
doStepIntoTest(fileName);
}
@TestMetadata("stepIntoSuspendFunctionSimple.kt")
public void testStepIntoSuspendFunctionSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepInto/stepIntoSuspendFunctionSimple.kt");
doStepIntoTest(fileName);
}
@TestMetadata("syntheticMethods.kt")
public void testSyntheticMethods() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepInto/syntheticMethods.kt");
@@ -608,6 +614,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
doStepOverTest(fileName);
}
@TestMetadata("soNonSuspendableSuspendCall.kt")
public void testSoNonSuspendableSuspendCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soNonSuspendableSuspendCall.kt");
doStepOverTest(fileName);
}
@TestMetadata("soReifiedInlineIfConditionFalse.kt")
public void testSoReifiedInlineIfConditionFalse() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soReifiedInlineIfConditionFalse.kt");
@@ -620,6 +632,36 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
doStepOverTest(fileName);
}
@TestMetadata("soSuspendableCallInEndOfFun.kt")
public void testSoSuspendableCallInEndOfFun() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soSuspendableCallInEndOfFun.kt");
doStepOverTest(fileName);
}
@TestMetadata("soSuspendableCallInEndOfLambda.kt")
public void testSoSuspendableCallInEndOfLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soSuspendableCallInEndOfLambda.kt");
doStepOverTest(fileName);
}
@TestMetadata("soSuspendableCallInFun.kt")
public void testSoSuspendableCallInFun() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soSuspendableCallInFun.kt");
doStepOverTest(fileName);
}
@TestMetadata("soSuspendableCallInFunFromOtherStepping.kt")
public void testSoSuspendableCallInFunFromOtherStepping() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soSuspendableCallInFunFromOtherStepping.kt");
doStepOverTest(fileName);
}
@TestMetadata("soSuspendableCallInLambda.kt")
public void testSoSuspendableCallInLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soSuspendableCallInLambda.kt");
doStepOverTest(fileName);
}
@TestMetadata("stepOverCatchClause.kt")
public void testStepOverCatchClause() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stepOverCatchClause.kt");