From dd33640238ed7321ad1a56389cc3ea7c07681afd Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Tue, 4 Feb 2020 23:15:17 +0900 Subject: [PATCH] Debugger: Skip inlined library frames on step over (KT-12016) --- .idea/dictionaries/yan.xml | 1 + .../stepping/DebuggerSteppingHelper.java | 3 +- .../stepping/KotlinSteppingCommandProvider.kt | 43 ++++++++++++++++++- .../test/KotlinSteppingTestGenerated.java | 20 +++++++++ .../stepping/stepOver/lambdaToInlineFold.kt | 11 +++++ .../stepping/stepOver/lambdaToInlineFold.out | 12 ++++++ .../lambdaToInlineFoldFiltersDisabled.kt | 12 ++++++ .../lambdaToInlineFoldFiltersDisabled.out | 14 ++++++ .../stepping/stepOver/lambdaToInlineMap.kt | 13 ++++++ .../stepping/stepOver/lambdaToInlineMap.out | 11 +++++ .../lambdaToInlineMapFiltersDisabled.kt | 14 ++++++ .../lambdaToInlineMapFiltersDisabled.out | 14 ++++++ 12 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFold.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFold.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFoldFiltersDisabled.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFoldFiltersDisabled.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMap.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMap.out create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.out diff --git a/.idea/dictionaries/yan.xml b/.idea/dictionaries/yan.xml index 6e6a8ec005f..2b004b50aa3 100644 --- a/.idea/dictionaries/yan.xml +++ b/.idea/dictionaries/yan.xml @@ -6,6 +6,7 @@ destructured hacky impls + inlined kapt kotlinc mutators diff --git a/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/DebuggerSteppingHelper.java b/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/DebuggerSteppingHelper.java index f550fdf4372..da4645436f3 100644 --- a/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/DebuggerSteppingHelper.java +++ b/idea/jvm-debugger/jvm-debugger-core/src/org/jetbrains/kotlin/idea/debugger/stepping/DebuggerSteppingHelper.java @@ -59,7 +59,8 @@ public class DebuggerSteppingHelper { if (frameProxy != null) { Location location = frameProxy.location(); - KotlinStepAction action = KotlinSteppingCommandProviderKt.getStepOverAction(location, sourcePosition, frameProxy); + KotlinStepAction action = KotlinSteppingCommandProviderKt + .getStepOverAction(location, sourcePosition, suspendContext, frameProxy); createStepRequest( suspendContext, getContextThread(), 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 56a08113866..2ae80b56bc3 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 @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.debugger.stepping +import com.intellij.debugger.PositionManager import com.intellij.debugger.SourcePosition import com.intellij.debugger.engine.DebugProcessImpl import com.intellij.debugger.engine.MethodFilter @@ -12,12 +13,14 @@ import com.intellij.debugger.engine.SuspendContextImpl import com.intellij.debugger.impl.DebuggerContextImpl import com.intellij.debugger.impl.JvmSteppingCommandProvider import com.intellij.debugger.jdi.StackFrameProxyImpl +import com.intellij.debugger.settings.DebuggerSettings import com.intellij.psi.PsiElement import com.sun.jdi.AbsentInformationException import com.sun.jdi.LocalVariable import com.sun.jdi.Location import com.sun.jdi.StackFrame import org.jetbrains.annotations.TestOnly +import org.jetbrains.kotlin.asJava.unwrapped import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils import org.jetbrains.kotlin.idea.core.util.getLineNumber @@ -25,9 +28,12 @@ import org.jetbrains.kotlin.idea.debugger.* import org.jetbrains.kotlin.idea.debugger.stepping.filter.KotlinSuspendCallStepOverFilter import org.jetbrains.kotlin.idea.debugger.stepping.filter.LocationToken import org.jetbrains.kotlin.idea.debugger.stepping.filter.StepOverCallerInfo +import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.inline.InlineUtil import kotlin.math.max @@ -156,12 +162,16 @@ interface KotlinMethodFilter : MethodFilter { fun locationMatches(context: SuspendContextImpl, location: Location): Boolean } -fun getStepOverAction(location: Location, sourcePosition: SourcePosition, frameProxy: StackFrameProxyImpl): KotlinStepAction { +fun getStepOverAction( + location: Location, sourcePosition: SourcePosition, + suspendContext: SuspendContextImpl, frameProxy: StackFrameProxyImpl +): KotlinStepAction { val stackFrame = frameProxy.safeStackFrame() ?: return KotlinStepAction.StepOver val method = location.safeMethod() ?: return KotlinStepAction.StepOver val token = LocationToken.from(stackFrame).takeIf { it.lineNumber > 0 } ?: return KotlinStepAction.StepOver val inlinedFunctionArgumentRanges = sourcePosition.collectInlineFunctionArgumentRanges() + val positionManager = suspendContext.debugProcess.positionManager val tokensToSkip = mutableSetOf(token) @@ -174,6 +184,7 @@ fun getStepOverAction(location: Location, sourcePosition: SourcePosition, frameP && candidateToken.lineNumber != token.lineNumber && inlinedFunctionArgumentRanges.none { range -> range.contains(candidateKotlinLineNumber) } && candidateToken.inlineVariables.none { it !in token.inlineVariables } + && !isInlineFunctionFromLibrary(positionManager, candidate, candidateToken) if (!isAcceptable) { tokensToSkip += candidateToken @@ -183,6 +194,36 @@ fun getStepOverAction(location: Location, sourcePosition: SourcePosition, frameP return KotlinStepAction.StepOverInlined(tokensToSkip, StepOverCallerInfo.from(location)) } +private fun isInlineFunctionFromLibrary(positionManager: PositionManager, location: Location, token: LocationToken): Boolean { + if (token.inlineVariables.isEmpty()) { + return false + } + + val debuggerSettings = DebuggerSettings.getInstance() + if (!debuggerSettings.TRACING_FILTERS_ENABLED) { + return false + } + + tailrec fun getDeclarationName(element: PsiElement?): FqName? { + val declaration = element?.getNonStrictParentOfType() ?: return null + declaration.getKotlinFqName()?.let { return it } + return getDeclarationName(declaration.parent) + } + + val fqn = runReadAction { + val element = positionManager.getSourcePosition(location)?.elementAt + getDeclarationName(element)?.takeIf { !it.isRoot }?.asString() + } ?: return false + + for (filter in debuggerSettings.steppingFilters) { + if (filter.isEnabled && filter.matches(fqn)) { + return true + } + } + + return false +} + private fun SourcePosition.collectInlineFunctionArgumentRanges(): List { return runReadAction { val ranges = mutableListOf() 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 6192fb1e831..4ecb7fbefb0 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 @@ -467,6 +467,26 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest { runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/kt24343.kt"); } + @TestMetadata("lambdaToInlineFold.kt") + public void testLambdaToInlineFold() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFold.kt"); + } + + @TestMetadata("lambdaToInlineFoldFiltersDisabled.kt") + public void testLambdaToInlineFoldFiltersDisabled() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFoldFiltersDisabled.kt"); + } + + @TestMetadata("lambdaToInlineMap.kt") + public void testLambdaToInlineMap() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMap.kt"); + } + + @TestMetadata("lambdaToInlineMapFiltersDisabled.kt") + public void testLambdaToInlineMapFiltersDisabled() throws Exception { + runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.kt"); + } + @TestMetadata("noParameterExtensionLambdaArgumentCallInInline.kt") public void testNoParameterExtensionLambdaArgumentCallInInline() throws Exception { runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/noParameterExtensionLambdaArgumentCallInInline.kt"); diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFold.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFold.kt new file mode 100644 index 00000000000..2bb98f3c863 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFold.kt @@ -0,0 +1,11 @@ +package test + +fun main() { + val l = listOf(1, 2, 3, 4) + val res = l.foldRightIndexed(0) { index, elem, akk -> + //Breakpoint! + akk + index - 4 + } +} + +// STEP_OVER: 5 \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFold.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFold.out new file mode 100644 index 00000000000..4f97453adc9 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFold.out @@ -0,0 +1,12 @@ +LineBreakpoint created at lambdaToInlineFold.kt:7 +Run Java +Connected to the target VM +lambdaToInlineFold.kt:7 +lambdaToInlineFold.kt:7 +lambdaToInlineFold.kt:7 +lambdaToInlineFold.kt:7 +lambdaToInlineFold.kt:5 +lambdaToInlineFold.kt:9 +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFoldFiltersDisabled.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFoldFiltersDisabled.kt new file mode 100644 index 00000000000..c3f8bb8aad0 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFoldFiltersDisabled.kt @@ -0,0 +1,12 @@ +package test + +fun main() { + val l = listOf(1, 2, 3, 4) + val res = l.foldRightIndexed(0) { index, elem, akk -> + //Breakpoint! + akk + index - 4 + } +} + +// TRACING_FILTERS_ENABLED: false +// STEP_OVER: 5 \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFoldFiltersDisabled.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFoldFiltersDisabled.out new file mode 100644 index 00000000000..ef125803fad --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFoldFiltersDisabled.out @@ -0,0 +1,14 @@ +LineBreakpoint created at lambdaToInlineFoldFiltersDisabled.kt:7 +Run Java +Connected to the target VM +lambdaToInlineFoldFiltersDisabled.kt:7 +_Collections.!EXT! +_Collections.!EXT! +_Collections.!EXT! +lambdaToInlineFoldFiltersDisabled.kt:7 +_Collections.!EXT! +resuming lambdaToInlineFoldFiltersDisabled.kt:7 +resuming lambdaToInlineFoldFiltersDisabled.kt:7 +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMap.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMap.kt new file mode 100644 index 00000000000..7a8f7f9c47f --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMap.kt @@ -0,0 +1,13 @@ +package test + +fun main() { + val l = listOf(1, 2, 3, 4) + l.map { element -> + //Breakpoint! + bar(element * 2) + } +} + +fun bar(n: Int) = n + +// STEP_OVER: 5 \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMap.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMap.out new file mode 100644 index 00000000000..cc1c2aed9b7 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMap.out @@ -0,0 +1,11 @@ +LineBreakpoint created at lambdaToInlineMap.kt:7 +Run Java +Connected to the target VM +lambdaToInlineMap.kt:7 +lambdaToInlineMap.kt:7 +lambdaToInlineMap.kt:7 +lambdaToInlineMap.kt:7 +lambdaToInlineMap.kt:9 +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.kt new file mode 100644 index 00000000000..7cdcaf1a243 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.kt @@ -0,0 +1,14 @@ +package test + +fun main() { + val l = listOf(1, 2, 3, 4) + l.map { element -> + //Breakpoint! + bar(element * 2) + } +} + +fun bar(n: Int) = n + +// TRACING_FILTERS_ENABLED: false +// STEP_OVER: 5 \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.out new file mode 100644 index 00000000000..4cb660fd787 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineMapFiltersDisabled.out @@ -0,0 +1,14 @@ +LineBreakpoint created at lambdaToInlineMapFiltersDisabled.kt:7 +Run Java +Connected to the target VM +lambdaToInlineMapFiltersDisabled.kt:7 +_Collections.!EXT! +_Collections.!EXT! +lambdaToInlineMapFiltersDisabled.kt:7 +_Collections.!EXT! +_Collections.!EXT! +resuming lambdaToInlineMapFiltersDisabled.kt:7 +resuming lambdaToInlineMapFiltersDisabled.kt:7 +Disconnected from the target VM + +Process finished with exit code 0