From 449fee74e8cc3c0880a99af7cb1493ee3641f60b Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Fri, 22 Dec 2017 14:49:37 +0300 Subject: [PATCH] Skip all same line locations when stepping over inline call (KT-20351) #KT-20351 --- .../stepping/KotlinSteppingCommandProvider.kt | 24 ++++---- .../stepOver/soInlineCallsInOneLine.kt | 57 +++++++++++++++++++ .../stepOver/soInlineCallsInOneLine.out | 10 ++++ .../debugger/KotlinSteppingTestGenerated.java | 6 ++ 4 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineCallsInOneLine.kt create mode 100644 idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineCallsInOneLine.out diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt index 038100fcc8c..4a8e77b8ae4 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt @@ -336,7 +336,7 @@ fun getStepOverAction( return ktFile?.name ?: this.sourceName(KOTLIN_STRATA_NAME) } - fun isLocationSuitable(nextLocation: Location): Boolean { + fun isThisMethodLocation(nextLocation: Location): Boolean { if (nextLocation.method() != location.method()) { return false } @@ -358,7 +358,7 @@ fun getStepOverAction( val previousSuitableLocation = methodLocations.reversed() .dropWhile { it != location } .drop(1) - .filter(::isLocationSuitable) + .filter(::isThisMethodLocation) .dropWhile { it.ktLineNumber() == location.ktLineNumber() } .firstOrNull() @@ -368,7 +368,7 @@ fun getStepOverAction( val patchedLocation = if (isBackEdgeLocation()) { // Pretend we had already done a backing step methodLocations - .filter(::isLocationSuitable) + .filter(::isThisMethodLocation) .firstOrNull { it.ktLineNumber() == location.ktLineNumber() } ?: location } else { @@ -388,22 +388,22 @@ fun getStepOverAction( val inlineRangeVariables = getInlineRangeLocalVariables(frameProxy) - // Try to find the range of inlined lines: - // - Lines from other files and from functions that are not in range of current one are definitely inlined + // Try to find the range for step over: + // - Lines from other files and from functions that are not in range of current one are definitely inlined and should be stepped over. // - Lines in function arguments of inlined functions are inlined too as we found them starting from the position of inlined call. + // - Current line locations should also be stepped over. // - // It also thinks that too many lines are inlined when there's a call of function argument or other - // inline function in last statement of inline function. The list of inlineRangeVariables is used to overcome it. - val probablyInlinedLocations = methodLocations + // We might erroneously extend this range too much when there's a call of function argument or other + // inline function in last statement of inline function. The list of inlineRangeVariables will be used later to overcome it. + val stepOverLocations = methodLocations .dropWhile { it != patchedLocation } .drop(1) .dropWhile { it.ktLineNumber() == patchedLineNumber } .takeWhile { loc -> - !isLocationSuitable(loc) || lambdaArgumentRanges.any { loc.ktLineNumber() in it } + !isThisMethodLocation(loc) || lambdaArgumentRanges.any { loc.ktLineNumber() in it } || loc.ktLineNumber() == patchedLineNumber } - .dropWhile { it.ktLineNumber() == patchedLineNumber } - if (!probablyInlinedLocations.isEmpty()) { + if (!stepOverLocations.isEmpty()) { // Some Kotlin inlined methods with 'for' (and maybe others) generates bytecode that after dexing have a strange artifact. // GOTO instructions are moved to the end of method and as they don't have proper line, line is obtained from the previous // instruction. It might be method return or previous GOTO from the inlining. Simple stepping over such function is really @@ -423,7 +423,7 @@ fun getStepOverAction( return Action.STEP_OVER_INLINED(StepOverFilterData( patchedLineNumber, - probablyInlinedLocations.map { it.ktLineNumber() }.toSet(), + stepOverLocations.map { it.ktLineNumber() }.toSet(), inlineRangeVariables, isDexDebug, returnCodeIndex diff --git a/idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineCallsInOneLine.kt b/idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineCallsInOneLine.kt new file mode 100644 index 00000000000..47f5c356265 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineCallsInOneLine.kt @@ -0,0 +1,57 @@ +package soInlineCallsInOneLine + +fun test(i: Int): Boolean { + return false +} + +fun foo() {} + +fun main(args: Array) { + //Breakpoint! + val listOf = listOf(1) + val testSome = listOf.filterNot(::test) + foo() +} + + +// STEP_OVER: 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineCallsInOneLine.out b/idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineCallsInOneLine.out new file mode 100644 index 00000000000..08376e13ea0 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineCallsInOneLine.out @@ -0,0 +1,10 @@ +LineBreakpoint created at soInlineCallsInOneLine.kt:11 +Run Java +Connected to the target VM +soInlineCallsInOneLine.kt:11 +soInlineCallsInOneLine.kt:12 +soInlineCallsInOneLine.kt:13 +soInlineCallsInOneLine.kt:14 +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java index 5650a5e270f..f740220e8ae 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java @@ -578,6 +578,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest { doStepOverTest(fileName); } + @TestMetadata("soInlineCallsInOneLine.kt") + public void testSoInlineCallsInOneLine() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineCallsInOneLine.kt"); + doStepOverTest(fileName); + } + @TestMetadata("soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn.kt") public void testSoInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn.kt");