Fix breakpoints for the same inline function nested calls (KT-22366)

This commit changes the format of the synthetic local variables for inline functions.
This commit is contained in:
Yan Zhulanow
2018-11-30 18:09:57 +09:00
parent ae4f05cf62
commit 4b4d8dd660
6 changed files with 72 additions and 22 deletions
@@ -10,6 +10,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.util.ArrayUtil;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.backend.common.CodegenUtil;
@@ -715,26 +716,23 @@ public class FunctionCodegen {
}
if (context instanceof InlineLambdaContext && thisType != null && lambdaFakeIndex != -1) {
String name = thisType.getClassName();
int indexOfLambdaOrdinal = name.lastIndexOf("$");
if (indexOfLambdaOrdinal > 0) {
int lambdaOrdinal = Integer.parseInt(name.substring(indexOfLambdaOrdinal + 1));
String internalName = thisType.getInternalName();
String lambdaLocalName = StringsKt.substringAfterLast(internalName, '/', internalName);
KtPureElement functionArgument = parentCodegen.element;
String functionName = "unknown";
if (functionArgument instanceof KtFunction) {
ValueParameterDescriptor inlineArgumentDescriptor =
InlineUtil.getInlineArgumentDescriptor((KtFunction) functionArgument, parentCodegen.bindingContext);
if (inlineArgumentDescriptor != null) {
functionName = inlineArgumentDescriptor.getContainingDeclaration().getName().asString();
}
KtPureElement functionArgument = parentCodegen.element;
String functionName = "unknown";
if (functionArgument instanceof KtFunction) {
ValueParameterDescriptor inlineArgumentDescriptor =
InlineUtil.getInlineArgumentDescriptor((KtFunction) functionArgument, parentCodegen.bindingContext);
if (inlineArgumentDescriptor != null) {
functionName = inlineArgumentDescriptor.getContainingDeclaration().getName().asString();
}
mv.visitLocalVariable(
JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT + lambdaOrdinal + "$" + functionName,
Type.INT_TYPE.getDescriptor(), null,
methodBegin, methodEnd,
lambdaFakeIndex);
}
mv.visitLocalVariable(
JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT + "-" + functionName + "-" + lambdaLocalName,
Type.INT_TYPE.getDescriptor(), null,
methodBegin, methodEnd,
lambdaFakeIndex);
}
}
@@ -237,7 +237,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
for (literal in literalsOrFunctions) {
if (InlineUtil.isInlinedArgument(literal, typeMapper.bindingContext, true)) {
if (isInsideInlineArgument(literal, location, myDebugProcess as DebugProcessImpl)) {
if (isInsideInlineArgument(literal, location, myDebugProcess as DebugProcessImpl, typeMapper.bindingContext)) {
return literal
}
continue
@@ -17,6 +17,7 @@ import com.intellij.psi.PsiElement
import com.sun.jdi.*
import com.sun.tools.jdi.LocalVariableImpl
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass
import org.jetbrains.kotlin.codegen.coroutines.DO_RESUME_METHOD_NAME
import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmTypes
@@ -123,7 +124,12 @@ fun numberOfInlinedFunctions(visibleVariables: List<LocalVariable>): Int {
return visibleVariables.count { it.name().startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) }
}
fun isInsideInlineArgument(inlineArgument: KtFunction, location: Location, debugProcess: DebugProcessImpl): Boolean {
fun isInsideInlineArgument(
inlineArgument: KtFunction,
location: Location,
debugProcess: DebugProcessImpl,
bindingContext: BindingContext = KotlinDebuggerCaches.getOrCreateTypeMapper(inlineArgument).bindingContext
): Boolean {
val visibleVariables = location.visibleVariables(debugProcess)
val markerLocalVariables = visibleVariables.filter { it.name().startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT) }
@@ -132,10 +138,19 @@ fun isInsideInlineArgument(inlineArgument: KtFunction, location: Location, debug
val functionName = runReadAction { functionNameByArgument(inlineArgument, context) }
return markerLocalVariables
.map { it.name() }
.any { variableName ->
lambdaOrdinalByLocalVariable(variableName) == lambdaOrdinal && functionNameByLocalVariable(variableName) == functionName
.map { it.name().drop(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT.length) }
.any { variableName ->
if (variableName.startsWith("-")) {
val lambdaClassName = asmTypeForAnonymousClass(bindingContext, inlineArgument)
.internalName.substringAfterLast("/")
variableName == "-$functionName-$lambdaClassName"
} else {
// For Kotlin up to 1.3.10
lambdaOrdinalByLocalVariable(variableName) == lambdaOrdinal
&& functionNameByLocalVariable(variableName) == functionName
}
}
}
fun <T : Any> DebugProcessImpl.invokeInManagerThread(f: (DebuggerContextImpl) -> T?): T? {
@@ -0,0 +1,14 @@
package kt22366
fun main(args: Array<String>) {
val yy = (0 .. 10).map { a ->
//Breakpoint! (lambdaOrdinal = -1)
(0 .. 10).map { b -> b }.max()
}
}
// EXPRESSION: a
// RESULT: 0: I
// EXPRESSION: b
// RESULT: Unresolved reference: b
@@ -0,0 +1,18 @@
LineBreakpoint created at kt22366.kt:6 lambdaOrdinal = -1
Run Java
Connected to the target VM
kt22366.kt:6
Compile bytecode for a
kt22366.kt:6
resuming kt22366.kt:6
resuming kt22366.kt:6
resuming kt22366.kt:6
resuming kt22366.kt:6
resuming kt22366.kt:6
resuming kt22366.kt:6
resuming kt22366.kt:6
resuming kt22366.kt:6
resuming kt22366.kt:6
Disconnected from the target VM
Process finished with exit code 0
@@ -226,6 +226,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt17514.kt");
}
@TestMetadata("kt22366.kt")
public void testKt22366() throws Exception {
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt22366.kt");
}
@TestMetadata("kt5554OnlyIntsShouldBeCoerced.kt")
public void testKt5554OnlyIntsShouldBeCoerced() throws Exception {
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt5554OnlyIntsShouldBeCoerced.kt");