Debugger: use extract method to get function arguments
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
<root>
|
||||||
|
<item name='com.intellij.debugger.engine.jdi.StackFrameProxy com.sun.jdi.StackFrame getStackFrame()'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
</root>
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
package org.jetbrains.jet.plugin.codeInsight;
|
package org.jetbrains.jet.plugin.codeInsight;
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
|
import com.intellij.openapi.editor.Document;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.psi.PsiComment;
|
import com.intellij.psi.*;
|
||||||
import com.intellij.psi.PsiElement;
|
|
||||||
import com.intellij.psi.PsiFile;
|
|
||||||
import com.intellij.psi.PsiWhiteSpace;
|
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import com.intellij.psi.util.PsiUtilCore;
|
import com.intellij.psi.util.PsiUtilCore;
|
||||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||||
|
import com.intellij.util.text.CharArrayUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
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;
|
DescriptorRenderer renderer = shortTypeNames ? DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES : DescriptorRenderer.SOURCE_CODE;
|
||||||
return renderer.render(descriptor);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ import com.sun.jdi.Location
|
|||||||
import com.intellij.psi.PsiMethod
|
import com.intellij.psi.PsiMethod
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils
|
||||||
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
|
||||||
public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
|
public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
|
||||||
|
|
||||||
@@ -49,27 +51,22 @@ public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
|
|||||||
if (position.getLine() < 0) return Collections.emptyList()
|
if (position.getLine() < 0) return Collections.emptyList()
|
||||||
|
|
||||||
val file = position.getFile()
|
val file = position.getFile()
|
||||||
val vFile = file.getVirtualFile()
|
|
||||||
if (vFile == null) return Collections.emptyList()
|
|
||||||
|
|
||||||
val doc = FileDocumentManager.getInstance()?.getDocument(vFile)
|
val lineStart = CodeInsightUtils.getStartLineOffset(file, position.getLine())
|
||||||
if (doc == null) return Collections.emptyList()
|
if (lineStart == null) return Collections.emptyList()
|
||||||
|
|
||||||
val line = position.getLine()
|
val elementAtOffset = file.findElementAt(lineStart)
|
||||||
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)
|
|
||||||
if (elementAtOffset == null) return Collections.emptyList()
|
if (elementAtOffset == null) return Collections.emptyList()
|
||||||
|
|
||||||
val element = getTopmostElementAtOffset(elementAtOffset, lineStartOffset)
|
val element = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart)
|
||||||
|
|
||||||
if (element !is JetElement) return Collections.emptyList()
|
if (element !is JetElement) return Collections.emptyList()
|
||||||
|
|
||||||
val elementTextRange = element.getTextRange()
|
val elementTextRange = element.getTextRange()
|
||||||
if (elementTextRange == null) return Collections.emptyList()
|
if (elementTextRange == null) return Collections.emptyList()
|
||||||
|
|
||||||
|
val doc = PsiDocumentManager.getInstance(file.getProject()).getDocument(file)
|
||||||
|
if (doc == null) return Collections.emptyList()
|
||||||
|
|
||||||
val lines = Range<Int>(doc.getLineNumber(elementTextRange.getStartOffset()), doc.getLineNumber(elementTextRange.getEndOffset()))
|
val lines = Range<Int>(doc.getLineNumber(elementTextRange.getStartOffset()), doc.getLineNumber(elementTextRange.getEndOffset()))
|
||||||
val bindingContext = AnalyzerFacadeWithCache.getContextForElement(element)
|
val bindingContext = AnalyzerFacadeWithCache.getContextForElement(element)
|
||||||
val result = OrderedSet<SmartStepTarget>()
|
val result = OrderedSet<SmartStepTarget>()
|
||||||
|
|||||||
@@ -45,6 +45,23 @@ import org.jetbrains.jet.lang.resolve.java.PackageClassUtils
|
|||||||
import org.jetbrains.jet.lang.resolve.name.FqName
|
import org.jetbrains.jet.lang.resolve.name.FqName
|
||||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||||
import org.jetbrains.jet.plugin.debugger.KotlinEditorTextProvider
|
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.OutputFileCollection
|
||||||
import org.jetbrains.jet.lang.psi.JetExpressionCodeFragment
|
import org.jetbrains.jet.lang.psi.JetExpressionCodeFragment
|
||||||
import org.jetbrains.jet.lang.psi.JetExpressionCodeFragmentImpl
|
import org.jetbrains.jet.lang.psi.JetExpressionCodeFragmentImpl
|
||||||
@@ -52,11 +69,11 @@ import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults
|
|||||||
|
|
||||||
object KotlinEvaluationBuilder: EvaluatorBuilder {
|
object KotlinEvaluationBuilder: EvaluatorBuilder {
|
||||||
override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator {
|
override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator {
|
||||||
if (codeFragment !is JetExpressionCodeFragment) {
|
if (codeFragment !is JetExpressionCodeFragment || position == null) {
|
||||||
return EvaluatorBuilderImpl.getInstance()!!.build(codeFragment, position)
|
return EvaluatorBuilderImpl.getInstance()!!.build(codeFragment, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
val elementAt = position?.getElementAt()
|
val elementAt = position.getElementAt()
|
||||||
if (elementAt != null) {
|
if (elementAt != null) {
|
||||||
codeFragment.addImportsFromString(KotlinEditorTextProvider.getImports(elementAt))
|
codeFragment.addImportsFromString(KotlinEditorTextProvider.getImports(elementAt))
|
||||||
|
|
||||||
@@ -65,11 +82,13 @@ object KotlinEvaluationBuilder: EvaluatorBuilder {
|
|||||||
codeFragment.addImportsFromString("import $packageName.*")
|
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? {
|
override fun evaluate(context: EvaluationContextImpl): Any? {
|
||||||
return ApplicationManager.getApplication()?.runReadAction(object: Computable<Any> {
|
return ApplicationManager.getApplication()?.runReadAction(object: Computable<Any> {
|
||||||
override fun compute(): Any? {
|
override fun compute(): Any? {
|
||||||
@@ -77,7 +96,12 @@ class KotlinEvaluator(val codeFragment: PsiElement) : Evaluator {
|
|||||||
throw AssertionError("KotlinEvaluator should be invoke only for KotlinCodeFragment")
|
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 analyzeExhaust = file.getAnalysisResults()
|
||||||
val bindingContext = analyzeExhaust.getBindingContext()
|
val bindingContext = analyzeExhaust.getBindingContext()
|
||||||
@@ -111,12 +135,12 @@ class KotlinEvaluator(val codeFragment: PsiElement) : Evaluator {
|
|||||||
|
|
||||||
ClassReader(outputFiles.first().asByteArray()).accept(object : ClassVisitor(ASM5) {
|
ClassReader(outputFiles.first().asByteArray()).accept(object : ClassVisitor(ASM5) {
|
||||||
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
||||||
if (name == "debugFun") {
|
if (name == extractedFunction.getName()) {
|
||||||
return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) {
|
return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) {
|
||||||
override fun visitEnd() {
|
override fun visitEnd() {
|
||||||
val value = interpreterLoop(
|
val value = interpreterLoop(
|
||||||
this,
|
this,
|
||||||
makeInitialFrame(this, listOf()),
|
makeInitialFrame(this, context.getArgumentsByNames(extractedFunction.getParameterNamesForDebugger())),
|
||||||
JDIEval(virtualMachine,
|
JDIEval(virtualMachine,
|
||||||
context.getClassLoader()!!,
|
context.getClassLoader()!!,
|
||||||
context.getSuspendContext().getThread()?.getThreadReference()!!)
|
context.getSuspendContext().getThread()?.getThreadReference()!!)
|
||||||
@@ -146,6 +170,39 @@ class KotlinEvaluator(val codeFragment: PsiElement) : Evaluator {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun JetNamedFunction.getParameterNamesForDebugger(): List<String> {
|
||||||
|
val result = arrayListOf<String>()
|
||||||
|
for (param in getValueParameters()) {
|
||||||
|
result.add(param.getName()!!)
|
||||||
|
}
|
||||||
|
if (getReceiverTypeRef() != null) {
|
||||||
|
result.add("this")
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun EvaluationContextImpl.getArgumentsByNames(parameterNames: List<String>): List<Value> {
|
||||||
|
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)
|
private fun exception(msg: String) = throw EvaluateExceptionUtil.createEvaluateException(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,22 +211,69 @@ package packageForDebugger
|
|||||||
|
|
||||||
!IMPORT_LIST!
|
!IMPORT_LIST!
|
||||||
|
|
||||||
fun debugFun() = run {
|
!FUNCTION!
|
||||||
!EXPRESSION!
|
|
||||||
}
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
private val packageInternalName = PackageClassUtils.getPackageClassFqName(FqName("packageForDebugger")).asString().replace(".", "/")
|
private val packageInternalName = PackageClassUtils.getPackageClassFqName(FqName("packageForDebugger")).asString().replace(".", "/")
|
||||||
|
|
||||||
private fun createFileForDebugger(codeFragment: JetExpressionCodeFragment): JetFile {
|
private fun createFileForDebugger(codeFragment: JetExpressionCodeFragment,
|
||||||
var fileText = template.replace("!EXPRESSION!", codeFragment.getText())
|
extractedFunction: JetNamedFunction
|
||||||
fileText = fileText.replace("!IMPORT_LIST!",
|
): JetFile {
|
||||||
codeFragment.importsToString()
|
var fileText = template.replace("!IMPORT_LIST!",
|
||||||
.split(JetExpressionCodeFragmentImpl.IMPORT_SEPARATOR)
|
codeFragment.importsToString()
|
||||||
.makeString("\n"))
|
.split(JetExpressionCodeFragmentImpl.IMPORT_SEPARATOR)
|
||||||
|
.makeString("\n"))
|
||||||
|
|
||||||
|
fileText = fileText.replace("!FUNCTION!", extractedFunction.getText())
|
||||||
|
|
||||||
val virtualFile = LightVirtualFile("debugFile.kt", JetLanguage.INSTANCE, fileText)
|
val virtualFile = LightVirtualFile("debugFile.kt", JetLanguage.INSTANCE, fileText)
|
||||||
virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET)
|
virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET)
|
||||||
return (PsiFileFactory.getInstance(codeFragment.getProject()) as PsiFileFactoryImpl)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -6,10 +6,10 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXPRESSION: array(1, 2).map { it.toString() }
|
// 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 }
|
// 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()
|
// EXPRESSION: array(1, 2).none()
|
||||||
// RESULT: 0: Z
|
// RESULT: 0: Z
|
||||||
@@ -27,7 +27,7 @@ fun main(args: Array<String>) {
|
|||||||
// RESULT: 2: I
|
// RESULT: 2: I
|
||||||
|
|
||||||
// EXPRESSION: intArray(1, 2).max()
|
// 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()
|
// 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;
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package classObjectVal
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
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
|
||||||
@@ -5,20 +5,20 @@ fun main(args: Array<String>) {
|
|||||||
args.size
|
args.size
|
||||||
}
|
}
|
||||||
|
|
||||||
//// EXPRESSION: arrayListOf(1, 2).map { it.toString() }
|
// EXPRESSION: arrayListOf(1, 2).map { it.toString() }
|
||||||
//// RESULT: instance of java.util.ArrayList(id=380): Ljava/util/ArrayList;
|
// RESULT: instance of java.util.ArrayList(id=ID): Ljava/util/ArrayList;
|
||||||
//
|
|
||||||
//// EXPRESSION: arrayListOf(1, 2, 101, 102).filter { it > 100 }
|
// EXPRESSION: arrayListOf(1, 2, 101, 102).filter { it > 100 }
|
||||||
//// RESULT: instance of java.util.ArrayList(id=390): Ljava/util/ArrayList;
|
// RESULT: instance of java.util.ArrayList(id=ID): Ljava/util/ArrayList;
|
||||||
//
|
|
||||||
// EXPRESSION: arrayListOf(1, 2).max()
|
// EXPRESSION: arrayListOf(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: arrayListOf(1, 2).count()
|
// EXPRESSION: arrayListOf(1, 2).count()
|
||||||
//// RESULT: 2: I
|
// RESULT: 2: I
|
||||||
//
|
|
||||||
//// EXPRESSION: arrayListOf(1, 2).size
|
// EXPRESSION: arrayListOf(1, 2).size
|
||||||
//// RESULT: 2: I
|
// RESULT: 2: I
|
||||||
//
|
|
||||||
//// EXPRESSION: arrayListOf(1, 2).drop(1)
|
// EXPRESSION: arrayListOf(1, 2).drop(1)
|
||||||
//// RESULT: instance of java.util.ArrayList(id=411): Ljava/util/ArrayList;
|
// RESULT: instance of java.util.ArrayList(id=ID): Ljava/util/ArrayList;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class Delegate {
|
|||||||
|
|
||||||
// EXPRESSION: 1.testExtVal
|
// EXPRESSION: 1.testExtVal
|
||||||
// RESULT: 1: I
|
// RESULT: 1: I
|
||||||
//
|
|
||||||
// EXPRESSION: testDelVal
|
// EXPRESSION: testDelVal
|
||||||
// RESULT: 1: I
|
// RESULT: 1: I
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package enums
|
||||||
|
|
||||||
|
import enums.MyEnum.A
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
//Breakpoint!
|
||||||
|
args.size
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class MyEnum { A }
|
||||||
|
|
||||||
|
// EXPRESSION: A == MyEnum.A
|
||||||
|
// RESULT: 1: Z
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package extractLocalVariables
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
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
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package extractThis
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
MyClass().test()
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyClass {
|
||||||
|
val prop = 1
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPRESSION: prop
|
||||||
|
// RESULT: 1: I
|
||||||
|
|
||||||
|
// EXPRESSION: this.prop
|
||||||
|
// RESULT: 1: I
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package extractVariablesFromCall
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
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
|
||||||
@@ -11,13 +11,13 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXPRESSION: Collections.emptyList<String>()
|
// EXPRESSION: Collections.emptyList<String>()
|
||||||
// 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<Int>()
|
// EXPRESSION: ArrayList<Int>()
|
||||||
// RESULT: instance of java.util.ArrayList(id=383): Ljava/util/ArrayList;
|
// RESULT: instance of java.util.ArrayList(id=ID): Ljava/util/ArrayList;
|
||||||
|
|
||||||
// EXPRESSION: HashSet<Int>()
|
// EXPRESSION: HashSet<Int>()
|
||||||
// RESULT: instance of java.util.HashSet(id=387): Ljava/util/HashSet;
|
// RESULT: instance of java.util.HashSet(id=ID): Ljava/util/HashSet;
|
||||||
|
|
||||||
// EXPRESSION: JHashMap<Int, Int>()
|
// EXPRESSION: JHashMap<Int, Int>()
|
||||||
// RESULT: instance of java.util.HashMap(id=391): Ljava/util/HashMap;
|
// RESULT: instance of java.util.HashMap(id=ID): Ljava/util/HashMap;
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package multilineExpressionAtBreakpoint
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
//Breakpoint!
|
||||||
|
args
|
||||||
|
.size
|
||||||
|
.indices
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPRESSION: 1 + 1
|
||||||
|
// RESULT: 2: I
|
||||||
@@ -6,19 +6,19 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXPRESSION: array(100, 101)
|
// 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")
|
// 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)
|
// EXPRESSION: intArray(1, 2)
|
||||||
// RESULT: instance of int[2] (id=352): [I
|
// RESULT: instance of int[2] (id=ID): [I
|
||||||
|
|
||||||
// EXPRESSION: javaClass<String>()
|
// EXPRESSION: javaClass<String>()
|
||||||
// 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<Int>()
|
// EXPRESSION: javaClass<Int>()
|
||||||
// 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()
|
// EXPRESSION: 100.toInt()
|
||||||
// RESULT: 100: I
|
// RESULT: 100: I
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package vars
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
var a = 1
|
||||||
|
a += 1
|
||||||
|
//Breakpoint!
|
||||||
|
args.size
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPRESSION: a
|
||||||
|
// RESULT: 2: I
|
||||||
|
|
||||||
|
// EXPRESSION: a += 1
|
||||||
|
// RESULT: 3: I
|
||||||
|
|
||||||
|
// EXPRESSION: a
|
||||||
|
// RESULT: 2: I
|
||||||
+11
-1
@@ -29,6 +29,9 @@ import com.intellij.openapi.util.io.FileUtil
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import org.jetbrains.jet.InTextDirectivesUtils
|
import org.jetbrains.jet.InTextDirectivesUtils
|
||||||
import org.jetbrains.eval4j.jdi.asValue
|
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() {
|
public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestCase() {
|
||||||
fun doTest(path: String) {
|
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")
|
if (evaluator == null) throw AssertionError("Cannot create an Evaluator for Evaluate Expression")
|
||||||
|
|
||||||
val value = evaluator.evaluate(createEvaluationContext(this))
|
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)
|
Assert.assertTrue("Evaluate expression returns wrong result for $expression:\nexpected = $expectedResult\nactual = $actualResult\n", expectedResult == actualResult)
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
resume(this)
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+35
@@ -46,6 +46,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
doTest("idea/testData/debugger/tinyApp/src/evaluate/arrays.kt");
|
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")
|
@TestMetadata("collections.kt")
|
||||||
public void testCollections() throws Exception {
|
public void testCollections() throws Exception {
|
||||||
doTest("idea/testData/debugger/tinyApp/src/evaluate/collections.kt");
|
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");
|
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")
|
@TestMetadata("imports.kt")
|
||||||
public void testImports() throws Exception {
|
public void testImports() throws Exception {
|
||||||
doTest("idea/testData/debugger/tinyApp/src/evaluate/imports.kt");
|
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")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
doTest("idea/testData/debugger/tinyApp/src/evaluate/simple.kt");
|
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");
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user