From 11dfbd5d3d3638821f87eca60abe8726a7466eec Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Tue, 5 Feb 2019 17:57:41 +0300 Subject: [PATCH] Allow '$this$label$' for extension receivers Our mangling works poorly with nested inline function calls (saying, `apply()` inside an another `apply()`). In that case, the generated local variable name for both cases will be `$this$apply`. As the debugger sees only the last (the closest) variable with the same name, we loose the ability to get the first one. This means we might want to add some additional information to the mangling (e.g. add the trailing indices `$this$apply$1`). This commit supports this case. --- .../evaluate/variables/VariableFinder.kt | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt index 8ef9daedff8..463b9bfadd1 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt @@ -237,7 +237,8 @@ class VariableFinder private constructor(private val context: ExecutionContext, val variables = frameProxy.safeVisibleVariables() // Local variables – direct search - findLocalVariable(variables, kind, kind.parameterName)?.let { return it } + val namePredicate = fun(name: String) = name == kind.parameterName || name.startsWith(kind.parameterName + '$') + findLocalVariable(variables, kind, namePredicate)?.let { return it } // Recursive search in local receiver variables findCapturedVariableInReceiver(variables, kind)?.let { return it } @@ -311,19 +312,43 @@ class VariableFinder private constructor(private val context: ExecutionContext, } private fun findLocalVariable(variables: List, kind: VariableKind, name: String): Result? { + return findLocalVariable(variables, kind) { it == name } + } + + private fun findLocalVariable( + variables: List, + kind: VariableKind, + namePredicate: (String) -> Boolean + ): Result? { val inlineDepth = getInlineDepth(variables) if (inlineDepth > 0) { - val nameInlineAwareRegex = getLocalVariableNameRegexInlineAware(name) + val inlineAwareNamePredicate = fun(name: String): Boolean { + var endIndex = name.length + var depth = 0 + + val suffixLen = INLINE_FUN_VAR_SUFFIX.length + while (endIndex >= suffixLen) { + if (name.substring(endIndex - suffixLen, endIndex) != INLINE_FUN_VAR_SUFFIX) { + break + } + + depth++ + endIndex -= suffixLen + } + + return namePredicate(name.take(endIndex)) + } + variables.namedEntitySequence() - .filter { it.name.matches(nameInlineAwareRegex) && getInlineDepth(it.name) == inlineDepth && kind.typeMatches(it.type) } + .filter { inlineAwareNamePredicate(it.name) && getInlineDepth(it.name) == inlineDepth && kind.typeMatches(it.type) } .mapNotNull { it.unwrapAndCheck(kind) } .firstOrNull() ?.let { return it } } variables.namedEntitySequence() - .filter { it.name == name && kind.typeMatches(it.type) } + .filter { namePredicate(it.name) && kind.typeMatches(it.type) } .mapNotNull { it.unwrapAndCheck(kind) } .firstOrNull() ?.let { return it }