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:
@@ -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
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user