Debugger: implement Jump to Source for localVariables
This commit is contained in:
@@ -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
|
||||
|
||||
+2
-1
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user