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");
+ }
+
}