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.CodeFragmentKind
|
||||
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.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.project.Project
|
||||
@@ -141,7 +143,7 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
||||
}
|
||||
|
||||
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 {
|
||||
val kotlinCodeFragment = createCodeFragment(item, context, project)
|
||||
@@ -202,7 +204,7 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
||||
companion object {
|
||||
val LABEL_VARIABLE_VALUE_KEY: Key<Value> = Key.create<Value>("_label_variable_value_key_")
|
||||
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? {
|
||||
if (elementAt == null) return null
|
||||
@@ -283,17 +285,19 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun wrapContextIfNeeded(project: Project, originalContext: KtElement?): KtElement? {
|
||||
val session = XDebuggerManager.getInstance(project).currentSession as? XDebugSessionImpl
|
||||
?: return originalContext
|
||||
private fun wrapContextIfNeeded(project: Project, originalContext: PsiElement?, newContext: KtElement?): KtElement? {
|
||||
val markupMap: Map<*, ValueMarkup>? =
|
||||
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 originalContext
|
||||
if (markupMap == null || markupMap.isEmpty()) return newContext
|
||||
|
||||
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
|
||||
|
||||
+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
|
||||
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 strArray_DebugLabel
|
||||
Compile bytecode for primitive_DebugLabel
|
||||
Compile bytecode for primitiveArray_DebugLabel
|
||||
Compile bytecode for localObj_DebugLabel
|
||||
Compile bytecode for localObjArray_DebugLabel
|
||||
|
||||
+6
-6
@@ -1,11 +1,11 @@
|
||||
package lIdentifier
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = 1
|
||||
val b = 1
|
||||
val c = 1
|
||||
val d = 1
|
||||
val e = 1
|
||||
val a = "1"
|
||||
val b = "1"
|
||||
val c = "1"
|
||||
val d = "1"
|
||||
val e = "1"
|
||||
//Breakpoint!
|
||||
val f = 1
|
||||
}
|
||||
@@ -17,4 +17,4 @@ fun main(args: Array<String>) {
|
||||
// DEBUG_LABEL: e = e-e
|
||||
|
||||
// EXPRESSION: a
|
||||
// RESULT: 1: I
|
||||
// RESULT: "1": Ljava/lang/String;
|
||||
-4
@@ -10,10 +10,6 @@ fun main(args: Array<String>) {
|
||||
// DEBUG_LABEL: strArray = strArray
|
||||
val strArray = arrayOf("str")
|
||||
|
||||
// EXPRESSION: primitive_DebugLabel
|
||||
// RESULT: 1: I
|
||||
// DEBUG_LABEL: primitive = primitive
|
||||
val primitive = 1
|
||||
// EXPRESSION: primitiveArray_DebugLabel
|
||||
// RESULT: instance of java.lang.Integer[1] (id=ID): [Ljava/lang/Integer;
|
||||
// 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.util.Disposer
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiExpression
|
||||
import com.intellij.xdebugger.impl.XDebugSessionImpl
|
||||
import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl
|
||||
@@ -135,6 +134,8 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
||||
doOnBreakpoint {
|
||||
val exceptions = linkedMapOf<String, Throwable>()
|
||||
try {
|
||||
createMarkers(fileText)
|
||||
|
||||
for ((expression, expected) in expressions) {
|
||||
mayThrow(exceptions, expression) {
|
||||
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()
|
||||
}
|
||||
|
||||
private fun createContextElement(context: SuspendContextImpl): PsiElement {
|
||||
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))
|
||||
private fun createMarkers(fileText: String) {
|
||||
val labelsAsText = findLinesWithPrefixesRemoved(fileText, "// DEBUG_LABEL: ")
|
||||
if (labelsAsText.isEmpty()) return
|
||||
|
||||
val labelsAsText = findLinesWithPrefixesRemoved(contextElement.containingFile.text, "// DEBUG_LABEL: ")
|
||||
if (labelsAsText.isEmpty()) return contextElement
|
||||
val markupMap = NodeDescriptorImpl.getMarkupMap(debugProcess)
|
||||
|
||||
val markupMap = hashMapOf<com.sun.jdi.Value, ValueMarkup>()
|
||||
for (labelAsText in labelsAsText) {
|
||||
val labelParts = labelAsText.split("=")
|
||||
assert(labelParts.size == 2) { "Wrong format for DEBUG_LABEL directive: // DEBUG_LABEL: {localVariableName} = {labelText}"}
|
||||
val localVariableName = labelParts[0].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" }
|
||||
val localVariableValue = context.frameProxy!!.getValue(localVariable)
|
||||
val localVariableValue = debuggerContext.frameProxy!!.getValue(localVariable) as? ObjectReference
|
||||
assert(localVariableValue != null) { "Local variable $localVariableName should be an ObjectReference" }
|
||||
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?) {
|
||||
@@ -461,9 +456,12 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
||||
private fun SuspendContextImpl.evaluate(item: TextWithImportsImpl, expectedResult: String?) {
|
||||
runReadAction {
|
||||
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 {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user