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 com.intellij.util.ArrayUtil;
|
||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
import kotlin.jvm.functions.Function1;
|
import kotlin.jvm.functions.Function1;
|
||||||
|
import kotlin.text.StringsKt;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||||
@@ -715,26 +716,23 @@ public class FunctionCodegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (context instanceof InlineLambdaContext && thisType != null && lambdaFakeIndex != -1) {
|
if (context instanceof InlineLambdaContext && thisType != null && lambdaFakeIndex != -1) {
|
||||||
String name = thisType.getClassName();
|
String internalName = thisType.getInternalName();
|
||||||
int indexOfLambdaOrdinal = name.lastIndexOf("$");
|
String lambdaLocalName = StringsKt.substringAfterLast(internalName, '/', internalName);
|
||||||
if (indexOfLambdaOrdinal > 0) {
|
|
||||||
int lambdaOrdinal = Integer.parseInt(name.substring(indexOfLambdaOrdinal + 1));
|
|
||||||
|
|
||||||
KtPureElement functionArgument = parentCodegen.element;
|
KtPureElement functionArgument = parentCodegen.element;
|
||||||
String functionName = "unknown";
|
String functionName = "unknown";
|
||||||
if (functionArgument instanceof KtFunction) {
|
if (functionArgument instanceof KtFunction) {
|
||||||
ValueParameterDescriptor inlineArgumentDescriptor =
|
ValueParameterDescriptor inlineArgumentDescriptor =
|
||||||
InlineUtil.getInlineArgumentDescriptor((KtFunction) functionArgument, parentCodegen.bindingContext);
|
InlineUtil.getInlineArgumentDescriptor((KtFunction) functionArgument, parentCodegen.bindingContext);
|
||||||
if (inlineArgumentDescriptor != null) {
|
if (inlineArgumentDescriptor != null) {
|
||||||
functionName = inlineArgumentDescriptor.getContainingDeclaration().getName().asString();
|
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) {
|
for (literal in literalsOrFunctions) {
|
||||||
if (InlineUtil.isInlinedArgument(literal, typeMapper.bindingContext, true)) {
|
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
|
return literal
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import com.intellij.psi.PsiElement
|
|||||||
import com.sun.jdi.*
|
import com.sun.jdi.*
|
||||||
import com.sun.tools.jdi.LocalVariableImpl
|
import com.sun.tools.jdi.LocalVariableImpl
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
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.DO_RESUME_METHOD_NAME
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME
|
import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmTypes
|
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) }
|
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 visibleVariables = location.visibleVariables(debugProcess)
|
||||||
val markerLocalVariables = visibleVariables.filter { it.name().startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT) }
|
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) }
|
val functionName = runReadAction { functionNameByArgument(inlineArgument, context) }
|
||||||
|
|
||||||
return markerLocalVariables
|
return markerLocalVariables
|
||||||
.map { it.name() }
|
.map { it.name().drop(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT.length) }
|
||||||
.any { variableName ->
|
.any { variableName ->
|
||||||
lambdaOrdinalByLocalVariable(variableName) == lambdaOrdinal && functionNameByLocalVariable(variableName) == functionName
|
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? {
|
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");
|
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")
|
@TestMetadata("kt5554OnlyIntsShouldBeCoerced.kt")
|
||||||
public void testKt5554OnlyIntsShouldBeCoerced() throws Exception {
|
public void testKt5554OnlyIntsShouldBeCoerced() throws Exception {
|
||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt5554OnlyIntsShouldBeCoerced.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/kt5554OnlyIntsShouldBeCoerced.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user