Switch to isApplicableAsync instead of isApplicable in ToStringRenderer

#KT-39717 fixed
This commit is contained in:
Vladimir Ilmov
2020-07-06 11:28:05 +02:00
parent 3d9353f7f5
commit 7f472ba24e
@@ -0,0 +1,121 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.render
import com.intellij.debugger.DebuggerManagerEx
import com.intellij.debugger.engine.DebuggerManagerThreadImpl
import com.intellij.debugger.engine.evaluation.EvaluationContext
import com.intellij.debugger.settings.NodeRendererSettings
import com.intellij.debugger.ui.impl.watch.MessageDescriptor
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl
import com.intellij.debugger.ui.tree.DebuggerTreeNode
import com.intellij.debugger.ui.tree.ValueDescriptor
import com.intellij.debugger.ui.tree.render.ChildrenBuilder
import com.intellij.debugger.ui.tree.render.ClassRenderer
import com.intellij.debugger.ui.tree.render.DescriptorLabelListener
import com.intellij.openapi.diagnostic.Logger
import com.intellij.xdebugger.settings.XDebuggerSettingsManager
import com.sun.jdi.*
import org.jetbrains.kotlin.idea.debugger.*
import org.jetbrains.kotlin.load.java.JvmAbi
import java.util.*
private val LOG = Logger.getInstance(KotlinClassWithDelegatedPropertyRenderer::class.java)
private fun notPreparedClassMessage(referenceType: ReferenceType) =
"$referenceType ${referenceType.isPrepared} ${referenceType.sourceName()}"
class KotlinClassWithDelegatedPropertyRenderer : ClassRenderer() {
private val rendererSettings = NodeRendererSettings.getInstance()
override fun isApplicable(jdiType: Type?): Boolean {
if (!super.isApplicable(jdiType) || jdiType !is ReferenceType || !jdiType.isPrepared || !jdiType.isInKotlinSources()) {
return false
}
try {
return jdiType.allFields().any { it.name().endsWith(JvmAbi.DELEGATED_PROPERTY_NAME_SUFFIX) }
} catch (notPrepared: ClassNotPreparedException) {
LOG.error(notPreparedClassMessage(jdiType), notPrepared)
}
return false
}
override fun calcLabel(
descriptor: ValueDescriptor,
evaluationContext: EvaluationContext,
listener: DescriptorLabelListener
): String {
val res = calcToStringLabel(descriptor, evaluationContext, listener)
if (res != null) {
return res
}
return super.calcLabel(descriptor, evaluationContext, listener)
}
private fun calcToStringLabel(
descriptor: ValueDescriptor, evaluationContext: EvaluationContext,
listener: DescriptorLabelListener
): String? {
val toStringRenderer = rendererSettings.toStringRenderer
if (toStringRenderer.isEnabled && DebuggerManagerEx.getInstanceEx(evaluationContext.project).context.canRunEvaluation) {
val label = toStringRenderer.isApplicableAsync(descriptor.type).thenApply { applicable: Boolean ->
if (applicable) toStringRenderer.calcLabel(descriptor, evaluationContext, listener) else null
}.get()
return label
}
return null
}
override fun buildChildren(value: Value?, builder: ChildrenBuilder, context: EvaluationContext) {
DebuggerManagerThreadImpl.assertIsManagerThread()
if (value !is ObjectReference) return
val nodeManager = builder.nodeManager!!
val nodeDescriptorFactory = builder.descriptorManager!!
val fields = value.referenceType().allFields()
if (fields.isEmpty()) {
builder.setChildren(listOf(nodeManager.createMessageNode(MessageDescriptor.CLASS_HAS_NO_FIELDS.label)))
return
}
val children = ArrayList<DebuggerTreeNode>()
for (field in fields) {
if (!shouldDisplay(context, value, field)) {
continue
}
val fieldDescriptor = nodeDescriptorFactory.getFieldDescriptor(builder.parentDescriptor, value, field)
if (field.name().endsWith(JvmAbi.DELEGATED_PROPERTY_NAME_SUFFIX)) {
val shouldRenderDelegatedProperty = KotlinDebuggerSettings.getInstance().renderDelegatedProperties
if (shouldRenderDelegatedProperty && !ToggleKotlinVariablesState.getService().kotlinVariableView) {
children.add(nodeManager.createNode(fieldDescriptor, context))
}
val delegatedPropertyDescriptor = DelegatedPropertyFieldDescriptor(
context.debugProcess.project!!,
value,
field,
shouldRenderDelegatedProperty
)
children.add(nodeManager.createNode(delegatedPropertyDescriptor, context))
} else {
children.add(nodeManager.createNode(fieldDescriptor, context))
}
}
if (XDebuggerSettingsManager.getInstance()!!.dataViewSettings.isSortValues) {
children.sortedWith(NodeManagerImpl.getNodeComparator())
}
builder.setChildren(children)
}
}