Fix breakpoint handling in Kotlin scripts (KT-29234)
This commit is contained in:
@@ -26,6 +26,7 @@ import com.sun.jdi.ObjectCollectedException
|
|||||||
import com.sun.jdi.ReferenceType
|
import com.sun.jdi.ReferenceType
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass
|
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClassOrNull
|
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClassOrNull
|
||||||
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||||
import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny
|
import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
|
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
|
||||||
@@ -120,6 +121,10 @@ class DebuggerClassNameProvider(
|
|||||||
if (element == null) return EMPTY
|
if (element == null) return EMPTY
|
||||||
|
|
||||||
return when (element) {
|
return when (element) {
|
||||||
|
is KtScript -> {
|
||||||
|
getClassType(element)?.let { return Cached(it) }
|
||||||
|
return EMPTY
|
||||||
|
}
|
||||||
is KtFile -> {
|
is KtFile -> {
|
||||||
val fileClassName = runReadAction { JvmFileClassUtil.getFileClassInternalName(element) }.toJdiName()
|
val fileClassName = runReadAction { JvmFileClassUtil.getFileClassInternalName(element) }.toJdiName()
|
||||||
ComputedClassNames.Cached(fileClassName)
|
ComputedClassNames.Cached(fileClassName)
|
||||||
@@ -190,20 +195,18 @@ class DebuggerClassNameProvider(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is KtNamedFunction -> {
|
is KtNamedFunction -> {
|
||||||
val typeMapper = KotlinDebuggerCaches.getOrCreateTypeMapper(element)
|
|
||||||
|
|
||||||
val classNamesOfContainingDeclaration = getOuterClassNamesForElement(element.relevantParentInReadAction)
|
val classNamesOfContainingDeclaration = getOuterClassNamesForElement(element.relevantParentInReadAction)
|
||||||
|
|
||||||
val nonInlineClasses: ComputedClassNames =
|
val nonInlineClasses: ComputedClassNames =
|
||||||
if (runReadAction { element.name == null || element.isLocal }) {
|
if (runReadAction { element.name == null || element.isLocal }) {
|
||||||
val typeForAnonymousClass = asmTypeForAnonymousClassOrNull(typeMapper.bindingContext, element)
|
val nameOfAnonymousClass = runReadAction { getClassType(element) }
|
||||||
|
|
||||||
if (typeForAnonymousClass == null) {
|
if (nameOfAnonymousClass == null) {
|
||||||
val parentText = runReadAction { getRelevantElement(element.parent)?.text } ?: "<parent was null>"
|
val parentText = runReadAction { getRelevantElement(element.parent)?.text } ?: "<parent was null>"
|
||||||
LOG.error("Can not get type for ${runReadAction { element.text }}, parent: $parentText")
|
LOG.error("Can not get type for ${runReadAction { element.text }}, parent: $parentText")
|
||||||
classNamesOfContainingDeclaration
|
classNamesOfContainingDeclaration
|
||||||
} else {
|
} else {
|
||||||
classNamesOfContainingDeclaration + ComputedClassNames.Cached(typeForAnonymousClass.internalName.toJdiName())
|
classNamesOfContainingDeclaration + Cached(nameOfAnonymousClass)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
classNamesOfContainingDeclaration
|
classNamesOfContainingDeclaration
|
||||||
@@ -243,6 +246,26 @@ class DebuggerClassNameProvider(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should be called in a read action
|
||||||
|
private fun getClassType(element: KtElement): String? {
|
||||||
|
val typeMapper = KotlinDebuggerCaches.getOrCreateTypeMapper(element)
|
||||||
|
asmTypeForAnonymousClassOrNull(typeMapper.bindingContext, element)?.let { return it.className }
|
||||||
|
|
||||||
|
val descriptor = typeMapper.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, element]
|
||||||
|
if (descriptor is ScriptDescriptor) {
|
||||||
|
return typeMapper.mapClass(descriptor).className
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor != null) {
|
||||||
|
val containingDeclaration = descriptor.containingDeclaration
|
||||||
|
if (containingDeclaration is ScriptDescriptor) {
|
||||||
|
return typeMapper.mapClass(containingDeclaration).className
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
private fun getNameForNonLocalClass(nonLocalClassOrObject: KtClassOrObject): String? {
|
private fun getNameForNonLocalClass(nonLocalClassOrObject: KtClassOrObject): String? {
|
||||||
val typeMapper = KotlinDebuggerCaches.getOrCreateTypeMapper(nonLocalClassOrObject)
|
val typeMapper = KotlinDebuggerCaches.getOrCreateTypeMapper(nonLocalClassOrObject)
|
||||||
val descriptor = typeMapper.bindingContext[BindingContext.CLASS, nonLocalClassOrObject] ?: return null
|
val descriptor = typeMapper.bindingContext[BindingContext.CLASS, nonLocalClassOrObject] ?: return null
|
||||||
|
|||||||
Reference in New Issue
Block a user