Skip to content

Commit 6f95667

Browse files
committed
Better diagnostic for inlined line under dex on step over
1 parent 2817e1a commit 6f95667

File tree

8 files changed

+58
-27
lines changed

8 files changed

+58
-27
lines changed

idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -122,16 +122,8 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
122122
}
123123

124124
if (sourceLineNumber > psiFile.getLineCount() && myDebugProcess.isDexDebug()) {
125-
val thisFunLine = getLastLineNumberForLocation(location, myDebugProcess.project)
126-
if (thisFunLine != null && thisFunLine != location.lineNumber()) {
127-
return SourcePosition.createFromLine(psiFile, thisFunLine - 1)
128-
}
129-
130-
val inlinePosition = getOriginalPositionOfInlinedLine(location, myDebugProcess.project)
131-
132-
if (inlinePosition != null) {
133-
return SourcePosition.createFromLine(inlinePosition.first, inlinePosition.second)
134-
}
125+
val (line, ktFile) = ktLocationInfo(location, true, myDebugProcess.project, false, psiFile)
126+
return SourcePosition.createFromLine(ktFile ?: psiFile, line - 1)
135127
}
136128

137129
return SourcePosition.createFromLine(psiFile, sourceLineNumber)

idea/src/org/jetbrains/kotlin/idea/debugger/NoStrataPositionManagerHelper.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,26 +67,30 @@ fun readBytecodeInfo(project: Project,
6767
return KotlinDebuggerCaches.getOrReadDebugInfoFromBytecode(project, jvmName, file)
6868
}
6969

70-
fun noStrataLineNumber(location: Location, isDexDebug: Boolean, project: Project, preferInlined: Boolean = false): Int {
71-
if (isDexDebug) {
70+
fun ktLocationInfo(location: Location, isDexDebug: Boolean, project: Project,
71+
preferInlined: Boolean = false, locationFile: KtFile? = null): Pair<Int, KtFile?> {
72+
if (isDexDebug && (locationFile == null || location.lineNumber() > locationFile.getLineCount())) {
7273
if (!preferInlined) {
7374
val thisFunLine = runReadAction { getLastLineNumberForLocation(location, project) }
7475
if (thisFunLine != null && thisFunLine != location.lineNumber()) {
75-
// TODO: bad line because of inlining
76-
return thisFunLine
76+
return thisFunLine to locationFile
7777
}
7878
}
7979

8080
val inlinePosition = runReadAction { getOriginalPositionOfInlinedLine(location, project) }
81-
8281
if (inlinePosition != null) {
83-
return inlinePosition.second + 1
82+
val (file, line) = inlinePosition
83+
return line + 1 to file
8484
}
8585
}
8686

87-
return location.lineNumber()
87+
return location.lineNumber() to locationFile
8888
}
8989

90+
/**
91+
* Only the first line number is stored for instruction in dex. It can be obtained through location.lineNumber().
92+
* This method allows to get last stored linenumber for instruction.
93+
*/
9094
fun getLastLineNumberForLocation(location: Location, project: Project, searchScope: GlobalSearchScope = GlobalSearchScope.allScope(project)): Int? {
9195
val lineNumber = location.lineNumber()
9296
val fqName = FqName(location.declaringType().name())

idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinStepOverInlineFilter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import com.intellij.openapi.project.Project
2222
import com.intellij.util.Range
2323
import com.sun.jdi.LocalVariable
2424
import com.sun.jdi.Location
25-
import org.jetbrains.kotlin.idea.debugger.noStrataLineNumber
25+
import org.jetbrains.kotlin.idea.debugger.ktLocationInfo
2626

2727
class StepOverFilterData(
2828
val lineNumber: Int,
@@ -33,7 +33,7 @@ class StepOverFilterData(
3333
)
3434

3535
class KotlinStepOverInlineFilter(val project: Project, val data: StepOverFilterData) : KotlinMethodFilter {
36-
private fun Location.ktLineNumber() = noStrataLineNumber(this, data.isDexDebug, project)
36+
private fun Location.ktLineNumber() = ktLocationInfo(this, data.isDexDebug, project).first
3737

3838
override fun locationMatches(context: SuspendContextImpl, location: Location): Boolean {
3939
val frameProxy = context.frameProxy ?: return true

idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSteppingCommandProvider.kt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
4141
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
4242
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
4343
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils
44-
import org.jetbrains.kotlin.idea.debugger.noStrataLineNumber
44+
import org.jetbrains.kotlin.idea.debugger.ktLocationInfo
4545
import org.jetbrains.kotlin.idea.debugger.stepping.DexBytecode.GOTO
4646
import org.jetbrains.kotlin.idea.debugger.stepping.DexBytecode.MOVE
4747
import org.jetbrains.kotlin.idea.debugger.stepping.DexBytecode.RETURN
@@ -317,20 +317,25 @@ fun getStepOverAction(
317317

318318
fun getStepOverAction(
319319
location: Location,
320-
file: KtFile,
320+
sourceFile: KtFile,
321321
range: IntRange,
322322
inlineFunctionArguments: List<KtElement>,
323323
frameProxy: StackFrameProxyImpl,
324324
isDexDebug: Boolean
325325
): Action {
326326
location.declaringType() ?: return Action.STEP_OVER()
327327

328-
val project = file.project
328+
val project = sourceFile.project
329329

330330
val methodLocations = location.method().allLineLocations()
331-
val ktLineNumbers = methodLocations.keysToMap { noStrataLineNumber(it, isDexDebug, project, true) }
331+
val locationsLineAndFile = methodLocations.keysToMap { ktLocationInfo(it, isDexDebug, project, true) }
332332

333-
fun Location.ktLineNumber(): Int = ktLineNumbers[this] ?: noStrataLineNumber(this, isDexDebug, project, true)
333+
fun Location.ktLineNumber(): Int = (locationsLineAndFile[this] ?: ktLocationInfo(this, isDexDebug, project, true)).first
334+
fun Location.ktFileName(): String {
335+
val ktFile = (locationsLineAndFile[this] ?: ktLocationInfo(this, isDexDebug, project, true)).second
336+
// File is not null only for inlined locations. Get file name from debugger information otherwise.
337+
return ktFile?.name ?: this.sourceName(KOTLIN_STRATA_NAME)
338+
}
334339

335340
fun isLocationSuitable(nextLocation: Location): Boolean {
336341
if (nextLocation.method() != location.method()) {
@@ -342,8 +347,8 @@ fun getStepOverAction(
342347
return false
343348
}
344349

345-
return try {
346-
nextLocation.sourceName(KOTLIN_STRATA_NAME) == file.name
350+
try {
351+
return nextLocation.ktFileName() == sourceFile.name
347352
}
348353
catch(e: AbsentInformationException) {
349354
return true
@@ -362,7 +367,7 @@ fun getStepOverAction(
362367
}
363368

364369
val patchedLocation = if (isBackEdgeLocation()) {
365-
// Pretend we had already did a backing step
370+
// Pretend we had already done a backing step
366371
methodLocations
367372
.filter(::isLocationSuitable)
368373
.firstOrNull { it.ktLineNumber() == location.ktLineNumber() } ?: location
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
LineBreakpoint created at stopInInlineInOtherFileWithLambdaArgumentDex.Other.kt:6
2+
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! stopInInlineInOtherFileWithLambdaArgumentDex.StopInInlineInOtherFileWithLambdaArgumentDexKt
3+
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
4+
stopInInlineInOtherFileWithLambdaArgumentDex.Other.kt:6
5+
stopInInlineInOtherFileWithLambdaArgumentDex.Other.kt:7
6+
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
7+
8+
Process finished with exit code 0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package stopInInlineInOtherFileWithLambdaArgumentDex
2+
3+
inline fun inlineFun(a: () -> Unit) {
4+
a()
5+
// Breakpoint 1
6+
a()
7+
a()
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package stopInInlineInOtherFileWithLambdaArgumentDex
2+
3+
fun main(args: Array<String>) {
4+
inlineFun { "hi" }
5+
val i = 1
6+
}
7+
8+
// ADDITIONAL_BREAKPOINT: stopInInlineInOtherFileWithLambdaArgumentDex.Other.kt: Breakpoint 1

idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,12 @@ public void testStopInInlineInOtherFileDex() throws Exception {
715715
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInInlineInOtherFileDex.kt");
716716
doStepOverTest(fileName);
717717
}
718+
719+
@TestMetadata("stopInInlineInOtherFileWithLambdaArgumentDex.kt")
720+
public void testStopInInlineInOtherFileWithLambdaArgumentDex() throws Exception {
721+
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInInlineInOtherFileWithLambdaArgumentDex.kt");
722+
doStepOverTest(fileName);
723+
}
718724
}
719725

720726
@TestMetadata("idea/testData/debugger/tinyApp/src/stepping/filters")

0 commit comments

Comments
 (0)