Better diagnostic for inlined line under dex on step over
This commit is contained in:
@@ -122,16 +122,8 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
||||
}
|
||||
|
||||
if (sourceLineNumber > psiFile.getLineCount() && myDebugProcess.isDexDebug()) {
|
||||
val thisFunLine = getLastLineNumberForLocation(location, myDebugProcess.project)
|
||||
if (thisFunLine != null && thisFunLine != location.lineNumber()) {
|
||||
return SourcePosition.createFromLine(psiFile, thisFunLine - 1)
|
||||
}
|
||||
|
||||
val inlinePosition = getOriginalPositionOfInlinedLine(location, myDebugProcess.project)
|
||||
|
||||
if (inlinePosition != null) {
|
||||
return SourcePosition.createFromLine(inlinePosition.first, inlinePosition.second)
|
||||
}
|
||||
val (line, ktFile) = ktLocationInfo(location, true, myDebugProcess.project, false, psiFile)
|
||||
return SourcePosition.createFromLine(ktFile ?: psiFile, line - 1)
|
||||
}
|
||||
|
||||
return SourcePosition.createFromLine(psiFile, sourceLineNumber)
|
||||
|
||||
@@ -67,26 +67,30 @@ fun readBytecodeInfo(project: Project,
|
||||
return KotlinDebuggerCaches.getOrReadDebugInfoFromBytecode(project, jvmName, file)
|
||||
}
|
||||
|
||||
fun noStrataLineNumber(location: Location, isDexDebug: Boolean, project: Project, preferInlined: Boolean = false): Int {
|
||||
if (isDexDebug) {
|
||||
fun ktLocationInfo(location: Location, isDexDebug: Boolean, project: Project,
|
||||
preferInlined: Boolean = false, locationFile: KtFile? = null): Pair<Int, KtFile?> {
|
||||
if (isDexDebug && (locationFile == null || location.lineNumber() > locationFile.getLineCount())) {
|
||||
if (!preferInlined) {
|
||||
val thisFunLine = runReadAction { getLastLineNumberForLocation(location, project) }
|
||||
if (thisFunLine != null && thisFunLine != location.lineNumber()) {
|
||||
// TODO: bad line because of inlining
|
||||
return thisFunLine
|
||||
return thisFunLine to locationFile
|
||||
}
|
||||
}
|
||||
|
||||
val inlinePosition = runReadAction { getOriginalPositionOfInlinedLine(location, project) }
|
||||
|
||||
if (inlinePosition != null) {
|
||||
return inlinePosition.second + 1
|
||||
val (file, line) = inlinePosition
|
||||
return line + 1 to file
|
||||
}
|
||||
}
|
||||
|
||||
return location.lineNumber()
|
||||
return location.lineNumber() to locationFile
|
||||
}
|
||||
|
||||
/**
|
||||
* Only the first line number is stored for instruction in dex. It can be obtained through location.lineNumber().
|
||||
* This method allows to get last stored linenumber for instruction.
|
||||
*/
|
||||
fun getLastLineNumberForLocation(location: Location, project: Project, searchScope: GlobalSearchScope = GlobalSearchScope.allScope(project)): Int? {
|
||||
val lineNumber = location.lineNumber()
|
||||
val fqName = FqName(location.declaringType().name())
|
||||
|
||||
@@ -22,7 +22,7 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.util.Range
|
||||
import com.sun.jdi.LocalVariable
|
||||
import com.sun.jdi.Location
|
||||
import org.jetbrains.kotlin.idea.debugger.noStrataLineNumber
|
||||
import org.jetbrains.kotlin.idea.debugger.ktLocationInfo
|
||||
|
||||
class StepOverFilterData(
|
||||
val lineNumber: Int,
|
||||
@@ -33,7 +33,7 @@ class StepOverFilterData(
|
||||
)
|
||||
|
||||
class KotlinStepOverInlineFilter(val project: Project, val data: StepOverFilterData) : KotlinMethodFilter {
|
||||
private fun Location.ktLineNumber() = noStrataLineNumber(this, data.isDexDebug, project)
|
||||
private fun Location.ktLineNumber() = ktLocationInfo(this, data.isDexDebug, project).first
|
||||
|
||||
override fun locationMatches(context: SuspendContextImpl, location: Location): Boolean {
|
||||
val frameProxy = context.frameProxy ?: return true
|
||||
|
||||
+13
-8
@@ -41,7 +41,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils
|
||||
import org.jetbrains.kotlin.idea.debugger.noStrataLineNumber
|
||||
import org.jetbrains.kotlin.idea.debugger.ktLocationInfo
|
||||
import org.jetbrains.kotlin.idea.debugger.stepping.DexBytecode.GOTO
|
||||
import org.jetbrains.kotlin.idea.debugger.stepping.DexBytecode.MOVE
|
||||
import org.jetbrains.kotlin.idea.debugger.stepping.DexBytecode.RETURN
|
||||
@@ -317,7 +317,7 @@ fun getStepOverAction(
|
||||
|
||||
fun getStepOverAction(
|
||||
location: Location,
|
||||
file: KtFile,
|
||||
sourceFile: KtFile,
|
||||
range: IntRange,
|
||||
inlineFunctionArguments: List<KtElement>,
|
||||
frameProxy: StackFrameProxyImpl,
|
||||
@@ -325,12 +325,17 @@ fun getStepOverAction(
|
||||
): Action {
|
||||
location.declaringType() ?: return Action.STEP_OVER()
|
||||
|
||||
val project = file.project
|
||||
val project = sourceFile.project
|
||||
|
||||
val methodLocations = location.method().allLineLocations()
|
||||
val ktLineNumbers = methodLocations.keysToMap { noStrataLineNumber(it, isDexDebug, project, true) }
|
||||
val locationsLineAndFile = methodLocations.keysToMap { ktLocationInfo(it, isDexDebug, project, true) }
|
||||
|
||||
fun Location.ktLineNumber(): Int = ktLineNumbers[this] ?: noStrataLineNumber(this, isDexDebug, project, true)
|
||||
fun Location.ktLineNumber(): Int = (locationsLineAndFile[this] ?: ktLocationInfo(this, isDexDebug, project, true)).first
|
||||
fun Location.ktFileName(): String {
|
||||
val ktFile = (locationsLineAndFile[this] ?: ktLocationInfo(this, isDexDebug, project, true)).second
|
||||
// File is not null only for inlined locations. Get file name from debugger information otherwise.
|
||||
return ktFile?.name ?: this.sourceName(KOTLIN_STRATA_NAME)
|
||||
}
|
||||
|
||||
fun isLocationSuitable(nextLocation: Location): Boolean {
|
||||
if (nextLocation.method() != location.method()) {
|
||||
@@ -342,8 +347,8 @@ fun getStepOverAction(
|
||||
return false
|
||||
}
|
||||
|
||||
return try {
|
||||
nextLocation.sourceName(KOTLIN_STRATA_NAME) == file.name
|
||||
try {
|
||||
return nextLocation.ktFileName() == sourceFile.name
|
||||
}
|
||||
catch(e: AbsentInformationException) {
|
||||
return true
|
||||
@@ -362,7 +367,7 @@ fun getStepOverAction(
|
||||
}
|
||||
|
||||
val patchedLocation = if (isBackEdgeLocation()) {
|
||||
// Pretend we had already did a backing step
|
||||
// Pretend we had already done a backing step
|
||||
methodLocations
|
||||
.filter(::isLocationSuitable)
|
||||
.firstOrNull { it.ktLineNumber() == location.ktLineNumber() } ?: location
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at stopInInlineInOtherFileWithLambdaArgumentDex.Other.kt:6
|
||||
!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
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
stopInInlineInOtherFileWithLambdaArgumentDex.Other.kt:6
|
||||
stopInInlineInOtherFileWithLambdaArgumentDex.Other.kt:7
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package stopInInlineInOtherFileWithLambdaArgumentDex
|
||||
|
||||
inline fun inlineFun(a: () -> Unit) {
|
||||
a()
|
||||
// Breakpoint 1
|
||||
a()
|
||||
a()
|
||||
}
|
||||
idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInInlineInOtherFileWithLambdaArgumentDex.kt
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package stopInInlineInOtherFileWithLambdaArgumentDex
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
inlineFun { "hi" }
|
||||
val i = 1
|
||||
}
|
||||
|
||||
// ADDITIONAL_BREAKPOINT: stopInInlineInOtherFileWithLambdaArgumentDex.Other.kt: Breakpoint 1
|
||||
@@ -715,6 +715,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInInlineInOtherFileDex.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stopInInlineInOtherFileWithLambdaArgumentDex.kt")
|
||||
public void testStopInInlineInOtherFileWithLambdaArgumentDex() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInInlineInOtherFileWithLambdaArgumentDex.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/debugger/tinyApp/src/stepping/filters")
|
||||
|
||||
Reference in New Issue
Block a user