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
This commit is contained in:
Natalia Selezneva
2018-01-15 15:20:02 +03:00
parent c5982e7ff5
commit dbd7ceb5fd
8 changed files with 41 additions and 8 deletions
@@ -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<KtDeclaration>(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!
@@ -36,7 +36,7 @@ interface ClassLoadingAdapter {
fun loadClasses(context: EvaluationContextImpl, classes: Collection<ClassToLoad>): 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(
@@ -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)
data class ClassToLoad(val className: String, val relativeFileName: String, val bytes: ByteArray) {
fun isMainClass() = className.endsWith(GENERATED_CLASS_NAME)
}
@@ -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;
// 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;
@@ -0,0 +1,10 @@
package inlineFunInMultiFilePackage
fun main(args: Array<String>) {
//Breakpoint!
val a = 1
}
// EXPRESSION: multiFilePackage.foo { 1 }
// RESULT: 1: I
@@ -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
@@ -0,0 +1,5 @@
@file:JvmMultifileClass
@file:JvmName("NewName")
package multiFilePackage
inline fun foo(f: () -> Int) = f()
@@ -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");