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.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
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.caches.resolve.unsafeResolveToDescriptor
|
||||||
import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils
|
import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils
|
||||||
import org.jetbrains.kotlin.idea.debugger.*
|
import org.jetbrains.kotlin.idea.debugger.*
|
||||||
@@ -95,7 +96,7 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class KotlinSourcePosition(
|
data class KotlinSourcePosition(
|
||||||
val file: KtFile, val function: KtNamedFunction,
|
val file: KtFile, val declaration: KtDeclaration,
|
||||||
val linesRange: IntRange, val sourcePosition: SourcePosition
|
val linesRange: IntRange, val sourcePosition: SourcePosition
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -104,17 +105,20 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
|||||||
if (sourcePosition.line < 0) return null
|
if (sourcePosition.line < 0) return null
|
||||||
|
|
||||||
val elementAt = sourcePosition.elementAt ?: 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 containingDeclaration = elementAt.parents
|
||||||
val endLineNumber = containingFunction.getLineNumber(false) + 1
|
.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
|
if (startLineNumber > endLineNumber) return null
|
||||||
|
|
||||||
val linesRange = startLineNumber..endLineNumber
|
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
|
// Step over calls to lambda arguments in inline function while execution is already in that function
|
||||||
val containingFunctionDescriptor = kotlinSourcePosition.function.unsafeResolveToDescriptor()
|
val containingDescriptor = kotlinSourcePosition.declaration.resolveToDescriptorIfAny()
|
||||||
if (InlineUtil.isInline(containingFunctionDescriptor)) {
|
if (containingDescriptor != null && InlineUtil.isInline(containingDescriptor)) {
|
||||||
val inlineArgumentsCallsIfAny = getInlineArgumentsCallsIfAny(sourcePosition, containingFunctionDescriptor)
|
val inlineArgumentsCallsIfAny = getInlineArgumentsCallsIfAny(sourcePosition, containingDescriptor)
|
||||||
if (inlineArgumentsCallsIfAny != null && inlineArgumentsCallsIfAny.isNotEmpty()) {
|
if (inlineArgumentsCallsIfAny != null && inlineArgumentsCallsIfAny.isNotEmpty()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
+25
@@ -422,6 +422,31 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
|||||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineCallInForRangeExpression.kt");
|
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")
|
@TestMetadata("inlineFunctionSameLines.kt")
|
||||||
public void testInlineFunctionSameLines() throws Exception {
|
public void testInlineFunctionSameLines() throws Exception {
|
||||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunctionSameLines.kt");
|
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