Debugger tests: mark objects using NodeDescriptorImpl.getMarkup. Primitive values cannot be marked.
This commit is contained in:
@@ -20,8 +20,10 @@ import com.intellij.debugger.DebuggerManagerEx
|
|||||||
import com.intellij.debugger.engine.evaluation.CodeFragmentFactory
|
import com.intellij.debugger.engine.evaluation.CodeFragmentFactory
|
||||||
import com.intellij.debugger.engine.evaluation.CodeFragmentKind
|
import com.intellij.debugger.engine.evaluation.CodeFragmentKind
|
||||||
import com.intellij.debugger.engine.evaluation.TextWithImports
|
import com.intellij.debugger.engine.evaluation.TextWithImports
|
||||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
import com.intellij.debugger.impl.DebuggerContextImpl
|
||||||
|
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl
|
||||||
import com.intellij.ide.highlighter.JavaFileType
|
import com.intellij.ide.highlighter.JavaFileType
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.progress.ProgressManager
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
@@ -141,7 +143,7 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getWrappedContextElement(project: Project, context: PsiElement?)
|
private fun getWrappedContextElement(project: Project, context: PsiElement?)
|
||||||
= wrapContextIfNeeded(project, getContextElement(context))
|
= wrapContextIfNeeded(project, context, getContextElement(context))
|
||||||
|
|
||||||
override fun createPresentationCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment {
|
override fun createPresentationCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment {
|
||||||
val kotlinCodeFragment = createCodeFragment(item, context, project)
|
val kotlinCodeFragment = createCodeFragment(item, context, project)
|
||||||
@@ -202,7 +204,7 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
companion object {
|
companion object {
|
||||||
val LABEL_VARIABLE_VALUE_KEY: Key<Value> = Key.create<Value>("_label_variable_value_key_")
|
val LABEL_VARIABLE_VALUE_KEY: Key<Value> = Key.create<Value>("_label_variable_value_key_")
|
||||||
val DEBUG_LABEL_SUFFIX: String = "_DebugLabel"
|
val DEBUG_LABEL_SUFFIX: String = "_DebugLabel"
|
||||||
@TestOnly val DEBUG_FRAME_FOR_TESTS: Key<StackFrameProxyImpl> = Key.create("DEBUG_FRAME_FOR_TESTS")
|
@TestOnly val DEBUG_CONTEXT_FOR_TESTS: Key<DebuggerContextImpl> = Key.create("DEBUG_CONTEXT_FOR_TESTS")
|
||||||
|
|
||||||
fun getContextElement(elementAt: PsiElement?): KtElement? {
|
fun getContextElement(elementAt: PsiElement?): KtElement? {
|
||||||
if (elementAt == null) return null
|
if (elementAt == null) return null
|
||||||
@@ -283,17 +285,19 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wrapContextIfNeeded(project: Project, originalContext: KtElement?): KtElement? {
|
private fun wrapContextIfNeeded(project: Project, originalContext: PsiElement?, newContext: KtElement?): KtElement? {
|
||||||
val session = XDebuggerManager.getInstance(project).currentSession as? XDebugSessionImpl
|
val markupMap: Map<*, ValueMarkup>? =
|
||||||
?: return originalContext
|
if (ApplicationManager.getApplication().isUnitTestMode)
|
||||||
|
NodeDescriptorImpl.getMarkupMap(originalContext?.getCopyableUserData(DEBUG_CONTEXT_FOR_TESTS)?.debugProcess)
|
||||||
|
else
|
||||||
|
(XDebuggerManager.getInstance(project).currentSession as? XDebugSessionImpl)?.valueMarkers?.allMarkers
|
||||||
|
|
||||||
val markupMap = session.valueMarkers?.allMarkers
|
if (markupMap == null || markupMap.isEmpty()) return newContext
|
||||||
if (markupMap == null || markupMap.isEmpty()) return originalContext
|
|
||||||
|
|
||||||
val (text, labels) = createCodeFragmentForLabeledObjects(project, markupMap)
|
val (text, labels) = createCodeFragmentForLabeledObjects(project, markupMap)
|
||||||
if (text.isEmpty()) return originalContext
|
if (text.isEmpty()) return newContext
|
||||||
|
|
||||||
return createWrappingContext(text, labels, originalContext, project)
|
return createWrappingContext(text, labels, newContext, project)
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal for test
|
// internal for test
|
||||||
|
|||||||
+2
-3
@@ -1,10 +1,9 @@
|
|||||||
LineBreakpoint created at ldifferentTypes.kt:92
|
LineBreakpoint created at ldifferentTypes.kt:88
|
||||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! ldifferentTypes.LdifferentTypesKt
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! ldifferentTypes.LdifferentTypesKt
|
||||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
ldifferentTypes.kt:92
|
ldifferentTypes.kt:88
|
||||||
Compile bytecode for str_DebugLabel
|
Compile bytecode for str_DebugLabel
|
||||||
Compile bytecode for strArray_DebugLabel
|
Compile bytecode for strArray_DebugLabel
|
||||||
Compile bytecode for primitive_DebugLabel
|
|
||||||
Compile bytecode for primitiveArray_DebugLabel
|
Compile bytecode for primitiveArray_DebugLabel
|
||||||
Compile bytecode for localObj_DebugLabel
|
Compile bytecode for localObj_DebugLabel
|
||||||
Compile bytecode for localObjArray_DebugLabel
|
Compile bytecode for localObjArray_DebugLabel
|
||||||
|
|||||||
+6
-6
@@ -1,11 +1,11 @@
|
|||||||
package lIdentifier
|
package lIdentifier
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val a = 1
|
val a = "1"
|
||||||
val b = 1
|
val b = "1"
|
||||||
val c = 1
|
val c = "1"
|
||||||
val d = 1
|
val d = "1"
|
||||||
val e = 1
|
val e = "1"
|
||||||
//Breakpoint!
|
//Breakpoint!
|
||||||
val f = 1
|
val f = 1
|
||||||
}
|
}
|
||||||
@@ -17,4 +17,4 @@ fun main(args: Array<String>) {
|
|||||||
// DEBUG_LABEL: e = e-e
|
// DEBUG_LABEL: e = e-e
|
||||||
|
|
||||||
// EXPRESSION: a
|
// EXPRESSION: a
|
||||||
// RESULT: 1: I
|
// RESULT: "1": Ljava/lang/String;
|
||||||
-4
@@ -10,10 +10,6 @@ fun main(args: Array<String>) {
|
|||||||
// DEBUG_LABEL: strArray = strArray
|
// DEBUG_LABEL: strArray = strArray
|
||||||
val strArray = arrayOf("str")
|
val strArray = arrayOf("str")
|
||||||
|
|
||||||
// EXPRESSION: primitive_DebugLabel
|
|
||||||
// RESULT: 1: I
|
|
||||||
// DEBUG_LABEL: primitive = primitive
|
|
||||||
val primitive = 1
|
|
||||||
// EXPRESSION: primitiveArray_DebugLabel
|
// EXPRESSION: primitiveArray_DebugLabel
|
||||||
// RESULT: instance of java.lang.Integer[1] (id=ID): [Ljava/lang/Integer;
|
// RESULT: instance of java.lang.Integer[1] (id=ID): [Ljava/lang/Integer;
|
||||||
// DEBUG_LABEL: primitiveArray = primitiveArray
|
// DEBUG_LABEL: primitiveArray = primitiveArray
|
||||||
|
|||||||
+14
-16
@@ -33,7 +33,6 @@ import com.intellij.openapi.application.ApplicationManager
|
|||||||
import com.intellij.openapi.application.ModalityState
|
import com.intellij.openapi.application.ModalityState
|
||||||
import com.intellij.openapi.util.Disposer
|
import com.intellij.openapi.util.Disposer
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiExpression
|
import com.intellij.psi.PsiExpression
|
||||||
import com.intellij.xdebugger.impl.XDebugSessionImpl
|
import com.intellij.xdebugger.impl.XDebugSessionImpl
|
||||||
import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl
|
import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl
|
||||||
@@ -135,6 +134,8 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
|||||||
doOnBreakpoint {
|
doOnBreakpoint {
|
||||||
val exceptions = linkedMapOf<String, Throwable>()
|
val exceptions = linkedMapOf<String, Throwable>()
|
||||||
try {
|
try {
|
||||||
|
createMarkers(fileText)
|
||||||
|
|
||||||
for ((expression, expected) in expressions) {
|
for ((expression, expected) in expressions) {
|
||||||
mayThrow(exceptions, expression) {
|
mayThrow(exceptions, expression) {
|
||||||
evaluate(expression, CodeFragmentKind.EXPRESSION, expected)
|
evaluate(expression, CodeFragmentKind.EXPRESSION, expected)
|
||||||
@@ -428,30 +429,24 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
|||||||
return mainFile.parentFile?.listFiles()?.filter { it.name.startsWith(mainFileName) && it.name != mainFileName } ?: Collections.emptyList()
|
return mainFile.parentFile?.listFiles()?.filter { it.name.startsWith(mainFileName) && it.name != mainFileName } ?: Collections.emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createContextElement(context: SuspendContextImpl): PsiElement {
|
private fun createMarkers(fileText: String) {
|
||||||
val contextElement = ContextUtil.getContextElement(debuggerContext)!!
|
val labelsAsText = findLinesWithPrefixesRemoved(fileText, "// DEBUG_LABEL: ")
|
||||||
Assert.assertTrue("KotlinCodeFragmentFactory should be accepted for context element otherwise default evaluator will be called. ContextElement = ${contextElement.text}",
|
if (labelsAsText.isEmpty()) return
|
||||||
KotlinCodeFragmentFactory().isContextAccepted(contextElement))
|
|
||||||
|
|
||||||
val labelsAsText = findLinesWithPrefixesRemoved(contextElement.containingFile.text, "// DEBUG_LABEL: ")
|
val markupMap = NodeDescriptorImpl.getMarkupMap(debugProcess)
|
||||||
if (labelsAsText.isEmpty()) return contextElement
|
|
||||||
|
|
||||||
val markupMap = hashMapOf<com.sun.jdi.Value, ValueMarkup>()
|
|
||||||
for (labelAsText in labelsAsText) {
|
for (labelAsText in labelsAsText) {
|
||||||
val labelParts = labelAsText.split("=")
|
val labelParts = labelAsText.split("=")
|
||||||
assert(labelParts.size == 2) { "Wrong format for DEBUG_LABEL directive: // DEBUG_LABEL: {localVariableName} = {labelText}"}
|
assert(labelParts.size == 2) { "Wrong format for DEBUG_LABEL directive: // DEBUG_LABEL: {localVariableName} = {labelText}"}
|
||||||
val localVariableName = labelParts[0].trim()
|
val localVariableName = labelParts[0].trim()
|
||||||
val labelName = labelParts[1].trim()
|
val labelName = labelParts[1].trim()
|
||||||
val localVariable = context.frameProxy!!.visibleVariableByName(localVariableName)
|
val localVariable = debuggerContext.frameProxy!!.visibleVariableByName(localVariableName)
|
||||||
assert(localVariable != null) { "Couldn't find localVariable for label: name = $localVariableName" }
|
assert(localVariable != null) { "Couldn't find localVariable for label: name = $localVariableName" }
|
||||||
val localVariableValue = context.frameProxy!!.getValue(localVariable)
|
val localVariableValue = debuggerContext.frameProxy!!.getValue(localVariable) as? ObjectReference
|
||||||
assert(localVariableValue != null) { "Local variable $localVariableName should be an ObjectReference" }
|
assert(localVariableValue != null) { "Local variable $localVariableName should be an ObjectReference" }
|
||||||
localVariableValue!!
|
localVariableValue!!
|
||||||
markupMap.put(localVariableValue, ValueMarkup(labelName, null, labelName))
|
markupMap?.put(localVariableValue, ValueMarkup(labelName, null, labelName))
|
||||||
}
|
}
|
||||||
|
|
||||||
val (text, labels) = KotlinCodeFragmentFactory.createCodeFragmentForLabeledObjects(contextElement.project, markupMap)
|
|
||||||
return KotlinCodeFragmentFactory().createWrappingContext(text, labels, KotlinCodeFragmentFactory.getContextElement(contextElement), project)!!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun SuspendContextImpl.evaluate(text: String, codeFragmentKind: CodeFragmentKind, expectedResult: String?) {
|
private fun SuspendContextImpl.evaluate(text: String, codeFragmentKind: CodeFragmentKind, expectedResult: String?) {
|
||||||
@@ -461,9 +456,12 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
|||||||
private fun SuspendContextImpl.evaluate(item: TextWithImportsImpl, expectedResult: String?) {
|
private fun SuspendContextImpl.evaluate(item: TextWithImportsImpl, expectedResult: String?) {
|
||||||
runReadAction {
|
runReadAction {
|
||||||
val sourcePosition = ContextUtil.getSourcePosition(this)
|
val sourcePosition = ContextUtil.getSourcePosition(this)
|
||||||
val contextElement = createContextElement(this)
|
|
||||||
|
|
||||||
contextElement.putCopyableUserData(KotlinCodeFragmentFactory.DEBUG_FRAME_FOR_TESTS, this@AbstractKotlinEvaluateExpressionTest.evaluationContext.frameProxy)
|
val contextElement = ContextUtil.getContextElement(debuggerContext)!!
|
||||||
|
Assert.assertTrue("KotlinCodeFragmentFactory should be accepted for context element otherwise default evaluator will be called. ContextElement = ${contextElement.text}",
|
||||||
|
KotlinCodeFragmentFactory().isContextAccepted(contextElement))
|
||||||
|
|
||||||
|
contextElement.putCopyableUserData(KotlinCodeFragmentFactory.DEBUG_CONTEXT_FOR_TESTS, this@AbstractKotlinEvaluateExpressionTest.debuggerContext)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user