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>destructured</w>
|
||||||
<w>hacky</w>
|
<w>hacky</w>
|
||||||
<w>impls</w>
|
<w>impls</w>
|
||||||
|
<w>inlined</w>
|
||||||
<w>kapt</w>
|
<w>kapt</w>
|
||||||
<w>kotlinc</w>
|
<w>kotlinc</w>
|
||||||
<w>mutators</w>
|
<w>mutators</w>
|
||||||
|
|||||||
+2
-1
@@ -59,7 +59,8 @@ public class DebuggerSteppingHelper {
|
|||||||
if (frameProxy != null) {
|
if (frameProxy != null) {
|
||||||
|
|
||||||
Location location = frameProxy.location();
|
Location location = frameProxy.location();
|
||||||
KotlinStepAction action = KotlinSteppingCommandProviderKt.getStepOverAction(location, sourcePosition, frameProxy);
|
KotlinStepAction action = KotlinSteppingCommandProviderKt
|
||||||
|
.getStepOverAction(location, sourcePosition, suspendContext, frameProxy);
|
||||||
|
|
||||||
createStepRequest(
|
createStepRequest(
|
||||||
suspendContext, getContextThread(),
|
suspendContext, getContextThread(),
|
||||||
|
|||||||
+42
-1
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.debugger.stepping
|
package org.jetbrains.kotlin.idea.debugger.stepping
|
||||||
|
|
||||||
|
import com.intellij.debugger.PositionManager
|
||||||
import com.intellij.debugger.SourcePosition
|
import com.intellij.debugger.SourcePosition
|
||||||
import com.intellij.debugger.engine.DebugProcessImpl
|
import com.intellij.debugger.engine.DebugProcessImpl
|
||||||
import com.intellij.debugger.engine.MethodFilter
|
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.DebuggerContextImpl
|
||||||
import com.intellij.debugger.impl.JvmSteppingCommandProvider
|
import com.intellij.debugger.impl.JvmSteppingCommandProvider
|
||||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||||
|
import com.intellij.debugger.settings.DebuggerSettings
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.sun.jdi.AbsentInformationException
|
import com.sun.jdi.AbsentInformationException
|
||||||
import com.sun.jdi.LocalVariable
|
import com.sun.jdi.LocalVariable
|
||||||
import com.sun.jdi.Location
|
import com.sun.jdi.Location
|
||||||
import com.sun.jdi.StackFrame
|
import com.sun.jdi.StackFrame
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||||
import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils
|
import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils
|
||||||
import org.jetbrains.kotlin.idea.core.util.getLineNumber
|
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.KotlinSuspendCallStepOverFilter
|
||||||
import org.jetbrains.kotlin.idea.debugger.stepping.filter.LocationToken
|
import org.jetbrains.kotlin.idea.debugger.stepping.filter.LocationToken
|
||||||
import org.jetbrains.kotlin.idea.debugger.stepping.filter.StepOverCallerInfo
|
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.idea.util.application.runReadAction
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
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.psi.psiUtil.startOffset
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
@@ -156,12 +162,16 @@ interface KotlinMethodFilter : MethodFilter {
|
|||||||
fun locationMatches(context: SuspendContextImpl, location: Location): Boolean
|
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 stackFrame = frameProxy.safeStackFrame() ?: return KotlinStepAction.StepOver
|
||||||
val method = location.safeMethod() ?: return KotlinStepAction.StepOver
|
val method = location.safeMethod() ?: return KotlinStepAction.StepOver
|
||||||
val token = LocationToken.from(stackFrame).takeIf { it.lineNumber > 0 } ?: return KotlinStepAction.StepOver
|
val token = LocationToken.from(stackFrame).takeIf { it.lineNumber > 0 } ?: return KotlinStepAction.StepOver
|
||||||
|
|
||||||
val inlinedFunctionArgumentRanges = sourcePosition.collectInlineFunctionArgumentRanges()
|
val inlinedFunctionArgumentRanges = sourcePosition.collectInlineFunctionArgumentRanges()
|
||||||
|
val positionManager = suspendContext.debugProcess.positionManager
|
||||||
|
|
||||||
val tokensToSkip = mutableSetOf(token)
|
val tokensToSkip = mutableSetOf(token)
|
||||||
|
|
||||||
@@ -174,6 +184,7 @@ fun getStepOverAction(location: Location, sourcePosition: SourcePosition, frameP
|
|||||||
&& candidateToken.lineNumber != token.lineNumber
|
&& candidateToken.lineNumber != token.lineNumber
|
||||||
&& inlinedFunctionArgumentRanges.none { range -> range.contains(candidateKotlinLineNumber) }
|
&& inlinedFunctionArgumentRanges.none { range -> range.contains(candidateKotlinLineNumber) }
|
||||||
&& candidateToken.inlineVariables.none { it !in token.inlineVariables }
|
&& candidateToken.inlineVariables.none { it !in token.inlineVariables }
|
||||||
|
&& !isInlineFunctionFromLibrary(positionManager, candidate, candidateToken)
|
||||||
|
|
||||||
if (!isAcceptable) {
|
if (!isAcceptable) {
|
||||||
tokensToSkip += candidateToken
|
tokensToSkip += candidateToken
|
||||||
@@ -183,6 +194,36 @@ fun getStepOverAction(location: Location, sourcePosition: SourcePosition, frameP
|
|||||||
return KotlinStepAction.StepOverInlined(tokensToSkip, StepOverCallerInfo.from(location))
|
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> {
|
private fun SourcePosition.collectInlineFunctionArgumentRanges(): List<IntRange> {
|
||||||
return runReadAction {
|
return runReadAction {
|
||||||
val ranges = mutableListOf<IntRange>()
|
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");
|
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")
|
@TestMetadata("noParameterExtensionLambdaArgumentCallInInline.kt")
|
||||||
public void testNoParameterExtensionLambdaArgumentCallInInline() throws Exception {
|
public void testNoParameterExtensionLambdaArgumentCallInInline() throws Exception {
|
||||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/noParameterExtensionLambdaArgumentCallInInline.kt");
|
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