Implement extra variables for debugger

This commit is contained in:
Natalia Ukhorskaya
2015-01-21 15:40:51 +03:00
parent 3a03cb48df
commit 2f931f36c8
30 changed files with 811 additions and 12 deletions
@@ -2,7 +2,14 @@
<item name='com.intellij.debugger.engine.DebugProcessImpl com.intellij.debugger.jdi.VirtualMachineProxyImpl getVirtualMachineProxy()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
<item
name='com.intellij.debugger.engine.FrameExtraVariablesProvider java.util.Set&lt;com.intellij.debugger.engine.evaluation.TextWithImports&gt; collectVariables(com.intellij.debugger.SourcePosition, com.intellij.debugger.engine.evaluation.EvaluationContext, java.util.Set&lt;java.lang.String&gt;)'>
<annotation name='kotlin.jvm.KotlinSignature'>
<val name="value"
val="&quot;fun collectVariables(sourcePosition: SourcePosition?, evalContext: EvaluationContext?, alreadyCollected: Set&lt;String&gt;?): Set&lt;TextWithImports&gt;?&quot;"/>
</annotation>
</item>
<item
name='com.intellij.debugger.engine.MethodFilter boolean locationMatches(com.intellij.debugger.engine.DebugProcessImpl, com.sun.jdi.Location) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
+1
View File
@@ -380,6 +380,7 @@
<debuggerClassFilterProvider implementation="org.jetbrains.kotlin.idea.debugger.filter.KotlinDebuggerInternalClassesFilterProvider"/>
<debugger.nodeRenderer implementation="org.jetbrains.kotlin.idea.debugger.render.KotlinClassWithDelegatedPropertyRenderer"/>
<debugger.sourcePositionProvider implementation="org.jetbrains.kotlin.idea.debugger.KotlinSourcePositionProvider"/>
<debugger.frameExtraVarsProvider implementation="org.jetbrains.kotlin.idea.debugger.KotlinFrameExtraVariablesProvider"/>
<xdebugger.settings implementation="org.jetbrains.kotlin.idea.debugger.KotlinDebuggerSettings"/>
<codeInsight.implementMethod language="jet" implementationClass="org.jetbrains.kotlin.idea.codeInsight.ImplementMethodsHandler"/>
@@ -0,0 +1,193 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.debugger
import com.intellij.debugger.engine.FrameExtraVariablesProvider
import com.intellij.debugger.SourcePosition
import com.intellij.debugger.engine.evaluation.EvaluationContext
import com.intellij.debugger.engine.evaluation.TextWithImports
import com.intellij.debugger.settings.DebuggerSettings
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl
import com.intellij.debugger.engine.evaluation.CodeFragmentKind
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.editor.Document
import com.intellij.psi.PsiFile
import com.intellij.util.text.CharArrayUtil
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.idea.JetFileType
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import java.util.LinkedHashSet
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
public class KotlinFrameExtraVariablesProvider : FrameExtraVariablesProvider {
override fun isAvailable(sourcePosition: SourcePosition?, evalContext: EvaluationContext?): Boolean {
if (sourcePosition == null) return false
if (sourcePosition.getLine() < 0) return false
return sourcePosition.getFile().getFileType() == JetFileType.INSTANCE && DebuggerSettings.getInstance().AUTO_VARIABLES_MODE
}
override fun collectVariables(sourcePosition: SourcePosition?, evalContext: EvaluationContext?, alreadyCollected: Set<String>?
): Set<TextWithImports>? {
if (sourcePosition != null) {
return runReadAction { findAdditionalExpressions(sourcePosition) }
}
return setOf()
}
}
private fun findAdditionalExpressions(position: SourcePosition): Set<TextWithImports> {
val line = position.getLine()
val file = position.getFile()
val vFile = file.getVirtualFile()
val doc = if (vFile != null) FileDocumentManager.getInstance().getDocument(vFile) else null
if (doc == null || doc.getLineCount() == 0 || line > (doc.getLineCount() - 1)) {
return setOf()
}
val offset = doc.getLineStartOffset(line)
if (offset < 0) return setOf()
val elem = file.findElementAt(offset)
val containingElement = getContainingElement(elem) ?: elem
if (containingElement == null) return setOf()
val limit = getLineRangeForElement(containingElement, doc)
var startLine = Math.max(limit.getStartOffset(), line)
while (startLine - 1 > limit.getStartOffset() && shouldSkipLine(file, doc, startLine - 1)) {
startLine--
}
var endLine = Math.min(limit.getEndOffset(), line)
while (endLine + 1 < limit.getEndOffset() && shouldSkipLine(file, doc, endLine + 1)) {
endLine++
}
val lineRange = TextRange(doc.getLineStartOffset(startLine), doc.getLineEndOffset(endLine))
if (lineRange.isEmpty()) return setOf()
val expressions = LinkedHashSet<TextWithImports>()
val variablesCollector = VariablesCollector(lineRange, expressions)
containingElement.accept(variablesCollector)
return expressions
}
private fun getContainingElement(element: PsiElement): JetElement? {
val contElement = PsiTreeUtil.getParentOfType(element, javaClass<JetDeclaration>()) ?: PsiTreeUtil.getParentOfType(element, javaClass<JetElement>())
if (contElement is JetProperty && contElement.isLocal()) {
val parent = contElement.getParent()
if (parent != null) {
return getContainingElement(parent)
}
}
if (contElement is JetDeclarationWithBody) {
return contElement.getBodyExpression()
}
return contElement
}
private fun getLineRangeForElement(containingElement: PsiElement, doc: Document): TextRange {
val elemRange = containingElement.getTextRange()
return TextRange(doc.getLineNumber(elemRange.getStartOffset()), doc.getLineNumber(elemRange.getEndOffset()))
}
private fun shouldSkipLine(file: PsiFile, doc: Document, line: Int): Boolean {
val start = CharArrayUtil.shiftForward(doc.getCharsSequence(), doc.getLineStartOffset(line), " \n\t")
val end = doc.getLineEndOffset(line)
if (start >= end) {
return true
}
val elemAtOffset = file.findElementAt(start)
val topmostElementAtOffset = CodeInsightUtils.getTopmostElementAtOffset(elemAtOffset, start)
return topmostElementAtOffset !is JetDeclaration
}
private class VariablesCollector(
private val myLineRange: TextRange,
private val myExpressions: MutableSet<TextWithImports>
) : JetTreeVisitorVoid() {
override fun visitJetElement(element: JetElement) {
if (element.isInRange()) {
super.visitJetElement(element)
}
}
override fun visitQualifiedExpression(expression: JetQualifiedExpression) {
if (expression.isInRange()) {
val selector = expression.getSelectorExpression()
if (selector is JetReferenceExpression) {
if (isRefToProperty(selector)) {
myExpressions.add(expression.createText())
return
}
}
}
super.visitQualifiedExpression(expression)
}
private fun isRefToProperty(expression: JetReferenceExpression): Boolean {
val context = expression.analyzeFully()
val descriptor = context[BindingContext.REFERENCE_TARGET, expression]
if (descriptor is PropertyDescriptor) {
val getter = descriptor.getGetter()
return (getter == null || context[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getter] == null) &&
descriptor.getCompileTimeInitializer() == null
}
return false
}
override fun visitReferenceExpression(expression: JetReferenceExpression) {
if (expression.isInRange()) {
if (isRefToProperty(expression)) {
myExpressions.add(expression.createText())
}
}
super.visitReferenceExpression(expression)
}
private fun JetElement.isInRange(): Boolean = myLineRange.intersects(this.getTextRange())
private fun JetElement.createText(): TextWithImports = TextWithImportsImpl(CodeFragmentKind.EXPRESSION, this.getText())
override fun visitClass(klass: JetClass) {
// Do not show expressions used in local classes
}
override fun visitNamedFunction(function: JetNamedFunction) {
// Do not show expressions used in local functions
}
override fun visitObjectLiteralExpression(expression: JetObjectLiteralExpression) {
// Do not show expressions used in anonymous objects
}
override fun visitFunctionLiteralExpression(expression: JetFunctionLiteralExpression) {
// Do not show expressions used in lambdas
}
}
@@ -9,7 +9,7 @@ import kotlin.properties.Delegates
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
args.size
args.size()
}
class A {
@@ -0,0 +1,36 @@
LineBreakpoint created at evBreakpointOnPropertyDeclaration.kt:14
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! evBreakpointOnPropertyDeclaration.EvBreakpointOnPropertyDeclarationPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
evBreakpointOnPropertyDeclaration.kt:14
package evBreakpointOnPropertyDeclaration
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a1 = A()
val a2 = A()
val a3 = A()
val p1 = a1.prop
//Breakpoint!
val p2 = a2.prop
val p3 = a3.prop
}
// PRINT_FRAME
frame = main():14, EvBreakpointOnPropertyDeclarationPackage$@packagePartHASH {evBreakpointOnPropertyDeclaration}
static = static = evBreakpointOnPropertyDeclaration.EvBreakpointOnPropertyDeclarationPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = evBreakpointOnPropertyDeclaration.kt, 7)
local = a1: evBreakpointOnPropertyDeclaration.A = {evBreakpointOnPropertyDeclaration.A@uniqueID} (sp = evBreakpointOnPropertyDeclaration.kt, 8)
field = prop: int = 1 (sp = evBreakpointOnPropertyDeclaration.kt, 4)
local = a2: evBreakpointOnPropertyDeclaration.A = {evBreakpointOnPropertyDeclaration.A@uniqueID} (sp = evBreakpointOnPropertyDeclaration.kt, 9)
field = prop: int = 1 (sp = evBreakpointOnPropertyDeclaration.kt, 4)
local = a3: evBreakpointOnPropertyDeclaration.A = {evBreakpointOnPropertyDeclaration.A@uniqueID} (sp = evBreakpointOnPropertyDeclaration.kt, 10)
field = prop: int = 1 (sp = evBreakpointOnPropertyDeclaration.kt, 4)
local = p1: int = 1 (sp = evBreakpointOnPropertyDeclaration.kt, 12)
extra = a2.prop
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,31 @@
LineBreakpoint created at evDelegatedProperty.kt:13
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! evDelegatedProperty.EvDelegatedPropertyPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
evDelegatedProperty.kt:13
package evDelegatedProperty
import kotlin.properties.Delegates
class A {
var prop: Int by Delegates.notNull()
}
fun main(args: Array<String>) {
val a = A()
a.prop = 1
//Breakpoint!
val b = a.prop
}
// PRINT_FRAME
frame = main():13, EvDelegatedPropertyPackage$@packagePartHASH {evDelegatedProperty}
static = static = evDelegatedProperty.EvDelegatedPropertyPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = evDelegatedProperty.kt, 9)
local = a: evDelegatedProperty.A = {evDelegatedProperty.A@uniqueID} (sp = evDelegatedProperty.kt, 10)
field = prop$delegate: kotlin.properties.ReadWriteProperty = {kotlin.properties.NotNullVar@uniqueID} (sp = evDelegatedProperty.kt, 6)
field = value: java.lang.Object = {java.lang.Integer@uniqueID}1 (sp = Delegation.!EXT!)
field = value: int = 1 (sp = Integer.!EXT!)
field = prop: int = 1 (sp = evDelegatedProperty.kt, 6)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,26 @@
LineBreakpoint created at evDuplicateItems.kt:10
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! evDuplicateItems.EvDuplicateItemsPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
evDuplicateItems.kt:10
package evDuplicateItems
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
val b = a.prop + a.prop
}
// PRINT_FRAME
frame = main():10, EvDuplicateItemsPackage$@packagePartHASH {evDuplicateItems}
static = static = evDuplicateItems.EvDuplicateItemsPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = evDuplicateItems.kt, 7)
local = a: evDuplicateItems.A = {evDuplicateItems.A@uniqueID} (sp = evDuplicateItems.kt, 8)
field = prop: int = 1 (sp = evDuplicateItems.kt, 4)
extra = a.prop
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,25 @@
LineBreakpoint created at evFinalProperty.kt:10
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! evFinalProperty.EvFinalPropertyPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
evFinalProperty.kt:10
package evFinalProperty
class A {
val prop = 1
}
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
val b = a.prop
}
// PRINT_FRAME
frame = main():10, EvFinalPropertyPackage$@packagePartHASH {evFinalProperty}
static = static = evFinalProperty.EvFinalPropertyPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = evFinalProperty.kt, 7)
local = a: evFinalProperty.A = {evFinalProperty.A@uniqueID} (sp = evFinalProperty.kt, 8)
field = prop: int = 1 (sp = evFinalProperty.kt, 4)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,40 @@
LineBreakpoint created at evLineRange.kt:15
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! evLineRange.EvLineRangePackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
evLineRange.kt:15
package evLineRange
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a1 = A()
val a2 = A()
val a3 = A()
foo(a1.prop)
val i1 = 1
//Breakpoint!
foo(a2.prop)
val i2 = 1
foo(a3.prop)
}
fun foo(i: Int) {}
// PRINT_FRAME
frame = main():15, EvLineRangePackage$@packagePartHASH {evLineRange}
static = static = evLineRange.EvLineRangePackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = evLineRange.kt, 7)
local = a1: evLineRange.A = {evLineRange.A@uniqueID} (sp = evLineRange.kt, 8)
field = prop: int = 1 (sp = evLineRange.kt, 4)
local = a2: evLineRange.A = {evLineRange.A@uniqueID} (sp = evLineRange.kt, 9)
field = prop: int = 1 (sp = evLineRange.kt, 4)
local = a3: evLineRange.A = {evLineRange.A@uniqueID} (sp = evLineRange.kt, 10)
field = prop: int = 1 (sp = evLineRange.kt, 4)
local = i1: int = 1 (sp = evLineRange.kt, 13)
extra = a2.prop
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,28 @@
LineBreakpoint created at evProperty.kt:10
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! evProperty.EvPropertyPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
evProperty.kt:10
package evProperty
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
if (a.prop == 1) {
}
}
// PRINT_FRAME
frame = main():10, EvPropertyPackage$@packagePartHASH {evProperty}
static = static = evProperty.EvPropertyPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = evProperty.kt, 7)
local = a: evProperty.A = {evProperty.A@uniqueID} (sp = evProperty.kt, 8)
field = prop: int = 1 (sp = evProperty.kt, 4)
extra = a.prop
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,29 @@
LineBreakpoint created at evPropertyRefExpr.kt:8
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! evPropertyRefExpr.EvPropertyRefExprPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
evPropertyRefExpr.kt:8
package evPropertyRefExpr
class A {
var prop = 1
fun test() {
//Breakpoint!
if (prop == 1) {
}
}
}
fun main(args: Array<String>) {
A().test()
}
// PRINT_FRAME
frame = test():8, A {evPropertyRefExpr}
this = this = {evPropertyRefExpr.A@uniqueID}
field = prop: int = 1 (sp = evPropertyRefExpr.kt, 4)
extra = prop
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,41 @@
LineBreakpoint created at evSkipAnonymousObject.kt:12
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! evSkipAnonymousObject.EvSkipAnonymousObjectPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
evSkipAnonymousObject.kt:12
package evSkipAnonymousObject
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a1 = A()
val a2 = A()
//Breakpoint!
foo(a1.prop)
object: T {
override fun f() {
foo(a2.prop)
}
}
}
trait T {
fun f() {}
}
fun foo(i: Int) {}
// PRINT_FRAME
frame = main():12, EvSkipAnonymousObjectPackage$@packagePartHASH {evSkipAnonymousObject}
static = static = evSkipAnonymousObject.EvSkipAnonymousObjectPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = evSkipAnonymousObject.kt, 7)
local = a1: evSkipAnonymousObject.A = {evSkipAnonymousObject.A@uniqueID} (sp = evSkipAnonymousObject.kt, 8)
field = prop: int = 1 (sp = evSkipAnonymousObject.kt, 4)
local = a2: evSkipAnonymousObject.A = {evSkipAnonymousObject.A@uniqueID} (sp = evSkipAnonymousObject.kt, 9)
field = prop: int = 1 (sp = evSkipAnonymousObject.kt, 4)
extra = a1.prop
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,36 @@
LineBreakpoint created at evSkipLambda.kt:12
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! evSkipLambda.EvSkipLambdaPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
evSkipLambda.kt:12
package evSkipLambda
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a1 = A()
val a2 = A()
//Breakpoint!
foo(a1.prop)
l {
foo(a2.prop)
}
}
fun foo(i: Int) {}
fun l(f: () -> Unit) {}
// PRINT_FRAME
frame = main():12, EvSkipLambdaPackage$@packagePartHASH {evSkipLambda}
static = static = evSkipLambda.EvSkipLambdaPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = evSkipLambda.kt, 7)
local = a1: evSkipLambda.A = {evSkipLambda.A@uniqueID} (sp = evSkipLambda.kt, 8)
field = prop: int = 1 (sp = evSkipLambda.kt, 4)
local = a2: evSkipLambda.A = {evSkipLambda.A@uniqueID} (sp = evSkipLambda.kt, 9)
field = prop: int = 1 (sp = evSkipLambda.kt, 4)
extra = a1.prop
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,37 @@
LineBreakpoint created at evSkipLocalClass.kt:12
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! evSkipLocalClass.EvSkipLocalClassPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
evSkipLocalClass.kt:12
package evSkipLocalClass
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a1 = A()
val a2 = A()
//Breakpoint!
foo(a1.prop)
class B {
fun bar() {
foo(a2.prop)
}
}
}
fun foo(i: Int) {}
// PRINT_FRAME
frame = main():12, EvSkipLocalClassPackage$@packagePartHASH {evSkipLocalClass}
static = static = evSkipLocalClass.EvSkipLocalClassPackage$@packagePartHASH
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = evSkipLocalClass.kt, 7)
local = a1: evSkipLocalClass.A = {evSkipLocalClass.A@uniqueID} (sp = evSkipLocalClass.kt, 8)
field = prop: int = 1 (sp = evSkipLocalClass.kt, 4)
local = a2: evSkipLocalClass.A = {evSkipLocalClass.A@uniqueID} (sp = evSkipLocalClass.kt, 9)
field = prop: int = 1 (sp = evSkipLocalClass.kt, 4)
extra = a1.prop
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -7,7 +7,7 @@ package toStringRenderer
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
args.size
args.size()
}
class A {
@@ -0,0 +1,18 @@
package evBreakpointOnPropertyDeclaration
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a1 = A()
val a2 = A()
val a3 = A()
val p1 = a1.prop
//Breakpoint!
val p2 = a2.prop
val p3 = a3.prop
}
// PRINT_FRAME
@@ -0,0 +1,16 @@
package evDelegatedProperty
import kotlin.properties.Delegates
class A {
var prop: Int by Delegates.notNull()
}
fun main(args: Array<String>) {
val a = A()
a.prop = 1
//Breakpoint!
val b = a.prop
}
// PRINT_FRAME
@@ -0,0 +1,13 @@
package evDuplicateItems
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
val b = a.prop + a.prop
}
// PRINT_FRAME
@@ -0,0 +1,13 @@
package evFinalProperty
class A {
val prop = 1
}
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
val b = a.prop
}
// PRINT_FRAME
@@ -0,0 +1,22 @@
package evLineRange
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a1 = A()
val a2 = A()
val a3 = A()
foo(a1.prop)
val i1 = 1
//Breakpoint!
foo(a2.prop)
val i2 = 1
foo(a3.prop)
}
fun foo(i: Int) {}
// PRINT_FRAME
@@ -0,0 +1,15 @@
package evProperty
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
if (a.prop == 1) {
}
}
// PRINT_FRAME
@@ -0,0 +1,18 @@
package evPropertyRefExpr
class A {
var prop = 1
fun test() {
//Breakpoint!
if (prop == 1) {
}
}
}
fun main(args: Array<String>) {
A().test()
}
// PRINT_FRAME
@@ -0,0 +1,26 @@
package evSkipAnonymousObject
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a1 = A()
val a2 = A()
//Breakpoint!
foo(a1.prop)
object: T {
override fun f() {
foo(a2.prop)
}
}
}
trait T {
fun f() {}
}
fun foo(i: Int) {}
// PRINT_FRAME
@@ -0,0 +1,21 @@
package evSkipLambda
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a1 = A()
val a2 = A()
//Breakpoint!
foo(a1.prop)
l {
foo(a2.prop)
}
}
fun foo(i: Int) {}
fun l(f: () -> Unit) {}
// PRINT_FRAME
@@ -0,0 +1,22 @@
package evSkipLocalClass
class A {
var prop = 1
}
fun main(args: Array<String>) {
val a1 = A()
val a2 = A()
//Breakpoint!
foo(a1.prop)
class B {
fun bar() {
foo(a2.prop)
}
}
}
fun foo(i: Int) {}
// PRINT_FRAME
@@ -5,7 +5,7 @@ import kotlin.properties.Delegates
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
args.size
args.size()
}
class A {
@@ -3,7 +3,7 @@ package toStringRenderer
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
args.size
args.size()
}
class A {
@@ -59,9 +59,10 @@ import com.intellij.debugger.DebuggerManagerEx
import com.intellij.psi.PsiDocumentManager
import com.intellij.openapi.application.ModalityState
import com.intellij.debugger.settings.NodeRendererSettings
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.SourcePosition
import com.intellij.debugger.engine.SourcePositionProvider
import com.intellij.debugger.engine.evaluation.TextWithImports
import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor
public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
private val logger = Logger.getLogger(javaClass<KotlinEvaluateExpressionCache>())!!
@@ -223,7 +224,11 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
tree.rebuild(debuggerContext)
expandAll(tree, Runnable {
try {
Printer().printTree(tree)
val printer = Printer()
printer.printTree(tree)
for (extra in getExtraVars()) {
printer.printDescriptor(tree.getNodeFactory().getWatchItemDescriptor(null, extra, null), 2)
}
}
finally {
resume(this@printFrame)
@@ -232,6 +237,10 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
}
}
fun getExtraVars(): Set<TextWithImports> {
return KotlinFrameExtraVariablesProvider().collectVariables(debuggerContext.getSourcePosition(), evaluationContext, hashSetOf())!!
}
private inner class Printer() {
fun printTree(tree: DebuggerTree) {
val root = tree.getMutableModel()!!.getRoot() as DebuggerTreeNodeImpl
@@ -240,14 +249,22 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
private fun printNode(node: DebuggerTreeNodeImpl, indent: Int) {
val descriptor: NodeDescriptorImpl = node.getDescriptor()!!
if (descriptor is DefaultNodeDescriptor) return
if (printDescriptor(descriptor, indent)) return
printChildren(node, indent + 2)
}
fun printDescriptor(descriptor: NodeDescriptorImpl, indent: Int): Boolean {
if (descriptor is DefaultNodeDescriptor) return true
val label = descriptor.getLabel()!!.replaceAll("Package\\$[\\w]*\\$[0-9a-f]+", "Package\\$@packagePartHASH")
if (label.endsWith(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE)) return
if (label.endsWith(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE)) return true
val curIndent = " ".repeat(indent)
when (descriptor) {
is StackFrameDescriptor -> logDescriptor(descriptor, "$curIndent frame = $label\n")
is WatchItemDescriptor -> logDescriptor(descriptor, "$curIndent extra = ${descriptor.calcValueName()}\n")
is LocalVariableDescriptor -> logDescriptor(descriptor, "$curIndent local = $label"
+ " (sp = ${render(SourcePositionProvider.getSourcePosition(descriptor, myProject, debuggerContext))})\n")
is StaticDescriptor -> logDescriptor(descriptor, "$curIndent static = $label\n")
@@ -256,8 +273,7 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
+ " (sp = ${render(SourcePositionProvider.getSourcePosition(descriptor, myProject, debuggerContext))})\n")
else -> logDescriptor(descriptor, "$curIndent unknown = $label\n")
}
printChildren(node, indent + 2)
return false
}
private fun printChildren(node: DebuggerTreeNodeImpl, indent: Int) {
@@ -33,7 +33,7 @@ import java.util.regex.Pattern;
public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluateExpressionTest {
@TestMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint")
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({SingleBreakpoint.Frame.class, SingleBreakpoint.Lambdas.class, SingleBreakpoint.Renderer.class})
@InnerTestClasses({SingleBreakpoint.ExtraVariables.class, SingleBreakpoint.Frame.class, SingleBreakpoint.Lambdas.class, SingleBreakpoint.Renderer.class})
@RunWith(JUnit3RunnerWithInners.class)
public static class SingleBreakpoint extends AbstractKotlinEvaluateExpressionTest {
@TestMetadata("abstractFunCall.kt")
@@ -226,6 +226,75 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
doSingleBreakpointTest(fileName);
}
@TestMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ExtraVariables extends AbstractKotlinEvaluateExpressionTest {
public void testAllFilesPresentInExtraVariables() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("evBreakpointOnPropertyDeclaration.kt")
public void testEvBreakpointOnPropertyDeclaration() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables/evBreakpointOnPropertyDeclaration.kt");
doSingleBreakpointTest(fileName);
}
@TestMetadata("evDelegatedProperty.kt")
public void testEvDelegatedProperty() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables/evDelegatedProperty.kt");
doSingleBreakpointTest(fileName);
}
@TestMetadata("evDuplicateItems.kt")
public void testEvDuplicateItems() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables/evDuplicateItems.kt");
doSingleBreakpointTest(fileName);
}
@TestMetadata("evFinalProperty.kt")
public void testEvFinalProperty() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables/evFinalProperty.kt");
doSingleBreakpointTest(fileName);
}
@TestMetadata("evLineRange.kt")
public void testEvLineRange() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables/evLineRange.kt");
doSingleBreakpointTest(fileName);
}
@TestMetadata("evProperty.kt")
public void testEvProperty() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables/evProperty.kt");
doSingleBreakpointTest(fileName);
}
@TestMetadata("evPropertyRefExpr.kt")
public void testEvPropertyRefExpr() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables/evPropertyRefExpr.kt");
doSingleBreakpointTest(fileName);
}
@TestMetadata("evSkipAnonymousObject.kt")
public void testEvSkipAnonymousObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables/evSkipAnonymousObject.kt");
doSingleBreakpointTest(fileName);
}
@TestMetadata("evSkipLambda.kt")
public void testEvSkipLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables/evSkipLambda.kt");
doSingleBreakpointTest(fileName);
}
@TestMetadata("evSkipLocalClass.kt")
public void testEvSkipLocalClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extraVariables/evSkipLocalClass.kt");
doSingleBreakpointTest(fileName);
}
}
@TestMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)