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:
+5
-5
@@ -80,7 +80,6 @@ import org.jetbrains.kotlin.resolve.AnalyzingUtils
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
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.*
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes.ASM5
|
import org.jetbrains.org.objectweb.asm.Opcodes.ASM5
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
@@ -91,7 +90,8 @@ import java.util.*
|
|||||||
internal val RECEIVER_NAME = "\$receiver"
|
internal val RECEIVER_NAME = "\$receiver"
|
||||||
internal val THIS_NAME = "this"
|
internal val THIS_NAME = "this"
|
||||||
internal val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluator")
|
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
|
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 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) {
|
if (isCompiledDataFromCache && result is ExceptionThrown && result.kind == ExceptionThrown.ExceptionKind.BROKEN_CODE) {
|
||||||
// We need only lambda classes here cause we using only eval4j evaluation method
|
// 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 {
|
try {
|
||||||
return runEval4j(context, extractAndCompile(codeFragment, sourcePosition, context)).toJdiValue(context)
|
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 classFileFactory = createClassFileFactory(codeFragment, extractedFunction, context, parametersDescriptor)
|
||||||
|
|
||||||
val outputFiles = classFileFactory.asList().filterClassFiles()
|
val outputFiles = classFileFactory.asList().filterClassFiles()
|
||||||
.sortedBy { it.relativePath.length }
|
|
||||||
|
|
||||||
for (file in outputFiles) {
|
for (file in outputFiles) {
|
||||||
if (LOG.isDebugEnabled) {
|
if (LOG.isDebugEnabled) {
|
||||||
@@ -260,7 +259,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val CompiledDataDescriptor.mainClass
|
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))
|
"Can't find main class for " + sourcePosition.elementAt.getParentOfType<KtDeclaration>(strict = false))
|
||||||
|
|
||||||
private fun evaluateWithCompilation(context: EvaluationContextImpl, compiledData: CompiledDataDescriptor): Any? {
|
private fun evaluateWithCompilation(context: EvaluationContextImpl, compiledData: CompiledDataDescriptor): Any? {
|
||||||
@@ -569,6 +568,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val template = """
|
private val template = """
|
||||||
|
@file:JvmName("$GENERATED_CLASS_NAME")
|
||||||
!PACKAGE!
|
!PACKAGE!
|
||||||
|
|
||||||
!IMPORT_LIST!
|
!IMPORT_LIST!
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ interface ClassLoadingAdapter {
|
|||||||
|
|
||||||
fun loadClasses(context: EvaluationContextImpl, classes: Collection<ClassToLoad>): ClassLoaderHandler? {
|
fun loadClasses(context: EvaluationContextImpl, classes: Collection<ClassToLoad>): ClassLoaderHandler? {
|
||||||
val hasAdditionalClasses = classes.size > 1
|
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) {
|
for (adapter in ADAPTERS) {
|
||||||
if (adapter.isApplicable(
|
if (adapter.isApplicable(
|
||||||
|
|||||||
+5
-1
@@ -16,5 +16,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.debugger.evaluate.classLoading
|
package org.jetbrains.kotlin.idea.debugger.evaluate.classLoading
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.evaluate.GENERATED_CLASS_NAME
|
||||||
|
|
||||||
@Suppress("ArrayInDataClass")
|
@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)
|
||||||
|
}
|
||||||
Vendored
+1
-1
@@ -16,4 +16,4 @@ interface T {
|
|||||||
// RESULT: 1: I
|
// RESULT: 1: I
|
||||||
|
|
||||||
// EXPRESSION: object: T {}
|
// 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;
|
||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package inlineFunInMultiFilePackage
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPRESSION: multiFilePackage.foo { 1 }
|
||||||
|
// RESULT: 1: I
|
||||||
|
|
||||||
Vendored
+8
@@ -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()
|
||||||
Generated
+6
@@ -177,6 +177,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
doSingleBreakpointTest(fileName);
|
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")
|
@TestMetadata("inlineFunction.kt")
|
||||||
public void testInlineFunction() throws Exception {
|
public void testInlineFunction() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunction.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/inlineFunction.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user