Debugger: Fix "Step over" with inline function calls in non-functions (KT-20342)
This commit is contained in:
+14
-10
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils
|
||||
import org.jetbrains.kotlin.idea.debugger.*
|
||||
@@ -95,7 +96,7 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
||||
}
|
||||
|
||||
data class KotlinSourcePosition(
|
||||
val file: KtFile, val function: KtNamedFunction,
|
||||
val file: KtFile, val declaration: KtDeclaration,
|
||||
val linesRange: IntRange, val sourcePosition: SourcePosition
|
||||
) {
|
||||
companion object {
|
||||
@@ -104,17 +105,20 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
||||
if (sourcePosition.line < 0) return null
|
||||
|
||||
val elementAt = sourcePosition.elementAt ?: return null
|
||||
val containingFunction = elementAt.parents
|
||||
.filterIsInstance<KtNamedFunction>()
|
||||
.firstOrNull { !it.isLocal } ?: return null
|
||||
|
||||
val startLineNumber = containingFunction.getLineNumber(true) + 1
|
||||
val endLineNumber = containingFunction.getLineNumber(false) + 1
|
||||
val containingDeclaration = elementAt.parents
|
||||
.filterIsInstance<KtDeclaration>()
|
||||
.filter { it is KtFunction || it is KtProperty || it is KtClassInitializer }
|
||||
.firstOrNull { !KtPsiUtil.isLocal(it) }
|
||||
?: return null
|
||||
|
||||
val startLineNumber = containingDeclaration.getLineNumber(true) + 1
|
||||
val endLineNumber = containingDeclaration.getLineNumber(false) + 1
|
||||
if (startLineNumber > endLineNumber) return null
|
||||
|
||||
val linesRange = startLineNumber..endLineNumber
|
||||
|
||||
return KotlinSourcePosition(file, containingFunction, linesRange, sourcePosition)
|
||||
return KotlinSourcePosition(file, containingDeclaration, linesRange, sourcePosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,9 +132,9 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
||||
}
|
||||
|
||||
// Step over calls to lambda arguments in inline function while execution is already in that function
|
||||
val containingFunctionDescriptor = kotlinSourcePosition.function.unsafeResolveToDescriptor()
|
||||
if (InlineUtil.isInline(containingFunctionDescriptor)) {
|
||||
val inlineArgumentsCallsIfAny = getInlineArgumentsCallsIfAny(sourcePosition, containingFunctionDescriptor)
|
||||
val containingDescriptor = kotlinSourcePosition.declaration.resolveToDescriptorIfAny()
|
||||
if (containingDescriptor != null && InlineUtil.isInline(containingDescriptor)) {
|
||||
val inlineArgumentsCallsIfAny = getInlineArgumentsCallsIfAny(sourcePosition, containingDescriptor)
|
||||
if (inlineArgumentsCallsIfAny != null && inlineArgumentsCallsIfAny.isNotEmpty()) {
|
||||
return true
|
||||
}
|
||||
|
||||
+25
@@ -422,6 +422,31 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineCallInForRangeExpression.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunInClassInitializer.kt")
|
||||
public void testInlineFunInClassInitializer() throws Exception {
|
||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunInClassInitializer2.kt")
|
||||
public void testInlineFunInClassInitializer2() throws Exception {
|
||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunInConstructor.kt")
|
||||
public void testInlineFunInConstructor() throws Exception {
|
||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInConstructor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunInLazyProperty.kt")
|
||||
public void testInlineFunInLazyProperty() throws Exception {
|
||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInLazyProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunInPropertyGetter.kt")
|
||||
public void testInlineFunInPropertyGetter() throws Exception {
|
||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInPropertyGetter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunctionSameLines.kt")
|
||||
public void testInlineFunctionSameLines() throws Exception {
|
||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunctionSameLines.kt");
|
||||
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
package inlineFunInClassInitializer
|
||||
|
||||
fun main() {
|
||||
Goo()
|
||||
}
|
||||
|
||||
class Foo(val a: String?)
|
||||
|
||||
class DumbList<T>(private val element: T) : AbstractList<T>() {
|
||||
override val size get() = 1
|
||||
override fun get(index: Int) = if (index == 0) element else error("Invalid index $index")
|
||||
}
|
||||
|
||||
class Goo {
|
||||
init {
|
||||
//Breakpoint!
|
||||
val a = DumbList(Foo("a"))
|
||||
val b = a.mapNotNull { it.a }
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
// STEP_OVER: 2
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at inlineFunInClassInitializer.kt:17
|
||||
Run Java
|
||||
Connected to the target VM
|
||||
inlineFunInClassInitializer.kt:17
|
||||
inlineFunInClassInitializer.kt:18
|
||||
inlineFunInClassInitializer.kt:19
|
||||
Disconnected from the target VM
|
||||
|
||||
Process finished with exit code 0
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
package inlineFunInClassInitializer2
|
||||
|
||||
fun main() {
|
||||
Goo()
|
||||
}
|
||||
|
||||
class Foo(val a: String?)
|
||||
|
||||
class DumbList<T>(private val element: T) : AbstractList<T>() {
|
||||
override val size get() = 1
|
||||
override fun get(index: Int) = if (index == 0) element else error("Invalid index $index")
|
||||
}
|
||||
|
||||
class Goo {
|
||||
init {
|
||||
block {
|
||||
//Breakpoint!
|
||||
val a = DumbList(Foo("a"))
|
||||
val b = a.mapNotNull { it.a }
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> block(block: () -> T): T {
|
||||
return block()
|
||||
}
|
||||
|
||||
// STEP_OVER: 2
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at inlineFunInClassInitializer2.kt:18
|
||||
Run Java
|
||||
Connected to the target VM
|
||||
inlineFunInClassInitializer2.kt:18
|
||||
inlineFunInClassInitializer2.kt:19
|
||||
inlineFunInClassInitializer2.kt:20
|
||||
Disconnected from the target VM
|
||||
|
||||
Process finished with exit code 0
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package inlineFunInConstructor
|
||||
|
||||
fun main() {
|
||||
Goo()
|
||||
}
|
||||
|
||||
class Foo(val a: String?)
|
||||
|
||||
class DumbList<T>(private val element: T) : AbstractList<T>() {
|
||||
override val size get() = 1
|
||||
override fun get(index: Int) = if (index == 0) element else error("Invalid index $index")
|
||||
}
|
||||
|
||||
class Goo {
|
||||
constructor() {
|
||||
//Breakpoint!
|
||||
val a = DumbList(Foo("a"))
|
||||
val b = a.mapNotNull { it.a }
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
// STEP_OVER: 2
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at inlineFunInConstructor.kt:17
|
||||
Run Java
|
||||
Connected to the target VM
|
||||
inlineFunInConstructor.kt:17
|
||||
inlineFunInConstructor.kt:18
|
||||
inlineFunInConstructor.kt:19
|
||||
Disconnected from the target VM
|
||||
|
||||
Process finished with exit code 0
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package inlineFunInLazyProperty
|
||||
|
||||
fun main() {
|
||||
Goo().f
|
||||
}
|
||||
|
||||
class Foo(val a: String?)
|
||||
|
||||
class DumbList<T>(private val element: T) : AbstractList<T>() {
|
||||
override val size get() = 1
|
||||
override fun get(index: Int) = if (index == 0) element else error("Invalid index $index")
|
||||
}
|
||||
|
||||
class Goo {
|
||||
val f by lazy {
|
||||
//Breakpoint!
|
||||
val a = DumbList(Foo("a"))
|
||||
val b = a.mapNotNull { it.a }
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
// STEP_OVER: 2
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at inlineFunInLazyProperty.kt:17
|
||||
Run Java
|
||||
Connected to the target VM
|
||||
inlineFunInLazyProperty.kt:17
|
||||
inlineFunInLazyProperty.kt:18
|
||||
inlineFunInLazyProperty.kt:19
|
||||
Disconnected from the target VM
|
||||
|
||||
Process finished with exit code 0
|
||||
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
package inlineFunInPropertyGetter
|
||||
|
||||
fun main() {
|
||||
Goo().f
|
||||
}
|
||||
|
||||
class Foo(val a: String?)
|
||||
|
||||
class DumbList<T>(private val element: T) : AbstractList<T>() {
|
||||
override val size get() = 1
|
||||
override fun get(index: Int) = if (index == 0) element else error("Invalid index $index")
|
||||
}
|
||||
|
||||
class Goo {
|
||||
val f: Int
|
||||
get() {
|
||||
//Breakpoint!
|
||||
val a = DumbList(Foo("a"))
|
||||
val b = a.mapNotNull { it.a }
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// STEP_OVER: 2
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at inlineFunInPropertyGetter.kt:18
|
||||
Run Java
|
||||
Connected to the target VM
|
||||
inlineFunInPropertyGetter.kt:18
|
||||
inlineFunInPropertyGetter.kt:19
|
||||
inlineFunInPropertyGetter.kt:20
|
||||
Disconnected from the target VM
|
||||
|
||||
Process finished with exit code 0
|
||||
Reference in New Issue
Block a user