@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
40
40
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
41
41
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
42
42
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils
43
+ import org.jetbrains.kotlin.idea.debugger.noStrataLineNumber
43
44
import org.jetbrains.kotlin.idea.refactoring.getLineEndOffset
44
45
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
45
46
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
@@ -268,12 +269,13 @@ private fun findCallsOnPosition(sourcePosition: SourcePosition, filter: (KtCallE
268
269
sealed class Action (val position : XSourcePositionImpl ? = null ,
269
270
val lineNumber : Int? = null ,
270
271
val stepOverLines : Set <Int >? = null ,
271
- val inlineRangeVariables : List <LocalVariable >? = null ) {
272
+ val inlineRangeVariables : List <LocalVariable >? = null ,
273
+ val isDexDebug : Boolean = false ) {
272
274
class STEP_OVER : Action ()
273
275
class STEP_OUT : Action ()
274
276
class RUN_TO_CURSOR (position : XSourcePositionImpl ) : Action(position)
275
- class STEP_OVER_INLINED (lineNumber : Int , stepOverLines : Set <Int >, inlineVariables : List <LocalVariable >) : Action(
276
- lineNumber = lineNumber, stepOverLines = stepOverLines, inlineRangeVariables = inlineVariables)
277
+ class STEP_OVER_INLINED (lineNumber : Int , stepOverLines : Set <Int >, inlineVariables : List <LocalVariable >, isDexDebug : Boolean ) : Action(
278
+ lineNumber = lineNumber, stepOverLines = stepOverLines, inlineRangeVariables = inlineVariables, isDexDebug = isDexDebug )
277
279
278
280
fun apply (debugProcess : DebugProcessImpl ,
279
281
suspendContext : SuspendContextImpl ,
@@ -287,39 +289,54 @@ sealed class Action(val position: XSourcePositionImpl? = null,
287
289
is Action .STEP_OUT -> debugProcess.createStepOutCommand(suspendContext).contextAction(suspendContext)
288
290
is Action .STEP_OVER -> debugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints).contextAction(suspendContext)
289
291
is Action .STEP_OVER_INLINED -> KotlinStepActionFactory (debugProcess).createKotlinStepOverInlineAction(
290
- KotlinStepOverInlineFilter (stepOverLines!! , lineNumber ? : - 1 , inlineRangeVariables!! )).contextAction(suspendContext)
292
+ KotlinStepOverInlineFilter (
293
+ isDexDebug,
294
+ debugProcess.project,
295
+ stepOverLines!! ,
296
+ lineNumber ? : - 1 ,
297
+ inlineRangeVariables!! )).contextAction(suspendContext)
291
298
}
292
299
}
293
300
}
294
301
295
- interface KotlinMethodFilter : MethodFilter {
302
+ interface KotlinMethodFilter : MethodFilter {
296
303
fun locationMatches (context : SuspendContextImpl , location : Location ): Boolean
297
304
}
298
305
299
306
fun getStepOverAction (
300
307
location : Location ,
301
308
kotlinSourcePosition : KotlinSteppingCommandProvider .KotlinSourcePosition ,
302
- frameProxy : StackFrameProxyImpl
309
+ frameProxy : StackFrameProxyImpl ,
310
+ isDexDebug : Boolean
303
311
): Action {
304
312
val inlineArgumentsToSkip = runReadAction {
305
313
getInlineCallFunctionArgumentsIfAny(kotlinSourcePosition.sourcePosition)
306
314
}
307
315
308
316
return getStepOverAction(location, kotlinSourcePosition.file, kotlinSourcePosition.linesRange,
309
- inlineArgumentsToSkip, frameProxy)
317
+ inlineArgumentsToSkip, frameProxy, isDexDebug )
310
318
}
311
319
312
320
fun getStepOverAction (
313
321
location : Location ,
314
322
file : KtFile ,
315
323
range : IntRange ,
316
324
inlineFunctionArguments : List <KtElement >,
317
- frameProxy : StackFrameProxyImpl
325
+ frameProxy : StackFrameProxyImpl ,
326
+ isDexDebug : Boolean
318
327
): Action {
319
328
val computedReferenceType = location.declaringType() ? : return Action .STEP_OVER ()
320
329
330
+ val project = file.project
331
+
332
+ fun Location.ktLineNumber () = noStrataLineNumber(this , isDexDebug, project, true )
333
+
321
334
fun isLocationSuitable (nextLocation : Location ): Boolean {
322
- if (nextLocation.method() != location.method() || nextLocation.lineNumber() !in range) {
335
+ if (nextLocation.method() != location.method()) {
336
+ return false
337
+ }
338
+
339
+ if (nextLocation.ktLineNumber() !in range) {
323
340
return false
324
341
}
325
342
@@ -336,22 +353,24 @@ fun getStepOverAction(
336
353
.dropWhile { it != location }
337
354
.drop(1 )
338
355
.filter(::isLocationSuitable)
339
- .dropWhile { it.lineNumber () == location.lineNumber () }
356
+ .dropWhile { it.ktLineNumber () == location.ktLineNumber () }
340
357
.firstOrNull()
341
358
342
- return previousSuitableLocation != null && previousSuitableLocation.lineNumber () > location.lineNumber ()
359
+ return previousSuitableLocation != null && previousSuitableLocation.ktLineNumber () > location.ktLineNumber ()
343
360
}
344
361
345
362
val patchedLocation = if (isBackEdgeLocation()) {
346
363
// Pretend we had already did a backing step
347
364
computedReferenceType.allLineLocations()
348
365
.filter(::isLocationSuitable)
349
- .first { it.lineNumber () == location.lineNumber () }
366
+ .first { it.ktLineNumber () == location.ktLineNumber () }
350
367
}
351
368
else {
352
369
location
353
370
}
354
371
372
+ val patchedLineNumber = patchedLocation.ktLineNumber()
373
+
355
374
val lambdaArgumentRanges = runReadAction {
356
375
inlineFunctionArguments.filterIsInstance<KtElement >().map {
357
376
val startLineNumber = it.getLineNumber(true ) + 1
@@ -367,21 +386,24 @@ fun getStepOverAction(
367
386
// - Lines from other files and from functions that are not in range of current one are definitely inlined
368
387
// - Lines in function arguments of inlined functions are inlined too as we found them starting from the position of inlined call.
369
388
//
370
- // This heuristic doesn't work for DEX, because of missing strata information (https://code.google.com/p/android/issues/detail?id=82972)
371
- //
372
389
// It also thinks that too many lines are inlined when there's a call of function argument or other
373
390
// inline function in last statement of inline function. The list of inlineRangeVariables is used to overcome it.
374
391
val probablyInlinedLocations = computedReferenceType.allLineLocations()
375
392
.dropWhile { it != patchedLocation }
376
393
.drop(1 )
377
- .dropWhile { it.lineNumber () == patchedLocation.lineNumber() }
378
- .takeWhile { locationAtLine ->
379
- ! isLocationSuitable(locationAtLine ) || lambdaArgumentRanges.any { locationAtLine.lineNumber () in it }
394
+ .dropWhile { it.ktLineNumber () == patchedLineNumber }
395
+ .takeWhile { location ->
396
+ ! isLocationSuitable(location ) || lambdaArgumentRanges.any { location.ktLineNumber () in it }
380
397
}
381
- .dropWhile { it.lineNumber () == patchedLocation.lineNumber() }
398
+ .dropWhile { it.ktLineNumber () == patchedLineNumber }
382
399
383
400
if (! probablyInlinedLocations.isEmpty()) {
384
- return Action .STEP_OVER_INLINED (patchedLocation.lineNumber(), probablyInlinedLocations.map { it.lineNumber() }.toSet(), inlineRangeVariables)
401
+ return Action .STEP_OVER_INLINED (
402
+ patchedLineNumber,
403
+ probablyInlinedLocations.map { it.ktLineNumber() }.toSet(),
404
+ inlineRangeVariables,
405
+ isDexDebug
406
+ )
385
407
}
386
408
387
409
return Action .STEP_OVER ()
0 commit comments