From 8325216d38689e615aa22d81d7ca356198691705 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Thu, 8 Aug 2019 21:39:07 +0900 Subject: [PATCH] Debugger: Fix "Step over" with inline function calls in non-functions (KT-20342) --- .../stepping/KotlinSteppingCommandProvider.kt | 24 ++++++++------- .../test/KotlinSteppingTestGenerated.java | 25 ++++++++++++++++ .../stepOver/inlineFunInClassInitializer.kt | 23 +++++++++++++++ .../stepOver/inlineFunInClassInitializer.out | 9 ++++++ .../stepOver/inlineFunInClassInitializer2.kt | 29 +++++++++++++++++++ .../stepOver/inlineFunInClassInitializer2.out | 9 ++++++ .../stepOver/inlineFunInConstructor.kt | 23 +++++++++++++++ .../stepOver/inlineFunInConstructor.out | 9 ++++++ .../stepOver/inlineFunInLazyProperty.kt | 23 +++++++++++++++ .../stepOver/inlineFunInLazyProperty.out | 9 ++++++ .../stepOver/inlineFunInPropertyGetter.kt | 24 +++++++++++++++ .../stepOver/inlineFunInPropertyGetter.out | 9 ++++++ 12 files changed, 206 insertions(+), 10 deletions(-) create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer2.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer2.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInConstructor.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInConstructor.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInLazyProperty.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInLazyProperty.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInPropertyGetter.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInPropertyGetter.out diff --git a/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt b/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt index a017d9830c8..c693d27465a 100644 --- a/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt +++ b/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt @@ -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() - .firstOrNull { !it.isLocal } ?: return null - val startLineNumber = containingFunction.getLineNumber(true) + 1 - val endLineNumber = containingFunction.getLineNumber(false) + 1 + val containingDeclaration = elementAt.parents + .filterIsInstance() + .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 } diff --git a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinSteppingTestGenerated.java b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinSteppingTestGenerated.java index 97dd7a8b8ce..4d3270cfeb8 100644 --- a/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinSteppingTestGenerated.java +++ b/idea/jvm-debugger/jvm-debugger-test/test/org/jetbrains/kotlin/idea/debugger/test/KotlinSteppingTestGenerated.java @@ -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"); diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer.kt new file mode 100644 index 00000000000..0829ca1b8ce --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer.kt @@ -0,0 +1,23 @@ +package inlineFunInClassInitializer + +fun main() { + Goo() +} + +class Foo(val a: String?) + +class DumbList(private val element: T) : AbstractList() { + 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 \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer.out new file mode 100644 index 00000000000..5878ae70245 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer.out @@ -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 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer2.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer2.kt new file mode 100644 index 00000000000..c8c41805d9a --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer2.kt @@ -0,0 +1,29 @@ +package inlineFunInClassInitializer2 + +fun main() { + Goo() +} + +class Foo(val a: String?) + +class DumbList(private val element: T) : AbstractList() { + 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 block(block: () -> T): T { + return block() +} + +// STEP_OVER: 2 \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer2.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer2.out new file mode 100644 index 00000000000..82bf0a8de95 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInClassInitializer2.out @@ -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 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInConstructor.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInConstructor.kt new file mode 100644 index 00000000000..b5079f7fc62 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInConstructor.kt @@ -0,0 +1,23 @@ +package inlineFunInConstructor + +fun main() { + Goo() +} + +class Foo(val a: String?) + +class DumbList(private val element: T) : AbstractList() { + 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 \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInConstructor.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInConstructor.out new file mode 100644 index 00000000000..3203e76edf9 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInConstructor.out @@ -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 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInLazyProperty.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInLazyProperty.kt new file mode 100644 index 00000000000..1b62ebf6e78 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInLazyProperty.kt @@ -0,0 +1,23 @@ +package inlineFunInLazyProperty + +fun main() { + Goo().f +} + +class Foo(val a: String?) + +class DumbList(private val element: T) : AbstractList() { + 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 \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInLazyProperty.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInLazyProperty.out new file mode 100644 index 00000000000..a0f4657c1d0 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInLazyProperty.out @@ -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 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInPropertyGetter.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInPropertyGetter.kt new file mode 100644 index 00000000000..9a90d0bb594 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInPropertyGetter.kt @@ -0,0 +1,24 @@ +package inlineFunInPropertyGetter + +fun main() { + Goo().f +} + +class Foo(val a: String?) + +class DumbList(private val element: T) : AbstractList() { + 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 \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInPropertyGetter.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInPropertyGetter.out new file mode 100644 index 00000000000..cae17c85fae --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/inlineFunInPropertyGetter.out @@ -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