Implement new stepping for suspend functions
This commit is contained in:
@@ -11,9 +11,7 @@ import com.intellij.debugger.engine.SuspendContext
|
|||||||
import com.intellij.debugger.settings.DebuggerSettings
|
import com.intellij.debugger.settings.DebuggerSettings
|
||||||
import com.sun.jdi.Location
|
import com.sun.jdi.Location
|
||||||
import com.sun.jdi.request.StepRequest
|
import com.sun.jdi.request.StepRequest
|
||||||
import org.jetbrains.kotlin.idea.debugger.KotlinPositionManager
|
import org.jetbrains.kotlin.idea.debugger.*
|
||||||
import org.jetbrains.kotlin.idea.debugger.isOnSuspendReturnOrReenter
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.isOneLineMethod
|
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
|
|
||||||
class KotlinExtraSteppingFilter : ExtraSteppingFilter {
|
class KotlinExtraSteppingFilter : ExtraSteppingFilter {
|
||||||
@@ -43,7 +41,7 @@ class KotlinExtraSteppingFilter : ExtraSteppingFilter {
|
|||||||
return false
|
return false
|
||||||
} ?: return false
|
} ?: return false
|
||||||
|
|
||||||
if (isOnSuspendReturnOrReenter(location) && !isOneLineMethod(location)) {
|
if (isInSuspendMethod(location) && isOnSuspendReturnOrReenter(location) && !isOneLineMethod(location)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-10
@@ -11,8 +11,10 @@ import com.intellij.debugger.engine.SuspendContextImpl
|
|||||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl
|
import com.intellij.debugger.engine.events.DebuggerCommandImpl
|
||||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl
|
import com.intellij.debugger.engine.events.SuspendContextCommandImpl
|
||||||
import com.intellij.debugger.impl.DebuggerContextImpl
|
import com.intellij.debugger.impl.DebuggerContextImpl
|
||||||
|
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.sun.jdi.*
|
import com.sun.jdi.*
|
||||||
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass
|
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.DO_RESUME_METHOD_NAME
|
import org.jetbrains.kotlin.codegen.coroutines.DO_RESUME_METHOD_NAME
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME
|
import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME
|
||||||
@@ -181,6 +183,17 @@ private class MockStackFrame(private val location: Location, private val vm: Vir
|
|||||||
private const val DO_RESUME_SIGNATURE = "(Ljava/lang/Object;Ljava/lang/Throwable;)Ljava/lang/Object;"
|
private const val DO_RESUME_SIGNATURE = "(Ljava/lang/Object;Ljava/lang/Throwable;)Ljava/lang/Object;"
|
||||||
private const val INVOKE_SUSPEND_SIGNATURE = "(Ljava/lang/Object;)Ljava/lang/Object;"
|
private const val INVOKE_SUSPEND_SIGNATURE = "(Ljava/lang/Object;)Ljava/lang/Object;"
|
||||||
|
|
||||||
|
fun StackFrameProxyImpl.isOnSuspensionPoint(): Boolean {
|
||||||
|
val location = this.safeLocation() ?: return false
|
||||||
|
|
||||||
|
if (isInSuspendMethod(location)) {
|
||||||
|
val firstLocation = getFirstMethodLocation(location) ?: return false
|
||||||
|
return firstLocation.safeLineNumber() == location.safeLineNumber() && firstLocation.codeIndex() != location.codeIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
fun isInSuspendMethod(location: Location): Boolean {
|
fun isInSuspendMethod(location: Location): Boolean {
|
||||||
val method = location.method()
|
val method = location.method()
|
||||||
val signature = method.signature()
|
val signature = method.signature()
|
||||||
@@ -194,22 +207,18 @@ fun isInSuspendMethod(location: Location): Boolean {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun suspendFunctionFirstLineLocation(location: Location): Int? {
|
private fun getFirstMethodLocation(location: Location): Location? {
|
||||||
if (!isInSuspendMethod(location)) {
|
val firstLocation = location.safeMethod()?.location() ?: return null
|
||||||
|
if (firstLocation.safeLineNumber() < 0) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val lineNumber = location.method().location()?.lineNumber()
|
return firstLocation
|
||||||
if (lineNumber == -1) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return lineNumber
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isOnSuspendReturnOrReenter(location: Location): Boolean {
|
fun isOnSuspendReturnOrReenter(location: Location): Boolean {
|
||||||
val suspendStartLineNumber = suspendFunctionFirstLineLocation(location) ?: return false
|
val firstLocation = getFirstMethodLocation(location) ?: return false
|
||||||
return suspendStartLineNumber == location.lineNumber()
|
return firstLocation.safeLineNumber() == location.safeLineNumber()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isLastLineLocationInMethod(location: Location): Boolean {
|
fun isLastLineLocationInMethod(location: Location): Boolean {
|
||||||
|
|||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.debugger.stepping
|
||||||
|
|
||||||
|
import com.intellij.debugger.DebuggerManagerEx
|
||||||
|
import com.intellij.debugger.engine.DebugProcessImpl
|
||||||
|
import com.intellij.debugger.engine.SuspendContextImpl
|
||||||
|
import com.intellij.debugger.engine.events.SuspendContextCommandImpl
|
||||||
|
import com.intellij.debugger.settings.DebuggerSettings
|
||||||
|
import com.intellij.debugger.ui.breakpoints.Breakpoint
|
||||||
|
import com.sun.jdi.Location
|
||||||
|
import com.sun.jdi.Method
|
||||||
|
import com.sun.jdi.request.EventRequest
|
||||||
|
|
||||||
|
abstract class AbstractCoroutineBreakpointFacility {
|
||||||
|
abstract fun installCoroutineResumedBreakpoint(context: SuspendContextImpl, location: Location, method: Method): Boolean
|
||||||
|
|
||||||
|
protected fun Breakpoint<*>.setSuspendPolicy(context: SuspendContextImpl) {
|
||||||
|
suspendPolicy = when (context.suspendPolicy) {
|
||||||
|
EventRequest.SUSPEND_ALL -> DebuggerSettings.SUSPEND_ALL
|
||||||
|
EventRequest.SUSPEND_EVENT_THREAD -> DebuggerSettings.SUSPEND_THREAD
|
||||||
|
EventRequest.SUSPEND_NONE -> DebuggerSettings.SUSPEND_NONE
|
||||||
|
else -> DebuggerSettings.SUSPEND_ALL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun Breakpoint<*>.stepOverSuspendSwitch(action: SuspendContextCommandImpl, debugProcess: DebugProcessImpl) {
|
||||||
|
val suspendContext = action.suspendContext
|
||||||
|
if (suspendContext != null) {
|
||||||
|
DebuggerSteppingHelper.createStepOverCommandForSuspendSwitch(suspendContext).contextAction(suspendContext)
|
||||||
|
}
|
||||||
|
debugProcess.requestsManager.deleteRequest(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected fun applyEmptyThreadFilter(debugProcess: DebugProcessImpl) {
|
||||||
|
// TODO this is nasty. Find a way to apply an empty thread filter only to the newly created breakpoint
|
||||||
|
val breakpointManager = DebuggerManagerEx.getInstanceEx(debugProcess.project).breakpointManager
|
||||||
|
breakpointManager.applyThreadFilter(debugProcess, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.debugger.stepping
|
||||||
|
|
||||||
|
import com.intellij.debugger.engine.StepIntoMethodBreakpoint
|
||||||
|
import com.intellij.debugger.engine.SuspendContextImpl
|
||||||
|
import com.intellij.debugger.engine.events.SuspendContextCommandImpl
|
||||||
|
import com.sun.jdi.Location
|
||||||
|
import com.sun.jdi.Method
|
||||||
|
import com.sun.jdi.event.LocatableEvent
|
||||||
|
|
||||||
|
object CoroutineBreakpointFacility : AbstractCoroutineBreakpointFacility() {
|
||||||
|
override fun installCoroutineResumedBreakpoint(context: SuspendContextImpl, location: Location, method: Method): Boolean {
|
||||||
|
val debugProcess = context.debugProcess
|
||||||
|
val project = debugProcess.project
|
||||||
|
|
||||||
|
val breakpoint = object : StepIntoMethodBreakpoint(location.declaringType().name(), method.name(), method.signature(), project) {
|
||||||
|
override fun processLocatableEvent(action: SuspendContextCommandImpl, event: LocatableEvent): Boolean {
|
||||||
|
val result = super.processLocatableEvent(action, event)
|
||||||
|
if (result) {
|
||||||
|
stepOverSuspendSwitch(action, debugProcess)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
breakpoint.setSuspendPolicy(context)
|
||||||
|
applyEmptyThreadFilter(debugProcess)
|
||||||
|
breakpoint.createRequest(debugProcess)
|
||||||
|
debugProcess.setSteppingBreakpoint(breakpoint)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.debugger.stepping
|
||||||
|
|
||||||
|
import com.intellij.debugger.engine.SuspendContextImpl
|
||||||
|
import com.intellij.debugger.engine.events.SuspendContextCommandImpl
|
||||||
|
import com.intellij.debugger.ui.breakpoints.RunToCursorBreakpoint
|
||||||
|
import com.sun.jdi.Location
|
||||||
|
import com.sun.jdi.Method
|
||||||
|
import com.sun.jdi.event.LocatableEvent
|
||||||
|
|
||||||
|
object CoroutineBreakpointFacility : AbstractCoroutineBreakpointFacility() {
|
||||||
|
override fun installCoroutineResumedBreakpoint(context: SuspendContextImpl, location: Location, method: Method): Boolean {
|
||||||
|
val debugProcess = context.debugProcess
|
||||||
|
val project = debugProcess.project
|
||||||
|
|
||||||
|
val methodLocation = method.location()
|
||||||
|
val position = debugProcess.positionManager.getSourcePosition(methodLocation) ?: return false
|
||||||
|
|
||||||
|
val breakpoint = object : RunToCursorBreakpoint(project, position, false) {
|
||||||
|
override fun processLocatableEvent(action: SuspendContextCommandImpl, event: LocatableEvent?): Boolean {
|
||||||
|
val result = super.processLocatableEvent(action, event)
|
||||||
|
if (result) {
|
||||||
|
stepOverSuspendSwitch(action, debugProcess)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
breakpoint.setSuspendPolicy(context)
|
||||||
|
applyEmptyThreadFilter(debugProcess)
|
||||||
|
breakpoint.createRequest(debugProcess)
|
||||||
|
debugProcess.setRunToCursorBreakpoint(breakpoint)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
+43
-47
@@ -38,7 +38,9 @@ import com.sun.jdi.request.StepRequest;
|
|||||||
import one.util.streamex.StreamEx;
|
import one.util.streamex.StreamEx;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.idea.debugger.stepping.filter.KotlinSuspendCallStepOverFilter;
|
import org.jetbrains.kotlin.idea.debugger.DebuggerUtilKt;
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.SafeUtilKt;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DebuggerSteppingHelper {
|
public class DebuggerSteppingHelper {
|
||||||
@@ -54,47 +56,44 @@ public class DebuggerSteppingHelper {
|
|||||||
return debugProcess.new ResumeCommand(suspendContext) {
|
return debugProcess.new ResumeCommand(suspendContext) {
|
||||||
@Override
|
@Override
|
||||||
public void contextAction() {
|
public void contextAction() {
|
||||||
try {
|
StackFrameProxyImpl frameProxy = suspendContext.getFrameProxy();
|
||||||
StackFrameProxyImpl frameProxy = suspendContext.getFrameProxy();
|
Location location = frameProxy == null ? null : SafeUtilKt.safeLocation(frameProxy);
|
||||||
if (frameProxy != null) {
|
|
||||||
|
|
||||||
Location location = frameProxy.location();
|
if (location != null) {
|
||||||
KotlinStepAction action = KotlinSteppingCommandProviderKt
|
KotlinStepAction action = KotlinSteppingCommandProviderKt
|
||||||
.getStepOverAction(location, sourcePosition, suspendContext, frameProxy);
|
.getStepOverAction(location, sourcePosition, suspendContext, frameProxy);
|
||||||
|
|
||||||
createStepRequest(
|
createStepRequest(
|
||||||
suspendContext, getContextThread(),
|
suspendContext, getContextThread(),
|
||||||
debugProcess.getVirtualMachineProxy().eventRequestManager(),
|
debugProcess.getVirtualMachineProxy().eventRequestManager(),
|
||||||
StepRequest.STEP_LINE, StepRequest.STEP_OUT);
|
StepRequest.STEP_LINE, StepRequest.STEP_OUT);
|
||||||
|
|
||||||
action.apply(debugProcess, suspendContext, ignoreBreakpoints);
|
action.apply(debugProcess, suspendContext, ignoreBreakpoints);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
debugProcess.createStepOutCommand(suspendContext).contextAction();
|
debugProcess.createStepOutCommand(suspendContext).contextAction();
|
||||||
}
|
|
||||||
catch (EvaluateException e) {
|
|
||||||
LOG.error(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DebugProcessImpl.StepOverCommand createStepOverCommandWithCustomFilter(
|
public static DebugProcessImpl.ResumeCommand createStepOverCommandForSuspendSwitch(SuspendContextImpl suspendContext) {
|
||||||
SuspendContextImpl suspendContext,
|
|
||||||
boolean ignoreBreakpoints,
|
|
||||||
KotlinSuspendCallStepOverFilter methodFilter
|
|
||||||
) {
|
|
||||||
DebugProcessImpl debugProcess = suspendContext.getDebugProcess();
|
DebugProcessImpl debugProcess = suspendContext.getDebugProcess();
|
||||||
return debugProcess.new StepOverCommand(suspendContext, ignoreBreakpoints, StepRequest.STEP_LINE) {
|
return debugProcess.new StepOverCommand(suspendContext, false, null, StepRequest.STEP_MIN) {
|
||||||
@NotNull
|
@NotNull @Override
|
||||||
@Override
|
|
||||||
protected RequestHint getHint(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl stepThread) {
|
protected RequestHint getHint(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl stepThread) {
|
||||||
@SuppressWarnings("MagicConstant")
|
RequestHint hint = new RequestHint(stepThread, suspendContext, StepRequest.STEP_MIN, StepRequest.STEP_OVER, myMethodFilter) {
|
||||||
RequestHint hint = new RequestHintWithMethodFilter(stepThread, suspendContext, StepRequest.STEP_OVER, methodFilter);
|
@Override
|
||||||
hint.setRestoreBreakpoints(ignoreBreakpoints);
|
public int getNextStepDepth(SuspendContextImpl context) {
|
||||||
hint.setIgnoreFilters(ignoreBreakpoints || debugProcess.getSession().shouldIgnoreSteppingFilters());
|
StackFrameProxyImpl frameProxy = context.getFrameProxy();
|
||||||
|
if (frameProxy != null && DebuggerUtilKt.isOnSuspensionPoint(frameProxy)) {
|
||||||
|
return StepRequest.STEP_OVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getNextStepDepth(context);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
hint.setIgnoreFilters(suspendContext.getDebugProcess().getSession().shouldIgnoreSteppingFilters());
|
||||||
return hint;
|
return hint;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -105,26 +104,22 @@ public class DebuggerSteppingHelper {
|
|||||||
return debugProcess.new ResumeCommand(suspendContext) {
|
return debugProcess.new ResumeCommand(suspendContext) {
|
||||||
@Override
|
@Override
|
||||||
public void contextAction() {
|
public void contextAction() {
|
||||||
try {
|
StackFrameProxyImpl frameProxy = suspendContext.getFrameProxy();
|
||||||
StackFrameProxyImpl frameProxy = suspendContext.getFrameProxy();
|
Location location = frameProxy == null ? null : SafeUtilKt.safeLocation(frameProxy);
|
||||||
if (frameProxy != null) {
|
|
||||||
Location location = frameProxy.location();
|
|
||||||
KotlinStepAction action = KotlinSteppingCommandProviderKt.getStepOutAction(location, frameProxy);
|
|
||||||
|
|
||||||
createStepRequest(
|
if (location != null) {
|
||||||
suspendContext, getContextThread(),
|
KotlinStepAction action = KotlinSteppingCommandProviderKt.getStepOutAction(location, frameProxy);
|
||||||
debugProcess.getVirtualMachineProxy().eventRequestManager(),
|
|
||||||
StepRequest.STEP_LINE, StepRequest.STEP_OUT);
|
|
||||||
|
|
||||||
action.apply(debugProcess, suspendContext, ignoreBreakpoints);
|
createStepRequest(
|
||||||
return;
|
suspendContext, getContextThread(),
|
||||||
}
|
debugProcess.getVirtualMachineProxy().eventRequestManager(),
|
||||||
|
StepRequest.STEP_LINE, StepRequest.STEP_OUT);
|
||||||
|
|
||||||
debugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints).contextAction();
|
action.apply(debugProcess, suspendContext, ignoreBreakpoints);
|
||||||
}
|
return;
|
||||||
catch (EvaluateException e) {
|
|
||||||
LOG.error(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints).contextAction();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -191,8 +186,9 @@ public class DebuggerSteppingHelper {
|
|||||||
try {
|
try {
|
||||||
if (thread != null && thread.frameCount() > 0) {
|
if (thread != null && thread.frameCount() > 0) {
|
||||||
StackFrameProxyImpl stackFrame = thread.frame(0);
|
StackFrameProxyImpl stackFrame = thread.frame(0);
|
||||||
|
Location location = stackFrame == null ? null : SafeUtilKt.safeLocation(stackFrame);
|
||||||
|
|
||||||
if (stackFrame != null) {
|
if (stackFrame != null) {
|
||||||
Location location = stackFrame.location();
|
|
||||||
ReferenceType referenceType = location == null ? null : location.declaringType();
|
ReferenceType referenceType = location == null ? null : location.declaringType();
|
||||||
if (referenceType != null) {
|
if (referenceType != null) {
|
||||||
return referenceType.name();
|
return referenceType.name();
|
||||||
|
|||||||
+3
-13
@@ -7,14 +7,12 @@ package org.jetbrains.kotlin.idea.debugger.stepping
|
|||||||
|
|
||||||
import com.intellij.debugger.engine.DebugProcessImpl
|
import com.intellij.debugger.engine.DebugProcessImpl
|
||||||
import com.intellij.debugger.engine.SuspendContextImpl
|
import com.intellij.debugger.engine.SuspendContextImpl
|
||||||
import com.intellij.xdebugger.impl.XSourcePositionImpl
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.stepping.filter.KotlinStepOverFilter
|
import org.jetbrains.kotlin.idea.debugger.stepping.filter.KotlinStepOverFilter
|
||||||
import org.jetbrains.kotlin.idea.debugger.stepping.filter.LocationToken
|
import org.jetbrains.kotlin.idea.debugger.stepping.filter.LocationToken
|
||||||
import org.jetbrains.kotlin.idea.debugger.stepping.filter.StepOverCallerInfo
|
import org.jetbrains.kotlin.idea.debugger.stepping.filter.StepOverCallerInfo
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
|
||||||
|
|
||||||
sealed class KotlinStepAction {
|
sealed class KotlinStepAction {
|
||||||
object StepOver : KotlinStepAction() {
|
object JvmStepOver : KotlinStepAction() {
|
||||||
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) {
|
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) {
|
||||||
debugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints).contextAction(suspendContext)
|
debugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints).contextAction(suspendContext)
|
||||||
}
|
}
|
||||||
@@ -26,18 +24,10 @@ sealed class KotlinStepAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RunToCursor(private val position: XSourcePositionImpl) : KotlinStepAction() {
|
class KotlinStepOver(private val tokensToSkip: Set<LocationToken>, private val callerInfo: StepOverCallerInfo) : KotlinStepAction() {
|
||||||
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) {
|
|
||||||
return runReadAction {
|
|
||||||
debugProcess.createRunToCursorCommand(suspendContext, position, ignoreBreakpoints)
|
|
||||||
}.contextAction(suspendContext)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StepOverInlined(private val tokensToSkip: Set<LocationToken>, private val callerInfo: StepOverCallerInfo) : KotlinStepAction() {
|
|
||||||
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) {
|
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) {
|
||||||
val filter = KotlinStepOverFilter(debugProcess.project, tokensToSkip, callerInfo)
|
val filter = KotlinStepOverFilter(debugProcess.project, tokensToSkip, callerInfo)
|
||||||
return KotlinStepActionFactory(debugProcess).createKotlinStepOverInlineAction(filter).contextAction(suspendContext)
|
return KotlinStepActionFactory(debugProcess).createKotlinStepOverAction(filter).contextAction(suspendContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-10
@@ -34,12 +34,8 @@ import java.lang.reflect.Field
|
|||||||
// Mass-copy-paste code for commands behaviour from com.intellij.debugger.engine.DebugProcessImpl
|
// Mass-copy-paste code for commands behaviour from com.intellij.debugger.engine.DebugProcessImpl
|
||||||
@SuppressWarnings("UnnecessaryFinalOnLocalVariableOrParameter")
|
@SuppressWarnings("UnnecessaryFinalOnLocalVariableOrParameter")
|
||||||
class KotlinStepActionFactory(private val debuggerProcess: DebugProcessImpl) {
|
class KotlinStepActionFactory(private val debuggerProcess: DebugProcessImpl) {
|
||||||
abstract class KotlinStepAction {
|
fun createKotlinStepOverAction(smartStepFilter: KotlinMethodFilter): KotlinStepOverCommand {
|
||||||
abstract fun contextAction(suspendContext: SuspendContextImpl)
|
return KotlinStepOverCommand(smartStepFilter, StepRequest.STEP_LINE)
|
||||||
}
|
|
||||||
|
|
||||||
fun createKotlinStepOverInlineAction(smartStepFilter: KotlinMethodFilter): KotlinStepAction {
|
|
||||||
return StepOverInlineCommand(smartStepFilter, StepRequest.STEP_LINE)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val debuggerContext: DebuggerContextImpl get() = debuggerProcess.debuggerContext
|
private val debuggerContext: DebuggerContextImpl get() = debuggerProcess.debuggerContext
|
||||||
@@ -94,8 +90,7 @@ class KotlinStepActionFactory(private val debuggerProcess: DebugProcessImpl) {
|
|||||||
return field.get(debuggerProcess) as T
|
return field.get(debuggerProcess) as T
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class StepOverInlineCommand(private val mySmartStepFilter: KotlinMethodFilter, private val myStepSize: Int) :
|
inner class KotlinStepOverCommand(private val mySmartStepFilter: KotlinMethodFilter, private val myStepSize: Int) {
|
||||||
KotlinStepAction() {
|
|
||||||
private fun getContextThread(suspendContext: SuspendContextImpl): ThreadReferenceProxyImpl? {
|
private fun getContextThread(suspendContext: SuspendContextImpl): ThreadReferenceProxyImpl? {
|
||||||
val contextThread = debuggerContext.threadProxy
|
val contextThread = debuggerContext.threadProxy
|
||||||
return contextThread ?: suspendContext.thread
|
return contextThread ?: suspendContext.thread
|
||||||
@@ -126,7 +121,7 @@ class KotlinStepActionFactory(private val debuggerProcess: DebugProcessImpl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See: StepIntoCommand.contextAction()
|
// See: StepIntoCommand.contextAction()
|
||||||
override fun contextAction(suspendContext: SuspendContextImpl) {
|
fun contextAction(suspendContext: SuspendContextImpl) {
|
||||||
showStatusText(KotlinDebuggerCoreBundle.message("stepping.over.inline"))
|
showStatusText(KotlinDebuggerCoreBundle.message("stepping.over.inline"))
|
||||||
val stepThread = getContextThread(suspendContext)
|
val stepThread = getContextThread(suspendContext)
|
||||||
|
|
||||||
@@ -136,7 +131,7 @@ class KotlinStepActionFactory(private val debuggerProcess: DebugProcessImpl) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val hint = KotlinStepOverInlinedLinesHint(stepThread, suspendContext, mySmartStepFilter)
|
val hint = KotlinStepOverRequestHint(stepThread, suspendContext, mySmartStepFilter)
|
||||||
hint.isResetIgnoreFilters = !session.shouldIgnoreSteppingFilters()
|
hint.isResetIgnoreFilters = !session.shouldIgnoreSteppingFilters()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
+27
-11
@@ -24,33 +24,40 @@ import com.intellij.debugger.jdi.ThreadReferenceProxyImpl
|
|||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.sun.jdi.VMDisconnectedException
|
import com.sun.jdi.VMDisconnectedException
|
||||||
import com.sun.jdi.request.StepRequest
|
import com.sun.jdi.request.StepRequest
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.isOnSuspensionPoint
|
||||||
import org.jetbrains.kotlin.idea.debugger.safeLineNumber
|
import org.jetbrains.kotlin.idea.debugger.safeLineNumber
|
||||||
import org.jetbrains.kotlin.idea.debugger.safeLocation
|
import org.jetbrains.kotlin.idea.debugger.safeLocation
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.safeMethod
|
||||||
|
|
||||||
// Originally copied from RequestHint
|
// Originally copied from RequestHint
|
||||||
class KotlinStepOverInlinedLinesHint(
|
class KotlinStepOverRequestHint(
|
||||||
stepThread: ThreadReferenceProxyImpl,
|
stepThread: ThreadReferenceProxyImpl,
|
||||||
suspendContext: SuspendContextImpl,
|
suspendContext: SuspendContextImpl,
|
||||||
private val filter: KotlinMethodFilter
|
private val filter: KotlinMethodFilter
|
||||||
) : RequestHint(stepThread, suspendContext, StepRequest.STEP_LINE, StepRequest.STEP_OVER, filter) {
|
) : RequestHint(stepThread, suspendContext, StepRequest.STEP_LINE, StepRequest.STEP_OVER, filter) {
|
||||||
private companion object {
|
private companion object {
|
||||||
private val LOG = Logger.getInstance(KotlinStepOverInlinedLinesHint::class.java)
|
private val LOG = Logger.getInstance(KotlinStepOverRequestHint::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNextStepDepth(context: SuspendContextImpl): Int {
|
override fun getNextStepDepth(context: SuspendContextImpl): Int {
|
||||||
try {
|
try {
|
||||||
val frameProxy = context.frameProxy
|
val frameProxy = context.frameProxy ?: return STOP
|
||||||
if (frameProxy != null) {
|
if (isTheSameFrame(context)) {
|
||||||
if (isTheSameFrame(context)) {
|
if (frameProxy.isOnSuspensionPoint()) {
|
||||||
val isAcceptable = (filter.locationMatches(context, frameProxy.location()))
|
// Coroutine will sleep now so we can't continue stepping.
|
||||||
return if (isAcceptable) STOP else StepRequest.STEP_OVER
|
// Let's put a run-to-cursor breakpoint and resume the debugger.
|
||||||
} else if (isSteppedOut) {
|
return if (!installCoroutineResumedBreakpoint(context)) STOP else RESUME
|
||||||
val lineNumber = frameProxy.safeLocation()?.safeLineNumber(JAVA_STRATUM) ?: -1
|
|
||||||
return if (lineNumber >= 0) STOP else StepRequest.STEP_OVER
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return StepRequest.STEP_OUT
|
val location = frameProxy.safeLocation()
|
||||||
|
val isAcceptable = location != null && filter.locationMatches(context, location)
|
||||||
|
return if (isAcceptable) STOP else StepRequest.STEP_OVER
|
||||||
|
} else if (isSteppedOut) {
|
||||||
|
val lineNumber = frameProxy.safeLocation()?.safeLineNumber(JAVA_STRATUM) ?: -1
|
||||||
|
return if (lineNumber >= 0) STOP else StepRequest.STEP_OVER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return StepRequest.STEP_OUT
|
||||||
} catch (ignored: VMDisconnectedException) {
|
} catch (ignored: VMDisconnectedException) {
|
||||||
} catch (e: EvaluateException) {
|
} catch (e: EvaluateException) {
|
||||||
LOG.error(e)
|
LOG.error(e)
|
||||||
@@ -58,4 +65,13 @@ class KotlinStepOverInlinedLinesHint(
|
|||||||
|
|
||||||
return STOP
|
return STOP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun installCoroutineResumedBreakpoint(context: SuspendContextImpl): Boolean {
|
||||||
|
val frameProxy = context.frameProxy ?: return false
|
||||||
|
val location = frameProxy.safeLocation() ?: return false
|
||||||
|
val method = location.safeMethod() ?: return false
|
||||||
|
|
||||||
|
context.debugProcess.cancelRunToCursorBreakpoint()
|
||||||
|
return CoroutineBreakpointFacility.installCoroutineResumedBreakpoint(context, location, method)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+5
-23
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
|||||||
import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils
|
import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils
|
||||||
import org.jetbrains.kotlin.idea.core.util.getLineNumber
|
import org.jetbrains.kotlin.idea.core.util.getLineNumber
|
||||||
import org.jetbrains.kotlin.idea.debugger.*
|
import org.jetbrains.kotlin.idea.debugger.*
|
||||||
import org.jetbrains.kotlin.idea.debugger.stepping.filter.KotlinSuspendCallStepOverFilter
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.stepping.filter.LocationToken
|
import org.jetbrains.kotlin.idea.debugger.stepping.filter.LocationToken
|
||||||
import org.jetbrains.kotlin.idea.debugger.stepping.filter.StepOverCallerInfo
|
import org.jetbrains.kotlin.idea.debugger.stepping.filter.StepOverCallerInfo
|
||||||
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
||||||
@@ -46,33 +45,16 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
|||||||
stepSize: Int
|
stepSize: Int
|
||||||
): DebugProcessImpl.ResumeCommand? {
|
): DebugProcessImpl.ResumeCommand? {
|
||||||
if (suspendContext == null || suspendContext.isResumed) return null
|
if (suspendContext == null || suspendContext.isResumed) return null
|
||||||
|
|
||||||
val sourcePosition = suspendContext.debugProcess.debuggerContext.sourcePosition ?: return null
|
val sourcePosition = suspendContext.debugProcess.debuggerContext.sourcePosition ?: return null
|
||||||
return getStepOverCommand(suspendContext, ignoreBreakpoints, sourcePosition)
|
return getStepOverCommand(suspendContext, ignoreBreakpoints, sourcePosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestOnly
|
@TestOnly
|
||||||
fun getStepOverCommand(
|
fun getStepOverCommand(
|
||||||
suspendContext: SuspendContextImpl,
|
|
||||||
ignoreBreakpoints: Boolean,
|
|
||||||
debuggerContext: DebuggerContextImpl
|
|
||||||
): DebugProcessImpl.ResumeCommand? {
|
|
||||||
return getStepOverCommand(suspendContext, ignoreBreakpoints, debuggerContext.sourcePosition)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getStepOverCommand(
|
|
||||||
suspendContext: SuspendContextImpl,
|
suspendContext: SuspendContextImpl,
|
||||||
ignoreBreakpoints: Boolean,
|
ignoreBreakpoints: Boolean,
|
||||||
sourcePosition: SourcePosition
|
sourcePosition: SourcePosition
|
||||||
): DebugProcessImpl.ResumeCommand? {
|
): DebugProcessImpl.ResumeCommand? {
|
||||||
val file = sourcePosition.elementAt.containingFile
|
|
||||||
val location = suspendContext.debugProcess.invokeInManagerThread { suspendContext.frameProxy?.safeLocation() } ?: return null
|
|
||||||
if (isInSuspendMethod(location) && !isOnSuspendReturnOrReenter(location) && !isLastLineLocationInMethod(location)) {
|
|
||||||
return DebuggerSteppingHelper.createStepOverCommandWithCustomFilter(
|
|
||||||
suspendContext, ignoreBreakpoints, KotlinSuspendCallStepOverFilter(sourcePosition.line, file, ignoreBreakpoints)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return DebuggerSteppingHelper.createStepOverCommand(suspendContext, ignoreBreakpoints, sourcePosition)
|
return DebuggerSteppingHelper.createStepOverCommand(suspendContext, ignoreBreakpoints, sourcePosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,9 +148,9 @@ fun getStepOverAction(
|
|||||||
location: Location, sourcePosition: SourcePosition,
|
location: Location, sourcePosition: SourcePosition,
|
||||||
suspendContext: SuspendContextImpl, frameProxy: StackFrameProxyImpl
|
suspendContext: SuspendContextImpl, frameProxy: StackFrameProxyImpl
|
||||||
): KotlinStepAction {
|
): KotlinStepAction {
|
||||||
val stackFrame = frameProxy.safeStackFrame() ?: return KotlinStepAction.StepOver
|
val stackFrame = frameProxy.safeStackFrame() ?: return KotlinStepAction.JvmStepOver
|
||||||
val method = location.safeMethod() ?: return KotlinStepAction.StepOver
|
val method = location.safeMethod() ?: return KotlinStepAction.JvmStepOver
|
||||||
val token = LocationToken.from(stackFrame).takeIf { it.lineNumber > 0 } ?: return KotlinStepAction.StepOver
|
val token = LocationToken.from(stackFrame).takeIf { it.lineNumber > 0 } ?: return KotlinStepAction.JvmStepOver
|
||||||
|
|
||||||
val inlinedFunctionArgumentRanges = sourcePosition.collectInlineFunctionArgumentRanges()
|
val inlinedFunctionArgumentRanges = sourcePosition.collectInlineFunctionArgumentRanges()
|
||||||
val positionManager = suspendContext.debugProcess.positionManager
|
val positionManager = suspendContext.debugProcess.positionManager
|
||||||
@@ -191,7 +173,7 @@ fun getStepOverAction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return KotlinStepAction.StepOverInlined(tokensToSkip, StepOverCallerInfo.from(location))
|
return KotlinStepAction.KotlinStepOver(tokensToSkip, StepOverCallerInfo.from(location))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isInlineFunctionFromLibrary(positionManager: PositionManager, location: Location, token: LocationToken): Boolean {
|
private fun isInlineFunctionFromLibrary(positionManager: PositionManager, location: Location, token: LocationToken): Boolean {
|
||||||
@@ -282,5 +264,5 @@ fun getStepOutAction(location: Location, frameProxy: StackFrameProxyImpl): Kotli
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return KotlinStepAction.StepOverInlined(tokensToSkip, StepOverCallerInfo.from(location))
|
return KotlinStepAction.KotlinStepOver(tokensToSkip, StepOverCallerInfo.from(location))
|
||||||
}
|
}
|
||||||
-81
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.filter
|
|
||||||
|
|
||||||
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,
|
|
||||||
private val ignoreBreakpoints: Boolean
|
|
||||||
) : 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, ignoreBreakpoints)
|
|
||||||
return RequestHint.RESUME
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createRunToCursorBreakpoint(context: SuspendContextImpl, line: Int, file: PsiFile, ignoreBreakpoints: Boolean) {
|
|
||||||
val position = XSourcePositionImpl.create(file.virtualFile, line) ?: return
|
|
||||||
val process = context.debugProcess
|
|
||||||
process.showStatusText(DebuggerBundle.message("status.run.to.cursor"))
|
|
||||||
process.cancelRunToCursorBreakpoint()
|
|
||||||
|
|
||||||
if (ignoreBreakpoints) {
|
|
||||||
DebuggerManagerEx.getInstanceEx(process.project).breakpointManager.disableBreakpoints(process)
|
|
||||||
}
|
|
||||||
|
|
||||||
val runToCursorBreakpoint =
|
|
||||||
runReadAction {
|
|
||||||
DebuggerManagerEx.getInstanceEx(process.project).breakpointManager.addRunToCursorBreakpoint(position, ignoreBreakpoints)
|
|
||||||
} ?: return
|
|
||||||
|
|
||||||
runToCursorBreakpoint.suspendPolicy = when {
|
|
||||||
context.suspendPolicy == EventRequest.SUSPEND_EVENT_THREAD -> DebuggerSettings.SUSPEND_THREAD
|
|
||||||
else -> DebuggerSettings.SUSPEND_ALL
|
|
||||||
}
|
|
||||||
|
|
||||||
runToCursorBreakpoint.createRequest(process)
|
|
||||||
process.setRunToCursorBreakpoint(runToCursorBreakpoint)
|
|
||||||
}
|
|
||||||
+4
-2
@@ -90,8 +90,10 @@ abstract class KotlinDescriptorTestCaseWithStepping : KotlinDescriptorTestCase()
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun SuspendContextImpl.doStepOver(ignoreBreakpoints: Boolean = false) {
|
private fun SuspendContextImpl.doStepOver(ignoreBreakpoints: Boolean = false) {
|
||||||
val stepOverCommand = runReadAction { commandProvider.getStepOverCommand(this, ignoreBreakpoints, debuggerContext) }
|
val stepOverCommand = runReadAction {
|
||||||
?: dp.createStepOverCommand(this, ignoreBreakpoints)
|
val sourcePosition = debuggerContext.sourcePosition
|
||||||
|
commandProvider.getStepOverCommand(this, ignoreBreakpoints, sourcePosition)
|
||||||
|
} ?: dp.createStepOverCommand(this, ignoreBreakpoints)
|
||||||
|
|
||||||
dp.managerThread.schedule(stepOverCommand)
|
dp.managerThread.schedule(stepOverCommand)
|
||||||
}
|
}
|
||||||
|
|||||||
+33
@@ -931,6 +931,39 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
|||||||
public void testWhenWithoutExpression() throws Exception {
|
public void testWhenWithoutExpression() throws Exception {
|
||||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/whenWithoutExpression.kt");
|
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/whenWithoutExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/coroutines")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Coroutines extends AbstractKotlinSteppingTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doStepOverTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInCoroutines() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/coroutines"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("sequenceNested.kt")
|
||||||
|
public void testSequenceNested() throws Exception {
|
||||||
|
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/coroutines/sequenceNested.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("sequenceNested2.kt")
|
||||||
|
public void testSequenceNested2() throws Exception {
|
||||||
|
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/coroutines/sequenceNested2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("sequenceSimple.kt")
|
||||||
|
public void testSequenceSimple() throws Exception {
|
||||||
|
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/coroutines/sequenceSimple.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("sequenceTake2.kt")
|
||||||
|
public void testSequenceTake2() throws Exception {
|
||||||
|
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/coroutines/sequenceTake2.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/stepping/filters")
|
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/stepping/filters")
|
||||||
|
|||||||
Vendored
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val seq = sequence {
|
||||||
|
//Breakpoint!
|
||||||
|
yield(
|
||||||
|
sequence {
|
||||||
|
yield(1)
|
||||||
|
yield(2)
|
||||||
|
yield(3)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
yield(
|
||||||
|
sequence {
|
||||||
|
yield(4)
|
||||||
|
yield(5)
|
||||||
|
yield(6)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
seq.map { it.toList() }.flatten().toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP_OVER: 10
|
||||||
Vendored
+15
@@ -0,0 +1,15 @@
|
|||||||
|
LineBreakpoint created at sequenceNested.kt:6
|
||||||
|
Run Java
|
||||||
|
Connected to the target VM
|
||||||
|
sequenceNested.kt:6
|
||||||
|
sequenceNested.kt:7
|
||||||
|
sequenceNested.kt:6
|
||||||
|
sequenceNested.kt:14
|
||||||
|
sequenceNested.kt:15
|
||||||
|
sequenceNested.kt:14
|
||||||
|
sequenceNested.kt:21
|
||||||
|
sequenceNested.kt:23
|
||||||
|
sequenceNested.kt:24
|
||||||
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
Vendored
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val seq = sequence {
|
||||||
|
yield(
|
||||||
|
sequence {
|
||||||
|
//Breakpoint!
|
||||||
|
yield(1)
|
||||||
|
yield(2)
|
||||||
|
yield(3)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
yield(
|
||||||
|
sequence {
|
||||||
|
yield(4)
|
||||||
|
yield(5)
|
||||||
|
yield(6)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
seq.map { it.toList() }.flatten().toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP_OVER: 10
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
LineBreakpoint created at sequenceNested2.kt:8
|
||||||
|
Run Java
|
||||||
|
Connected to the target VM
|
||||||
|
sequenceNested2.kt:8
|
||||||
|
sequenceNested2.kt:9
|
||||||
|
sequenceNested2.kt:10
|
||||||
|
sequenceNested2.kt:11
|
||||||
|
sequenceNested2.kt:23
|
||||||
|
sequenceNested2.kt:23
|
||||||
|
sequenceNested2.kt:24
|
||||||
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val seq = sequence {
|
||||||
|
//Breakpoint!
|
||||||
|
yield(1)
|
||||||
|
yield(2)
|
||||||
|
yield(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
seq.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP_OVER: 4
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
LineBreakpoint created at sequenceSimple.kt:6
|
||||||
|
Run Java
|
||||||
|
Connected to the target VM
|
||||||
|
sequenceSimple.kt:6
|
||||||
|
sequenceSimple.kt:7
|
||||||
|
sequenceSimple.kt:8
|
||||||
|
sequenceSimple.kt:9
|
||||||
|
sequenceSimple.kt:11
|
||||||
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val seq = sequence {
|
||||||
|
//Breakpoint!
|
||||||
|
yield(1)
|
||||||
|
yield(2)
|
||||||
|
yield(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
seq.take(2).toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP_OVER: 4
|
||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
LineBreakpoint created at sequenceTake2.kt:6
|
||||||
|
Run Java
|
||||||
|
Connected to the target VM
|
||||||
|
sequenceTake2.kt:6
|
||||||
|
sequenceTake2.kt:7
|
||||||
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
Reference in New Issue
Block a user