Fix breakpoint handling in Kotlin scripts (KT-29234)

This commit is contained in:
Yan Zhulanow
2019-03-05 21:32:02 +03:00
parent 4870b2e6ba
commit d0a61fa7e2
@@ -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