Support labels evaluation in debugger
This commit is contained in:
@@ -16,34 +16,51 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.evaluate
|
||||
|
||||
import com.intellij.debugger.engine.evaluation.CodeFragmentFactory
|
||||
import com.intellij.debugger.engine.evaluation.TextWithImports
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.JavaCodeFragment
|
||||
import org.jetbrains.kotlin.idea.JetFileType
|
||||
import org.jetbrains.kotlin.psi.JetExpressionCodeFragment
|
||||
import com.intellij.psi.PsiCodeBlock
|
||||
import com.intellij.debugger.engine.evaluation.CodeFragmentKind
|
||||
import org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.JetBlockCodeFragment
|
||||
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
||||
import com.intellij.debugger.DebuggerManagerEx
|
||||
import org.jetbrains.kotlin.psi.JetCodeFragment
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import com.intellij.util.concurrency.Semaphore
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import com.intellij.debugger.engine.evaluation.CodeFragmentFactory
|
||||
import com.intellij.debugger.engine.evaluation.CodeFragmentKind
|
||||
import com.intellij.debugger.engine.evaluation.TextWithImports
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.JavaCodeFragment
|
||||
import com.intellij.psi.PsiCodeBlock
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.concurrency.Semaphore
|
||||
import com.intellij.xdebugger.XDebuggerManager
|
||||
import com.intellij.xdebugger.impl.XDebugSessionImpl
|
||||
import com.intellij.xdebugger.impl.ui.tree.ValueMarkup
|
||||
import com.sun.jdi.ObjectReference
|
||||
import com.sun.jdi.Value
|
||||
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
||||
import org.jetbrains.kotlin.idea.JetFileType
|
||||
import org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import java.util.HashMap
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
||||
override fun createCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment {
|
||||
val codeFragment = if (item.getKind() == CodeFragmentKind.EXPRESSION) {
|
||||
JetExpressionCodeFragment(project, "fragment.kt", item.getText(), item.getImports(), getContextElement(context))
|
||||
JetExpressionCodeFragment(
|
||||
project,
|
||||
"fragment.kt",
|
||||
item.getText(),
|
||||
item.getImports(),
|
||||
getWrappedContextElement(project, context)
|
||||
)
|
||||
}
|
||||
else {
|
||||
JetBlockCodeFragment(project, "fragment.kt", item.getText(), item.getImports(), getContextElement(context))
|
||||
JetBlockCodeFragment(
|
||||
project,
|
||||
"fragment.kt",
|
||||
item.getText(),
|
||||
item.getImports(),
|
||||
getWrappedContextElement(project, context)
|
||||
)
|
||||
}
|
||||
|
||||
codeFragment.putCopyableUserData(JetCodeFragment.RUNTIME_TYPE_EVALUATOR, {
|
||||
@@ -79,6 +96,9 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
||||
return codeFragment
|
||||
}
|
||||
|
||||
private fun getWrappedContextElement(project: Project, context: PsiElement?)
|
||||
= wrapContextIfNeeded(project, getContextElement(context))
|
||||
|
||||
override fun createPresentationCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment {
|
||||
return createCodeFragment(item, context, project)
|
||||
}
|
||||
@@ -96,6 +116,9 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
||||
override fun getEvaluatorBuilder() = KotlinEvaluationBuilder
|
||||
|
||||
companion object {
|
||||
public val LABEL_VARIABLE_VALUE_KEY: Key<Value> = Key.create<Value>("_label_variable_value_key_")
|
||||
public val DEBUG_LABEL_SUFFIX: String = "_DebugLabel"
|
||||
|
||||
fun getContextElement(elementAt: PsiElement?): PsiElement? {
|
||||
if (elementAt == null) return null
|
||||
|
||||
@@ -107,16 +130,65 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
||||
return getContextElement(elementAt.getOrigin())
|
||||
}
|
||||
|
||||
// If label for some variable is set
|
||||
if (elementAt.getParent() is JetCodeFragment) {
|
||||
return elementAt.getParent().getContext()
|
||||
}
|
||||
|
||||
val expressionAtOffset = PsiTreeUtil.findElementOfClassAtOffset(elementAt.getContainingFile()!!, elementAt.getTextOffset(), javaClass<JetExpression>(), false)
|
||||
if (expressionAtOffset != null) {
|
||||
return expressionAtOffset
|
||||
}
|
||||
return KotlinEditorTextProvider.findExpressionInner(elementAt, true)
|
||||
}
|
||||
|
||||
//internal for tests
|
||||
fun createCodeFragmentForLabeledObjects(markupMap: Map<*, ValueMarkup>): Pair<String, Map<String, ObjectReference>> {
|
||||
val sb = StringBuilder()
|
||||
val labeledObjects = HashMap<String, ObjectReference>()
|
||||
for ((value, markup) in markupMap.entrySet()) {
|
||||
val labelName = markup.getText()
|
||||
if (!Name.isValidIdentifier(labelName)) continue
|
||||
|
||||
val objectRef = value as ObjectReference
|
||||
|
||||
val typeName = value.type().name()
|
||||
val labelNameWithSuffix = labelName + DEBUG_LABEL_SUFFIX
|
||||
sb.append("val ").append(labelNameWithSuffix).append(": ").append(typeName).append("? = null\n")
|
||||
|
||||
labeledObjects.put(labelNameWithSuffix, objectRef)
|
||||
}
|
||||
sb.append("val _debug_context_val = 1")
|
||||
return sb.toString() to labeledObjects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun wrapContextIfNeeded(project: Project, originalContext: PsiElement?): PsiElement? {
|
||||
val session = XDebuggerManager.getInstance(project).getCurrentSession() as? XDebugSessionImpl
|
||||
?: return originalContext
|
||||
|
||||
val markupMap = session.getValueMarkers()?.getAllMarkers()
|
||||
if (markupMap == null || markupMap.isEmpty()) return originalContext
|
||||
|
||||
val (text, labels) = createCodeFragmentForLabeledObjects(markupMap)
|
||||
if (text.isEmpty()) return originalContext
|
||||
|
||||
return createWrappingContext(text, labels, originalContext, project)
|
||||
}
|
||||
|
||||
// internal for test
|
||||
fun createWrappingContext(
|
||||
newFragmentText: String,
|
||||
labels: Map<String, ObjectReference>,
|
||||
originalContext: PsiElement?,
|
||||
project: Project
|
||||
): PsiElement? {
|
||||
val codeFragment = JetPsiFactory(project).createBlockCodeFragment(newFragmentText, originalContext)
|
||||
|
||||
codeFragment.accept(object : JetTreeVisitorVoid() {
|
||||
override fun visitProperty(property: JetProperty) {
|
||||
val reference = labels.get(property.getName())
|
||||
if (reference != null) {
|
||||
property.putUserData(LABEL_VARIABLE_VALUE_KEY, reference)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return getContextElement(codeFragment.findElementAt(codeFragment.getText().length() - 1))
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@ import com.sun.jdi.request.EventRequest
|
||||
import org.jetbrains.eval4j.*
|
||||
import org.jetbrains.eval4j.jdi.JDIEval
|
||||
import org.jetbrains.eval4j.jdi.asJdiValue
|
||||
import org.jetbrains.eval4j.jdi.asValue
|
||||
import org.jetbrains.eval4j.jdi.makeInitialFrame
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
@@ -80,7 +81,7 @@ import org.jetbrains.kotlin.types.Flexibility
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ASM5
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import java.util.Collections
|
||||
import java.util.*
|
||||
|
||||
private val RECEIVER_NAME = "\$receiver"
|
||||
private val THIS_NAME = "this"
|
||||
@@ -176,7 +177,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
if (extractionResult == null) {
|
||||
throw IllegalStateException("Code fragment cannot be extracted to function")
|
||||
}
|
||||
val parametersDescriptor = extractionResult.getParametersForDebugger()
|
||||
val parametersDescriptor = extractionResult.getParametersForDebugger(codeFragment)
|
||||
val extractedFunction = extractionResult.declaration as JetNamedFunction
|
||||
|
||||
val classFileFactory = createClassFileFactory(codeFragment, extractedFunction, context, parametersDescriptor)
|
||||
@@ -287,8 +288,22 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
return jdiValue.asJdiValue(vm, jdiValue.asmType)
|
||||
}
|
||||
|
||||
private fun ExtractionResult.getParametersForDebugger(): ParametersDescriptor {
|
||||
private fun ExtractionResult.getParametersForDebugger(fragment: JetCodeFragment): ParametersDescriptor {
|
||||
return runReadAction {
|
||||
val valuesForLabels = HashMap<String, Value>()
|
||||
|
||||
val contextElementFile = fragment.getContext()?.getContainingFile()
|
||||
if (contextElementFile is JetCodeFragment) {
|
||||
contextElementFile.accept(object: JetTreeVisitorVoid() {
|
||||
override fun visitProperty(property: JetProperty) {
|
||||
val value = property.getUserData(KotlinCodeFragmentFactory.LABEL_VARIABLE_VALUE_KEY)
|
||||
if (value != null) {
|
||||
valuesForLabels.put(property.getName(), value.asValue())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
val parameters = ParametersDescriptor()
|
||||
val receiver = config.descriptor.receiverParameter
|
||||
if (receiver != null) {
|
||||
@@ -301,7 +316,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
param.argumentText.startsWith("::") -> param.argumentText.substring(2)
|
||||
else -> param.argumentText
|
||||
}
|
||||
parameters.add(paramName, param.getParameterType(true))
|
||||
parameters.add(paramName, param.getParameterType(true), valuesForLabels[paramName])
|
||||
}
|
||||
parameters
|
||||
}
|
||||
@@ -310,7 +325,12 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
|
||||
private fun EvaluationContextImpl.getArgumentsForEval4j(parameters: ParametersDescriptor, parameterTypes: Array<Type>): List<Value> {
|
||||
val frameVisitor = FrameVisitor(this)
|
||||
return parameters.zip(parameterTypes).map {
|
||||
frameVisitor.findValue(it.first.callText, it.second, checkType = false, failIfNotFound = true)!!
|
||||
if (it.first.value != null) {
|
||||
it.first.value!!
|
||||
}
|
||||
else {
|
||||
frameVisitor.findValue(it.first.callText, it.second, checkType = false, failIfNotFound = true)!!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-18
@@ -153,6 +153,11 @@ private fun getExpressionToAddDebugExpressionBefore(tmpFile: JetFile, contextEle
|
||||
return CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset
|
||||
}
|
||||
|
||||
val containingFile = contextElement.getContainingFile()
|
||||
if (containingFile is JetCodeFragment) {
|
||||
return getExpressionToAddDebugExpressionBefore(tmpFile, containingFile.getContext(), line)
|
||||
}
|
||||
|
||||
fun shouldStop(el: PsiElement?, p: PsiElement?) = p is JetBlockExpression || el is JetDeclaration
|
||||
|
||||
var elementAt = tmpFile.getElementInCopy(contextElement)
|
||||
@@ -239,28 +244,25 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment
|
||||
|
||||
parent.addBefore(psiFactory.createNewLine(), elementBefore)
|
||||
|
||||
val debugExpression = codeFragment.getContentElement() ?: return emptyList()
|
||||
|
||||
val expressions = ArrayList<JetExpression>()
|
||||
|
||||
fun insertExpression(expr: JetExpression) {
|
||||
val newDebugExpression = parent.addBefore(expr, elementBefore) ?: return
|
||||
|
||||
expressions.add(newDebugExpression as JetExpression)
|
||||
|
||||
parent.addBefore(psiFactory.createNewLine(), elementBefore)
|
||||
}
|
||||
|
||||
when (debugExpression) {
|
||||
is JetBlockExpression -> {
|
||||
for (statement in debugExpression.getStatements()) {
|
||||
insertExpression(statement)
|
||||
fun insertExpression(expr: JetElement?): List<JetExpression> {
|
||||
when (expr) {
|
||||
is JetBlockExpression -> return expr.getStatements().flatMap { insertExpression(it) }
|
||||
is JetExpression -> {
|
||||
val newDebugExpression = parent.addBefore(expr, elementBefore) ?: return emptyList()
|
||||
parent.addBefore(psiFactory.createNewLine(), elementBefore)
|
||||
return listOf(newDebugExpression as JetExpression)
|
||||
}
|
||||
}
|
||||
is JetExpression -> insertExpression(debugExpression)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return expressions
|
||||
val containingFile = codeFragment.getContext()?.getContainingFile()
|
||||
if (containingFile is JetCodeFragment) {
|
||||
insertExpression(containingFile.getContentElement() as? JetExpression)
|
||||
}
|
||||
|
||||
val debugExpression = codeFragment.getContentElement() ?: return emptyList()
|
||||
return insertExpression(debugExpression)
|
||||
}
|
||||
|
||||
private fun replaceByRunFunction(expression: JetExpression): JetCallExpression {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at lCallOnLabeledObj.kt:6
|
||||
!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! lCallOnLabeledObj.LCallOnLabeledObjPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
lCallOnLabeledObj.kt:6
|
||||
Compile bytecode for myClass_DebugLabel.foo()
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,10 @@
|
||||
LineBreakpoint created at lSeveralLabels.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! lSeveralLabels.LSeveralLabelsPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
lSeveralLabels.kt:8
|
||||
Compile bytecode for a_DebugLabel
|
||||
Compile bytecode for b_DebugLabel
|
||||
Compile bytecode for c_DebugLabel
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at lSimple.kt:6
|
||||
!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! lSimple.LSimplePackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
lSimple.kt:6
|
||||
Compile bytecode for a
|
||||
Compile bytecode for aLabel_DebugLabel
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package lCallOnLabeledObj
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val myClass = MyClass()
|
||||
//Breakpoint!
|
||||
val a = 1
|
||||
}
|
||||
|
||||
class MyClass {
|
||||
fun foo() = 1
|
||||
}
|
||||
|
||||
// DEBUG_LABEL: myClass = myClass
|
||||
|
||||
// EXPRESSION: myClass_DebugLabel.foo()
|
||||
// RESULT: 1: I
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package lSeveralLabels
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = "str1"
|
||||
val b = "str2"
|
||||
val c = "str3"
|
||||
//Breakpoint!
|
||||
val d = 1
|
||||
}
|
||||
|
||||
// DEBUG_LABEL: a = a
|
||||
// DEBUG_LABEL: b = b
|
||||
// DEBUG_LABEL: c = c
|
||||
|
||||
// EXPRESSION: a_DebugLabel
|
||||
// RESULT: "str1": Ljava/lang/String;
|
||||
|
||||
// EXPRESSION: b_DebugLabel
|
||||
// RESULT: "str2": Ljava/lang/String;
|
||||
|
||||
// EXPRESSION: c_DebugLabel
|
||||
// RESULT: "str3": Ljava/lang/String;
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package lSimple
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = "str"
|
||||
//Breakpoint!
|
||||
val b = 1
|
||||
}
|
||||
|
||||
// DEBUG_LABEL: a = aLabel
|
||||
|
||||
// EXPRESSION: a
|
||||
// RESULT: "str": Ljava/lang/String;
|
||||
|
||||
// EXPRESSION: aLabel_DebugLabel
|
||||
// RESULT: "str": Ljava/lang/String;
|
||||
+33
-9
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.evaluate
|
||||
|
||||
import com.intellij.debugger.DebuggerInvocationUtil
|
||||
import com.intellij.debugger.DebuggerManagerEx
|
||||
import com.intellij.debugger.SourcePosition
|
||||
import com.intellij.debugger.engine.ContextUtil
|
||||
import com.intellij.debugger.engine.SourcePositionProvider
|
||||
@@ -35,13 +33,11 @@ import com.intellij.debugger.ui.tree.LocalVariableDescriptor
|
||||
import com.intellij.debugger.ui.tree.StackFrameDescriptor
|
||||
import com.intellij.debugger.ui.tree.StaticDescriptor
|
||||
import com.intellij.execution.process.ProcessOutputTypes
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.search.FilenameIndex
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants
|
||||
import com.intellij.xdebugger.impl.ui.tree.ValueMarkup
|
||||
import com.sun.jdi.ObjectReference
|
||||
import org.apache.log4j.AppenderSkeleton
|
||||
import org.apache.log4j.Level
|
||||
@@ -58,6 +54,7 @@ import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
import java.util.Collections
|
||||
import kotlin.test.fail
|
||||
|
||||
public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
||||
private val logger = Logger.getLogger(javaClass<KotlinEvaluateExpressionCache>())!!
|
||||
@@ -278,12 +275,39 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
|
||||
return mainFile.getParentFile()?.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.getText()}",
|
||||
KotlinCodeFragmentFactory().isContextAccepted(contextElement))
|
||||
|
||||
if (contextElement != null) {
|
||||
val labelsAsText = InTextDirectivesUtils.findLinesWithPrefixesRemoved(contextElement.getContainingFile().getText(), "// DEBUG_LABEL: ")
|
||||
if (labelsAsText.isEmpty()) return contextElement
|
||||
|
||||
val markupMap = hashMapOf<ObjectReference, ValueMarkup>()
|
||||
for (labelAsText in labelsAsText) {
|
||||
val labelParts = labelAsText.splitBy("=")
|
||||
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.getFrameProxy().visibleVariableByName(localVariableName)
|
||||
assert(localVariable != null) { "Couldn't find localVariable for label: name = $localVariableName" }
|
||||
val localVariableValue = context.getFrameProxy().getValue(localVariable) as? ObjectReference
|
||||
assert(localVariableValue != null) { "Local variable $localVariableName should be an ObjectReference" }
|
||||
markupMap.put(localVariableValue, ValueMarkup(labelName, null, labelName))
|
||||
}
|
||||
|
||||
val (text, labels) = KotlinCodeFragmentFactory.createCodeFragmentForLabeledObjects(markupMap)
|
||||
return KotlinCodeFragmentFactory().createWrappingContext(text, labels, KotlinCodeFragmentFactory.getContextElement(contextElement), getProject())!!
|
||||
}
|
||||
|
||||
return contextElement!!
|
||||
}
|
||||
|
||||
private fun SuspendContextImpl.evaluate(text: String, codeFragmentKind: CodeFragmentKind, expectedResult: String) {
|
||||
runReadAction {
|
||||
val sourcePosition = ContextUtil.getSourcePosition(this)
|
||||
val contextElement = ContextUtil.getContextElement(sourcePosition)!!
|
||||
Assert.assertTrue("KotlinCodeFragmentFactory should be accepted for context element otherwise default evaluator will be called. ContextElement = ${contextElement.getText()}",
|
||||
KotlinCodeFragmentFactory().isContextAccepted(contextElement))
|
||||
val contextElement = createContextElement(this)
|
||||
|
||||
try {
|
||||
|
||||
|
||||
+27
@@ -526,6 +526,33 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/labels")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Labels extends AbstractKotlinEvaluateExpressionTest {
|
||||
public void testAllFilesPresentInLabels() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/labels"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("lCallOnLabeledObj.kt")
|
||||
public void testLCallOnLabeledObj() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/labels/lCallOnLabeledObj.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lSeveralLabels.kt")
|
||||
public void testLSeveralLabels() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/labels/lSeveralLabels.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lSimple.kt")
|
||||
public void testLSimple() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/labels/lSimple.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user