Debugger: implement Jump to Source for localVariables

This commit is contained in:
Natalia Ukhorskaya
2014-12-26 15:48:42 +03:00
parent 8dcb4ab5bb
commit 2aaa94cccb
10 changed files with 65 additions and 15 deletions
@@ -33,6 +33,19 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import com.sun.jdi.AbsentInformationException
import com.sun.jdi.ClassNotPreparedException
import com.intellij.debugger.ui.tree.FieldDescriptor
import com.intellij.debugger.ui.tree.LocalVariableDescriptor
import com.intellij.debugger.impl.PositionUtil
import com.intellij.psi.PsiVariable
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.jet.plugin.caches.resolve.analyze
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.resolve.BindingContext
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.resolve.source.getPsi
public class KotlinSourcePositionProvider: SourcePositionProvider() {
override fun computeSourcePosition(descriptor: NodeDescriptor, project: Project, context: DebuggerContextImpl, nearest: Boolean): SourcePosition? {
@@ -42,6 +55,42 @@ public class KotlinSourcePositionProvider: SourcePositionProvider() {
return computeSourcePosition(descriptor, project, context, nearest)
}
if (descriptor is LocalVariableDescriptor) {
return computeSourcePosition(descriptor, project, context, nearest)
}
return null
}
fun computeSourcePosition(descriptor: LocalVariableDescriptor, project: Project, context: DebuggerContextImpl, nearest: Boolean): SourcePosition? {
val place = PositionUtil.getContextElement(context)
if (place == null) {
return null
}
val contextElement = PsiTreeUtil.getParentOfType(place, javaClass<JetElement>())
if (contextElement == null) {
return null
}
val codeFragment = JetPsiFactory(project).createExpressionCodeFragment(descriptor.getName(), contextElement)
val expression = codeFragment.getContentElement()
if (expression is JetSimpleNameExpression) {
val bindingContext = expression.analyze()
val declarationDescriptor = BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, expression, false)
val sourceElement = declarationDescriptor?.getSource()
if (sourceElement is KotlinSourceElement) {
val element = sourceElement.getPsi()
if (element == null) {
return null
}
if (nearest) {
return DebuggerContextUtil.findNearest(context, element, element.getContainingFile())
}
return SourcePosition.createFromOffset(element.getContainingFile(), element.getTextOffset())
}
}
return null
}
@@ -28,8 +28,8 @@ class MyDelegateThrowsException {
// PRINT_FRAME
frame = main():8, DelegatedPropertyInClassPackage$@packagePartHASH {delegatedPropertyInClass}
static = static = delegatedPropertyInClass.DelegatedPropertyInClassPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
local = a: delegatedPropertyInClass.A = {delegatedPropertyInClass.A@uniqueID}
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = delegatedPropertyInClass.kt, 5)
local = a: delegatedPropertyInClass.A = {delegatedPropertyInClass.A@uniqueID} (sp = delegatedPropertyInClass.kt, 6)
field = prop$delegate: delegatedPropertyInClass.MyDelegate = {delegatedPropertyInClass.MyDelegate@uniqueID} (sp = delegatedPropertyInClass.kt, 12)
field = prop: int = 1 (sp = delegatedPropertyInClass.kt, 12)
field = propEx$delegate: delegatedPropertyInClass.MyDelegateThrowsException = {delegatedPropertyInClass.MyDelegateThrowsException@uniqueID} (sp = delegatedPropertyInClass.kt, 13)
@@ -16,8 +16,8 @@ fun main(args: Array<String>) {
frame = main():6, FrameClosingBracketPackage$@packagePartHASH {frameClosingBracket}
static = static = frameClosingBracket.FrameClosingBracketPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
local = a: int = 1
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = frameClosingBracket.kt, 3)
local = a: int = 1 (sp = frameClosingBracket.kt, 4)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -24,7 +24,7 @@ fun A.foo() {
// RESULT: 1: I
frame = foo():13, FrameExtensionFunPackage$@packagePartHASH {frameExtensionFun}
static = static = frameExtensionFun.FrameExtensionFunPackage$@packagePartHASH
local = $receiver: frameExtensionFun.A = {frameExtensionFun.A@uniqueID}
local = $receiver: frameExtensionFun.A = {frameExtensionFun.A@uniqueID} (sp = null)
field = prop: int = 1 (sp = frameExtensionFun.kt, 8)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
@@ -23,7 +23,7 @@ fun foo(f: () -> Unit) {
// RESULT: Cannot find local variable: name = val1
frame = invoke():7, FrameLambdaNotUsedPackage$@packagePartHASH$main$1 {frameLambdaNotUsed}
this = this = {frameLambdaNotUsed.FrameLambdaNotUsedPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
local = a: int = 0
local = a: int = 0 (sp = frameLambdaNotUsed.kt, 7)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -23,8 +23,8 @@ inline fun foo(f: () -> Unit) {
// RESULT: 1: I
frame = main():7, FrameSharedVarLocalVarPackage$@packagePartHASH {frameSharedVarLocalVar}
static = static = frameSharedVarLocalVar.FrameSharedVarLocalVarPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
local = var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = frameSharedVarLocalVar.kt, 3)
local = var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1 (sp = frameSharedVarLocalVar.kt, 4)
field = element: int = 1 (sp = Ref.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
@@ -33,9 +33,9 @@ fun main(args: Array<String>) {
frame = main():9, FrameSimplePackage$@packagePartHASH {frameSimple}
static = static = frameSimple.FrameSimplePackage$@packagePartHASH
field = topVal1: int = 1 (sp = null)
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
local = val1: int = 1
local = val2: java.lang.String = {@uniqueID}str
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = frameSimple.kt, 5)
local = val1: int = 1 (sp = frameSimple.kt, 6)
local = val2: java.lang.String = {@uniqueID}str (sp = frameSimple.kt, 7)
field = value: char[] = {char[3]@uniqueID} (sp = String.!EXT!)
unknown = [0] = 's' 115
unknown = [1] = 't' 116
@@ -47,7 +47,7 @@ fun foo(f: () -> Unit) {
field = this$0: frameThis0.A = {frameThis0.A@uniqueID} (sp = null)
field = prop1: int = 1 (sp = frameThis0.kt, 8)
field = $val1: int = 1 (sp = null)
local = val2: int = 1
local = val2: int = 1 (sp = frameThis0.kt, 13)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -17,8 +17,8 @@ class A {
// PRINT_FRAME
frame = main():6, ToStringRendererPackage$@packagePartHASH {toStringRenderer}
static = static = toStringRenderer.ToStringRendererPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
local = a: toStringRenderer.A = {toStringRenderer.A@uniqueID}myA
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = toStringRenderer.kt, 3)
local = a: toStringRenderer.A = {toStringRenderer.A@uniqueID}myA (sp = toStringRenderer.kt, 4)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -250,7 +250,8 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
val curIndent = " ".repeat(indent)
when (descriptor) {
is StackFrameDescriptor -> logDescriptor(descriptor, "$curIndent frame = $label\n")
is LocalVariableDescriptor -> logDescriptor(descriptor, "$curIndent local = $label\n")
is LocalVariableDescriptor -> logDescriptor(descriptor, "$curIndent local = $label"
+ " (sp = ${render(SourcePositionProvider.getSourcePosition(descriptor, myProject, debuggerContext))})\n")
is StaticDescriptor -> logDescriptor(descriptor, "$curIndent static = $label\n")
is ThisDescriptorImpl -> logDescriptor(descriptor, "$curIndent this = $label\n")
is FieldDescriptor -> logDescriptor(descriptor, "$curIndent field = $label"