@@ -20,8 +20,12 @@ import com.intellij.debugger.NoDataException
20
20
import com.intellij.debugger.SourcePosition
21
21
import com.intellij.debugger.engine.DebugProcessImpl
22
22
import com.intellij.debugger.engine.SuspendContextImpl
23
+ import com.intellij.debugger.engine.evaluation.EvaluateException
23
24
import com.intellij.debugger.impl.DebuggerContextImpl
24
25
import com.intellij.debugger.impl.JvmSteppingCommandProvider
26
+ import com.intellij.debugger.ui.breakpoints.FilteredRequestorImpl
27
+ import com.intellij.openapi.application.ApplicationManager
28
+ import com.intellij.openapi.util.Computable
25
29
import com.intellij.psi.PsiElement
26
30
import com.intellij.xdebugger.impl.XSourcePositionImpl
27
31
import com.sun.jdi.AbsentInformationException
@@ -36,6 +40,7 @@ import org.jetbrains.kotlin.idea.refactoring.getLineEndOffset
36
40
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
37
41
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
38
42
import org.jetbrains.kotlin.idea.util.DebuggerUtils
43
+ import org.jetbrains.kotlin.idea.util.application.runReadAction
39
44
import org.jetbrains.kotlin.psi.*
40
45
import org.jetbrains.kotlin.psi.psiUtil.endOffset
41
46
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
@@ -78,7 +83,9 @@ class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
78
83
79
84
val linesRange = startLineNumber + 1 .. endLineNumber + 1
80
85
81
- val inlineFunctionCalls = getInlineFunctionCallsIfAny(sourcePosition)
86
+ val inlineArguments = getElementsToSkip(containingFunction as KtNamedFunction , sourcePosition) ? : return null
87
+
88
+ /* val inlineFunctionCalls = getInlineFunctionCallsIfAny(sourcePosition)
82
89
if (inlineFunctionCalls.isEmpty()) return null
83
90
84
91
val inlineArguments = getInlineArgumentsIfAny(inlineFunctionCalls)
@@ -89,13 +96,33 @@ class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
89
96
90
97
if (inlineArguments.isEmpty() && inlineFunctionCalls.any { it.shouldNotUseStepOver(sourcePosition.elementAt) }) {
91
98
return null
92
- }
99
+ }*/
93
100
94
101
val additionalElementsToSkip = sourcePosition.elementAt.getAdditionalElementsToSkip()
95
102
96
103
return DebuggerSteppingHelper .createStepOverCommand(suspendContext, ignoreBreakpoints, file, linesRange, inlineArguments, additionalElementsToSkip)
97
104
}
98
105
106
+ private fun getElementsToSkip (containingFunction : KtNamedFunction , sourcePosition : SourcePosition ): List <KtFunction >? {
107
+ val inlineFunctionCalls = getInlineFunctionCallsIfAny(sourcePosition)
108
+ if (! inlineFunctionCalls.isEmpty()) {
109
+ val inlineArguments = getInlineArgumentsIfAny(inlineFunctionCalls)
110
+ if (inlineArguments.isNotEmpty() && inlineArguments.all { ! it.shouldNotUseStepOver(sourcePosition.elementAt) }) {
111
+ return inlineArguments
112
+ }
113
+
114
+ if (inlineArguments.isEmpty() && inlineFunctionCalls.all { ! it.shouldNotUseStepOver(sourcePosition.elementAt) }) {
115
+ return emptyList()
116
+ }
117
+ }
118
+
119
+ if (InlineUtil .isInline(containingFunction.resolveToDescriptor())) {
120
+ return emptyList()
121
+ }
122
+
123
+ return null
124
+ }
125
+
99
126
private fun PsiElement.getAdditionalElementsToSkip (): List <PsiElement > {
100
127
val result = arrayListOf<PsiElement >()
101
128
val ifParent = getParentOfType<KtIfExpression >(false )
@@ -287,14 +314,20 @@ class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
287
314
}
288
315
}
289
316
317
+ sealed class Action (val position : XSourcePositionImpl ? ) {
318
+ class STEP_OVER : Action (null )
319
+ class STEP_OUT : Action (null )
320
+ class RUN_TO_CURSOR (position : XSourcePositionImpl ): Action(position)
321
+ }
322
+
290
323
fun getStepOverPosition (
324
+ debugProcess : DebugProcessImpl ,
291
325
location : Location ,
292
326
file : KtFile ,
293
327
range : IntRange ,
294
- inlinedArguments : List <KtElement >,
295
- elementsToSkip : List <PsiElement >
296
- ): XSourcePositionImpl ? {
297
- val computedReferenceType = location.declaringType() ? : return null
328
+ inlinedArguments : MutableList <out KtElement >, elementsToSkip : MutableList <out PsiElement >
329
+ ): Action {
330
+ val computedReferenceType = location.declaringType() ? : return Action .STEP_OVER ()
298
331
299
332
fun isLocationSuitable (nextLocation : Location ): Boolean {
300
333
if (nextLocation.method() != location.method() || nextLocation.lineNumber() !in range) {
@@ -316,26 +349,54 @@ fun getStepOverPosition(
316
349
.dropWhile { it.lineNumber() == location.lineNumber() }
317
350
318
351
for (locationAtLine in locations) {
319
- val lineNumber = locationAtLine.lineNumber()
320
- val lineStartOffset = file.getLineStartOffset(lineNumber - 1 ) ? : continue
321
- if (inlinedArguments.any { it.textRange.contains(lineStartOffset) }) continue
322
- if (elementsToSkip.any { it.textRange.contains(lineStartOffset) }) continue
352
+ val xPosition = runReadAction {
353
+ val lineNumber = locationAtLine.lineNumber()
354
+ val lineStartOffset = file.getLineStartOffset(lineNumber - 1 ) ? : return @runReadAction null
355
+ if (inlinedArguments.any { it.textRange.contains(lineStartOffset) }) return @runReadAction null
356
+ if (elementsToSkip.any { it.textRange.contains(lineStartOffset) }) return @runReadAction null
357
+
358
+ if (locationAtLine.lineNumber() == location.lineNumber()) return @runReadAction null
323
359
324
- val elementAt = file.findElementAt(lineStartOffset) ? : continue
360
+ val elementAt = file.findElementAt(lineStartOffset) ? : return @runReadAction null
361
+ XSourcePositionImpl .createByElement(elementAt)
362
+ }
325
363
326
- return XSourcePositionImpl .createByElement(elementAt) ? : return null
364
+ if (xPosition != null ) {
365
+ return Action .RUN_TO_CURSOR (xPosition)
366
+ }
327
367
}
328
368
329
- return null
369
+ if (locations.isNotEmpty()) {
370
+ return Action .STEP_OUT ()
371
+ }
372
+
373
+ return Action .STEP_OVER ()
374
+ }
375
+
376
+ fun createCommand (
377
+ debugProcess : DebugProcessImpl ,
378
+ suspendContext : SuspendContextImpl ,
379
+ ignoreBreakpoints : Boolean ,
380
+ action : Action
381
+ ): DebugProcessImpl .ResumeCommand ? {
382
+ return when (action) {
383
+ is Action .RUN_TO_CURSOR -> {
384
+ runReadAction {
385
+ debugProcess.createRunToCursorCommand(suspendContext, action.position!! , ignoreBreakpoints)
386
+ }
387
+ }
388
+ is Action .STEP_OUT -> debugProcess.createStepOutCommand(suspendContext)
389
+ is Action .STEP_OVER -> debugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints)
390
+ }
330
391
}
331
392
332
393
fun getStepOutPosition (
333
394
location : Location ,
334
395
suspendContext : SuspendContextImpl ,
335
396
inlineFunctions : List <KtNamedFunction >,
336
397
inlinedArgument : KtFunctionLiteral ?
337
- ): XSourcePositionImpl ? {
338
- val computedReferenceType = location.declaringType() ? : return null
398
+ ): Action {
399
+ val computedReferenceType = location.declaringType() ? : return Action . STEP_OUT ()
339
400
340
401
val locations = computedReferenceType.allLineLocations()
341
402
val nextLineLocations = locations
@@ -345,14 +406,16 @@ fun getStepOutPosition(
345
406
.dropWhile { it.lineNumber() == location.lineNumber() }
346
407
347
408
if (inlineFunctions.isNotEmpty()) {
348
- return suspendContext.getXPositionForStepOutFromInlineFunction(nextLineLocations, inlineFunctions) ? : return null
409
+ val position = suspendContext.getXPositionForStepOutFromInlineFunction(nextLineLocations, inlineFunctions)
410
+ return position?.let { Action .RUN_TO_CURSOR (it) } ? : Action .STEP_OVER ()
349
411
}
350
412
351
413
if (inlinedArgument != null ) {
352
- return suspendContext.getXPositionForStepOutFromInlinedArgument(nextLineLocations, inlinedArgument) ? : return null
414
+ val position = suspendContext.getXPositionForStepOutFromInlinedArgument(nextLineLocations, inlinedArgument)
415
+ return position?.let { Action .RUN_TO_CURSOR (it) } ? : Action .STEP_OVER ()
353
416
}
354
417
355
- return null
418
+ return Action . STEP_OVER ()
356
419
}
357
420
358
421
private fun SuspendContextImpl.getXPositionForStepOutFromInlineFunction (
@@ -384,20 +447,25 @@ private fun SuspendContextImpl.getNextPositionWithFilter(
384
447
skip : (Int , PsiElement ) -> Boolean
385
448
): XSourcePositionImpl ? {
386
449
for (location in locations) {
387
- val sourcePosition = try {
388
- this .debugProcess.positionManager.getSourcePosition(location)
389
- }
390
- catch (e: NoDataException ) {
391
- null
392
- } ? : continue
450
+ val position = runReadAction {
451
+ val sourcePosition = try {
452
+ this .debugProcess.positionManager.getSourcePosition(location)
453
+ }
454
+ catch (e: NoDataException ) {
455
+ null
456
+ } ? : return @runReadAction null
393
457
394
- val file = sourcePosition.file as ? KtFile ? : continue
395
- val elementAt = sourcePosition.elementAt ? : continue
396
- val currentLine = location.lineNumber() - 1
397
- val lineStartOffset = file.getLineStartOffset(currentLine) ? : continue
398
- if (skip(lineStartOffset, elementAt)) continue
458
+ val file = sourcePosition.file as ? KtFile ? : return @runReadAction null
459
+ val elementAt = sourcePosition.elementAt ? : return @runReadAction null
460
+ val currentLine = location.lineNumber() - 1
461
+ val lineStartOffset = file.getLineStartOffset(currentLine) ? : return @runReadAction null
462
+ if (skip(lineStartOffset, elementAt)) return @runReadAction null
399
463
400
- return XSourcePositionImpl .createByElement(elementAt)
464
+ XSourcePositionImpl .createByElement(elementAt)
465
+ }
466
+ if (position != null ) {
467
+ return position
468
+ }
401
469
}
402
470
403
471
return null
0 commit comments