diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaMethodFilter.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaMethodFilter.kt index b11eac95cf0..3a7944a3f9d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaMethodFilter.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaMethodFilter.kt @@ -21,6 +21,7 @@ import com.intellij.debugger.engine.BreakpointStepMethodFilter import com.intellij.debugger.engine.DebugProcessImpl import com.intellij.util.Range import com.sun.jdi.Location +import org.jetbrains.kotlin.codegen.coroutines.DO_RESUME_METHOD_NAME import org.jetbrains.kotlin.idea.refactoring.isMultiLine import org.jetbrains.kotlin.idea.debugger.isInsideInlineArgument import org.jetbrains.kotlin.psi.KtBlockExpression @@ -30,7 +31,8 @@ import org.jetbrains.kotlin.util.OperatorNameConventions class KotlinLambdaMethodFilter( private val lambda: KtFunction, private val myCallingExpressionLines: Range, - private val isInline: Boolean + private val isInline: Boolean, + private val isSuspend: Boolean ): BreakpointStepMethodFilter { private val myFirstStatementPosition: SourcePosition? private val myLastStatementLine: Int @@ -72,9 +74,12 @@ class KotlinLambdaMethodFilter( override fun getCallingExpressionLines() = if (isInline) Range(0, 999) else myCallingExpressionLines - companion object { - fun isLambdaName(name: String?): Boolean { - return name == OperatorNameConventions.INVOKE.asString() + private fun isLambdaName(name: String?): Boolean { + if (isSuspend) { + return name == DO_RESUME_METHOD_NAME } + + return name == OperatorNameConventions.INVOKE.asString() } + } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaSmartStepIntoTarget.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaSmartStepIntoTarget.kt index bfb3b62fb3b..62c965a032f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaSmartStepIntoTarget.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinLambdaSmartStepIntoTarget.kt @@ -23,14 +23,16 @@ import org.jetbrains.kotlin.idea.KotlinIcons import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.util.OperatorNameConventions +import javax.swing.Icon class KotlinLambdaSmartStepTarget( label: String, highlightElement: KtFunction, lines: Range, - val isInline: Boolean + val isInline: Boolean, + val isSuspend: Boolean ): SmartStepTarget(label, highlightElement, true, lines) { - override fun getIcon() = KotlinIcons.LAMBDA + override fun getIcon(): Icon = KotlinIcons.LAMBDA fun getLambda() = highlightElement as KtFunction diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt index 819f285f0a8..900f8fdf381 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt @@ -25,6 +25,7 @@ import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiMethod import com.intellij.util.Range import com.intellij.util.containers.OrderedSet +import org.jetbrains.kotlin.builtins.isSuspendFunctionType import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor @@ -50,8 +51,8 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() { val elementAtOffset = position.elementAt ?: return emptyList() - val element = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, elementAtOffset.textRange.startOffset) - if (element !is KtElement) return emptyList() + val element = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, elementAtOffset.textRange.startOffset) as? KtElement ?: + return emptyList() val elementTextRange = element.textRange ?: return emptyList() @@ -80,8 +81,10 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() { val arguments = resolvedCall.valueArguments for ((param, argument) in arguments) { if (argument.arguments.any { getArgumentExpression(it) == function }) { - val label = KotlinLambdaSmartStepTarget.calcLabel(resolvedCall.resultingDescriptor, param.name) - result.add(KotlinLambdaSmartStepTarget(label, function, lines, InlineUtil.isInline(resolvedCall.resultingDescriptor))) + val resultingDescriptor = resolvedCall.resultingDescriptor + val label = KotlinLambdaSmartStepTarget.calcLabel(resultingDescriptor, param.name) + result.add(KotlinLambdaSmartStepTarget( + label, function, lines, InlineUtil.isInline(resultingDescriptor), param.type.isSuspendFunctionType)) return true } } @@ -195,8 +198,11 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() { override fun createMethodFilter(stepTarget: SmartStepTarget?): MethodFilter? { return when (stepTarget) { - is KotlinMethodSmartStepTarget -> KotlinBasicStepMethodFilter(stepTarget.descriptor, stepTarget.callingExpressionLines!!) - is KotlinLambdaSmartStepTarget -> KotlinLambdaMethodFilter(stepTarget.getLambda(), stepTarget.callingExpressionLines!!, stepTarget.isInline) + is KotlinMethodSmartStepTarget -> + KotlinBasicStepMethodFilter(stepTarget.descriptor, stepTarget.callingExpressionLines!!) + is KotlinLambdaSmartStepTarget -> + KotlinLambdaMethodFilter( + stepTarget.getLambda(), stepTarget.callingExpressionLines!!, stepTarget.isInline, stepTarget.isSuspend) else -> super.createMethodFilter(stepTarget) } } diff --git a/idea/testData/debugger/tinyApp/outs/coroutine.out b/idea/testData/debugger/tinyApp/outs/coroutine.out new file mode 100644 index 00000000000..ac2063169c3 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/coroutine.out @@ -0,0 +1,8 @@ +LineBreakpoint created at coroutine.kt:15 +!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! coroutine.CoroutineKt +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +coroutine.kt:15 +coroutine.kt:16 +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/coroutine.kt b/idea/testData/debugger/tinyApp/src/stepping/custom/coroutine.kt new file mode 100644 index 00000000000..cd882e11038 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/custom/coroutine.kt @@ -0,0 +1,18 @@ +package coroutine + +import forTests.builder + +suspend fun second() { +} + +suspend fun first() { + second() +} + +fun main(args: Array) { + // SMART_STEP_INTO_BY_INDEX: 2 + //Breakpoint! + builder { + first() + } +} \ 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 5400b14d747..6a97ed7c607 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestBase.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestBase.kt @@ -213,8 +213,11 @@ abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() { stepTargets.filterIsInstance().mapNotNull { stepTarget -> when (stepTarget) { - is KotlinLambdaSmartStepTarget -> KotlinLambdaMethodFilter(stepTarget.getLambda(), stepTarget.getCallingExpressionLines()!!, stepTarget.isInline) - is KotlinMethodSmartStepTarget -> KotlinBasicStepMethodFilter(stepTarget.descriptor, stepTarget.getCallingExpressionLines()!!) + is KotlinLambdaSmartStepTarget -> + KotlinLambdaMethodFilter( + stepTarget.getLambda(), stepTarget.getCallingExpressionLines()!!, stepTarget.isInline, stepTarget.isSuspend) + is KotlinMethodSmartStepTarget -> + KotlinBasicStepMethodFilter(stepTarget.descriptor, stepTarget.getCallingExpressionLines()!!) is MethodSmartStepTarget -> BasicStepMethodFilter(stepTarget.method, stepTarget.getCallingExpressionLines()) else -> null } diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java index d73319b025f..2ef2f5fcf83 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java @@ -944,6 +944,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/stepping/custom"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("coroutine.kt") + public void testCoroutine() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/coroutine.kt"); + doCustomTest(fileName); + } + @TestMetadata("crossinlineLiteral.kt") public void testCrossinlineLiteral() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/crossinlineLiteral.kt");