From dbd7ceb5fd10418dca2c0eb346cc66e493286a92 Mon Sep 17 00:00:00 2001 From: Natalia Selezneva Date: Mon, 15 Jan 2018 15:20:02 +0300 Subject: [PATCH] Fix Evaluate Expression for inline functions from multifile package class. Find main class generated for debugger by its name instead of relativePath length. #KT-22311 Fixed --- .../idea/debugger/evaluate/KotlinEvaluationBuilder.kt | 10 +++++----- .../evaluate/classLoading/ClassLoadingAdapter.kt | 2 +- .../idea/debugger/evaluate/classLoading/ClassToLoad.kt | 6 +++++- .../singleBreakpoint/compilingEvaluator/ceObject.kt | 2 +- .../singleBreakpoint/inlineFunInMultiFilePackage.kt | 10 ++++++++++ .../singleBreakpoint/inlineFunInMultiFilePackage.out | 8 ++++++++ .../debugger/tinyApp/src/forTests/multiFilePackage.kt | 5 +++++ .../KotlinEvaluateExpressionTestGenerated.java | 6 ++++++ 8 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunInMultiFilePackage.kt create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunInMultiFilePackage.out create mode 100644 idea/testData/debugger/tinyApp/src/forTests/multiFilePackage.kt diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt index 6b2a9162108..60b4701395c 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -80,7 +80,6 @@ import org.jetbrains.kotlin.resolve.AnalyzingUtils import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.jvm.JvmClassName -import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.Opcodes.ASM5 import org.jetbrains.org.objectweb.asm.Type @@ -91,7 +90,8 @@ import java.util.* internal val RECEIVER_NAME = "\$receiver" internal val THIS_NAME = "this" internal val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluator") -internal val GENERATED_FUNCTION_NAME = "generated_for_debugger_kotlin_rulezzzz" +internal val GENERATED_FUNCTION_NAME = "generated_for_debugger_fun" +internal val GENERATED_CLASS_NAME = "Generated_for_debugger_class" private val DEBUG_MODE = false @@ -158,7 +158,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour // If bytecode was taken from cache and exception was thrown - recompile bytecode and run eval4j again if (isCompiledDataFromCache && result is ExceptionThrown && result.kind == ExceptionThrown.ExceptionKind.BROKEN_CODE) { // We need only lambda classes here cause we using only eval4j evaluation method - val classLoaderHandler = loadClasses(context, compiledData.classes.drop(1)) + val classLoaderHandler = loadClasses(context, compiledData.classes.filter { !it.isMainClass() }) try { return runEval4j(context, extractAndCompile(codeFragment, sourcePosition, context)).toJdiValue(context) @@ -236,7 +236,6 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour val classFileFactory = createClassFileFactory(codeFragment, extractedFunction, context, parametersDescriptor) val outputFiles = classFileFactory.asList().filterClassFiles() - .sortedBy { it.relativePath.length } for (file in outputFiles) { if (LOG.isDebugEnabled) { @@ -260,7 +259,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour } private val CompiledDataDescriptor.mainClass - get() = classes.firstOrNull() ?: error( + get() = classes.firstOrNull { it.isMainClass() } ?: error( "Can't find main class for " + sourcePosition.elementAt.getParentOfType(strict = false)) private fun evaluateWithCompilation(context: EvaluationContextImpl, compiledData: CompiledDataDescriptor): Any? { @@ -569,6 +568,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour } private val template = """ +@file:JvmName("$GENERATED_CLASS_NAME") !PACKAGE! !IMPORT_LIST! diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt index 8c815db5c40..21867f39d0d 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt @@ -36,7 +36,7 @@ interface ClassLoadingAdapter { fun loadClasses(context: EvaluationContextImpl, classes: Collection): ClassLoaderHandler? { val hasAdditionalClasses = classes.size > 1 - val hasLoops = classes.isNotEmpty() && doesContainLoops(classes.first().bytes) + val hasLoops = classes.isNotEmpty() && doesContainLoops(classes.first { it.isMainClass() }.bytes) for (adapter in ADAPTERS) { if (adapter.isApplicable( diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassToLoad.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassToLoad.kt index 571d242ffd3..ef4340f9673 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassToLoad.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassToLoad.kt @@ -16,5 +16,9 @@ package org.jetbrains.kotlin.idea.debugger.evaluate.classLoading +import org.jetbrains.kotlin.idea.debugger.evaluate.GENERATED_CLASS_NAME + @Suppress("ArrayInDataClass") -data class ClassToLoad(val className: String, val relativeFileName: String, val bytes: ByteArray) \ No newline at end of file +data class ClassToLoad(val className: String, val relativeFileName: String, val bytes: ByteArray) { + fun isMainClass() = className.endsWith(GENERATED_CLASS_NAME) +} \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceObject.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceObject.kt index 14ca878ae87..cd5ac5bb602 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceObject.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/compilingEvaluator/ceObject.kt @@ -16,4 +16,4 @@ interface T { // RESULT: 1: I // EXPRESSION: object: T {} -// RESULT: instance of ceObject.DebugFileKt$generated_for_debugger_kotlin_rulezzzz$1(id=ID): LceObject/DebugFileKt$generated_for_debugger_kotlin_rulezzzz$1; \ No newline at end of file +// RESULT: instance of ceObject.Generated_for_debugger_class$generated_for_debugger_fun$1(id=ID): LceObject/Generated_for_debugger_class$generated_for_debugger_fun$1; \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunInMultiFilePackage.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunInMultiFilePackage.kt new file mode 100644 index 00000000000..c05f14cbd35 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunInMultiFilePackage.kt @@ -0,0 +1,10 @@ +package inlineFunInMultiFilePackage + +fun main(args: Array) { + //Breakpoint! + val a = 1 +} + +// EXPRESSION: multiFilePackage.foo { 1 } +// RESULT: 1: I + diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunInMultiFilePackage.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunInMultiFilePackage.out new file mode 100644 index 00000000000..e3b16a3d8ab --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunInMultiFilePackage.out @@ -0,0 +1,8 @@ +LineBreakpoint created at inlineFunInMultiFilePackage.kt:5 +Run Java +Connected to the target VM +inlineFunInMultiFilePackage.kt:5 +Compile bytecode for multiFilePackage.foo { 1 } +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/forTests/multiFilePackage.kt b/idea/testData/debugger/tinyApp/src/forTests/multiFilePackage.kt new file mode 100644 index 00000000000..43d1a6bca3b --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/forTests/multiFilePackage.kt @@ -0,0 +1,5 @@ +@file:JvmMultifileClass +@file:JvmName("NewName") +package multiFilePackage + +inline fun foo(f: () -> Int) = f() \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index 6ae27ac43c9..c0e6d154fed 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -177,6 +177,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat doSingleBreakpointTest(fileName); } + @TestMetadata("inlineFunInMultiFilePackage.kt") + public void testInlineFunInMultiFilePackage() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunInMultiFilePackage.kt"); + doSingleBreakpointTest(fileName); + } + @TestMetadata("inlineFunction.kt") public void testInlineFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunction.kt");