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.AbsentInformationException
|
||||||
import com.sun.jdi.ClassNotPreparedException
|
import com.sun.jdi.ClassNotPreparedException
|
||||||
import com.intellij.debugger.ui.tree.FieldDescriptor
|
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() {
|
public class KotlinSourcePositionProvider: SourcePositionProvider() {
|
||||||
override fun computeSourcePosition(descriptor: NodeDescriptor, project: Project, context: DebuggerContextImpl, nearest: Boolean): SourcePosition? {
|
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)
|
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
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ class MyDelegateThrowsException {
|
|||||||
// PRINT_FRAME
|
// PRINT_FRAME
|
||||||
frame = main():8, DelegatedPropertyInClassPackage$@packagePartHASH {delegatedPropertyInClass}
|
frame = main():8, DelegatedPropertyInClassPackage$@packagePartHASH {delegatedPropertyInClass}
|
||||||
static = static = delegatedPropertyInClass.DelegatedPropertyInClassPackage$@packagePartHASH
|
static = static = delegatedPropertyInClass.DelegatedPropertyInClassPackage$@packagePartHASH
|
||||||
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
|
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = delegatedPropertyInClass.kt, 5)
|
||||||
local = a: delegatedPropertyInClass.A = {delegatedPropertyInClass.A@uniqueID}
|
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$delegate: delegatedPropertyInClass.MyDelegate = {delegatedPropertyInClass.MyDelegate@uniqueID} (sp = delegatedPropertyInClass.kt, 12)
|
||||||
field = prop: int = 1 (sp = delegatedPropertyInClass.kt, 12)
|
field = prop: int = 1 (sp = delegatedPropertyInClass.kt, 12)
|
||||||
field = propEx$delegate: delegatedPropertyInClass.MyDelegateThrowsException = {delegatedPropertyInClass.MyDelegateThrowsException@uniqueID} (sp = delegatedPropertyInClass.kt, 13)
|
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}
|
frame = main():6, FrameClosingBracketPackage$@packagePartHASH {frameClosingBracket}
|
||||||
static = static = frameClosingBracket.FrameClosingBracketPackage$@packagePartHASH
|
static = static = frameClosingBracket.FrameClosingBracketPackage$@packagePartHASH
|
||||||
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
|
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = frameClosingBracket.kt, 3)
|
||||||
local = a: int = 1
|
local = a: int = 1 (sp = frameClosingBracket.kt, 4)
|
||||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
Process finished with exit code 0
|
Process finished with exit code 0
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ fun A.foo() {
|
|||||||
// RESULT: 1: I
|
// RESULT: 1: I
|
||||||
frame = foo():13, FrameExtensionFunPackage$@packagePartHASH {frameExtensionFun}
|
frame = foo():13, FrameExtensionFunPackage$@packagePartHASH {frameExtensionFun}
|
||||||
static = static = frameExtensionFun.FrameExtensionFunPackage$@packagePartHASH
|
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)
|
field = prop: int = 1 (sp = frameExtensionFun.kt, 8)
|
||||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
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
|
// RESULT: Cannot find local variable: name = val1
|
||||||
frame = invoke():7, FrameLambdaNotUsedPackage$@packagePartHASH$main$1 {frameLambdaNotUsed}
|
frame = invoke():7, FrameLambdaNotUsedPackage$@packagePartHASH$main$1 {frameLambdaNotUsed}
|
||||||
this = this = {frameLambdaNotUsed.FrameLambdaNotUsedPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
|
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'
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
Process finished with exit code 0
|
Process finished with exit code 0
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ inline fun foo(f: () -> Unit) {
|
|||||||
// RESULT: 1: I
|
// RESULT: 1: I
|
||||||
frame = main():7, FrameSharedVarLocalVarPackage$@packagePartHASH {frameSharedVarLocalVar}
|
frame = main():7, FrameSharedVarLocalVarPackage$@packagePartHASH {frameSharedVarLocalVar}
|
||||||
static = static = frameSharedVarLocalVar.FrameSharedVarLocalVarPackage$@packagePartHASH
|
static = static = frameSharedVarLocalVar.FrameSharedVarLocalVarPackage$@packagePartHASH
|
||||||
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
|
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
|
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!)
|
field = element: int = 1 (sp = Ref.!EXT!)
|
||||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
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}
|
frame = main():9, FrameSimplePackage$@packagePartHASH {frameSimple}
|
||||||
static = static = frameSimple.FrameSimplePackage$@packagePartHASH
|
static = static = frameSimple.FrameSimplePackage$@packagePartHASH
|
||||||
field = topVal1: int = 1 (sp = null)
|
field = topVal1: int = 1 (sp = null)
|
||||||
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
|
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = frameSimple.kt, 5)
|
||||||
local = val1: int = 1
|
local = val1: int = 1 (sp = frameSimple.kt, 6)
|
||||||
local = val2: java.lang.String = {@uniqueID}str
|
local = val2: java.lang.String = {@uniqueID}str (sp = frameSimple.kt, 7)
|
||||||
field = value: char[] = {char[3]@uniqueID} (sp = String.!EXT!)
|
field = value: char[] = {char[3]@uniqueID} (sp = String.!EXT!)
|
||||||
unknown = [0] = 's' 115
|
unknown = [0] = 's' 115
|
||||||
unknown = [1] = 't' 116
|
unknown = [1] = 't' 116
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ fun foo(f: () -> Unit) {
|
|||||||
field = this$0: frameThis0.A = {frameThis0.A@uniqueID} (sp = null)
|
field = this$0: frameThis0.A = {frameThis0.A@uniqueID} (sp = null)
|
||||||
field = prop1: int = 1 (sp = frameThis0.kt, 8)
|
field = prop1: int = 1 (sp = frameThis0.kt, 8)
|
||||||
field = $val1: int = 1 (sp = null)
|
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'
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
Process finished with exit code 0
|
Process finished with exit code 0
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ class A {
|
|||||||
// PRINT_FRAME
|
// PRINT_FRAME
|
||||||
frame = main():6, ToStringRendererPackage$@packagePartHASH {toStringRenderer}
|
frame = main():6, ToStringRendererPackage$@packagePartHASH {toStringRenderer}
|
||||||
static = static = toStringRenderer.ToStringRendererPackage$@packagePartHASH
|
static = static = toStringRenderer.ToStringRendererPackage$@packagePartHASH
|
||||||
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID}
|
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = toStringRenderer.kt, 3)
|
||||||
local = a: toStringRenderer.A = {toStringRenderer.A@uniqueID}myA
|
local = a: toStringRenderer.A = {toStringRenderer.A@uniqueID}myA (sp = toStringRenderer.kt, 4)
|
||||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
Process finished with exit code 0
|
Process finished with exit code 0
|
||||||
|
|||||||
+2
-1
@@ -250,7 +250,8 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
|
|||||||
val curIndent = " ".repeat(indent)
|
val curIndent = " ".repeat(indent)
|
||||||
when (descriptor) {
|
when (descriptor) {
|
||||||
is StackFrameDescriptor -> logDescriptor(descriptor, "$curIndent frame = $label\n")
|
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 StaticDescriptor -> logDescriptor(descriptor, "$curIndent static = $label\n")
|
||||||
is ThisDescriptorImpl -> logDescriptor(descriptor, "$curIndent this = $label\n")
|
is ThisDescriptorImpl -> logDescriptor(descriptor, "$curIndent this = $label\n")
|
||||||
is FieldDescriptor -> logDescriptor(descriptor, "$curIndent field = $label"
|
is FieldDescriptor -> logDescriptor(descriptor, "$curIndent field = $label"
|
||||||
|
|||||||
Reference in New Issue
Block a user