Evaluate: Fix for evaluating local variables captured by an inline function (KT-17514)
This commit is contained in:
@@ -69,7 +69,7 @@ internal const val THIS = "this"
|
|||||||
internal const val THIS_0 = "this$0"
|
internal const val THIS_0 = "this$0"
|
||||||
internal const val FIRST_FUN_LABEL = "$$$$\$ROOT$$$$$"
|
internal const val FIRST_FUN_LABEL = "$$$$\$ROOT$$$$$"
|
||||||
internal const val SPECIAL_TRANSFORMATION_NAME = "\$special"
|
internal const val SPECIAL_TRANSFORMATION_NAME = "\$special"
|
||||||
internal const val INLINE_TRANSFORMATION_SUFFIX = "\$inlined"
|
const val INLINE_TRANSFORMATION_SUFFIX = "\$inlined"
|
||||||
internal const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX
|
internal const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX
|
||||||
internal const val INLINE_FUN_THIS_0_SUFFIX = "\$inline_fun"
|
internal const val INLINE_FUN_THIS_0_SUFFIX = "\$inline_fun"
|
||||||
internal const val DEFAULT_LAMBDA_FAKE_CALL = "$$\$DEFAULT_LAMBDA_FAKE_CALL$$$"
|
internal const val DEFAULT_LAMBDA_FAKE_CALL = "$$\$DEFAULT_LAMBDA_FAKE_CALL$$$"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.debugger.evaluate
|
|||||||
|
|
||||||
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
||||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||||
|
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||||
import com.sun.jdi.ClassType
|
import com.sun.jdi.ClassType
|
||||||
import com.sun.jdi.InvalidStackFrameException
|
import com.sun.jdi.InvalidStackFrameException
|
||||||
import com.sun.jdi.ObjectReference
|
import com.sun.jdi.ObjectReference
|
||||||
@@ -27,6 +28,7 @@ import org.jetbrains.eval4j.jdi.asValue
|
|||||||
import org.jetbrains.eval4j.obj
|
import org.jetbrains.eval4j.obj
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX
|
import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.INLINE_TRANSFORMATION_SUFFIX
|
||||||
import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX
|
import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX
|
||||||
import org.jetbrains.kotlin.idea.debugger.isInsideInlineFunctionBody
|
import org.jetbrains.kotlin.idea.debugger.isInsideInlineFunctionBody
|
||||||
import org.jetbrains.kotlin.idea.debugger.numberOfInlinedFunctions
|
import org.jetbrains.kotlin.idea.debugger.numberOfInlinedFunctions
|
||||||
@@ -78,11 +80,10 @@ class FrameVisitor(context: EvaluationContextImpl) {
|
|||||||
return localVariable
|
return localVariable
|
||||||
}
|
}
|
||||||
|
|
||||||
val capturedValName = getCapturedFieldName(name)
|
getCapturedFieldNames(name).asSequence()
|
||||||
val capturedVal = findCapturedLocalVariable(capturedValName, asmType, checkType)
|
.mapNotNull { findCapturedLocalVariable(it, asmType, checkType) }
|
||||||
if (capturedVal != null) {
|
.firstOrNull()
|
||||||
return capturedVal
|
?.let { return it }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,12 +222,15 @@ class FrameVisitor(context: EvaluationContextImpl) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCapturedFieldName(name: String) = when (name) {
|
private fun getCapturedFieldNames(name: String): List<String> = when (name) {
|
||||||
RECEIVER_NAME -> AsmUtil.CAPTURED_RECEIVER_FIELD
|
RECEIVER_NAME -> listOf(AsmUtil.CAPTURED_RECEIVER_FIELD)
|
||||||
THIS_NAME -> AsmUtil.CAPTURED_THIS_FIELD
|
THIS_NAME -> listOf(AsmUtil.CAPTURED_THIS_FIELD)
|
||||||
AsmUtil.CAPTURED_RECEIVER_FIELD -> name
|
AsmUtil.CAPTURED_RECEIVER_FIELD -> listOf(name)
|
||||||
AsmUtil.CAPTURED_THIS_FIELD -> name
|
AsmUtil.CAPTURED_THIS_FIELD -> listOf(name)
|
||||||
else -> "$$name"
|
else -> {
|
||||||
|
val simpleName = "$$name"
|
||||||
|
listOf(simpleName, simpleName + INLINE_TRANSFORMATION_SUFFIX)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun com.sun.jdi.Type?.isSubclass(superClassName: String): Boolean {
|
private fun com.sun.jdi.Type?.isSubclass(superClassName: String): Boolean {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package kt17514
|
||||||
|
|
||||||
|
fun <T> checkSucceeds(callable: () -> T) = callable()
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val isPresent = true
|
||||||
|
val isPresent2 = true
|
||||||
|
val expectedLibs = listOf("aa", "bb", "cc")
|
||||||
|
expectedLibs
|
||||||
|
.forEach {
|
||||||
|
checkSucceeds {
|
||||||
|
val isPresent2 = false
|
||||||
|
//Breakpoint!
|
||||||
|
val v = isPresent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPRESSION: isPresent
|
||||||
|
// RESULT: 1: Z
|
||||||
|
|
||||||
|
// EXPRESSION: isPresent2
|
||||||
|
// RESULT: 0: Z
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
LineBreakpoint created at kt17514.kt:14
|
||||||
|
Run Java
|
||||||
|
Connected to the target VM
|
||||||
|
kt17514.kt:14
|
||||||
|
Compile bytecode for isPresent
|
||||||
|
Compile bytecode for isPresent2
|
||||||
|
kt17514.kt:14
|
||||||
|
resuming kt17514.kt:14
|
||||||
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
+6
@@ -236,6 +236,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
doSingleBreakpointTest(fileName);
|
doSingleBreakpointTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt17514.kt")
|
||||||
|
public void testKt17514() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt17514.kt");
|
||||||
|
doSingleBreakpointTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt5554OnlyIntsShouldBeCoerced.kt")
|
@TestMetadata("kt5554OnlyIntsShouldBeCoerced.kt")
|
||||||
public void testKt5554OnlyIntsShouldBeCoerced() throws Exception {
|
public void testKt5554OnlyIntsShouldBeCoerced() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt5554OnlyIntsShouldBeCoerced.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt5554OnlyIntsShouldBeCoerced.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user