From 08c29b73252dff4d6d8724f0c00fee4eb7c7c982 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Tue, 1 Dec 2015 19:19:02 +0300 Subject: [PATCH] Fix step out from inline function literal placed at one line #KT-10187 Fixed --- .../stepping/KotlinSteppingCommandProvider.kt | 31 ++++++++++--------- .../stepOutInlinedLambdaArgumentOneLine.out | 8 +++++ .../stepOutInlinedLambdaArgumentOneLine.kt | 10 ++++++ .../debugger/KotlinSteppingTestGenerated.java | 6 ++++ 4 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 idea/testData/debugger/tinyApp/outs/stepOutInlinedLambdaArgumentOneLine.out create mode 100644 idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlinedLambdaArgumentOneLine.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 2ecdfbb9b92..05c67273306 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt @@ -202,7 +202,7 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() { val lineStartOffset = file.getLineStartOffset(sourcePosition.line) ?: return null val inlineFunctions = getInlineFunctionsIfAny(file, lineStartOffset) - val inlinedArgument = getInlineArgumentIfAny(file, lineStartOffset) + val inlinedArgument = getInlineArgumentIfAny(sourcePosition.elementAt) if (inlineFunctions.isEmpty() && inlinedArgument == null) return null @@ -334,7 +334,11 @@ fun getStepOutPosition( val computedReferenceType = location.declaringType() ?: return null val locations = computedReferenceType.allLineLocations() - val nextLineLocations = locations.dropWhile { it.lineNumber() != location.lineNumber() }.filter { it.method() == location.method() } + val nextLineLocations = locations + .dropWhile { it != location } + .drop(1) + .filter { it.method() == location.method() } + .dropWhile { it.lineNumber() == location.lineNumber() } if (inlineFunctions.isNotEmpty()) { return suspendContext.getXPositionForStepOutFromInlineFunction(nextLineLocations, inlineFunctions) ?: return null @@ -352,13 +356,12 @@ private fun SuspendContextImpl.getXPositionForStepOutFromInlineFunction( inlineFunctionsToSkip: List ): XSourcePositionImpl? { return getNextPositionWithFilter(locations) { - file, offset -> + offset, elementAt -> if (inlineFunctionsToSkip.any { it.textRange.contains(offset) }) { return@getNextPositionWithFilter true } - val inlinedArgument = getInlineArgumentIfAny(file, offset) - inlinedArgument != null && inlinedArgument.textRange.contains(offset) + getInlineArgumentIfAny(elementAt) != null } } @@ -367,37 +370,37 @@ private fun SuspendContextImpl.getXPositionForStepOutFromInlinedArgument( inlinedArgumentToSkip: KtFunctionLiteral ): XSourcePositionImpl? { return getNextPositionWithFilter(locations) { - file, offset -> + offset, elementAt -> inlinedArgumentToSkip.textRange.contains(offset) } } private fun SuspendContextImpl.getNextPositionWithFilter( locations: List, - skip: (KtFile, Int) -> Boolean + skip: (Int, PsiElement) -> Boolean ): XSourcePositionImpl? { for (location in locations) { - val file = try { - this.debugProcess.positionManager.getSourcePosition(location)?.file as? KtFile + val sourcePosition = try { + this.debugProcess.positionManager.getSourcePosition(location) } catch(e: NoDataException) { null } ?: continue + val file = sourcePosition.file as? KtFile ?: continue + val elementAt = sourcePosition.elementAt ?: continue val currentLine = location.lineNumber() - 1 val lineStartOffset = file.getLineStartOffset(currentLine) ?: continue - if (skip(file, lineStartOffset)) continue + if (skip(lineStartOffset, elementAt)) continue - val elementAt = file.findElementAt(lineStartOffset) ?: continue return XSourcePositionImpl.createByElement(elementAt) } return null } -private fun getInlineArgumentIfAny(file: KtFile, offset: Int): KtFunctionLiteral? { - val elementAt = file.findElementAt(offset) ?: return null - val functionLiteralExpression = elementAt.getParentOfType(false) ?: return null +private fun getInlineArgumentIfAny(elementAt: PsiElement?): KtFunctionLiteral? { + val functionLiteralExpression = elementAt?.getParentOfType(false) ?: return null val context = functionLiteralExpression.analyze(BodyResolveMode.PARTIAL) if (!InlineUtil.isInlinedArgument(functionLiteralExpression.functionLiteral, context, false)) return null diff --git a/idea/testData/debugger/tinyApp/outs/stepOutInlinedLambdaArgumentOneLine.out b/idea/testData/debugger/tinyApp/outs/stepOutInlinedLambdaArgumentOneLine.out new file mode 100644 index 00000000000..3a889e53cac --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/stepOutInlinedLambdaArgumentOneLine.out @@ -0,0 +1,8 @@ +LineBreakpoint created at stepOutInlinedLambdaArgumentOneLine.kt:5 lambdaOrdinal = 0 +!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! stepOutInlinedLambdaArgumentOneLine.StepOutInlinedLambdaArgumentOneLineKt +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +stepOutInlinedLambdaArgumentOneLine.kt:5 +stepOutInlinedLambdaArgumentOneLine.kt:6 +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/stepOut/stepOutInlinedLambdaArgumentOneLine.kt b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlinedLambdaArgumentOneLine.kt new file mode 100644 index 00000000000..21d7b7ff4a0 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlinedLambdaArgumentOneLine.kt @@ -0,0 +1,10 @@ +package stepOutInlinedLambdaArgumentOneLine + +fun main(args: Array) { + //Breakpoint! (lambdaOrdinal = 0) + dive(3) { x -> x + 4 } +} + +inline fun dive(p: Int, f:(Int) -> Int) = f(p) + +// STEP_OUT: 2 \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java index 1a5c11d3140..2642b0e8247 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java @@ -316,6 +316,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest { doStepOutTest(fileName); } + @TestMetadata("stepOutInlinedLambdaArgumentOneLine.kt") + public void testStepOutInlinedLambdaArgumentOneLine() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlinedLambdaArgumentOneLine.kt"); + doStepOutTest(fileName); + } + @TestMetadata("stepOutSeveralInlineArgumentDeepest.kt") public void testStepOutSeveralInlineArgumentDeepest() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineArgumentDeepest.kt");