Debugger: Skip inlined library frames on step over (KT-12016)
This commit is contained in:
Generated
+1
@@ -6,6 +6,7 @@
|
||||
<w>destructured</w>
|
||||
<w>hacky</w>
|
||||
<w>impls</w>
|
||||
<w>inlined</w>
|
||||
<w>kapt</w>
|
||||
<w>kotlinc</w>
|
||||
<w>mutators</w>
|
||||
|
||||
+2
-1
@@ -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(),
|
||||
|
||||
+42
-1
@@ -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<KtDeclaration>() ?: 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<IntRange> {
|
||||
return runReadAction {
|
||||
val ranges = mutableListOf<IntRange>()
|
||||
|
||||
+20
@@ -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");
|
||||
|
||||
+11
@@ -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
|
||||
+12
@@ -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
|
||||
Vendored
+12
@@ -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
|
||||
idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/lambdaToInlineFoldFiltersDisabled.out
Vendored
+14
@@ -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
|
||||
+13
@@ -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
|
||||
+11
@@ -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
|
||||
Vendored
+14
@@ -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
|
||||
Vendored
+14
@@ -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
|
||||
Reference in New Issue
Block a user