Count JVM class name for inlined function from base declaration
Drop code with naive removing all anonymous classes. Breakpoints now works when inline call is in anonymous call.
This commit is contained in:
committed by
Nikolay Krasko
parent
cd92e3fc98
commit
dffbe0f707
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
|
|||||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
@@ -187,7 +188,7 @@ class DebuggerClassNameProvider(val myDebugProcess: DebugProcess, val scopes: Li
|
|||||||
private fun inlineCallClassPatterns(typeMapper: KotlinTypeMapper, element: KtElement): List<String> {
|
private fun inlineCallClassPatterns(typeMapper: KotlinTypeMapper, element: KtElement): List<String> {
|
||||||
val context = typeMapper.bindingContext
|
val context = typeMapper.bindingContext
|
||||||
|
|
||||||
val (inlineCall, ktAnonymousClassElementProducer) = runReadAction {
|
val inlineCall = runReadAction {
|
||||||
element.parents.map {
|
element.parents.map {
|
||||||
val ktCallExpression: KtCallExpression = when(it) {
|
val ktCallExpression: KtCallExpression = when(it) {
|
||||||
is KtFunctionLiteral -> {
|
is KtFunctionLiteral -> {
|
||||||
@@ -210,31 +211,26 @@ class DebuggerClassNameProvider(val myDebugProcess: DebugProcess, val scopes: Li
|
|||||||
ktCallExpression to (it as KtElement)
|
ktCallExpression to (it as KtElement)
|
||||||
}.lastOrNull {
|
}.lastOrNull {
|
||||||
it != null && isInlineCall(context, it.component1())
|
it != null && isInlineCall(context, it.component1())
|
||||||
}
|
}?.first
|
||||||
} ?: return emptyList()
|
} ?: return emptyList()
|
||||||
|
|
||||||
val lexicalScope = context[BindingContext.LEXICAL_SCOPE, inlineCall] ?: return emptyList()
|
val lexicalScope = context[BindingContext.LEXICAL_SCOPE, inlineCall] ?: return emptyList()
|
||||||
|
val baseClassName = classNamesForPosition(inlineCall, false).firstOrNull() ?: return emptyList()
|
||||||
|
|
||||||
val resolvedCall = runReadAction { inlineCall.getResolvedCall(context) } ?: return emptyList()
|
val resolvedCall = runReadAction { inlineCall.getResolvedCall(context) } ?: return emptyList()
|
||||||
val inlineFunctionName = resolvedCall.resultingDescriptor.name
|
val inlineFunctionName = resolvedCall.resultingDescriptor.name
|
||||||
|
|
||||||
val originalInternalClassName = CodegenBinding.asmTypeForAnonymousClass(
|
|
||||||
typeMapper.bindingContext, ktAnonymousClassElementProducer).internalName
|
|
||||||
|
|
||||||
val ownerDescriptor = lexicalScope.ownerDescriptor
|
val ownerDescriptor = lexicalScope.ownerDescriptor
|
||||||
|
val ownerDescriptorName = if (isFunctionWithSuspendStateMachine(ownerDescriptor, typeMapper.bindingContext)) {
|
||||||
val className = if (isFunctionWithSuspendStateMachine(ownerDescriptor, typeMapper.bindingContext)) {
|
Name.identifier(DO_RESUME_METHOD_NAME)
|
||||||
originalInternalClassName.replaceAfterLast("$", DO_RESUME_METHOD_NAME)
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
originalInternalClassName.funPrefix()
|
ownerDescriptor.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val ownerJvmName = if (ownerDescriptorName.isSpecial) InlineCodegenUtil.SPECIAL_TRANSFORMATION_NAME else ownerDescriptorName.asString()
|
||||||
val mangledInternalClassName =
|
val mangledInternalClassName =
|
||||||
className +
|
baseClassName + "$" + ownerJvmName + InlineCodegenUtil.INLINE_CALL_TRANSFORMATION_SUFFIX + "$" + inlineFunctionName
|
||||||
(if (ownerDescriptor.name.isSpecial) "$" + InlineCodegenUtil.SPECIAL_TRANSFORMATION_NAME else "") +
|
|
||||||
InlineCodegenUtil.INLINE_CALL_TRANSFORMATION_SUFFIX + "$" +
|
|
||||||
inlineFunctionName
|
|
||||||
|
|
||||||
return listOf("$mangledInternalClassName*")
|
return listOf("$mangledInternalClassName*")
|
||||||
}
|
}
|
||||||
@@ -254,7 +250,7 @@ class DebuggerClassNameProvider(val myDebugProcess: DebugProcess, val scopes: Li
|
|||||||
KtSecondaryConstructor::class.java)
|
KtSecondaryConstructor::class.java)
|
||||||
|
|
||||||
private fun getElementToCalculateClassName(notPositionedElement: PsiElement?): KtElement? {
|
private fun getElementToCalculateClassName(notPositionedElement: PsiElement?): KtElement? {
|
||||||
if (notPositionedElement?.javaClass as Class<*> in TYPES_TO_CALCULATE_CLASSNAME) return notPositionedElement as KtElement
|
if (notPositionedElement?.let { it::class.java } as Class<*> in TYPES_TO_CALCULATE_CLASSNAME) return notPositionedElement as KtElement
|
||||||
|
|
||||||
return readAction { PsiTreeUtil.getParentOfType(notPositionedElement, *TYPES_TO_CALCULATE_CLASSNAME) }
|
return readAction { PsiTreeUtil.getParentOfType(notPositionedElement, *TYPES_TO_CALCULATE_CLASSNAME) }
|
||||||
}
|
}
|
||||||
@@ -411,17 +407,6 @@ private fun isInlineCall(context: BindingContext, expr: KtCallExpression): Boole
|
|||||||
|
|
||||||
private inline fun <reified T : PsiElement> PsiElement.typedParent(): T? = getStrictParentOfType()
|
private inline fun <reified T : PsiElement> PsiElement.typedParent(): T? = getStrictParentOfType()
|
||||||
|
|
||||||
private fun String.funPrefix(): String {
|
|
||||||
if (lastIndexOf("$") < 0) return this
|
|
||||||
|
|
||||||
val trimmed = trimEnd { it == '$' || it.isDigit() } // Can accidentally trim end of function name if it ends with a number
|
|
||||||
val nextDollarIndex = indexOf('$', startIndex = trimmed.length - 1)
|
|
||||||
|
|
||||||
if (nextDollarIndex < 0) return this
|
|
||||||
|
|
||||||
return this.substring(0, nextDollarIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String.substringIndex(): String {
|
private fun String.substringIndex(): String {
|
||||||
if (lastIndexOf("$") < 0) return this
|
if (lastIndexOf("$") < 0) return this
|
||||||
|
|
||||||
|
|||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
LineBreakpoint created at stopInObjectLiteralInInlineCallWithClosureInAnonymous.kt:11
|
||||||
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! stopInObjectLiteralInInlineCallWithClosureInAnonymous.StopInObjectLiteralInInlineCallWithClosureInAnonymousKt
|
||||||
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
stopInObjectLiteralInInlineCallWithClosureInAnonymous.kt:11
|
||||||
|
stopInObjectLiteralInInlineCallWithClosureInAnonymous.kt:12
|
||||||
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package stopInObjectLiteralInInlineCallWithClosureInAnonymous
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val a = 12
|
||||||
|
|
||||||
|
{
|
||||||
|
inlineF {
|
||||||
|
val s = object : () -> Unit {
|
||||||
|
override fun invoke() {
|
||||||
|
//Breakpoint!
|
||||||
|
nop(a)
|
||||||
|
nop(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <R> inlineF(block: () -> R): R = block()
|
||||||
|
|
||||||
|
fun nop(a: Any) {}
|
||||||
@@ -824,6 +824,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
|||||||
doStepOverTest(fileName);
|
doStepOverTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("stopInObjectLiteralInInlineCallWithClosureInAnonymous.kt")
|
||||||
|
public void testStopInObjectLiteralInInlineCallWithClosureInAnonymous() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInObjectLiteralInInlineCallWithClosureInAnonymous.kt");
|
||||||
|
doStepOverTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("stopInSuspendFunctionWithSuspendPoints.kt")
|
@TestMetadata("stopInSuspendFunctionWithSuspendPoints.kt")
|
||||||
public void testStopInSuspendFunctionWithSuspendPoints() throws Exception {
|
public void testStopInSuspendFunctionWithSuspendPoints() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInSuspendFunctionWithSuspendPoints.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInSuspendFunctionWithSuspendPoints.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user