Debugger: Hide call-site 'this' in inline functions in Kotlin variables mode (KT-30610)
This commit is contained in:
@@ -104,6 +104,8 @@ public class AsmUtil {
|
|||||||
|
|
||||||
public static final String LABELED_THIS_FIELD = THIS + "_";
|
public static final String LABELED_THIS_FIELD = THIS + "_";
|
||||||
|
|
||||||
|
public static final String INLINE_DECLARATION_SITE_THIS = "this_";
|
||||||
|
|
||||||
public static final String LABELED_THIS_PARAMETER = "$" + THIS + "$";
|
public static final String LABELED_THIS_PARAMETER = "$" + THIS + "$";
|
||||||
|
|
||||||
public static final String CAPTURED_THIS_FIELD = "this$0";
|
public static final String CAPTURED_THIS_FIELD = "this$0";
|
||||||
|
|||||||
@@ -487,7 +487,7 @@ class MethodInliner(
|
|||||||
) {
|
) {
|
||||||
if (isInliningLambda || GENERATE_DEBUG_INFO) {
|
if (isInliningLambda || GENERATE_DEBUG_INFO) {
|
||||||
val varSuffix = if (inliningContext.isRoot && !isFakeLocalVariableForInline(name)) INLINE_FUN_VAR_SUFFIX else ""
|
val varSuffix = if (inliningContext.isRoot && !isFakeLocalVariableForInline(name)) INLINE_FUN_VAR_SUFFIX else ""
|
||||||
val varName = if (!varSuffix.isEmpty() && name == "this") name + "_" else name
|
val varName = if (!varSuffix.isEmpty() && name == AsmUtil.THIS) AsmUtil.INLINE_DECLARATION_SITE_THIS else name
|
||||||
super.visitLocalVariable(varName + varSuffix, desc, signature, start, end, getNewIndex(index))
|
super.visitLocalVariable(varName + varSuffix, desc, signature, start, end, getNewIndex(index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,24 @@ class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDe
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return removeCallSiteThisInInlineFunction(evaluationContext, children)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeCallSiteThisInInlineFunction(evaluationContext: EvaluationContextImpl, children: XValueChildrenList): Boolean {
|
||||||
|
val frameProxy = evaluationContext.frameProxy
|
||||||
|
|
||||||
|
val variables = frameProxy?.safeVisibleVariables() ?: return false
|
||||||
|
val inlineDepth = VariableFinder.getInlineDepth(variables)
|
||||||
|
val declarationSiteThis = variables.firstOrNull { v ->
|
||||||
|
val name = v.name()
|
||||||
|
name.endsWith(INLINE_FUN_VAR_SUFFIX) && name.dropInlineSuffix() == AsmUtil.INLINE_DECLARATION_SITE_THIS
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inlineDepth > 0 && declarationSiteThis != null) {
|
||||||
|
ExistingInstanceThis.find(children)?.remove()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-4
@@ -75,10 +75,7 @@ class VariableFinder(private val context: ExecutionContext) {
|
|||||||
return EvaluateExceptionUtil.createEvaluateException(message)
|
return EvaluateExceptionUtil.createEvaluateException(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// org.jetbrains.kotlin.codegen.inline.MethodInliner.prepareNode
|
val inlinedThisRegex = getLocalVariableNameRegexInlineAware(AsmUtil.INLINE_DECLARATION_SITE_THIS)
|
||||||
private const val OUTER_THIS_FOR_INLINE = AsmUtil.THIS + '_'
|
|
||||||
|
|
||||||
val inlinedThisRegex = getLocalVariableNameRegexInlineAware(OUTER_THIS_FOR_INLINE)
|
|
||||||
|
|
||||||
private fun getCapturedVariableNameRegex(capturedName: String): Regex {
|
private fun getCapturedVariableNameRegex(capturedName: String): Regex {
|
||||||
val escapedName = Regex.escape(capturedName)
|
val escapedName = Regex.escape(capturedName)
|
||||||
|
|||||||
-2
@@ -7,8 +7,6 @@ frameInlineFunCallInsideInlineFunKotlinVariables.kt:8
|
|||||||
Compile bytecode for element
|
Compile bytecode for element
|
||||||
Compile bytecode for this.prop
|
Compile bytecode for this.prop
|
||||||
frame = bar:8, C {frameInlineFunCallInsideInlineFunKotlinVariables}
|
frame = bar:8, C {frameInlineFunCallInsideInlineFunKotlinVariables}
|
||||||
this = this = {frameInlineFunCallInsideInlineFunKotlinVariables.C@uniqueID}
|
|
||||||
- Class has no fields
|
|
||||||
local = this: frameInlineFunCallInsideInlineFunKotlinVariables.A = {frameInlineFunCallInsideInlineFunKotlinVariables.A@uniqueID} (sp = null)
|
local = this: frameInlineFunCallInsideInlineFunKotlinVariables.A = {frameInlineFunCallInsideInlineFunKotlinVariables.A@uniqueID} (sp = null)
|
||||||
field = prop: int = 1 (sp = frameInlineFunCallInsideInlineFunKotlinVariables.kt, 11)
|
field = prop: int = 1 (sp = frameInlineFunCallInsideInlineFunKotlinVariables.kt, 11)
|
||||||
local = element: double = 1.0 (sp = frameInlineFunCallInsideInlineFunKotlinVariables.kt, 7)
|
local = element: double = 1.0 (sp = frameInlineFunCallInsideInlineFunKotlinVariables.kt, 7)
|
||||||
|
|||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package inlineFunThisKotlinVariables
|
||||||
|
|
||||||
|
class Same {
|
||||||
|
fun useInline() {
|
||||||
|
Different().inlineFun()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Different {
|
||||||
|
inline fun inlineFun() {
|
||||||
|
//Breakpoint!
|
||||||
|
println(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
Same().useInline()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRINT_FRAME
|
||||||
|
// SHOW_KOTLIN_VARIABLES
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
LineBreakpoint created at inlineFunThisKotlinVariables.kt:12
|
||||||
|
Run Java
|
||||||
|
Connected to the target VM
|
||||||
|
inlineFunThisKotlinVariables.kt:12
|
||||||
|
frame = useInline:12, Same {inlineFunThisKotlinVariables}
|
||||||
|
local = this: inlineFunThisKotlinVariables.Different = {inlineFunThisKotlinVariables.Different@uniqueID} (sp = null)
|
||||||
|
- Class has no fields
|
||||||
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
|
1
|
||||||
Generated
+5
@@ -800,6 +800,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/hideSyntheticThis.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/hideSyntheticThis.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineFunThisKotlinVariables.kt")
|
||||||
|
public void testInlineFunThisKotlinVariables() throws Exception {
|
||||||
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/inlineFunThisKotlinVariables.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambdaFun1.kt")
|
@TestMetadata("lambdaFun1.kt")
|
||||||
public void testLambdaFun1() throws Exception {
|
public void testLambdaFun1() throws Exception {
|
||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/lambdaFun1.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/frame/lambdaFun1.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user