Skip all same line locations when stepping over inline call (KT-20351)

#KT-20351
This commit is contained in:
Nikolay Krasko
2017-12-22 14:49:37 +03:00
parent f39250c9a2
commit 449fee74e8
4 changed files with 85 additions and 12 deletions
@@ -336,7 +336,7 @@ fun getStepOverAction(
return ktFile?.name ?: this.sourceName(KOTLIN_STRATA_NAME) return ktFile?.name ?: this.sourceName(KOTLIN_STRATA_NAME)
} }
fun isLocationSuitable(nextLocation: Location): Boolean { fun isThisMethodLocation(nextLocation: Location): Boolean {
if (nextLocation.method() != location.method()) { if (nextLocation.method() != location.method()) {
return false return false
} }
@@ -358,7 +358,7 @@ fun getStepOverAction(
val previousSuitableLocation = methodLocations.reversed() val previousSuitableLocation = methodLocations.reversed()
.dropWhile { it != location } .dropWhile { it != location }
.drop(1) .drop(1)
.filter(::isLocationSuitable) .filter(::isThisMethodLocation)
.dropWhile { it.ktLineNumber() == location.ktLineNumber() } .dropWhile { it.ktLineNumber() == location.ktLineNumber() }
.firstOrNull() .firstOrNull()
@@ -368,7 +368,7 @@ fun getStepOverAction(
val patchedLocation = if (isBackEdgeLocation()) { val patchedLocation = if (isBackEdgeLocation()) {
// Pretend we had already done a backing step // Pretend we had already done a backing step
methodLocations methodLocations
.filter(::isLocationSuitable) .filter(::isThisMethodLocation)
.firstOrNull { it.ktLineNumber() == location.ktLineNumber() } ?: location .firstOrNull { it.ktLineNumber() == location.ktLineNumber() } ?: location
} }
else { else {
@@ -388,22 +388,22 @@ fun getStepOverAction(
val inlineRangeVariables = getInlineRangeLocalVariables(frameProxy) val inlineRangeVariables = getInlineRangeLocalVariables(frameProxy)
// Try to find the range of inlined lines: // 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 // - 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. // - 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 // 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 is used to overcome it. // inline function in last statement of inline function. The list of inlineRangeVariables will be used later to overcome it.
val probablyInlinedLocations = methodLocations val stepOverLocations = methodLocations
.dropWhile { it != patchedLocation } .dropWhile { it != patchedLocation }
.drop(1) .drop(1)
.dropWhile { it.ktLineNumber() == patchedLineNumber } .dropWhile { it.ktLineNumber() == patchedLineNumber }
.takeWhile { loc -> .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. // 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 // 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 // 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( return Action.STEP_OVER_INLINED(StepOverFilterData(
patchedLineNumber, patchedLineNumber,
probablyInlinedLocations.map { it.ktLineNumber() }.toSet(), stepOverLocations.map { it.ktLineNumber() }.toSet(),
inlineRangeVariables, inlineRangeVariables,
isDexDebug, isDexDebug,
returnCodeIndex returnCodeIndex
@@ -0,0 +1,57 @@
package soInlineCallsInOneLine
fun test(i: Int): Boolean {
return false
}
fun foo() {}
fun main(args: Array<String>) {
//Breakpoint!
val listOf = listOf(1)
val testSome = listOf.filterNot(::test)
foo()
}
// STEP_OVER: 3
@@ -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
@@ -578,6 +578,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
doStepOverTest(fileName); 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") @TestMetadata("soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn.kt")
public void testSoInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn() throws Exception { public void testSoInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn.kt");