From 2ffcc5124ed9aecab24b283e353aef18d1df5d3a Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Tue, 15 Apr 2014 14:12:02 +0400 Subject: [PATCH] Debugger: use extract method to get function arguments --- .../debugger/engine/jdi/annotations.xml | 5 + .../plugin/codeInsight/CodeInsightUtils.java | 30 +++- .../debugger/KotlinSmartStepIntoHandler.kt | 21 ++- .../evaluate/KotlinEvaluationBuilder.kt | 138 +++++++++++++++--- .../debugger/tinyApp/outs/classObjectVal.out | 7 + idea/testData/debugger/tinyApp/outs/enums.out | 7 + .../tinyApp/outs/extractLocalVariables.out | 7 + .../debugger/tinyApp/outs/extractThis.out | 7 + .../tinyApp/outs/extractVariablesFromCall.out | 7 + .../outs/multilineExpressionAtBreakpoint.out | 7 + idea/testData/debugger/tinyApp/outs/vars.out | 7 + .../debugger/tinyApp/src/evaluate/arrays.kt | 8 +- .../tinyApp/src/evaluate/classObjectVal.kt | 22 +++ .../tinyApp/src/evaluate/collections.kt | 32 ++-- .../tinyApp/src/evaluate/dependentOnFile.kt | 2 +- .../debugger/tinyApp/src/evaluate/enums.kt | 13 ++ .../src/evaluate/extractLocalVariables.kt | 25 ++++ .../tinyApp/src/evaluate/extractThis.kt | 20 +++ .../src/evaluate/extractVariablesFromCall.kt | 28 ++++ .../debugger/tinyApp/src/evaluate/imports.kt | 8 +- .../multilineExpressionAtBreakpoint.kt | 11 ++ .../debugger/tinyApp/src/evaluate/stdlib.kt | 10 +- .../debugger/tinyApp/src/evaluate/vars.kt | 17 +++ .../AbstractKotlinEvaluateExpressionTest.kt | 12 +- ...KotlinEvaluateExpressionTestGenerated.java | 35 +++++ 25 files changed, 422 insertions(+), 64 deletions(-) create mode 100644 annotations/com/intellij/debugger/engine/jdi/annotations.xml create mode 100644 idea/testData/debugger/tinyApp/outs/classObjectVal.out create mode 100644 idea/testData/debugger/tinyApp/outs/enums.out create mode 100644 idea/testData/debugger/tinyApp/outs/extractLocalVariables.out create mode 100644 idea/testData/debugger/tinyApp/outs/extractThis.out create mode 100644 idea/testData/debugger/tinyApp/outs/extractVariablesFromCall.out create mode 100644 idea/testData/debugger/tinyApp/outs/multilineExpressionAtBreakpoint.out create mode 100644 idea/testData/debugger/tinyApp/outs/vars.out create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/classObjectVal.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/enums.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/extractLocalVariables.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/extractThis.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/extractVariablesFromCall.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/multilineExpressionAtBreakpoint.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/vars.kt diff --git a/annotations/com/intellij/debugger/engine/jdi/annotations.xml b/annotations/com/intellij/debugger/engine/jdi/annotations.xml new file mode 100644 index 00000000000..98db9537421 --- /dev/null +++ b/annotations/com/intellij/debugger/engine/jdi/annotations.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/CodeInsightUtils.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/CodeInsightUtils.java index 5bd877608b2..f0b6d8ed2b6 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/CodeInsightUtils.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/CodeInsightUtils.java @@ -1,15 +1,14 @@ package org.jetbrains.jet.plugin.codeInsight; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiComment; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.refactoring.util.CommonRefactoringUtil; +import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; @@ -188,4 +187,27 @@ public class CodeInsightUtils { DescriptorRenderer renderer = shortTypeNames ? DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES : DescriptorRenderer.SOURCE_CODE; return renderer.render(descriptor); } + + @Nullable + public static Integer getStartLineOffset(@NotNull PsiFile file, int line) { + Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); + if (document == null) return null; + + int lineStartOffset = document.getLineStartOffset(line); + return CharArrayUtil.shiftForward(document.getCharsSequence(), lineStartOffset, " \t"); + } + + @Nullable + public static PsiElement getTopmostElementAtOffset(@NotNull PsiElement element, int offset) { + do { + PsiElement parent = element.getParent(); + if (parent == null || (parent.getTextOffset() < offset)) { + break; + } + element = parent; + } + while(true); + + return element; + } } diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/KotlinSmartStepIntoHandler.kt b/idea/src/org/jetbrains/jet/plugin/debugger/KotlinSmartStepIntoHandler.kt index 5eb15cbcb49..a22cf3bc24e 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/KotlinSmartStepIntoHandler.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/KotlinSmartStepIntoHandler.kt @@ -40,6 +40,8 @@ import com.sun.jdi.Location import com.intellij.psi.PsiMethod import com.intellij.psi.PsiFile import com.intellij.openapi.editor.Editor +import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils +import com.intellij.psi.PsiDocumentManager public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() { @@ -49,27 +51,22 @@ public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() { if (position.getLine() < 0) return Collections.emptyList() val file = position.getFile() - val vFile = file.getVirtualFile() - if (vFile == null) return Collections.emptyList() - val doc = FileDocumentManager.getInstance()?.getDocument(vFile) - if (doc == null) return Collections.emptyList() + val lineStart = CodeInsightUtils.getStartLineOffset(file, position.getLine()) + if (lineStart == null) return Collections.emptyList() - val line = position.getLine() - if (line >= doc.getLineCount()) return Collections.emptyList() - - val lineStartOffset = doc.getLineStartOffset(line) - val offsetWithoutTab = CharArrayUtil.shiftForward(doc.getCharsSequence(), lineStartOffset, " \t") - val elementAtOffset = file.findElementAt(offsetWithoutTab) + val elementAtOffset = file.findElementAt(lineStart) if (elementAtOffset == null) return Collections.emptyList() - val element = getTopmostElementAtOffset(elementAtOffset, lineStartOffset) - + val element = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) if (element !is JetElement) return Collections.emptyList() val elementTextRange = element.getTextRange() if (elementTextRange == null) return Collections.emptyList() + val doc = PsiDocumentManager.getInstance(file.getProject()).getDocument(file) + if (doc == null) return Collections.emptyList() + val lines = Range(doc.getLineNumber(elementTextRange.getStartOffset()), doc.getLineNumber(elementTextRange.getEndOffset())) val bindingContext = AnalyzerFacadeWithCache.getContextForElement(element) val result = OrderedSet() diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt index 1375025d76d..bf2bb0e7794 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -45,6 +45,23 @@ import org.jetbrains.jet.lang.resolve.java.PackageClassUtils import org.jetbrains.jet.lang.resolve.name.FqName import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache import org.jetbrains.jet.plugin.debugger.KotlinEditorTextProvider +import org.jetbrains.jet.lang.psi.JetPsiFactory +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.eval4j.jdi.asValue +import org.jetbrains.jet.plugin.refactoring.createTempCopy +import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionData +import org.jetbrains.jet.plugin.refactoring.extractFunction.performAnalysis +import org.jetbrains.jet.plugin.util.MaybeError +import org.jetbrains.jet.plugin.util.MaybeValue +import org.jetbrains.jet.plugin.refactoring.extractFunction.validate +import org.jetbrains.jet.plugin.refactoring.checkConflictsInteractively +import org.jetbrains.jet.plugin.refactoring.extractFunction.generateFunction +import org.jetbrains.jet.lang.psi.JetElement +import com.intellij.util.text.CharArrayUtil +import org.jetbrains.jet.lang.psi.JetNamedFunction +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiFile +import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils import org.jetbrains.jet.OutputFileCollection import org.jetbrains.jet.lang.psi.JetExpressionCodeFragment import org.jetbrains.jet.lang.psi.JetExpressionCodeFragmentImpl @@ -52,11 +69,11 @@ import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults object KotlinEvaluationBuilder: EvaluatorBuilder { override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator { - if (codeFragment !is JetExpressionCodeFragment) { + if (codeFragment !is JetExpressionCodeFragment || position == null) { return EvaluatorBuilderImpl.getInstance()!!.build(codeFragment, position) } - val elementAt = position?.getElementAt() + val elementAt = position.getElementAt() if (elementAt != null) { codeFragment.addImportsFromString(KotlinEditorTextProvider.getImports(elementAt)) @@ -65,11 +82,13 @@ object KotlinEvaluationBuilder: EvaluatorBuilder { codeFragment.addImportsFromString("import $packageName.*") } } - return ExpressionEvaluatorImpl(KotlinEvaluator(codeFragment)) + return ExpressionEvaluatorImpl(KotlinEvaluator(codeFragment, position)) } } -class KotlinEvaluator(val codeFragment: PsiElement) : Evaluator { +class KotlinEvaluator(val codeFragment: PsiElement, + val sourcePosition: SourcePosition +) : Evaluator { override fun evaluate(context: EvaluationContextImpl): Any? { return ApplicationManager.getApplication()?.runReadAction(object: Computable { override fun compute(): Any? { @@ -77,7 +96,12 @@ class KotlinEvaluator(val codeFragment: PsiElement) : Evaluator { throw AssertionError("KotlinEvaluator should be invoke only for KotlinCodeFragment") } - val file = createFileForDebugger(codeFragment) + val extractedFunction = getFunctionForExtractedFragment(codeFragment, sourcePosition.getFile(), sourcePosition.getLine()) + if (extractedFunction == null) { + exception("This code fragment cannot be extracted to function") + } + + val file = createFileForDebugger(codeFragment, extractedFunction) val analyzeExhaust = file.getAnalysisResults() val bindingContext = analyzeExhaust.getBindingContext() @@ -111,12 +135,12 @@ class KotlinEvaluator(val codeFragment: PsiElement) : Evaluator { ClassReader(outputFiles.first().asByteArray()).accept(object : ClassVisitor(ASM5) { override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor? { - if (name == "debugFun") { + if (name == extractedFunction.getName()) { return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) { override fun visitEnd() { val value = interpreterLoop( this, - makeInitialFrame(this, listOf()), + makeInitialFrame(this, context.getArgumentsByNames(extractedFunction.getParameterNamesForDebugger())), JDIEval(virtualMachine, context.getClassLoader()!!, context.getSuspendContext().getThread()?.getThreadReference()!!) @@ -146,6 +170,39 @@ class KotlinEvaluator(val codeFragment: PsiElement) : Evaluator { return null } + private fun JetNamedFunction.getParameterNamesForDebugger(): List { + val result = arrayListOf() + for (param in getValueParameters()) { + result.add(param.getName()!!) + } + if (getReceiverTypeRef() != null) { + result.add("this") + } + return result + } + + private fun EvaluationContextImpl.getArgumentsByNames(parameterNames: List): List { + val frames = getFrameProxy()?.getStackFrame() + if (frames != null) { + try { + return parameterNames.map { + name -> + if (name == "this") { + frames.thisObject().asValue() + } + else { + frames.getValue(frames.visibleVariableByName(name)).asValue() + } + } + } + catch(e: Throwable) { + throw IllegalArgumentException( + "Cannot get parameter values from VirtualMachine: ${e.javaClass}\nFunction parameters:\n${parameterNames.makeString("\n")}\nVisible variables:\n${frames.visibleVariables().makeString("\n")}") + } + } + return Collections.emptyList() + } + private fun exception(msg: String) = throw EvaluateExceptionUtil.createEvaluateException(msg) } @@ -154,22 +211,69 @@ package packageForDebugger !IMPORT_LIST! -fun debugFun() = run { - !EXPRESSION! -} +!FUNCTION! """ private val packageInternalName = PackageClassUtils.getPackageClassFqName(FqName("packageForDebugger")).asString().replace(".", "/") -private fun createFileForDebugger(codeFragment: JetExpressionCodeFragment): JetFile { - var fileText = template.replace("!EXPRESSION!", codeFragment.getText()) - fileText = fileText.replace("!IMPORT_LIST!", - codeFragment.importsToString() - .split(JetExpressionCodeFragmentImpl.IMPORT_SEPARATOR) - .makeString("\n")) +private fun createFileForDebugger(codeFragment: JetExpressionCodeFragment, + extractedFunction: JetNamedFunction +): JetFile { + var fileText = template.replace("!IMPORT_LIST!", + codeFragment.importsToString() + .split(JetExpressionCodeFragmentImpl.IMPORT_SEPARATOR) + .makeString("\n")) + + fileText = fileText.replace("!FUNCTION!", extractedFunction.getText()) val virtualFile = LightVirtualFile("debugFile.kt", JetLanguage.INSTANCE, fileText) virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET) return (PsiFileFactory.getInstance(codeFragment.getProject()) as PsiFileFactoryImpl) - .trySetupPsiForFile(virtualFile, JetLanguage.INSTANCE, true, false) as JetFile + .trySetupPsiForFile(virtualFile, JetLanguage.INSTANCE, true, false) as JetFile } + +private fun getFunctionForExtractedFragment( + codeFragment: PsiElement, + breakpointFile: PsiFile, + breakpointLine: Int +): JetNamedFunction? { + val project = codeFragment.getProject() + + val originalFile = breakpointFile as JetFile + + val lineStart = CodeInsightUtils.getStartLineOffset(originalFile, breakpointLine) + if (lineStart == null) return null + + val tmpFile = originalFile.createTempCopy { it } + val elementAtOffset = tmpFile.findElementAt(lineStart) + if (elementAtOffset == null) return null + + val element: PsiElement = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset + + val debugExpression = JetPsiFactory.createExpression(project, codeFragment.getText()) + + val parent = element.getParent() + if (parent == null) return null + + parent.addBefore(JetPsiFactory.createNewLine(project), element) + val newDebugExpression = parent.addBefore(debugExpression, element) + if (newDebugExpression == null) return null + + parent.addBefore(JetPsiFactory.createNewLine(project), element) + + val nextSibling = tmpFile.getDeclarations().firstOrNull() + if (nextSibling == null) return null + + val analysisResult = ExtractionData(tmpFile, Collections.singletonList(newDebugExpression), nextSibling).performAnalysis() + if (analysisResult is MaybeError) { + throw EvaluateExceptionUtil.createEvaluateException(analysisResult.error) + } + + val validationResult = (analysisResult as MaybeValue).value.validate() + if (!validationResult.conflicts.isEmpty()) { + throw EvaluateExceptionUtil.createEvaluateException("Some declarations are unavailable") + } + + return validationResult.descriptor.generateFunction(true) +} + diff --git a/idea/testData/debugger/tinyApp/outs/classObjectVal.out b/idea/testData/debugger/tinyApp/outs/classObjectVal.out new file mode 100644 index 00000000000..67eb6a81afc --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/classObjectVal.out @@ -0,0 +1,7 @@ +LineBreakpoint created at classObjectVal.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!;!RT_JAR! classObjectVal.ClassObjectValPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +classObjectVal.kt:9 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/enums.out b/idea/testData/debugger/tinyApp/outs/enums.out new file mode 100644 index 00000000000..1c98f3af07a --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/enums.out @@ -0,0 +1,7 @@ +LineBreakpoint created at enums.kt:7 +!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!;!RT_JAR! enums.EnumsPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +enums.kt:6 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/extractLocalVariables.out b/idea/testData/debugger/tinyApp/outs/extractLocalVariables.out new file mode 100644 index 00000000000..fca8952e6a5 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/extractLocalVariables.out @@ -0,0 +1,7 @@ +LineBreakpoint created at extractLocalVariables.kt:7 +!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!;!RT_JAR! extractLocalVariables.ExtractLocalVariablesPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +extractLocalVariables.kt:6 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/extractThis.out b/idea/testData/debugger/tinyApp/outs/extractThis.out new file mode 100644 index 00000000000..f337859bcc6 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/extractThis.out @@ -0,0 +1,7 @@ +LineBreakpoint created at extractThis.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!;!RT_JAR! extractThis.ExtractThisPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +extractThis.kt:11 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/extractVariablesFromCall.out b/idea/testData/debugger/tinyApp/outs/extractVariablesFromCall.out new file mode 100644 index 00000000000..ac9998a6ba8 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/extractVariablesFromCall.out @@ -0,0 +1,7 @@ +LineBreakpoint created at extractVariablesFromCall.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!;!RT_JAR! extractVariablesFromCall.ExtractVariablesFromCallPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +extractVariablesFromCall.kt:7 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/multilineExpressionAtBreakpoint.out b/idea/testData/debugger/tinyApp/outs/multilineExpressionAtBreakpoint.out new file mode 100644 index 00000000000..03b028c046d --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/multilineExpressionAtBreakpoint.out @@ -0,0 +1,7 @@ +LineBreakpoint created at multilineExpressionAtBreakpoint.kt:5 +!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!;!RT_JAR! multilineExpressionAtBreakpoint.MultilineExpressionAtBreakpointPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +multilineExpressionAtBreakpoint.kt:4 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/vars.out b/idea/testData/debugger/tinyApp/outs/vars.out new file mode 100644 index 00000000000..764afeee9d0 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/vars.out @@ -0,0 +1,7 @@ +LineBreakpoint created at vars.kt:7 +!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!;!RT_JAR! vars.VarsPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +vars.kt:6 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/arrays.kt b/idea/testData/debugger/tinyApp/src/evaluate/arrays.kt index 2cd229d7f8f..ad83485a327 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/arrays.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/arrays.kt @@ -6,10 +6,10 @@ fun main(args: Array) { } // EXPRESSION: array(1, 2).map { it.toString() } -// RESULT: instance of java.util.ArrayList(id=347): Ljava/util/ArrayList; +// RESULT: instance of java.util.ArrayList(id=ID): Ljava/util/ArrayList; // EXPRESSION: array(1, 2, 101, 102).filter { it > 100 } -// RESULT: instance of java.util.ArrayList(id=369): Ljava/util/ArrayList; +// RESULT: instance of java.util.ArrayList(id=ID): Ljava/util/ArrayList; // EXPRESSION: array(1, 2).none() // RESULT: 0: Z @@ -27,7 +27,7 @@ fun main(args: Array) { // RESULT: 2: I // EXPRESSION: intArray(1, 2).max() -// RESULT: instance of java.lang.Integer(id=343): Ljava/lang/Integer; +// RESULT: instance of java.lang.Integer(id=ID): Ljava/lang/Integer; // EXPRESSION: array(1, 2).max() -// RESULT: instance of java.lang.Integer(id=343): Ljava/lang/Integer; +// RESULT: instance of java.lang.Integer(id=ID): Ljava/lang/Integer; diff --git a/idea/testData/debugger/tinyApp/src/evaluate/classObjectVal.kt b/idea/testData/debugger/tinyApp/src/evaluate/classObjectVal.kt new file mode 100644 index 00000000000..4c354387a30 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/classObjectVal.kt @@ -0,0 +1,22 @@ +package classObjectVal + +fun main(args: Array) { + MyClass().test() +} + +class MyClass { + fun test() { + //Breakpoint! + val a = 1 + } + + class object { + val coProp = 1 + } +} + +// EXPRESSION: coProp +// RESULT: 1: I + +// EXPRESSION: MyClass.coProp +// RESULT: 1: I \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/collections.kt b/idea/testData/debugger/tinyApp/src/evaluate/collections.kt index 7abb1c75ce1..6737ac6d09c 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/collections.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/collections.kt @@ -5,20 +5,20 @@ fun main(args: Array) { args.size } -//// EXPRESSION: arrayListOf(1, 2).map { it.toString() } -//// RESULT: instance of java.util.ArrayList(id=380): Ljava/util/ArrayList; - // -//// EXPRESSION: arrayListOf(1, 2, 101, 102).filter { it > 100 } -//// RESULT: instance of java.util.ArrayList(id=390): Ljava/util/ArrayList; - // +// EXPRESSION: arrayListOf(1, 2).map { it.toString() } +// RESULT: instance of java.util.ArrayList(id=ID): Ljava/util/ArrayList; + +// EXPRESSION: arrayListOf(1, 2, 101, 102).filter { it > 100 } +// RESULT: instance of java.util.ArrayList(id=ID): Ljava/util/ArrayList; + // EXPRESSION: arrayListOf(1, 2).max() -// RESULT: instance of java.lang.Integer(id=343): Ljava/lang/Integer; - // -//// EXPRESSION: arrayListOf(1, 2).count() -//// RESULT: 2: I - // -//// EXPRESSION: arrayListOf(1, 2).size -//// RESULT: 2: I - // -//// EXPRESSION: arrayListOf(1, 2).drop(1) -//// RESULT: instance of java.util.ArrayList(id=411): Ljava/util/ArrayList; +// RESULT: instance of java.lang.Integer(id=ID): Ljava/lang/Integer; + +// EXPRESSION: arrayListOf(1, 2).count() +// RESULT: 2: I + +// EXPRESSION: arrayListOf(1, 2).size +// RESULT: 2: I + +// EXPRESSION: arrayListOf(1, 2).drop(1) +// RESULT: instance of java.util.ArrayList(id=ID): Ljava/util/ArrayList; diff --git a/idea/testData/debugger/tinyApp/src/evaluate/dependentOnFile.kt b/idea/testData/debugger/tinyApp/src/evaluate/dependentOnFile.kt index 46cccb50ff0..e6ae81e5616 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/dependentOnFile.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/dependentOnFile.kt @@ -48,7 +48,7 @@ class Delegate { // EXPRESSION: 1.testExtVal // RESULT: 1: I -// + // EXPRESSION: testDelVal // RESULT: 1: I diff --git a/idea/testData/debugger/tinyApp/src/evaluate/enums.kt b/idea/testData/debugger/tinyApp/src/evaluate/enums.kt new file mode 100644 index 00000000000..f5ae3d71828 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/enums.kt @@ -0,0 +1,13 @@ +package enums + +import enums.MyEnum.A + +fun main(args: Array) { + //Breakpoint! + args.size +} + +enum class MyEnum { A } + +// EXPRESSION: A == MyEnum.A +// RESULT: 1: Z diff --git a/idea/testData/debugger/tinyApp/src/evaluate/extractLocalVariables.kt b/idea/testData/debugger/tinyApp/src/evaluate/extractLocalVariables.kt new file mode 100644 index 00000000000..d3e8fa703ff --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/extractLocalVariables.kt @@ -0,0 +1,25 @@ +package extractLocalVariables + +fun main(args: Array) { + val a = 1 + val klass = MyClass() + //Breakpoint! + klass.f1(a) +} + +class MyClass { + val b = 1 + fun f1(p1: Int) = p1 +} + +// EXPRESSION: a +// RESULT: 1: I + +// EXPRESSION: klass.f1(1) +// RESULT: 1: I + +// EXPRESSION: args.size +// RESULT: 0: I + +// EXPRESSION: klass.b +// RESULT: 1: I diff --git a/idea/testData/debugger/tinyApp/src/evaluate/extractThis.kt b/idea/testData/debugger/tinyApp/src/evaluate/extractThis.kt new file mode 100644 index 00000000000..488a39c173c --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/extractThis.kt @@ -0,0 +1,20 @@ +package extractThis + +fun main(args: Array) { + MyClass().test() +} + +class MyClass { + val prop = 1 + + fun test() { + //Breakpoint! + val a = 1 + } +} + +// EXPRESSION: prop +// RESULT: 1: I + +// EXPRESSION: this.prop +// RESULT: 1: I \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/extractVariablesFromCall.kt b/idea/testData/debugger/tinyApp/src/evaluate/extractVariablesFromCall.kt new file mode 100644 index 00000000000..c6441f29616 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/extractVariablesFromCall.kt @@ -0,0 +1,28 @@ +package extractVariablesFromCall + +fun main(args: Array) { + val a = 1 + val s = "str" + val klass = MyClass() + //Breakpoint! + val c = 0 +} + +fun f1(i: Int, s: String) = i + s.size +fun Int.f2(s: String) = this + s.size + +class MyClass { + fun f1(i: Int, s: String) = i + s.size +} + +// EXPRESSION: f1(a, s) +// RESULT: 4: I + +// EXPRESSION: a.f2(s) +// RESULT: 4: I + +// EXPRESSION: a f2 s +// RESULT: 4: I + +// EXPRESSION: klass.f1(a, s) +// RESULT: 4: I diff --git a/idea/testData/debugger/tinyApp/src/evaluate/imports.kt b/idea/testData/debugger/tinyApp/src/evaluate/imports.kt index 10c9a801371..ada125a5b97 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/imports.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/imports.kt @@ -11,13 +11,13 @@ fun main(args: Array) { } // EXPRESSION: Collections.emptyList() -// RESULT: instance of java.util.Collections$EmptyList(id=337): Ljava/util/Collections$EmptyList; +// RESULT: instance of java.util.Collections$EmptyList(id=ID): Ljava/util/Collections$EmptyList; // EXPRESSION: ArrayList() -// RESULT: instance of java.util.ArrayList(id=383): Ljava/util/ArrayList; +// RESULT: instance of java.util.ArrayList(id=ID): Ljava/util/ArrayList; // EXPRESSION: HashSet() -// RESULT: instance of java.util.HashSet(id=387): Ljava/util/HashSet; +// RESULT: instance of java.util.HashSet(id=ID): Ljava/util/HashSet; // EXPRESSION: JHashMap() -// RESULT: instance of java.util.HashMap(id=391): Ljava/util/HashMap; +// RESULT: instance of java.util.HashMap(id=ID): Ljava/util/HashMap; diff --git a/idea/testData/debugger/tinyApp/src/evaluate/multilineExpressionAtBreakpoint.kt b/idea/testData/debugger/tinyApp/src/evaluate/multilineExpressionAtBreakpoint.kt new file mode 100644 index 00000000000..8dde51f2bd2 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/multilineExpressionAtBreakpoint.kt @@ -0,0 +1,11 @@ +package multilineExpressionAtBreakpoint + +fun main(args: Array) { + //Breakpoint! + args + .size + .indices +} + +// EXPRESSION: 1 + 1 +// RESULT: 2: I diff --git a/idea/testData/debugger/tinyApp/src/evaluate/stdlib.kt b/idea/testData/debugger/tinyApp/src/evaluate/stdlib.kt index f957ac26eeb..14ca45fdb91 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/stdlib.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/stdlib.kt @@ -6,19 +6,19 @@ fun main(args: Array) { } // EXPRESSION: array(100, 101) -// RESULT: instance of java.lang.Integer[2] (id=338): [Ljava/lang/Integer; +// RESULT: instance of java.lang.Integer[2] (id=ID): [Ljava/lang/Integer; // EXPRESSION: array("a", "b", "c") -// RESULT: instance of java.lang.String[3] (id=346): [Ljava/lang/String; +// RESULT: instance of java.lang.String[3] (id=ID): [Ljava/lang/String; // EXPRESSION: intArray(1, 2) -// RESULT: instance of int[2] (id=352): [I +// RESULT: instance of int[2] (id=ID): [I // EXPRESSION: javaClass() -// RESULT: instance of java.lang.Class(reflected class=java.lang.String, id=194): Ljava/lang/Class; +// RESULT: instance of java.lang.Class(reflected class=java.lang.String, id=ID): Ljava/lang/Class; // EXPRESSION: javaClass() -// RESULT: instance of java.lang.Class(reflected class=int, id=355): Ljava/lang/Class; +// RESULT: instance of java.lang.Class(reflected class=int, id=ID): Ljava/lang/Class; // EXPRESSION: 100.toInt() // RESULT: 100: I diff --git a/idea/testData/debugger/tinyApp/src/evaluate/vars.kt b/idea/testData/debugger/tinyApp/src/evaluate/vars.kt new file mode 100644 index 00000000000..ade36005e61 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/vars.kt @@ -0,0 +1,17 @@ +package vars + +fun main(args: Array) { + var a = 1 + a += 1 + //Breakpoint! + args.size +} + +// EXPRESSION: a +// RESULT: 2: I + +// EXPRESSION: a += 1 +// RESULT: 3: I + +// EXPRESSION: a +// RESULT: 2: I diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt index c4f4d75305e..8fd4444625c 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt @@ -29,6 +29,9 @@ import com.intellij.openapi.util.io.FileUtil import java.io.File import org.jetbrains.jet.InTextDirectivesUtils import org.jetbrains.eval4j.jdi.asValue +import org.jetbrains.eval4j.Value +import org.jetbrains.eval4j.ObjectValue +import com.sun.jdi.ObjectReference public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestCase() { fun doTest(path: String) { @@ -89,11 +92,18 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestC if (evaluator == null) throw AssertionError("Cannot create an Evaluator for Evaluate Expression") val value = evaluator.evaluate(createEvaluationContext(this)) - val actualResult = value.asValue().toString() + val actualResult = value.asValue().asString() Assert.assertTrue("Evaluate expression returns wrong result for $expression:\nexpected = $expectedResult\nactual = $actualResult\n", expectedResult == actualResult) } finally { resume(this) } } + + private fun Value.asString(): String { + if (this is ObjectValue && this.value is ObjectReference) { + return this.toString().replaceFirst("id=[0-9]*", "id=ID") + } + return this.toString() + } } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index 62f36ce0982..18a0be61452 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -46,6 +46,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat doTest("idea/testData/debugger/tinyApp/src/evaluate/arrays.kt"); } + @TestMetadata("classObjectVal.kt") + public void testClassObjectVal() throws Exception { + doTest("idea/testData/debugger/tinyApp/src/evaluate/classObjectVal.kt"); + } + @TestMetadata("collections.kt") public void testCollections() throws Exception { doTest("idea/testData/debugger/tinyApp/src/evaluate/collections.kt"); @@ -56,11 +61,36 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat doTest("idea/testData/debugger/tinyApp/src/evaluate/dependentOnFile.kt"); } + @TestMetadata("enums.kt") + public void testEnums() throws Exception { + doTest("idea/testData/debugger/tinyApp/src/evaluate/enums.kt"); + } + + @TestMetadata("extractLocalVariables.kt") + public void testExtractLocalVariables() throws Exception { + doTest("idea/testData/debugger/tinyApp/src/evaluate/extractLocalVariables.kt"); + } + + @TestMetadata("extractThis.kt") + public void testExtractThis() throws Exception { + doTest("idea/testData/debugger/tinyApp/src/evaluate/extractThis.kt"); + } + + @TestMetadata("extractVariablesFromCall.kt") + public void testExtractVariablesFromCall() throws Exception { + doTest("idea/testData/debugger/tinyApp/src/evaluate/extractVariablesFromCall.kt"); + } + @TestMetadata("imports.kt") public void testImports() throws Exception { doTest("idea/testData/debugger/tinyApp/src/evaluate/imports.kt"); } + @TestMetadata("multilineExpressionAtBreakpoint.kt") + public void testMultilineExpressionAtBreakpoint() throws Exception { + doTest("idea/testData/debugger/tinyApp/src/evaluate/multilineExpressionAtBreakpoint.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { doTest("idea/testData/debugger/tinyApp/src/evaluate/simple.kt"); @@ -71,4 +101,9 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat doTest("idea/testData/debugger/tinyApp/src/evaluate/stdlib.kt"); } + @TestMetadata("vars.kt") + public void testVars() throws Exception { + doTest("idea/testData/debugger/tinyApp/src/evaluate/vars.kt"); + } + }