Support labels evaluation in debugger

This commit is contained in:
Natalia Ukhorskaya
2015-06-17 12:19:26 +03:00
parent 0f108eee2f
commit 8bb33f0df5
12 changed files with 283 additions and 58 deletions
@@ -16,34 +16,51 @@
package org.jetbrains.kotlin.idea.debugger.evaluate 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 com.intellij.debugger.DebuggerManagerEx
import org.jetbrains.kotlin.psi.JetCodeFragment import com.intellij.debugger.engine.evaluation.CodeFragmentFactory
import org.jetbrains.kotlin.types.JetType import com.intellij.debugger.engine.evaluation.CodeFragmentKind
import com.intellij.util.concurrency.Semaphore import com.intellij.debugger.engine.evaluation.TextWithImports
import java.util.concurrent.atomic.AtomicReference
import com.intellij.openapi.progress.ProgressManager 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() { class KotlinCodeFragmentFactory: CodeFragmentFactory() {
override fun createCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment { override fun createCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment {
val codeFragment = if (item.getKind() == CodeFragmentKind.EXPRESSION) { 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 { 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, { codeFragment.putCopyableUserData(JetCodeFragment.RUNTIME_TYPE_EVALUATOR, {
@@ -79,6 +96,9 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
return codeFragment return codeFragment
} }
private fun getWrappedContextElement(project: Project, context: PsiElement?)
= wrapContextIfNeeded(project, getContextElement(context))
override fun createPresentationCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment { override fun createPresentationCodeFragment(item: TextWithImports, context: PsiElement?, project: Project): JavaCodeFragment {
return createCodeFragment(item, context, project) return createCodeFragment(item, context, project)
} }
@@ -96,6 +116,9 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
override fun getEvaluatorBuilder() = KotlinEvaluationBuilder override fun getEvaluatorBuilder() = KotlinEvaluationBuilder
companion object { 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? { fun getContextElement(elementAt: PsiElement?): PsiElement? {
if (elementAt == null) return null if (elementAt == null) return null
@@ -107,16 +130,65 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
return getContextElement(elementAt.getOrigin()) 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) val expressionAtOffset = PsiTreeUtil.findElementOfClassAtOffset(elementAt.getContainingFile()!!, elementAt.getTextOffset(), javaClass<JetExpression>(), false)
if (expressionAtOffset != null) { if (expressionAtOffset != null) {
return expressionAtOffset return expressionAtOffset
} }
return KotlinEditorTextProvider.findExpressionInner(elementAt, true) 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.*
import org.jetbrains.eval4j.jdi.JDIEval import org.jetbrains.eval4j.jdi.JDIEval
import org.jetbrains.eval4j.jdi.asJdiValue import org.jetbrains.eval4j.jdi.asJdiValue
import org.jetbrains.eval4j.jdi.asValue
import org.jetbrains.eval4j.jdi.makeInitialFrame import org.jetbrains.eval4j.jdi.makeInitialFrame
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding 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.*
import org.jetbrains.org.objectweb.asm.Opcodes.ASM5 import org.jetbrains.org.objectweb.asm.Opcodes.ASM5
import org.jetbrains.org.objectweb.asm.tree.MethodNode import org.jetbrains.org.objectweb.asm.tree.MethodNode
import java.util.Collections import java.util.*
private val RECEIVER_NAME = "\$receiver" private val RECEIVER_NAME = "\$receiver"
private val THIS_NAME = "this" private val THIS_NAME = "this"
@@ -176,7 +177,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
if (extractionResult == null) { if (extractionResult == null) {
throw IllegalStateException("Code fragment cannot be extracted to function") 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 extractedFunction = extractionResult.declaration as JetNamedFunction
val classFileFactory = createClassFileFactory(codeFragment, extractedFunction, context, parametersDescriptor) val classFileFactory = createClassFileFactory(codeFragment, extractedFunction, context, parametersDescriptor)
@@ -287,8 +288,22 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
return jdiValue.asJdiValue(vm, jdiValue.asmType) return jdiValue.asJdiValue(vm, jdiValue.asmType)
} }
private fun ExtractionResult.getParametersForDebugger(): ParametersDescriptor { private fun ExtractionResult.getParametersForDebugger(fragment: JetCodeFragment): ParametersDescriptor {
return runReadAction { 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 parameters = ParametersDescriptor()
val receiver = config.descriptor.receiverParameter val receiver = config.descriptor.receiverParameter
if (receiver != null) { if (receiver != null) {
@@ -301,7 +316,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
param.argumentText.startsWith("::") -> param.argumentText.substring(2) param.argumentText.startsWith("::") -> param.argumentText.substring(2)
else -> param.argumentText else -> param.argumentText
} }
parameters.add(paramName, param.getParameterType(true)) parameters.add(paramName, param.getParameterType(true), valuesForLabels[paramName])
} }
parameters parameters
} }
@@ -310,7 +325,12 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
private fun EvaluationContextImpl.getArgumentsForEval4j(parameters: ParametersDescriptor, parameterTypes: Array<Type>): List<Value> { private fun EvaluationContextImpl.getArgumentsForEval4j(parameters: ParametersDescriptor, parameterTypes: Array<Type>): List<Value> {
val frameVisitor = FrameVisitor(this) val frameVisitor = FrameVisitor(this)
return parameters.zip(parameterTypes).map { 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)!!
}
} }
} }
@@ -153,6 +153,11 @@ private fun getExpressionToAddDebugExpressionBefore(tmpFile: JetFile, contextEle
return CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset 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 fun shouldStop(el: PsiElement?, p: PsiElement?) = p is JetBlockExpression || el is JetDeclaration
var elementAt = tmpFile.getElementInCopy(contextElement) var elementAt = tmpFile.getElementInCopy(contextElement)
@@ -239,28 +244,25 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment
parent.addBefore(psiFactory.createNewLine(), elementBefore) parent.addBefore(psiFactory.createNewLine(), elementBefore)
val debugExpression = codeFragment.getContentElement() ?: return emptyList() fun insertExpression(expr: JetElement?): List<JetExpression> {
when (expr) {
val expressions = ArrayList<JetExpression>() is JetBlockExpression -> return expr.getStatements().flatMap { insertExpression(it) }
is JetExpression -> {
fun insertExpression(expr: JetExpression) { val newDebugExpression = parent.addBefore(expr, elementBefore) ?: return emptyList()
val newDebugExpression = parent.addBefore(expr, elementBefore) ?: return parent.addBefore(psiFactory.createNewLine(), elementBefore)
return listOf(newDebugExpression as JetExpression)
expressions.add(newDebugExpression as JetExpression)
parent.addBefore(psiFactory.createNewLine(), elementBefore)
}
when (debugExpression) {
is JetBlockExpression -> {
for (statement in debugExpression.getStatements()) {
insertExpression(statement)
} }
} }
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 { 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
+10
View File
@@ -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
+9
View File
@@ -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
@@ -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
@@ -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;
@@ -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;
@@ -16,8 +16,6 @@
package org.jetbrains.kotlin.idea.debugger.evaluate 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.SourcePosition
import com.intellij.debugger.engine.ContextUtil import com.intellij.debugger.engine.ContextUtil
import com.intellij.debugger.engine.SourcePositionProvider 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.StackFrameDescriptor
import com.intellij.debugger.ui.tree.StaticDescriptor import com.intellij.debugger.ui.tree.StaticDescriptor
import com.intellij.execution.process.ProcessOutputTypes import com.intellij.execution.process.ProcessOutputTypes
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.PsiDocumentManager import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.search.FilenameIndex
import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants
import com.intellij.xdebugger.impl.ui.tree.ValueMarkup
import com.sun.jdi.ObjectReference import com.sun.jdi.ObjectReference
import org.apache.log4j.AppenderSkeleton import org.apache.log4j.AppenderSkeleton
import org.apache.log4j.Level import org.apache.log4j.Level
@@ -58,6 +54,7 @@ import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.junit.Assert import org.junit.Assert
import java.io.File import java.io.File
import java.util.Collections import java.util.Collections
import kotlin.test.fail
public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() { public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
private val logger = Logger.getLogger(javaClass<KotlinEvaluateExpressionCache>())!! 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() 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) { private fun SuspendContextImpl.evaluate(text: String, codeFragmentKind: CodeFragmentKind, expectedResult: String) {
runReadAction { runReadAction {
val sourcePosition = ContextUtil.getSourcePosition(this) val sourcePosition = ContextUtil.getSourcePosition(this)
val contextElement = ContextUtil.getContextElement(sourcePosition)!! val contextElement = createContextElement(this)
Assert.assertTrue("KotlinCodeFragmentFactory should be accepted for context element otherwise default evaluator will be called. ContextElement = ${contextElement.getText()}",
KotlinCodeFragmentFactory().isContextAccepted(contextElement))
try { try {
@@ -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") @TestMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)