diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt index efd6de8ed5e..ca58ca8b5d9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt @@ -24,9 +24,7 @@ import com.intellij.debugger.engine.DebugProcessImpl import com.intellij.debugger.engine.PositionManagerEx import com.intellij.debugger.engine.evaluation.EvaluationContext import com.intellij.debugger.jdi.StackFrameProxyImpl -import com.intellij.debugger.jdi.VirtualMachineProxyImpl import com.intellij.debugger.requests.ClassPrepareRequestor -import com.intellij.openapi.application.ApplicationManager import com.intellij.psi.PsiFile import com.intellij.psi.impl.compiled.ClsFileImpl import com.intellij.psi.search.GlobalSearchScope @@ -124,7 +122,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq } if (lineNumber > psiFile.getLineCount() && myDebugProcess.isDexDebug()) { - val inlinePosition = inlineLineAndFileByPosition( + val inlinePosition = getOriginalPositionOfInlinedLine( location.lineNumber(), FqName(location.declaringType().name()), location.sourceName(), myDebugProcess.project, GlobalSearchScope.allScope(myDebugProcess.project)) @@ -257,7 +255,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq } try { if (myDebugProcess.isDexDebug()) { - val inlineLocations = noStrataLocationsOfLineForInlineFunctions(type, position, myDebugProcess.searchScope) + val inlineLocations = getLocationsOfInlinedLine(type, position, myDebugProcess.searchScope) if (!inlineLocations.isEmpty()) { return inlineLocations } @@ -302,10 +300,4 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq inline fun U.readAction(crossinline f: (U) -> V): V { return runReadAction { f(this) } -} - -@Volatile var emulateDexDebugInTests: Boolean = false - -private fun DebugProcess.isDexDebug() = - (emulateDexDebugInTests && ApplicationManager.getApplication ().isUnitTestMode) || - (this.virtualMachineProxy as? VirtualMachineProxyImpl)?.virtualMachine?.name() == "Dalvik" // TODO: check other machine name +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/NoStrataPositionManagerHelper.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/NoStrataPositionManagerHelper.kt index 3074e212d73..44299ef8bb0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/NoStrataPositionManagerHelper.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/NoStrataPositionManagerHelper.kt @@ -17,6 +17,10 @@ package org.jetbrains.kotlin.idea.debugger import com.intellij.debugger.SourcePosition +import com.intellij.debugger.engine.DebugProcess +import com.intellij.debugger.jdi.VirtualMachineProxyImpl +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope import com.sun.jdi.Location import com.sun.jdi.ReferenceType @@ -24,10 +28,26 @@ import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.psiUtil.parents +import org.jetbrains.kotlin.resolve.jvm.JvmClassName -fun noStrataLocationsOfLineForInlineFunctions(type: ReferenceType, position: SourcePosition, sourceSearchScope: GlobalSearchScope): List { +internal fun getOriginalPositionOfInlinedLine( + lineNumber: Int, fqName: FqName, fileName: String, project: Project, searchScope: GlobalSearchScope): Pair? { + val internalName = fqName.asString().replace('.', '/') + val jvmClassName = JvmClassName.byInternalName(internalName) + + val file = DebuggerUtils.findSourceFileForClassIncludeLibrarySources(project, searchScope, jvmClassName, fileName) ?: return null + + val virtualFile = file.virtualFile ?: return null + + val bytes = readClassFile(project, jvmClassName, virtualFile, { isInlineFunctionLineNumber(it, lineNumber, project) }) ?: return null + val smapData = readDebugInfo(bytes) ?: return null + return mapStacktraceLineToSource(smapData, lineNumber, project, SourceLineKind.EXECUTED_LINE, searchScope) +} + +internal fun getLocationsOfInlinedLine(type: ReferenceType, position: SourcePosition, sourceSearchScope: GlobalSearchScope): List { val line = position.line val file = position.file val project = position.file.project @@ -42,4 +62,31 @@ fun noStrataLocationsOfLineForInlineFunctions(type: ReferenceType, position: Sou val inlineLocations = lines.flatMap { type.locationsOfLine(it) } return inlineLocations -} \ No newline at end of file +} + +private fun inlinedLinesNumbers( + inlineLineNumber: Int, inlineFileName: String, + destinationTypeFqName: FqName, destinationFileName: String, + project: Project, sourceSearchScope: GlobalSearchScope): List { + val internalName = destinationTypeFqName.asString().replace('.', '/') + val jvmClassName = JvmClassName.byInternalName(internalName) + + val file = DebuggerUtils.findSourceFileForClassIncludeLibrarySources(project, sourceSearchScope, jvmClassName, destinationFileName) ?: + return listOf() + + val virtualFile = file.virtualFile ?: return listOf() + + val bytes = readClassFile(project, jvmClassName, virtualFile) ?: return listOf() + val smapData = readDebugInfo(bytes) ?: return listOf() + + val smap = smapData.kotlinStrata ?: return listOf() + + val mappingToInlinedFile = smap.fileMappings.firstOrNull() { it.name == inlineFileName } ?: return listOf() + return mappingToInlinedFile.lineMappings.map { it.mapSourceToDest(inlineLineNumber) } +} + +@Volatile var emulateDexDebugInTests: Boolean = false + +fun DebugProcess.isDexDebug() = + (emulateDexDebugInTests && ApplicationManager.getApplication ().isUnitTestMode) || + (this.virtualMachineProxy as? VirtualMachineProxyImpl)?.virtualMachine?.name() == "Dalvik" // TODO: check other machine names \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/smapUtil.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/smapUtil.kt index c2f4c116d5e..86dc3ce10b8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/smapUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/smapUtil.kt @@ -31,7 +31,6 @@ import org.jetbrains.kotlin.idea.refactoring.toPsiFile import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinder import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.tail import org.jetbrains.kotlin.psi.KtFile @@ -41,40 +40,6 @@ import org.jetbrains.org.objectweb.asm.ClassReader import org.jetbrains.org.objectweb.asm.ClassVisitor import java.io.File -fun inlineLineAndFileByPosition(lineNumber: Int, fqName: FqName, fileName: String, project: Project, searchScope: GlobalSearchScope): Pair? { - val internalName = fqName.asString().replace('.', '/') - val jvmClassName = JvmClassName.byInternalName(internalName) - - val file = DebuggerUtils.findSourceFileForClassIncludeLibrarySources(project, searchScope, jvmClassName, fileName) ?: return null - - val virtualFile = file.virtualFile ?: return null - - val bytes = readClassFile(project, jvmClassName, virtualFile, { isInlineFunctionLineNumber(it, lineNumber, project) }) ?: return null - val smapData = readDebugInfo(bytes) ?: return null - return mapStacktraceLineToSource(smapData, lineNumber, project, SourceLineKind.EXECUTED_LINE, searchScope) -} - -internal fun inlinedLinesNumbers( - inlineLineNumber: Int, inlineFileName: String, - destinationTypeFqName: FqName, destinationFileName: String, - project: Project, sourceSearchScope: GlobalSearchScope): List { - val internalName = destinationTypeFqName.asString().replace('.', '/') - val jvmClassName = JvmClassName.byInternalName(internalName) - - val file = DebuggerUtils.findSourceFileForClassIncludeLibrarySources(project, sourceSearchScope, jvmClassName, destinationFileName) ?: - return listOf() - - val virtualFile = file.virtualFile ?: return listOf() - - val bytes = readClassFile(project, jvmClassName, virtualFile) ?: return listOf() - val smapData = readDebugInfo(bytes) ?: return listOf() - - val smap = smapData.kotlinStrata ?: return listOf() - - val mappingToInlinedFile = smap.fileMappings.firstOrNull() { it.name == inlineFileName } ?: return listOf() - return mappingToInlinedFile.lineMappings.map { it.mapSourceToDest(inlineLineNumber) } -} - fun isInlineFunctionLineNumber(file: VirtualFile, lineNumber: Int, project: Project): Boolean { val linesInFile = file.toPsiFile(project)?.getLineCount() ?: return false return lineNumber > linesInFile diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestCase.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestCase.java index 8a66015f671..91ecc34ed0b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestCase.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinDebuggerTestCase.java @@ -84,7 +84,7 @@ public abstract class KotlinDebuggerTestCase extends DescriptorTestCase { protected void setUp() throws Exception { VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory()); if (getTestName(true).startsWith("dex")) { - KotlinPositionManagerKt.setEmulateDexDebugInTests(true); + NoStrataPositionManagerHelperKt.setEmulateDexDebugInTests(true); } super.setUp(); } @@ -102,7 +102,7 @@ public abstract class KotlinDebuggerTestCase extends DescriptorTestCase { @Override protected void tearDown() throws Exception { if (getTestName(true).startsWith("dex")) { - KotlinPositionManagerKt.setEmulateDexDebugInTests(false); + NoStrataPositionManagerHelperKt.setEmulateDexDebugInTests(false); } EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() {