Change the way 'step over' over inline calls works (KT-13751)

Previously it worked by invoking 'Run To Cursor' for the last position of inline function. As there's only one 'run to cursor' breakpoint
available in Idea framework, it couldn't work when inline function call was was used in conditions of control flow statements.

A new approach works through multiple step over operation and controlling stop position. In other words we try to "step over" inlined lines.
Same thing is actually done in "Smart Step Into" action.

(cherry picked from commit 2e8775d)

 #KT-13751 Fixed
This commit is contained in:
Nikolay Krasko
2016-09-26 15:14:54 +03:00
committed by Nikolay Krasko
parent 9594316b0a
commit 7992df7b93
49 changed files with 1004 additions and 322 deletions
@@ -0,0 +1,16 @@
package inlineInIfFalse
fun main(args: Array<String>) {
val bar = ""
//Breakpoint!
if (inlineCall { true }) {
foo()
}
foo()
}
fun foo() {}
inline fun inlineCall(predicate: (String?) -> Boolean): Boolean {
return false
}
@@ -0,0 +1,15 @@
package inlineInIfTrue
fun main(args: Array<String>) {
val bar = ""
//Breakpoint!
if (inlineCall { true }) {
foo()
}
}
fun foo() {}
inline fun inlineCall(predicate: (String?) -> Boolean): Boolean {
return true
}
@@ -0,0 +1,20 @@
package soInlineAnonymousFunctionArgument
fun main(args: Array<String>) {
//Breakpoint!
val b = 1 // 1
foo( // 2
fun (){ test(1) }
)
foo(fun (){ test(1) }) // 3
} // 4
inline fun foo(f: () -> Unit) {
f()
}
fun test(i: Int) = 1
// STEP_OVER: 6
@@ -0,0 +1,17 @@
package soInlineCallInLastStatementInInline
fun main(args: Array<String>) {
bar()
}
inline fun bar() {
//Breakpoint!
val a = 1
foo { 42 }
}
inline fun foo(f: () -> Unit) {
f()
}
// STEP_OVER: 2
@@ -0,0 +1,18 @@
package soInlineCallInLastStatementInInlineInInline
fun main(args: Array<String>) {
bar()
val i = 45
}
inline fun bar() {
val a = 1
foo { 42 }
}
inline fun foo(f: () -> Unit) {
//Breakpoint!
f()
}
// STEP_OVER: 4
@@ -0,0 +1,20 @@
package soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn
fun main(args: Array<String>) {
bar {
println("")
}
}
inline fun bar(f2: () -> Unit) {
//Breakpoint! (lambdaOrdinal = -1)
foo({ 42 },
f2)
}
inline fun foo(f1: () -> Unit, f2: () -> Unit) {
f1()
f2()
}
// STEP_OVER 5
@@ -0,0 +1,17 @@
package soInlineFunWithLastStatementMultilineArgumentCall
fun main(args: Array<String>) {
var k = 444
bar {
val b = 1
}
k++
}
inline fun bar(f: (Int) -> Unit) {
//Breakpoint!
f(1)
}
// STEP_OVER: 1
@@ -0,0 +1,14 @@
package soInlineFunWithLastStatementOneLineArgumentCall
fun main(args: Array<String>) {
var k = 444
bar { val b = 1 }
k++
}
inline fun bar(f: (Int) -> Unit) {
//Breakpoint!
f(1)
}
// STEP_OVER: 4
@@ -0,0 +1,23 @@
package soInlineIfConditionLambdaFalse
fun main(args: Array<String>) {
bar {
false
}
}
inline fun bar(f: (Int) -> Boolean) {
//Breakpoint!
if (f(42)) {
foo()
}
else {
foo()
}
foo()
}
fun foo() {}
// STEP_OVER: 4
@@ -0,0 +1,23 @@
package soInlineIfConditionLambdaTrue
fun main(args: Array<String>) {
bar {
true
}
} // 4
inline fun bar(f: (Int) -> Boolean) {
//Breakpoint!
if (f(42)) { // 1
foo() // 2
}
else {
foo()
}
foo() // 3
}
fun foo() {}
// STEP_OVER: 4
@@ -0,0 +1,23 @@
package soInlineWhileCondition
fun main(args: Array<String>) {
//Breakpoint!
var i = 1 // 1
// inline in while condition (true)
while (id { i < 2 }) { // 2 4
i++ // 3
}
// inline in while condition (false)
while (id { false }) { // 5
bar()
}
} // 6
inline fun id(f: () -> Boolean): Boolean {
return f()
}
fun bar() {}
// STEP_OVER: 6
@@ -0,0 +1,15 @@
package soReifiedInlineIfConditionFalse
fun main(args: Array<String>) {
// Reified function call in if condition
//Breakpoint!
if (reified(11) != 11) { // 1
val a = 22
}
} // 2
inline fun <reified T> reified(f: T): T {
val a = 33
return f
}
@@ -0,0 +1,18 @@
package soSimpleInlineIfCondition
fun main(args: Array<String>) {
//Breakpoint!
if (foo {
test(2)
}) {
bar()
}
bar()
}
inline fun foo(f: () -> Boolean): Boolean = f()
fun test(i: Int): Boolean = true
fun bar() {}
@@ -0,0 +1,11 @@
package stepOverDeclarationInInlineFun
fun main(args: Array<String>) {
foo { 1 }
}
inline fun foo(f: () -> Int): Int {
//Breakpoint!
val a = 15
return f()
}
@@ -2,45 +2,40 @@ package stepOverIfWithInline
fun main(args: Array<String>) {
//Breakpoint!
val prop = 1
val prop = 1 // 1
// False with braces
val a = if (1 > 2) {
val a = if (1 > 2) { // 2 4(?)
foo { test(1) }
}
else {
foo { test(1) }
foo { test(1) } // 3
}
// False without braces
val b = if (1 > 2)
val b = if (1 > 2) // 5 7(?)
foo { test(1) }
else
foo { test(1) }
foo { test(1) } // 6
// One line
val c = if (1 > 2) foo { test(1) } else foo { test(1) }
val c = if (1 > 2) foo { test(1) } else foo { test(1) } // 8
// Else on next line, false
val d = if (1 > 2) foo { test(1) }
else foo { test(1) }
val d = if (1 > 2) foo { test(1) } // 9 11
else foo { test(1) } // 10
// Else on next line, true
val e = if (1 < 2) foo { test(1) }
val e = if (1 < 2) foo { test(1) } // 12
else foo { test(1) }
// Inline function call in condition
val f = if (foo { test(1) } > 2) {
val f = if (foo { test(1) } > 2) { // 13 15(?)
foo { test(1) }
}
else {
foo { test(1) }
foo { test(1) } // 14
}
// Reified function call in if condition
if (reified(1) != 1) {
val a = 1
}
}
} // 16
inline fun foo(f: () -> Int): Int {
val a = 1
@@ -49,9 +44,4 @@ inline fun foo(f: () -> Int): Int {
fun test(i: Int) = 1
inline fun <reified T> reified(f: T): Int {
val a = 1
return 1
}
// STEP_OVER: 25
// STEP_OVER: 17
@@ -1,8 +1,8 @@
package stepOverInlinedLambda
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
val a = A()
foo { test(1) }
foo {
test(2)
@@ -27,8 +27,6 @@ fun main(args: Array<String>) {
})
val b = foo { test(1) }
foo(fun (){ test(1) })
}
inline fun foo(f: () -> Unit) {
@@ -49,4 +47,4 @@ class A {
fun test(i: Int) = 1
// STEP_OVER: 11
// STEP_OVER: 12
@@ -3,16 +3,16 @@ package stepOverInlinedLambdaStdlib
fun main(args: Array<String>) {
//Breakpoint!
val a = listOf(1, 2, 3)
a.filter { it > 1 }
a.filter { it > 1 } /*!*/
a.filter { it > 1 }.map { it * 2 }
a.filter { it > 1 }.map { it * 2 } /*!*/
a.filter {
a.filter { /*!*/
it > 1
}.map {
it * 2
}
}
} /*!*/
// TRACING_FILTERS_ENABLED: false
// STEP_OVER: 4
@@ -9,8 +9,11 @@ fun main(args: Array<String>) {
inline fun bar(f: (Int) -> Unit) {
//Breakpoint!
val a = 1
foo()
val f = f(1)
val c = 1
}
// STEP_OVER: 3
fun foo() {}
// STEP_OVER: 4
@@ -4,43 +4,43 @@ fun main(args: Array<String>) {
try {
bar()
}
catch(e: Exception) {
val a = 1
catch(e: Exception) { // 13
val a = 1 // 14
}
}
} // 15
fun bar() {
//Breakpoint!
val prop = 1
val prop = 1 // 1
// Try
try {
foo { test(1) }
try { // 2
foo { test(1) } // 3
}
catch(e: Exception) {
foo { test(1) }
}
// Many catch clauses
try {
throw IllegalStateException()
try { // 4
throw IllegalStateException() // 5
}
catch(e: IllegalStateException) {
foo { test(1) }
catch(e: IllegalStateException) { // 6
foo { test(1) } // 7
}
catch(e: Exception) {
foo { test(1) }
}
// exception in lambda
try {
foo { throw IllegalStateException() }
try { // 8
foo { throw IllegalStateException() } // 9
}
catch(e: Exception) {
foo { test(1) }
catch(e: Exception) { // 10
foo { test(1) } // 11
}
// Exception without catch
foo { throw IllegalStateException() }
foo { throw IllegalStateException() } // 12
val prop2 = 1
}
@@ -51,4 +51,4 @@ inline fun foo(f: () -> Int): Int {
fun test(i: Int) = 1
// STEP_OVER: 20
// STEP_OVER: 15
@@ -1,23 +1,23 @@
package stepOverWhenInReturn
fun main(args: Array<String>) {
whenInReturn()
}
whenInReturn() // 4?
} // 5
fun whenInReturn(): Int {
val a = 1
//Breakpoint!
return when(a) {
1 -> foo { 1 }
return when(a) { // 1 3?
1 -> foo { 1 } // 2
else -> 3
}
}
inline fun foo(f: () -> Int): Int {
val a = 1
val a = 15
return f()
}
fun test(i: Int) = 1
fun test(i: Int) = 42
// STEP_OVER: 6
@@ -2,45 +2,45 @@ package stepOverWhenWithInline
fun main(args: Array<String>) {
//Breakpoint!
val prop = 1
val prop = 1 // 1
// Break after second
val a = when {
1 > 2 -> foo { test(1) }
2 > 1 -> foo { test(1) }
val a = when { // 4
1 > 2 -> foo { test(1) } // 2
2 > 1 -> foo { test(1) } // 3
else -> foo { test(1) }
}
val b = when {
1 > 2 -> {
val b = when { // 8
1 > 2 -> { // 5
foo { test(1) }
}
2 > 1 -> {
foo { test(1) }
2 > 1 -> { // 6
foo { test(1) } // 7
}
else -> {
foo { test(1) }
}
}
val c = when {
foo { test(1) } > 2 -> 1
2 > foo { test(1) } -> 2
val c = when { // 11
foo { test(1) } > 2 -> 1 // 9
2 > foo { test(1) } -> 2 // 10
else -> foo { test(1) }
}
// When with expression
val a1 = when(prop) {
val a1 = when(1) { // 12 14
2 -> foo { test(1) }
1 -> foo { test(1) }
1 -> foo { test(1) } // 13
else -> foo { test(1) }
}
val b1 = when(prop) {
val b1 = when(1) { // 15 17
2 -> {
foo { test(1) }
}
1 -> {
foo { test(1) }
foo { test(1) } // 16
}
else -> {
foo { test(1) }
@@ -48,21 +48,21 @@ fun main(args: Array<String>) {
}
// Break after first
val c1 = when(prop) {
foo { test(1) } -> 1
val c1 = when(1) { // 18 20
foo { test(1) } -> 1 // 19
foo { test(2) } -> 2
else -> foo { test(1) }
}
val a2 = when {
2 > 1 -> foo { test(1) }
val a2 = when { // 22
2 > 1 -> foo { test(1) } // 21
1 > 2 -> foo { test(1) }
else -> foo { test(1) }
}
val b2 = when {
2 > 1 -> {
foo { test(1) }
val b2 = when { // 25
2 > 1 -> { // 23
foo { test(1) } // 24
}
1 > 2 -> {
foo { test(1) }
@@ -72,12 +72,12 @@ fun main(args: Array<String>) {
}
}
val c2 = when {
2 > foo { test(1) } -> 2
val c2 = when { // 27
2 > foo { test(1) } -> 2 // 26
foo { test(1) } > 2 -> 1
else -> foo { test(1) }
}
}
} // 28
inline fun foo(f: () -> Int): Int {
val a = 1
@@ -86,4 +86,4 @@ inline fun foo(f: () -> Int): Int {
fun test(i: Int) = i
// STEP_OVER: 41
// STEP_OVER: 30
@@ -2,40 +2,29 @@ package stepOverWhileWithInline
fun main(args: Array<String>) {
//Breakpoint!
var prop = 0
var prop = 0 // 1
// inline on last line of while
while(prop < 1) {
prop++
foo { test(1) }
while(prop < 1) { // 2 5
prop++ // 3
foo { test(1) } // 4
}
// inline call inside while
while(prop < 2) {
foo { test(1) }
prop++
while(prop < 2) { // 6 9
foo { test(1) } // 7
prop++ // 8
}
do {
prop++
foo { test(1) }
} while(prop < 3)
prop++ // 10
foo { test(1) } // 11
} while(prop < 3) // 12
do {
foo { test(1) }
prop++
} while(prop < 4)
var i = 1
// inline in while condition (true)
while(foo { test(i++) } == 1) {
prop++
}
// inline in while condition (false)
while(foo { test(2) } == 1) {
prop++
}
}
foo { test(1) } // 13
prop++ // 14
} while(prop < 4) // 15
} // 16
inline fun foo(f: () -> Int): Int {
val a = 1
@@ -44,4 +33,4 @@ inline fun foo(f: () -> Int): Int {
fun test(i: Int) = i
// STEP_OVER: 41
// STEP_OVER: 16