(CoroutineDebugger) Minor issued fixed, log level adjusted for missing classes in JVM.
This commit is contained in:
+1
-2
@@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.jetbrains.kotlin.idea.debugger.coroutine;
|
package org.jetbrains.kotlin.idea.debugger.coroutine;
|
||||||
|
|
||||||
import com.intellij.execution.ExecutionException;
|
|
||||||
import com.intellij.execution.RunConfigurationExtension;
|
import com.intellij.execution.RunConfigurationExtension;
|
||||||
import com.intellij.execution.configurations.JavaParameters;
|
import com.intellij.execution.configurations.JavaParameters;
|
||||||
import com.intellij.execution.configurations.RunConfigurationBase;
|
import com.intellij.execution.configurations.RunConfigurationBase;
|
||||||
@@ -19,7 +18,7 @@ public class CoroutineDebugConfigurationExtension extends RunConfigurationExtens
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends RunConfigurationBase> void updateJavaParameters(
|
public <T extends RunConfigurationBase> void updateJavaParameters(
|
||||||
@NotNull T configuration, @NotNull JavaParameters params, RunnerSettings runnerSettings
|
T configuration, @NotNull JavaParameters params, RunnerSettings runnerSettings
|
||||||
) {
|
) {
|
||||||
if (configuration != null) {
|
if (configuration != null) {
|
||||||
Project project = configuration.getProject();
|
Project project = configuration.getProject();
|
||||||
|
|||||||
+2
-4
@@ -5,11 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.debugger.coroutine
|
package org.jetbrains.kotlin.idea.debugger.coroutine
|
||||||
|
|
||||||
import org.jetbrains.annotations.NonNls
|
|
||||||
|
|
||||||
class CoroutineDebuggerContentInfo {
|
class CoroutineDebuggerContentInfo {
|
||||||
companion object {
|
companion object {
|
||||||
val XCOROUTINE_THREADS_CONTENT = "XCoroutineThreadsContent"
|
const val XCOROUTINE_THREADS_CONTENT = "XCoroutineThreadsContent"
|
||||||
val XCOROUTINE_POPUP_ACTION_GROUP = "Kotlin.XDebugger.Actions"
|
const val XCOROUTINE_POPUP_ACTION_GROUP = "Kotlin.XDebugger.Actions"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-4
@@ -7,16 +7,12 @@ package org.jetbrains.kotlin.idea.debugger.coroutine
|
|||||||
|
|
||||||
import com.intellij.debugger.actions.AsyncStacksToggleAction
|
import com.intellij.debugger.actions.AsyncStacksToggleAction
|
||||||
import com.intellij.debugger.engine.DebugProcessImpl
|
import com.intellij.debugger.engine.DebugProcessImpl
|
||||||
import com.intellij.debugger.engine.SuspendContextImpl
|
|
||||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||||
import com.intellij.openapi.application.Application
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.xdebugger.frame.XStackFrame
|
import com.intellij.xdebugger.frame.XStackFrame
|
||||||
import com.intellij.xdebugger.impl.XDebugSessionImpl
|
import com.intellij.xdebugger.impl.XDebugSessionImpl
|
||||||
import com.sun.jdi.Location
|
import com.sun.jdi.Location
|
||||||
import org.jetbrains.kotlin.idea.debugger.StackFrameInterceptor
|
import org.jetbrains.kotlin.idea.debugger.StackFrameInterceptor
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.ContinuationHolder
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.SkipCoroutineStackFrameProxyImpl
|
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.SkipCoroutineStackFrameProxyImpl
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.CoroutineFrameBuilder
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.CoroutineFrameBuilder
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isInUnitTest
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isInUnitTest
|
||||||
|
|||||||
+12
-9
@@ -45,12 +45,15 @@ class DebuggerConnection(
|
|||||||
val kotlinxCoroutinesCore = params.classPath?.pathList?.firstOrNull { it.contains("kotlinx-coroutines-core") }
|
val kotlinxCoroutinesCore = params.classPath?.pathList?.firstOrNull { it.contains("kotlinx-coroutines-core") }
|
||||||
val kotlinxCoroutinesDebug = params.classPath?.pathList?.firstOrNull { it.contains("kotlinx-coroutines-debug") }
|
val kotlinxCoroutinesDebug = params.classPath?.pathList?.firstOrNull { it.contains("kotlinx-coroutines-debug") }
|
||||||
|
|
||||||
val mode = if (kotlinxCoroutinesDebug != null) {
|
val mode = when {
|
||||||
CoroutineDebuggerMode.VERSION_UP_TO_1_3_5
|
kotlinxCoroutinesDebug != null -> {
|
||||||
} else if (kotlinxCoroutinesCore != null) {
|
CoroutineDebuggerMode.VERSION_UP_TO_1_3_5
|
||||||
determineCoreVersionMode(kotlinxCoroutinesCore)
|
}
|
||||||
} else
|
kotlinxCoroutinesCore != null -> {
|
||||||
CoroutineDebuggerMode.DISABLED
|
determineCoreVersionMode(kotlinxCoroutinesCore)
|
||||||
|
}
|
||||||
|
else -> CoroutineDebuggerMode.DISABLED
|
||||||
|
}
|
||||||
|
|
||||||
when (mode) {
|
when (mode) {
|
||||||
CoroutineDebuggerMode.VERSION_1_3_6_AND_UP -> initializeCoroutineAgent(params, kotlinxCoroutinesCore)
|
CoroutineDebuggerMode.VERSION_1_3_6_AND_UP -> initializeCoroutineAgent(params, kotlinxCoroutinesCore)
|
||||||
@@ -62,12 +65,12 @@ class DebuggerConnection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun determineCoreVersionMode(kotlinxCoroutinesCore: String): CoroutineDebuggerMode {
|
private fun determineCoreVersionMode(kotlinxCoroutinesCore: String): CoroutineDebuggerMode {
|
||||||
val regex = Regex(""".+\Wkotlinx\-coroutines\-core\-(.+)?\.jar""")
|
val regex = Regex(""".+\Wkotlinx-coroutines-core-(.+)?\.jar""")
|
||||||
val matchResult = regex.matchEntire(kotlinxCoroutinesCore) ?: return CoroutineDebuggerMode.DISABLED
|
val matchResult = regex.matchEntire(kotlinxCoroutinesCore) ?: return CoroutineDebuggerMode.DISABLED
|
||||||
|
|
||||||
val coroutinesCoreVersion = DefaultArtifactVersion(matchResult.groupValues.get(1))
|
val coroutinesCoreVersion = DefaultArtifactVersion(matchResult.groupValues[1])
|
||||||
val versionToCompareTo = DefaultArtifactVersion("1.3.5")
|
val versionToCompareTo = DefaultArtifactVersion("1.3.5")
|
||||||
return if (versionToCompareTo.compareTo(coroutinesCoreVersion) < 0)
|
return if (versionToCompareTo < coroutinesCoreVersion)
|
||||||
CoroutineDebuggerMode.VERSION_1_3_6_AND_UP
|
CoroutineDebuggerMode.VERSION_1_3_6_AND_UP
|
||||||
else
|
else
|
||||||
CoroutineDebuggerMode.DISABLED
|
CoroutineDebuggerMode.DISABLED
|
||||||
|
|||||||
+2
-2
@@ -24,9 +24,9 @@ import com.intellij.psi.search.GlobalSearchScope
|
|||||||
import com.intellij.util.text.DateFormatUtil
|
import com.intellij.util.text.DateFormatUtil
|
||||||
import com.intellij.xdebugger.impl.XDebuggerManagerImpl
|
import com.intellij.xdebugger.impl.XDebuggerManagerImpl
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
|
import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.view.CoroutineDumpPanel
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.CoroutineDebugProbesProxy
|
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.CoroutineDebugProbesProxy
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.coroutine.view.CoroutineDumpPanel
|
||||||
|
|
||||||
@Suppress("ComponentNotRegistered")
|
@Suppress("ComponentNotRegistered")
|
||||||
class CoroutineDumpAction : AnAction(), AnAction.TransparentUpdate {
|
class CoroutineDumpAction : AnAction(), AnAction.TransparentUpdate {
|
||||||
@@ -49,7 +49,7 @@ class CoroutineDumpAction : AnAction(), AnAction.TransparentUpdate {
|
|||||||
ApplicationManager.getApplication().invokeLater(f, ModalityState.NON_MODAL)
|
ApplicationManager.getApplication().invokeLater(f, ModalityState.NON_MODAL)
|
||||||
} else {
|
} else {
|
||||||
val message = KotlinDebuggerCoroutinesBundle.message("coroutine.dump.failed")
|
val message = KotlinDebuggerCoroutinesBundle.message("coroutine.dump.failed")
|
||||||
XDebuggerManagerImpl.NOTIFICATION_GROUP.createNotification(message,MessageType.ERROR).notify(project)
|
XDebuggerManagerImpl.NOTIFICATION_GROUP.createNotification(message, MessageType.ERROR).notify(project)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-2
@@ -12,13 +12,12 @@ import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.sun.jdi.ObjectReference
|
import com.sun.jdi.ObjectReference
|
||||||
import com.sun.jdi.Value
|
import com.sun.jdi.Value
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.ContinuationHolder
|
|
||||||
|
|
||||||
class ContinuationValueDescriptorImpl(
|
class ContinuationValueDescriptorImpl(
|
||||||
project: Project,
|
project: Project,
|
||||||
val continuation: ObjectReference,
|
val continuation: ObjectReference,
|
||||||
val fieldName: String,
|
val fieldName: String,
|
||||||
val variableName: String
|
private val variableName: String
|
||||||
) : ValueDescriptorImpl(project) {
|
) : ValueDescriptorImpl(project) {
|
||||||
override fun calcValueName() = variableName
|
override fun calcValueName() = variableName
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -9,7 +9,7 @@ import com.sun.jdi.ObjectReference
|
|||||||
import com.sun.jdi.ThreadReference
|
import com.sun.jdi.ThreadReference
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData.Companion.DEFAULT_COROUTINE_NAME
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData.Companion.DEFAULT_COROUTINE_NAME
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData.Companion.DEFAULT_COROUTINE_STATE
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData.Companion.DEFAULT_COROUTINE_STATE
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.*
|
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.MirrorOfCoroutineInfo
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,9 +31,9 @@ data class CoroutineInfoData(
|
|||||||
|
|
||||||
fun isRunning() = key.state == State.RUNNING
|
fun isRunning() = key.state == State.RUNNING
|
||||||
|
|
||||||
fun topRestoredFrame() = stackTrace.firstOrNull()
|
private fun topRestoredFrame() = stackTrace.firstOrNull()
|
||||||
|
|
||||||
fun topFrameVariables() = stackTrace.firstOrNull()?.spilledVariables ?: emptyList()
|
fun topFrameVariables() = topRestoredFrame()?.spilledVariables ?: emptyList()
|
||||||
|
|
||||||
fun restoredStackTrace(mode: SuspendExitMode): List<CoroutineStackFrameItem> =
|
fun restoredStackTrace(mode: SuspendExitMode): List<CoroutineStackFrameItem> =
|
||||||
if (stackTrace.isNotEmpty() && stackTrace.first().isInvokeSuspend())
|
if (stackTrace.isNotEmpty() && stackTrace.first().isInvokeSuspend())
|
||||||
|
|||||||
+2
-3
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBund
|
|||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
@Deprecated("moved to XCoroutineView")
|
@Deprecated("moved to XCoroutineView")
|
||||||
class CoroutineDescriptorImpl(val infoData: CoroutineInfoData) : NodeDescriptorImpl() {
|
class CoroutineDescriptorImpl(private val infoData: CoroutineInfoData) : NodeDescriptorImpl() {
|
||||||
lateinit var icon: Icon
|
lateinit var icon: Icon
|
||||||
|
|
||||||
override fun getName() = infoData.key.name
|
override fun getName() = infoData.key.name
|
||||||
@@ -74,10 +74,9 @@ class SuspendStackFrameDescriptor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getName() : String? = frame.methodName
|
override fun getName(): String? = frame.methodName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For the case when no data inside frame is available
|
* For the case when no data inside frame is available
|
||||||
*/
|
*/
|
||||||
|
|||||||
+4
-9
@@ -10,16 +10,11 @@ import com.intellij.debugger.jdi.LocalVariableProxyImpl
|
|||||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||||
import com.intellij.debugger.memory.utils.StackFrameItem
|
import com.intellij.debugger.memory.utils.StackFrameItem
|
||||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
||||||
import com.intellij.ui.ColoredTextContainer
|
|
||||||
import com.intellij.ui.SimpleTextAttributes
|
|
||||||
import com.intellij.xdebugger.frame.XCompositeNode
|
import com.intellij.xdebugger.frame.XCompositeNode
|
||||||
import com.intellij.xdebugger.frame.XNamedValue
|
import com.intellij.xdebugger.frame.XNamedValue
|
||||||
import com.intellij.xdebugger.frame.XStackFrame
|
import com.intellij.xdebugger.frame.XStackFrame
|
||||||
import com.intellij.xdebugger.frame.XValueChildrenList
|
import com.intellij.xdebugger.frame.XValueChildrenList
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
|
import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.SkipCoroutineStackFrameProxyImpl
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.coroutineDebuggerTraceEnabled
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.invokeInManagerThread
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.stackFrame.KotlinStackFrame
|
import org.jetbrains.kotlin.idea.debugger.stackFrame.KotlinStackFrame
|
||||||
|
|
||||||
|
|
||||||
@@ -32,10 +27,10 @@ import org.jetbrains.kotlin.idea.debugger.stackFrame.KotlinStackFrame
|
|||||||
|
|
||||||
class CoroutinePreflightStackFrame(
|
class CoroutinePreflightStackFrame(
|
||||||
val coroutineInfoData: CoroutineInfoData,
|
val coroutineInfoData: CoroutineInfoData,
|
||||||
val stackFrameDescriptorImpl: StackFrameDescriptorImpl,
|
private val stackFrameDescriptorImpl: StackFrameDescriptorImpl,
|
||||||
val threadPreCoroutineFrames: List<StackFrameProxyImpl>,
|
val threadPreCoroutineFrames: List<StackFrameProxyImpl>,
|
||||||
val mode: SuspendExitMode,
|
val mode: SuspendExitMode,
|
||||||
val firstFrameVariables: List<XNamedValue> = coroutineInfoData.topFrameVariables()
|
private val firstFrameVariables: List<XNamedValue> = coroutineInfoData.topFrameVariables()
|
||||||
) : KotlinStackFrame(stackFrameDescriptorImpl), JVMStackFrameInfoProvider {
|
) : KotlinStackFrame(stackFrameDescriptorImpl), JVMStackFrameInfoProvider {
|
||||||
|
|
||||||
override fun computeChildren(node: XCompositeNode) {
|
override fun computeChildren(node: XCompositeNode) {
|
||||||
@@ -49,7 +44,7 @@ class CoroutinePreflightStackFrame(
|
|||||||
|
|
||||||
override fun getVisibleVariables(): List<LocalVariableProxyImpl> {
|
override fun getVisibleVariables(): List<LocalVariableProxyImpl> {
|
||||||
// skip restored variables
|
// skip restored variables
|
||||||
return super.getVisibleVariables().filter { v -> ! firstFrameVariables.any { it.name == v.name() } }
|
return super.getVisibleVariables().filter { v -> !firstFrameVariables.any { it.name == v.name() } }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isInLibraryContent() = false
|
override fun isInLibraryContent() = false
|
||||||
@@ -77,7 +72,7 @@ class CreationCoroutineStackFrame(debugProcess: DebugProcessImpl, item: StackFra
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
open class CoroutineStackFrame(debugProcess: DebugProcessImpl, val item: StackFrameItem, val realStackFrame: XStackFrame? = null) :
|
open class CoroutineStackFrame(debugProcess: DebugProcessImpl, val item: StackFrameItem, private val realStackFrame: XStackFrame? = null) :
|
||||||
StackFrameItem.CapturedStackFrame(debugProcess, item) {
|
StackFrameItem.CapturedStackFrame(debugProcess, item) {
|
||||||
|
|
||||||
override fun computeChildren(node: XCompositeNode) {
|
override fun computeChildren(node: XCompositeNode) {
|
||||||
|
|||||||
+7
-6
@@ -6,10 +6,11 @@
|
|||||||
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy
|
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy
|
||||||
|
|
||||||
import com.intellij.debugger.engine.JavaValue
|
import com.intellij.debugger.engine.JavaValue
|
||||||
import com.sun.jdi.*
|
import com.sun.jdi.ObjectReference
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.*
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.*
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.*
|
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.*
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.*
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isAbstractCoroutine
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||||
|
|
||||||
class ContinuationHolder private constructor(val context: DefaultExecutionContext) {
|
class ContinuationHolder private constructor(val context: DefaultExecutionContext) {
|
||||||
@@ -46,8 +47,8 @@ class ContinuationHolder private constructor(val context: DefaultExecutionContex
|
|||||||
val ci = debugProbesImpl?.getCoroutineInfo(input, context)
|
val ci = debugProbesImpl?.getCoroutineInfo(input, context)
|
||||||
if (ci != null) {
|
if (ci != null) {
|
||||||
if (ci.creationStackTrace != null)
|
if (ci.creationStackTrace != null)
|
||||||
for (index in 0 until ci.creationStackTrace.size) {
|
for (index in ci.creationStackTrace.indices) {
|
||||||
val frame = ci.creationStackTrace.get(index)
|
val frame = ci.creationStackTrace[index]
|
||||||
val ste = frame.stackTraceElement()
|
val ste = frame.stackTraceElement()
|
||||||
val location = locationCache.createLocation(ste)
|
val location = locationCache.createLocation(ste)
|
||||||
creationStackTrace.add(CreationCoroutineStackFrameItem(ste, location, index == 0))
|
creationStackTrace.add(CreationCoroutineStackFrameItem(ste, location, index == 0))
|
||||||
@@ -64,14 +65,14 @@ class ContinuationHolder private constructor(val context: DefaultExecutionContex
|
|||||||
fun state(value: ObjectReference?): CoroutineNameIdState? {
|
fun state(value: ObjectReference?): CoroutineNameIdState? {
|
||||||
value ?: return null
|
value ?: return null
|
||||||
val reference = JavaLangMirror(context)
|
val reference = JavaLangMirror(context)
|
||||||
val standaloneCoroutine = StandaloneCoroutine(context)
|
val standaloneCoroutine = StandaloneCoroutine.instance(context) ?: return null
|
||||||
val standAloneCoroutineMirror = standaloneCoroutine.mirror(value, context)
|
val standAloneCoroutineMirror = standaloneCoroutine.mirror(value, context)
|
||||||
if (standAloneCoroutineMirror?.context is MirrorOfCoroutineContext) {
|
if (standAloneCoroutineMirror?.context is MirrorOfCoroutineContext) {
|
||||||
val id = standAloneCoroutineMirror.context.id
|
val id = standAloneCoroutineMirror.context.id
|
||||||
val name = standAloneCoroutineMirror.context.name ?: CoroutineInfoData.DEFAULT_COROUTINE_NAME
|
val name = standAloneCoroutineMirror.context.name ?: CoroutineInfoData.DEFAULT_COROUTINE_NAME
|
||||||
val toString = reference.string(value, context)
|
val toString = reference.string(value, context)
|
||||||
// trying to get coroutine information by calling JobSupport.toString(), ${nameString()}{${stateString(state)}}@$hexAddress
|
// trying to get coroutine information by calling JobSupport.toString(), ${nameString()}{${stateString(state)}}@$hexAddress
|
||||||
val r = """\w+\{(\w+)\}\@([\w\d]+)""".toRegex()
|
val r = """\w+\{(\w+)}@([\w\d]+)""".toRegex()
|
||||||
val matcher = r.toPattern().matcher(toString)
|
val matcher = r.toPattern().matcher(toString)
|
||||||
if (matcher.matches()) {
|
if (matcher.matches()) {
|
||||||
val state = stateOf(matcher.group(1))
|
val state = stateOf(matcher.group(1))
|
||||||
|
|||||||
-1
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.debugger.coroutine.proxy
|
|||||||
import com.intellij.debugger.engine.DebuggerManagerThreadImpl
|
import com.intellij.debugger.engine.DebuggerManagerThreadImpl
|
||||||
import com.intellij.debugger.engine.SuspendContextImpl
|
import com.intellij.debugger.engine.SuspendContextImpl
|
||||||
import com.intellij.openapi.util.registry.Registry
|
import com.intellij.openapi.util.registry.Registry
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.CoroutineFrameBuilder
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoCache
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoCache
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.executionContext
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.executionContext
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||||
|
|||||||
+15
-12
@@ -6,7 +6,10 @@
|
|||||||
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy
|
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy
|
||||||
|
|
||||||
import com.intellij.xdebugger.frame.XNamedValue
|
import com.intellij.xdebugger.frame.XNamedValue
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.*
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineNameIdState
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CreationCoroutineStackFrameItem
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.SuspendCoroutineStackFrameItem
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.DebugMetadata
|
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.DebugMetadata
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.DebugProbesImpl
|
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.DebugProbesImpl
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.MirrorOfCoroutineInfo
|
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.MirrorOfCoroutineInfo
|
||||||
@@ -26,16 +29,16 @@ class CoroutineLibraryAgent2Proxy(private val executionContext: DefaultExecution
|
|||||||
return result.mapNotNull { mapToCoroutineInfoData(it) }
|
return result.mapNotNull { mapToCoroutineInfoData(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mapToCoroutineInfoData(mirror: MirrorOfCoroutineInfo): CoroutineInfoData? {
|
private fun mapToCoroutineInfoData(mirror: MirrorOfCoroutineInfo): CoroutineInfoData? {
|
||||||
val cnis = CoroutineNameIdState.instance(mirror)
|
val coroutineNameIdState = CoroutineNameIdState.instance(mirror)
|
||||||
val stackTrace = mirror.enchancedStackTrace?.mapNotNull { it.stackTraceElement() } ?: emptyList()
|
val stackTrace = mirror.enhancedStackTrace?.mapNotNull { it.stackTraceElement() } ?: emptyList()
|
||||||
val variables: List<XNamedValue> = mirror.lastObservedFrame?.let {
|
val variables: List<XNamedValue> = mirror.lastObservedFrame?.let {
|
||||||
val spilledVariables = debugMetadata?.baseContinuationImpl?.mirror(it, executionContext)
|
val spilledVariables = debugMetadata?.baseContinuationImpl?.mirror(it, executionContext)
|
||||||
spilledVariables?.spilledValues(executionContext)
|
spilledVariables?.spilledValues(executionContext)
|
||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
var stackFrames = findStackFrames(stackTrace, variables)
|
val stackFrames = findStackFrames(stackTrace, variables)
|
||||||
return CoroutineInfoData(
|
return CoroutineInfoData(
|
||||||
cnis,
|
coroutineNameIdState,
|
||||||
stackFrames.restoredStackFrames,
|
stackFrames.restoredStackFrames,
|
||||||
stackFrames.creationStackFrames,
|
stackFrames.creationStackFrames,
|
||||||
mirror.lastObservedThread,
|
mirror.lastObservedThread,
|
||||||
@@ -44,11 +47,11 @@ class CoroutineLibraryAgent2Proxy(private val executionContext: DefaultExecution
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isInstalled(): Boolean {
|
fun isInstalled(): Boolean {
|
||||||
try {
|
return try {
|
||||||
return debugProbesImpl?.isInstalledValue ?: false
|
debugProbesImpl?.isInstalledValue ?: false
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.error("Exception happened while checking agent status.", e)
|
log.error("Exception happened while checking agent status.", e)
|
||||||
return false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,10 +77,10 @@ class CoroutineLibraryAgent2Proxy(private val executionContext: DefaultExecution
|
|||||||
companion object {
|
companion object {
|
||||||
fun instance(executionContext: DefaultExecutionContext): CoroutineLibraryAgent2Proxy? {
|
fun instance(executionContext: DefaultExecutionContext): CoroutineLibraryAgent2Proxy? {
|
||||||
val agentProxy = CoroutineLibraryAgent2Proxy(executionContext)
|
val agentProxy = CoroutineLibraryAgent2Proxy(executionContext)
|
||||||
if (agentProxy.isInstalled())
|
return if (agentProxy.isInstalled())
|
||||||
return agentProxy
|
agentProxy
|
||||||
else
|
else
|
||||||
return null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-190
@@ -1,190 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2020 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.coroutine.proxy
|
|
||||||
|
|
||||||
import com.intellij.debugger.engine.evaluation.EvaluateException
|
|
||||||
import com.sun.jdi.*
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.*
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.CoroutineContext
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.JavaLangMirror
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isCreationSeparatorFrame
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
|
||||||
|
|
||||||
class CoroutineLibraryAgentProxy(private val debugProbesClsRef: ClassType, private val executionContext: DefaultExecutionContext) :
|
|
||||||
CoroutineInfoProvider {
|
|
||||||
private val coroutineContextReference: JavaLangMirror = JavaLangMirror(executionContext)
|
|
||||||
|
|
||||||
private val debugProbesImplClsRef = executionContext.findClass("$DEBUG_PACKAGE.internal.DebugProbesImpl") as ClassType
|
|
||||||
private val debugProbesImplInstance = with(debugProbesImplClsRef) { getValue(fieldByName("INSTANCE")) as ObjectReference }
|
|
||||||
private val enhanceStackTraceWithThreadDumpRef: Method = debugProbesImplClsRef
|
|
||||||
.methodsByName("enhanceStackTraceWithThreadDump").single()
|
|
||||||
|
|
||||||
private val dumpMethod: Method = debugProbesClsRef.concreteMethodByName("dumpCoroutinesInfo", "()Ljava/util/List;")
|
|
||||||
val instance = with(debugProbesClsRef) { getValue(fieldByName("INSTANCE")) as ObjectReference }
|
|
||||||
|
|
||||||
// CoroutineInfo
|
|
||||||
private val coroutineInfoClsRef = executionContext.findClass("$DEBUG_PACKAGE.CoroutineInfo") as ClassType
|
|
||||||
|
|
||||||
private val getStateRef: Method = coroutineInfoClsRef.concreteMethodByName("getState", "()Lkotlinx/coroutines/debug/State;")
|
|
||||||
private val getContextRef: Method = coroutineInfoClsRef.concreteMethodByName("getContext", "()Lkotlin/coroutines/CoroutineContext;")
|
|
||||||
private val lastObservedStackTraceRef: Method = coroutineInfoClsRef.methodsByName("lastObservedStackTrace").single()
|
|
||||||
|
|
||||||
private val sequenceNumberFieldRef: Field = coroutineInfoClsRef.fieldByName("sequenceNumber")
|
|
||||||
private val lastObservedThreadFieldRef: Field = coroutineInfoClsRef.fieldByName("lastObservedThread")
|
|
||||||
private val lastObservedFrameFieldRef: Field = coroutineInfoClsRef.fieldByName("lastObservedFrame") // continuation
|
|
||||||
|
|
||||||
// value
|
|
||||||
private val vm = executionContext.vm
|
|
||||||
private val locationCache = LocationCache(executionContext)
|
|
||||||
|
|
||||||
private val coroutineContext: CoroutineContext = CoroutineContext(executionContext)
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
@Suppress("unused")
|
|
||||||
fun install() =
|
|
||||||
executionContext.invokeMethodAsVoid(instance, "install")
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
@Suppress("unused")
|
|
||||||
fun uninstall() =
|
|
||||||
executionContext.invokeMethodAsVoid(instance, "uninstall")
|
|
||||||
|
|
||||||
override fun dumpCoroutinesInfo(): List<CoroutineInfoData> {
|
|
||||||
val coroutinesInfo = executionContext.invokeMethodAsObject(instance, dumpMethod) ?: return emptyList()
|
|
||||||
executionContext.keepReference(coroutinesInfo)
|
|
||||||
val size = coroutineContextReference.sizeOf(coroutinesInfo, executionContext)
|
|
||||||
|
|
||||||
return MutableList(size) {
|
|
||||||
val elem = coroutineContextReference.elementFromList(coroutinesInfo, it, executionContext)
|
|
||||||
fetchCoroutineState(elem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fetchCoroutineState(instance: ObjectReference): CoroutineInfoData {
|
|
||||||
val name = getName(instance)
|
|
||||||
val state = getState(instance)
|
|
||||||
val thread = getLastObservedThread(instance, lastObservedThreadFieldRef)
|
|
||||||
val lastObservedFrameFieldRef = instance.getValue(lastObservedFrameFieldRef) as? ObjectReference
|
|
||||||
val stackTrace = getStackTrace(instance)
|
|
||||||
val creationFrameSeparatorIndex = findCreationFrameIndex(stackTrace)
|
|
||||||
val coroutineStackTrace = stackTrace.take(creationFrameSeparatorIndex)
|
|
||||||
|
|
||||||
val coroutineStackTraceFrameItems = coroutineStackTrace.map {
|
|
||||||
SuspendCoroutineStackFrameItem(it, locationCache.createLocation(it))
|
|
||||||
}
|
|
||||||
val creationStackTrace = stackTrace.subList(creationFrameSeparatorIndex + 1, stackTrace.size)
|
|
||||||
val creationStackTraceFrameItems = creationStackTrace.mapIndexed { index, stackTraceElement ->
|
|
||||||
CreationCoroutineStackFrameItem(stackTraceElement, locationCache.createLocation(stackTraceElement), index == 0)
|
|
||||||
}
|
|
||||||
val key = CoroutineNameIdState(name, "", State.valueOf(state), "")
|
|
||||||
|
|
||||||
return CoroutineInfoData(
|
|
||||||
key,
|
|
||||||
coroutineStackTraceFrameItems.toMutableList(),
|
|
||||||
creationStackTraceFrameItems,
|
|
||||||
thread,
|
|
||||||
lastObservedFrameFieldRef
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to find creation frame separator if any, returns last index if none found
|
|
||||||
*/
|
|
||||||
private fun findCreationFrameIndex(frames: List<StackTraceElement>): Int {
|
|
||||||
val index = frames.indexOfFirst { it.isCreationSeparatorFrame() }
|
|
||||||
return if (index < 0)
|
|
||||||
frames.lastIndex
|
|
||||||
else
|
|
||||||
index
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getName(
|
|
||||||
info: ObjectReference // CoroutineInfo instance
|
|
||||||
): String {
|
|
||||||
// equals to `coroutineInfo.context.get(CoroutineName).name`
|
|
||||||
val coroutineContextInst = executionContext.invokeMethod(
|
|
||||||
info,
|
|
||||||
getContextRef,
|
|
||||||
emptyList()
|
|
||||||
) as? ObjectReference ?: throw IllegalArgumentException("Coroutine context must not be null")
|
|
||||||
val context = coroutineContext.mirror(coroutineContextInst, executionContext)
|
|
||||||
val name = context?.name ?: "coroutine"
|
|
||||||
val id = (info.getValue(sequenceNumberFieldRef) as LongValue).value()
|
|
||||||
return "$name#$id"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getState(
|
|
||||||
info: ObjectReference // CoroutineInfo instance
|
|
||||||
): String {
|
|
||||||
// equals to `stringState = coroutineInfo.state.toString()`
|
|
||||||
val state = executionContext.invokeMethod(info, getStateRef, emptyList()) as ObjectReference
|
|
||||||
return coroutineContextReference.string(state, executionContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getLastObservedThread(
|
|
||||||
info: ObjectReference, // CoroutineInfo instance
|
|
||||||
threadRef: Field // reference to lastObservedThread
|
|
||||||
): ThreadReference? = info.getValue(threadRef) as? ThreadReference
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns list of stackTraceElements for the given CoroutineInfo's [ObjectReference]
|
|
||||||
*/
|
|
||||||
private fun getStackTrace(
|
|
||||||
info: ObjectReference
|
|
||||||
): List<StackTraceElement> {
|
|
||||||
val frameList = lastObservedStackTrace(info)
|
|
||||||
// val tmpList = mutableListOf<StackTraceElement>()
|
|
||||||
// val sizeOfFrameList = coroutineContextReference.sizeOf(frameList, executionContext)
|
|
||||||
// for (it in 0 until sizeOfFrameList) {
|
|
||||||
// val frame = coroutineContextReference.elementFromList(frameList, it, executionContext)
|
|
||||||
// val ste = coroutineContextReference.stackTraceElement(frame)
|
|
||||||
// tmpList.add(ste)
|
|
||||||
// }
|
|
||||||
val mergedFrameList = enhanceStackTraceWithThreadDump(listOf(info, frameList))
|
|
||||||
val sizeOfMergedFrameList = coroutineContextReference.sizeOf(mergedFrameList, executionContext)
|
|
||||||
|
|
||||||
val list = mutableListOf<StackTraceElement>()
|
|
||||||
|
|
||||||
for (it in 0 until sizeOfMergedFrameList) {
|
|
||||||
val frame = coroutineContextReference.elementFromList(mergedFrameList, it, executionContext)
|
|
||||||
val ste = coroutineContextReference.stackTraceElement(frame)
|
|
||||||
list.add(// 0, // add in the beginning // @TODO what's the point?
|
|
||||||
ste
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun lastObservedStackTrace(instance: ObjectReference) =
|
|
||||||
executionContext.invokeMethod(instance, lastObservedStackTraceRef, emptyList()) as ObjectReference
|
|
||||||
|
|
||||||
private fun enhanceStackTraceWithThreadDump(args: List<ObjectReference>) =
|
|
||||||
executionContext.invokeMethod(
|
|
||||||
debugProbesImplInstance,
|
|
||||||
enhanceStackTraceWithThreadDumpRef, args
|
|
||||||
) as ObjectReference
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val DEBUG_PACKAGE = "kotlinx.coroutines.debug"
|
|
||||||
|
|
||||||
fun instance(executionContext: DefaultExecutionContext): CoroutineLibraryAgentProxy? {
|
|
||||||
try {
|
|
||||||
val debugProbesClsRef = executionContext.findClass("$DEBUG_PACKAGE.DebugProbes") ?: return null
|
|
||||||
if (debugProbesClsRef is ClassType) {
|
|
||||||
val instanceField = debugProbesClsRef.fieldByName("INSTANCE")
|
|
||||||
val debugProbes = debugProbesClsRef.getValue(instanceField) as ObjectReference
|
|
||||||
val f = debugProbes.referenceType().fieldByName("isInstalled")
|
|
||||||
val debugProbesActivated = if (f != null) (debugProbes.getValue(f) as BooleanValue).value() else true
|
|
||||||
if (debugProbesActivated)
|
|
||||||
return CoroutineLibraryAgentProxy(debugProbesClsRef, executionContext)
|
|
||||||
}
|
|
||||||
} catch (e: EvaluateException) {
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+8
-7
@@ -6,7 +6,8 @@
|
|||||||
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy
|
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy
|
||||||
|
|
||||||
import com.intellij.openapi.util.registry.Registry
|
import com.intellij.openapi.util.registry.Registry
|
||||||
import com.sun.jdi.*
|
import com.sun.jdi.Field
|
||||||
|
import com.sun.jdi.ObjectReference
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.CancellableContinuationImpl
|
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror.CancellableContinuationImpl
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.findCancellableContinuationImplReferenceType
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.findCancellableContinuationImplReferenceType
|
||||||
@@ -15,10 +16,10 @@ import org.jetbrains.kotlin.idea.debugger.coroutine.util.findDispatchedContinuat
|
|||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||||
|
|
||||||
class CoroutineNoLibraryProxy(val executionContext: DefaultExecutionContext) : CoroutineInfoProvider {
|
class CoroutineNoLibraryProxy(private val executionContext: DefaultExecutionContext) : CoroutineInfoProvider {
|
||||||
val log by logger
|
val log by logger
|
||||||
val debugMetadataKtType = executionContext.findCoroutineMetadataType()
|
private val debugMetadataKtType = executionContext.findCoroutineMetadataType()
|
||||||
val holder = ContinuationHolder.instance(executionContext)
|
private val holder = ContinuationHolder.instance(executionContext)
|
||||||
|
|
||||||
override fun dumpCoroutinesInfo(): List<CoroutineInfoData> {
|
override fun dumpCoroutinesInfo(): List<CoroutineInfoData> {
|
||||||
val vm = executionContext.vm
|
val vm = executionContext.vm
|
||||||
@@ -49,13 +50,13 @@ class CoroutineNoLibraryProxy(val executionContext: DefaultExecutionContext) : C
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun extractCancellableContinuation(
|
private fun extractCancellableContinuation(
|
||||||
dispatchedContinuation: ObjectReference,
|
dispatchedContinuation: ObjectReference,
|
||||||
ccMirrorProvider: CancellableContinuationImpl
|
ccMirrorProvider: CancellableContinuationImpl
|
||||||
): CoroutineInfoData? {
|
): CoroutineInfoData? {
|
||||||
val mirror = ccMirrorProvider.mirror(dispatchedContinuation, executionContext) ?: return null
|
val mirror = ccMirrorProvider.mirror(dispatchedContinuation, executionContext) ?: return null
|
||||||
val continuation = mirror.delegate?.continuation ?: return null
|
val continuation = mirror.delegate?.continuation ?: return null
|
||||||
return holder?.extractCoroutineInfoData(continuation)
|
return holder.extractCoroutineInfoData(continuation)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dispatchedContinuation(resultList: MutableList<CoroutineInfoData>): Boolean {
|
private fun dispatchedContinuation(resultList: MutableList<CoroutineInfoData>): Boolean {
|
||||||
@@ -75,7 +76,7 @@ class CoroutineNoLibraryProxy(val executionContext: DefaultExecutionContext) : C
|
|||||||
private fun extractDispatchedContinuation(dispatchedContinuation: ObjectReference, continuation: Field): CoroutineInfoData? {
|
private fun extractDispatchedContinuation(dispatchedContinuation: ObjectReference, continuation: Field): CoroutineInfoData? {
|
||||||
debugMetadataKtType ?: return null
|
debugMetadataKtType ?: return null
|
||||||
val initialContinuation = dispatchedContinuation.getValue(continuation) as ObjectReference
|
val initialContinuation = dispatchedContinuation.getValue(continuation) as ObjectReference
|
||||||
return holder?.extractCoroutineInfoData(initialContinuation)
|
return holder.extractCoroutineInfoData(initialContinuation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-8
@@ -50,15 +50,7 @@ class ManagerThreadExecutor(val debugProcess: DebugProcessImpl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ApplicationThreadExecutor {
|
class ApplicationThreadExecutor {
|
||||||
fun <T> readAction(f: () -> T): T {
|
|
||||||
return ApplicationManager.getApplication().runReadAction(Computable(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun schedule(f: () -> Unit, component: Component) {
|
fun schedule(f: () -> Unit, component: Component) {
|
||||||
return ApplicationManager.getApplication().invokeLater({ f() }, ModalityState.stateForComponent(component))
|
return ApplicationManager.getApplication().invokeLater({ f() }, ModalityState.stateForComponent(component))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun schedule(f: () -> Unit) {
|
|
||||||
return ApplicationManager.getApplication().invokeLater { f() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
-10
@@ -6,16 +6,6 @@
|
|||||||
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy
|
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy
|
||||||
|
|
||||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl
|
|
||||||
import com.sun.jdi.Location
|
|
||||||
import com.sun.jdi.StackFrame
|
|
||||||
|
|
||||||
class LocationStackFrameProxyImpl(val location: Location, frame: StackFrameProxyImpl) :
|
|
||||||
StackFrameProxyImpl(frame.threadProxy(), frame.stackFrame, frame.indexFromBottom) {
|
|
||||||
override fun location(): Location {
|
|
||||||
return location
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SkipCoroutineStackFrameProxyImpl(frame: StackFrameProxyImpl) :
|
class SkipCoroutineStackFrameProxyImpl(frame: StackFrameProxyImpl) :
|
||||||
StackFrameProxyImpl(frame.threadProxy(), frame.stackFrame, frame.indexFromBottom)
|
StackFrameProxyImpl(frame.threadProxy(), frame.stackFrame, frame.indexFromBottom)
|
||||||
+9
-9
@@ -13,26 +13,26 @@ import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
|||||||
abstract class BaseDynamicMirror<T>(val value: ObjectReference, val name: String, val context: DefaultExecutionContext) {
|
abstract class BaseDynamicMirror<T>(val value: ObjectReference, val name: String, val context: DefaultExecutionContext) {
|
||||||
val log by logger
|
val log by logger
|
||||||
|
|
||||||
val cls: ReferenceType? = value.referenceType()
|
private val cls: ReferenceType? = value.referenceType()
|
||||||
|
|
||||||
fun makeField(fieldName: String): Field? =
|
private fun makeField(fieldName: String): Field? =
|
||||||
cls?.let { it.fieldByName(fieldName) }
|
cls?.fieldByName(fieldName)
|
||||||
|
|
||||||
fun findMethod(methodName: String): Method? =
|
fun findMethod(methodName: String): Method? =
|
||||||
cls?.let { it.methodsByName(methodName).single() }
|
cls?.methodsByName(methodName)?.single()
|
||||||
|
|
||||||
fun findMethod(methodName: String, signature: String): Method? =
|
fun findMethod(methodName: String, signature: String): Method? =
|
||||||
cls?.let { it.methodsByName(methodName, signature).single() }
|
cls?.methodsByName(methodName, signature)?.single()
|
||||||
|
|
||||||
fun isCompatible(value: ObjectReference?) =
|
fun isCompatible(value: ObjectReference?) =
|
||||||
value?.let { it.referenceType().isSubTypeOrSame(name) } ?: false
|
value?.referenceType()?.isSubTypeOrSame(name) ?: false
|
||||||
|
|
||||||
fun mirror(): T? {
|
fun mirror(): T? {
|
||||||
if (!isCompatible(value)) {
|
return if (!isCompatible(value)) {
|
||||||
log.trace("Value ${value.referenceType()} is not compatible with $name.")
|
log.trace("Value ${value.referenceType()} is not compatible with $name.")
|
||||||
return null
|
null
|
||||||
} else
|
} else
|
||||||
return fetchMirror(value, context)
|
fetchMirror(value, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun staticObjectValue(fieldName: String): ObjectReference? {
|
fun staticObjectValue(fieldName: String): ObjectReference? {
|
||||||
|
|||||||
+12
-14
@@ -5,18 +5,16 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror
|
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror
|
||||||
|
|
||||||
import com.sun.jdi.Method
|
|
||||||
import com.sun.jdi.ObjectReference
|
import com.sun.jdi.ObjectReference
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||||
import java.lang.StackTraceElement
|
|
||||||
|
|
||||||
class CoroutineContext(context: DefaultExecutionContext) :
|
class CoroutineContext(context: DefaultExecutionContext) :
|
||||||
BaseMirror<MirrorOfCoroutineContext>("kotlin.coroutines.CombinedContext", context) {
|
BaseMirror<MirrorOfCoroutineContext>("kotlin.coroutines.CombinedContext", context) {
|
||||||
val coroutineNameRef = CoroutineName(context)
|
private val coroutineNameRef = CoroutineName(context)
|
||||||
val coroutineIdRef = CoroutineId(context)
|
private val coroutineIdRef = CoroutineId(context)
|
||||||
val jobRef = Job(context)
|
private val jobRef = Job(context)
|
||||||
val dispatcherRef = CoroutineDispatcher(context)
|
private val dispatcherRef = CoroutineDispatcher(context)
|
||||||
val getContextElement = makeMethod("get")
|
private val getContextElement = makeMethod("get")
|
||||||
|
|
||||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfCoroutineContext? {
|
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfCoroutineContext? {
|
||||||
val coroutineName = getElementValue(value, context, coroutineNameRef)
|
val coroutineName = getElementValue(value, context, coroutineNameRef)
|
||||||
@@ -26,7 +24,7 @@ class CoroutineContext(context: DefaultExecutionContext) :
|
|||||||
return MirrorOfCoroutineContext(value, coroutineName, coroutineId, dispatcher, job)
|
return MirrorOfCoroutineContext(value, coroutineName, coroutineId, dispatcher, job)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> getElementValue(value: ObjectReference, context: DefaultExecutionContext, keyProvider: ContextKey<T>): T? {
|
private fun <T> getElementValue(value: ObjectReference, context: DefaultExecutionContext, keyProvider: ContextKey<T>): T? {
|
||||||
val key = keyProvider.key() ?: return null
|
val key = keyProvider.key() ?: return null
|
||||||
val elementValue = objectValue(value, getContextElement, context, key) ?: return null
|
val elementValue = objectValue(value, getContextElement, context, key) ?: return null
|
||||||
return keyProvider.mirror(elementValue, context)
|
return keyProvider.mirror(elementValue, context)
|
||||||
@@ -42,12 +40,12 @@ data class MirrorOfCoroutineContext(
|
|||||||
)
|
)
|
||||||
|
|
||||||
abstract class ContextKey<T>(name: String, context: DefaultExecutionContext) : BaseMirror<T>(name, context) {
|
abstract class ContextKey<T>(name: String, context: DefaultExecutionContext) : BaseMirror<T>(name, context) {
|
||||||
abstract fun key() : ObjectReference?
|
abstract fun key(): ObjectReference?
|
||||||
}
|
}
|
||||||
|
|
||||||
class CoroutineName(context: DefaultExecutionContext) : ContextKey<String>("kotlinx.coroutines.CoroutineName", context) {
|
class CoroutineName(context: DefaultExecutionContext) : ContextKey<String>("kotlinx.coroutines.CoroutineName", context) {
|
||||||
val key = staticObjectValue("Key")
|
val key = staticObjectValue("Key")
|
||||||
val getNameRef = makeMethod("getName")
|
private val getNameRef = makeMethod("getName")
|
||||||
|
|
||||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): String? {
|
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): String? {
|
||||||
return stringValue(value, getNameRef, context)
|
return stringValue(value, getNameRef, context)
|
||||||
@@ -57,8 +55,8 @@ class CoroutineName(context: DefaultExecutionContext) : ContextKey<String>("kotl
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CoroutineId(context: DefaultExecutionContext) : ContextKey<Long>("kotlinx.coroutines.CoroutineId", context) {
|
class CoroutineId(context: DefaultExecutionContext) : ContextKey<Long>("kotlinx.coroutines.CoroutineId", context) {
|
||||||
val key = staticObjectValue("Key")
|
private val key = staticObjectValue("Key")
|
||||||
val getIdRef = makeMethod("getId")
|
private val getIdRef = makeMethod("getId")
|
||||||
|
|
||||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): Long? {
|
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): Long? {
|
||||||
return longValue(value, getIdRef, context)
|
return longValue(value, getIdRef, context)
|
||||||
@@ -79,8 +77,8 @@ class Job(context: DefaultExecutionContext) : ContextKey<ObjectReference>("kotli
|
|||||||
|
|
||||||
|
|
||||||
class CoroutineDispatcher(context: DefaultExecutionContext) : ContextKey<String>("kotlinx.coroutines.CoroutineDispatcher", context) {
|
class CoroutineDispatcher(context: DefaultExecutionContext) : ContextKey<String>("kotlinx.coroutines.CoroutineDispatcher", context) {
|
||||||
val key = staticObjectValue("Key")
|
private val key = staticObjectValue("Key")
|
||||||
val jlm = JavaLangMirror(context)
|
private val jlm = JavaLangMirror(context)
|
||||||
|
|
||||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): String? {
|
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): String? {
|
||||||
return jlm.string(value, context)
|
return jlm.string(value, context)
|
||||||
|
|||||||
+28
-28
@@ -5,29 +5,31 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror
|
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror
|
||||||
|
|
||||||
import com.sun.jdi.*
|
import com.sun.jdi.ObjectReference
|
||||||
|
import com.sun.jdi.ThreadReference
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isSubTypeOrSame
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isSubTypeOrSame
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||||
|
|
||||||
class DebugProbesImpl private constructor(context: DefaultExecutionContext) :
|
class DebugProbesImpl private constructor(context: DefaultExecutionContext) :
|
||||||
BaseMirror<MirrorOfDebugProbesImpl>("kotlinx.coroutines.debug.internal.DebugProbesImpl", context) {
|
BaseMirror<MirrorOfDebugProbesImpl>("kotlinx.coroutines.debug.internal.DebugProbesImpl", context) {
|
||||||
val javaLangListMirror = JavaUtilAbstractCollection(context)
|
private val javaLangListMirror = JavaUtilAbstractCollection(context)
|
||||||
val stackTraceElement = StackTraceElement(context)
|
private val stackTraceElement = StackTraceElement(context)
|
||||||
val coroutineInfo = CoroutineInfo.instance(this, context) ?: throw IllegalStateException("CoroutineInfo implementation not found.")
|
private val coroutineInfo =
|
||||||
val debugProbesCoroutineOwner = DebugProbesImpl_CoroutineOwner(coroutineInfo, context)
|
CoroutineInfo.instance(this, context) ?: throw IllegalStateException("CoroutineInfo implementation not found.")
|
||||||
val instance = staticObjectValue("INSTANCE")
|
private val debugProbesCoroutineOwner = DebugProbesImplCoroutineOwner(coroutineInfo, context)
|
||||||
val isInstalledMethod = makeMethod("isInstalled\$kotlinx_coroutines_debug", "()Z")
|
private val instance = staticObjectValue("INSTANCE")
|
||||||
|
private val isInstalledMethod = makeMethod("isInstalled\$kotlinx_coroutines_debug", "()Z")
|
||||||
?: makeMethod("isInstalled\$kotlinx_coroutines_core", "()Z") ?: throw IllegalStateException("isInstalledMethod not found")
|
?: makeMethod("isInstalled\$kotlinx_coroutines_core", "()Z") ?: throw IllegalStateException("isInstalledMethod not found")
|
||||||
val isInstalledValue = booleanValue(instance, isInstalledMethod, context)
|
val isInstalledValue = booleanValue(instance, isInstalledMethod, context)
|
||||||
val enhanceStackTraceWithThreadDumpMethod = makeMethod("enhanceStackTraceWithThreadDump")
|
private val enhanceStackTraceWithThreadDumpMethod = makeMethod("enhanceStackTraceWithThreadDump")
|
||||||
val dumpMethod = makeMethod("dumpCoroutinesInfo", "()Ljava/util/List;")
|
private val dumpMethod = makeMethod("dumpCoroutinesInfo", "()Ljava/util/List;")
|
||||||
|
|
||||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfDebugProbesImpl? {
|
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfDebugProbesImpl? {
|
||||||
return MirrorOfDebugProbesImpl(value, instance, isInstalledValue)
|
return MirrorOfDebugProbesImpl(value, instance, isInstalledValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun enchanceStackTraceWithThreadDump(
|
fun enhanceStackTraceWithThreadDump(
|
||||||
context: DefaultExecutionContext,
|
context: DefaultExecutionContext,
|
||||||
coroutineInfo: ObjectReference,
|
coroutineInfo: ObjectReference,
|
||||||
lastObservedStackTrace: ObjectReference
|
lastObservedStackTrace: ObjectReference
|
||||||
@@ -57,12 +59,13 @@ class DebugProbesImpl private constructor(context: DefaultExecutionContext) :
|
|||||||
try {
|
try {
|
||||||
DebugProbesImpl(context)
|
DebugProbesImpl(context)
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
|
log.debug("Attempt to access DebugProbesImpl but none found.", e)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DebugProbesImpl_CoroutineOwner(val coroutineInfo: CoroutineInfo, context: DefaultExecutionContext) :
|
class DebugProbesImplCoroutineOwner(private val coroutineInfo: CoroutineInfo, context: DefaultExecutionContext) :
|
||||||
BaseMirror<MirrorOfCoroutineOwner>(COROUTINE_OWNER_CLASS_NAME, context) {
|
BaseMirror<MirrorOfCoroutineOwner>(COROUTINE_OWNER_CLASS_NAME, context) {
|
||||||
private val infoField = makeField("info")
|
private val infoField = makeField("info")
|
||||||
|
|
||||||
@@ -75,7 +78,7 @@ class DebugProbesImpl_CoroutineOwner(val coroutineInfo: CoroutineInfo, context:
|
|||||||
const val COROUTINE_OWNER_CLASS_NAME = "kotlinx.coroutines.debug.internal.DebugProbesImpl\$CoroutineOwner"
|
const val COROUTINE_OWNER_CLASS_NAME = "kotlinx.coroutines.debug.internal.DebugProbesImpl\$CoroutineOwner"
|
||||||
|
|
||||||
fun instanceOf(value: ObjectReference?) =
|
fun instanceOf(value: ObjectReference?) =
|
||||||
value?.let { it.referenceType().isSubTypeOrSame(COROUTINE_OWNER_CLASS_NAME) } ?: false
|
value?.referenceType()?.isSubTypeOrSame(COROUTINE_OWNER_CLASS_NAME) ?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,13 +87,13 @@ data class MirrorOfCoroutineOwner(val that: ObjectReference, val coroutineInfo:
|
|||||||
data class MirrorOfDebugProbesImpl(val that: ObjectReference, val instance: ObjectReference?, val isInstalled: Boolean?)
|
data class MirrorOfDebugProbesImpl(val that: ObjectReference, val instance: ObjectReference?, val isInstalled: Boolean?)
|
||||||
|
|
||||||
class CoroutineInfo private constructor(
|
class CoroutineInfo private constructor(
|
||||||
val debugProbesImplMirror: DebugProbesImpl,
|
private val debugProbesImplMirror: DebugProbesImpl,
|
||||||
context: DefaultExecutionContext,
|
context: DefaultExecutionContext,
|
||||||
val className: String = AGENT_134_CLASS_NAME
|
val className: String = AGENT_134_CLASS_NAME
|
||||||
) :
|
) :
|
||||||
BaseMirror<MirrorOfCoroutineInfo>(className, context) {
|
BaseMirror<MirrorOfCoroutineInfo>(className, context) {
|
||||||
val javaLangMirror = JavaLangMirror(context)
|
private val javaLangMirror = JavaLangMirror(context)
|
||||||
val javaLangListMirror = JavaUtilAbstractCollection(context)
|
private val javaLangListMirror = JavaUtilAbstractCollection(context)
|
||||||
private val coroutineContextMirror = CoroutineContext(context)
|
private val coroutineContextMirror = CoroutineContext(context)
|
||||||
private val stackTraceElement = StackTraceElement(context)
|
private val stackTraceElement = StackTraceElement(context)
|
||||||
private val contextFieldRef = makeField("context")
|
private val contextFieldRef = makeField("context")
|
||||||
@@ -105,16 +108,16 @@ class CoroutineInfo private constructor(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val log by logger
|
val log by logger
|
||||||
const val AGENT_134_CLASS_NAME = "kotlinx.coroutines.debug.CoroutineInfo"
|
private const val AGENT_134_CLASS_NAME = "kotlinx.coroutines.debug.CoroutineInfo"
|
||||||
const val AGENT_135_AND_UP_CLASS_NAME = "kotlinx.coroutines.debug.internal.DebugCoroutineInfo"
|
private const val AGENT_135_AND_UP_CLASS_NAME = "kotlinx.coroutines.debug.internal.DebugCoroutineInfo"
|
||||||
|
|
||||||
fun instance(debugProbesImplMirror: DebugProbesImpl, context: DefaultExecutionContext): CoroutineInfo? {
|
fun instance(debugProbesImplMirror: DebugProbesImpl, context: DefaultExecutionContext): CoroutineInfo? {
|
||||||
val classType = context.findClassSafe(AGENT_134_CLASS_NAME) ?: context.findClassSafe(AGENT_135_AND_UP_CLASS_NAME) ?: return null
|
val classType = context.findClassSafe(AGENT_134_CLASS_NAME) ?: context.findClassSafe(AGENT_135_AND_UP_CLASS_NAME) ?: return null
|
||||||
try {
|
return try {
|
||||||
return CoroutineInfo(debugProbesImplMirror, context, classType.name())
|
CoroutineInfo(debugProbesImplMirror, context, classType.name())
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
log.warn("coroutine-debugger: $classType not found", e)
|
log.warn("coroutine-debugger: $classType not found", e)
|
||||||
return null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,9 +136,9 @@ class CoroutineInfo private constructor(
|
|||||||
val creationStackTrace = creationStackTraceMirror?.values?.mapNotNull { stackTraceElement.mirror(it, context) }
|
val creationStackTrace = creationStackTraceMirror?.values?.mapNotNull { stackTraceElement.mirror(it, context) }
|
||||||
|
|
||||||
val lastObservedStackTrace = objectValue(value, lastObservedStackTraceMethod, context)
|
val lastObservedStackTrace = objectValue(value, lastObservedStackTraceMethod, context)
|
||||||
val enchancedList =
|
val enhancedList =
|
||||||
if (lastObservedStackTrace != null)
|
if (lastObservedStackTrace != null)
|
||||||
debugProbesImplMirror.enchanceStackTraceWithThreadDump(context, value, lastObservedStackTrace)
|
debugProbesImplMirror.enhanceStackTraceWithThreadDump(context, value, lastObservedStackTrace)
|
||||||
else emptyList()
|
else emptyList()
|
||||||
val lastObservedThread = threadValue(value, lastObservedThreadField)
|
val lastObservedThread = threadValue(value, lastObservedThreadField)
|
||||||
val lastObservedFrame = threadValue(value, lastObservedFrameField)
|
val lastObservedFrame = threadValue(value, lastObservedFrameField)
|
||||||
@@ -144,7 +147,7 @@ class CoroutineInfo private constructor(
|
|||||||
coroutineContext,
|
coroutineContext,
|
||||||
creationStackBottom,
|
creationStackBottom,
|
||||||
sequenceNumber,
|
sequenceNumber,
|
||||||
enchancedList,
|
enhancedList,
|
||||||
creationStackTrace,
|
creationStackTrace,
|
||||||
state,
|
state,
|
||||||
lastObservedThread,
|
lastObservedThread,
|
||||||
@@ -159,7 +162,7 @@ data class MirrorOfCoroutineInfo(
|
|||||||
val context: MirrorOfCoroutineContext?,
|
val context: MirrorOfCoroutineContext?,
|
||||||
val creationStackBottom: MirrorOfCoroutineStackFrame?,
|
val creationStackBottom: MirrorOfCoroutineStackFrame?,
|
||||||
val sequenceNumber: Long?,
|
val sequenceNumber: Long?,
|
||||||
val enchancedStackTrace: List<MirrorOfStackTraceElement>?,
|
val enhancedStackTrace: List<MirrorOfStackTraceElement>?,
|
||||||
val creationStackTrace: List<MirrorOfStackTraceElement>?,
|
val creationStackTrace: List<MirrorOfStackTraceElement>?,
|
||||||
val state: String?,
|
val state: String?,
|
||||||
val lastObservedThread: ThreadReference?,
|
val lastObservedThread: ThreadReference?,
|
||||||
@@ -234,11 +237,8 @@ data class MirrorOfStackTraceElement(
|
|||||||
val lineNumber: Int?,
|
val lineNumber: Int?,
|
||||||
val format: Byte?
|
val format: Byte?
|
||||||
) {
|
) {
|
||||||
fun isInvokeSuspend() =
|
|
||||||
"invokeSuspend" == methodName
|
|
||||||
|
|
||||||
fun stackTraceElement() =
|
fun stackTraceElement() =
|
||||||
java.lang.StackTraceElement(
|
StackTraceElement(
|
||||||
declaringClass,
|
declaringClass,
|
||||||
methodName,
|
methodName,
|
||||||
fileName,
|
fileName,
|
||||||
|
|||||||
+23
-21
@@ -9,36 +9,35 @@ import com.sun.jdi.*
|
|||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isSubTypeOrSame
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isSubTypeOrSame
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||||
import java.lang.IllegalStateException
|
|
||||||
|
|
||||||
abstract class BaseMirror<T>(val name: String, context: DefaultExecutionContext) {
|
abstract class BaseMirror<T>(val name: String, context: DefaultExecutionContext) {
|
||||||
val log by logger
|
val log by logger
|
||||||
protected val cls = context.findClassSafe(name) ?: throw IllegalStateException("coroutine-debugger: class $name not found.")
|
protected val cls = context.findClassSafe(name) ?: throw IllegalStateException("coroutine-debugger: class $name not found.")
|
||||||
|
|
||||||
fun makeField(fieldName: String): Field? =
|
fun makeField(fieldName: String): Field? =
|
||||||
cls?.let { it.fieldByName(fieldName) }
|
cls.fieldByName(fieldName)
|
||||||
|
|
||||||
fun makeMethod(methodName: String): Method? =
|
fun makeMethod(methodName: String): Method? =
|
||||||
cls?.let { it.methodsByName(methodName).singleOrNull() }
|
cls.methodsByName(methodName).singleOrNull()
|
||||||
|
|
||||||
fun makeMethod(methodName: String, signature: String): Method? =
|
fun makeMethod(methodName: String, signature: String): Method? =
|
||||||
cls?.let { it.methodsByName(methodName, signature).singleOrNull() }
|
cls.methodsByName(methodName, signature).singleOrNull()
|
||||||
|
|
||||||
fun isCompatible(value: ObjectReference?) =
|
fun isCompatible(value: ObjectReference?) =
|
||||||
value?.let { it.referenceType().isSubTypeOrSame(name) } ?: false
|
value?.referenceType()?.isSubTypeOrSame(name) ?: false
|
||||||
|
|
||||||
fun mirror(value: ObjectReference?, context: DefaultExecutionContext): T? {
|
fun mirror(value: ObjectReference?, context: DefaultExecutionContext): T? {
|
||||||
value ?: return null
|
value ?: return null
|
||||||
if (!isCompatible(value)) {
|
return if (!isCompatible(value)) {
|
||||||
log.trace("Value ${value.referenceType()} is not compatible with $name.")
|
log.trace("Value ${value.referenceType()} is not compatible with $name.")
|
||||||
return null
|
null
|
||||||
} else
|
} else
|
||||||
return fetchMirror(value, context)
|
fetchMirror(value, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun staticObjectValue(fieldName: String): ObjectReference? {
|
fun staticObjectValue(fieldName: String): ObjectReference? {
|
||||||
val keyFieldRef = makeField(fieldName)
|
val keyFieldRef = makeField(fieldName)
|
||||||
return cls?.let { it.getValue(keyFieldRef) as? ObjectReference }
|
return cls.let { it.getValue(keyFieldRef) as? ObjectReference }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun staticMethodValue(instance: ObjectReference?, method: Method?, context: DefaultExecutionContext, vararg values: Value?) =
|
fun staticMethodValue(instance: ObjectReference?, method: Method?, context: DefaultExecutionContext, vararg values: Value?) =
|
||||||
@@ -49,7 +48,7 @@ abstract class BaseMirror<T>(val name: String, context: DefaultExecutionContext)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun staticMethodValue(method: Method?, context: DefaultExecutionContext, vararg values: Value?) =
|
fun staticMethodValue(method: Method?, context: DefaultExecutionContext, vararg values: Value?) =
|
||||||
cls?.let {
|
cls.let {
|
||||||
method?.let {
|
method?.let {
|
||||||
context.invokeMethodSafe(cls, method, values.asList()) as? ObjectReference
|
context.invokeMethodSafe(cls, method, values.asList()) as? ObjectReference
|
||||||
}
|
}
|
||||||
@@ -109,7 +108,7 @@ abstract class BaseMirror<T>(val name: String, context: DefaultExecutionContext)
|
|||||||
protected abstract fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): T?
|
protected abstract fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): T?
|
||||||
}
|
}
|
||||||
|
|
||||||
class StandaloneCoroutine(context: DefaultExecutionContext) :
|
class StandaloneCoroutine private constructor(context: DefaultExecutionContext) :
|
||||||
BaseMirror<MirrorOfStandaloneCoroutine>("kotlinx.coroutines.StandaloneCoroutine", context) {
|
BaseMirror<MirrorOfStandaloneCoroutine>("kotlinx.coroutines.StandaloneCoroutine", context) {
|
||||||
private val coroutineContextMirror = CoroutineContext(context)
|
private val coroutineContextMirror = CoroutineContext(context)
|
||||||
private val childContinuationMirror = ChildContinuation(context)
|
private val childContinuationMirror = ChildContinuation(context)
|
||||||
@@ -118,19 +117,22 @@ class StandaloneCoroutine(context: DefaultExecutionContext) :
|
|||||||
|
|
||||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfStandaloneCoroutine {
|
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfStandaloneCoroutine {
|
||||||
val state = objectValue(value, stateFieldRef)
|
val state = objectValue(value, stateFieldRef)
|
||||||
val childcontinuation = childContinuationMirror.mirror(state, context)
|
val childContinuation = childContinuationMirror.mirror(state, context)
|
||||||
val cc = objectValue(value, contextFieldRef)
|
val cc = objectValue(value, contextFieldRef)
|
||||||
val coroutineContext = coroutineContextMirror.mirror(cc, context)
|
val coroutineContext = coroutineContextMirror.mirror(cc, context)
|
||||||
return MirrorOfStandaloneCoroutine(value, childcontinuation, coroutineContext)
|
return MirrorOfStandaloneCoroutine(value, childContinuation, coroutineContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
val log by logger
|
||||||
|
|
||||||
fun instance(context: DefaultExecutionContext): StandaloneCoroutine? {
|
fun instance(context: DefaultExecutionContext): StandaloneCoroutine? {
|
||||||
val sc = StandaloneCoroutine(context)
|
return try {
|
||||||
if (sc.cls == null)
|
StandaloneCoroutine(context)
|
||||||
return null
|
} catch (e: IllegalStateException) {
|
||||||
else
|
log.debug("Attempt to access DebugProbesImpl but none found.", e)
|
||||||
return sc
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +162,7 @@ data class MirrorOfChildContinuation(
|
|||||||
class CancellableContinuationImpl(context: DefaultExecutionContext) :
|
class CancellableContinuationImpl(context: DefaultExecutionContext) :
|
||||||
BaseMirror<MirrorOfCancellableContinuationImpl>("kotlinx.coroutines.CancellableContinuationImpl", context) {
|
BaseMirror<MirrorOfCancellableContinuationImpl>("kotlinx.coroutines.CancellableContinuationImpl", context) {
|
||||||
private val coroutineContextMirror = CoroutineContext(context)
|
private val coroutineContextMirror = CoroutineContext(context)
|
||||||
private val dispatchedContinuationtMirror = DispatchedContinuation(context)
|
private val dispatchedContinuationMirror = DispatchedContinuation(context)
|
||||||
private val decisionFieldRef = makeField("_decision")
|
private val decisionFieldRef = makeField("_decision")
|
||||||
private val delegateFieldRef = makeField("delegate") // DispatchedContinuation
|
private val delegateFieldRef = makeField("delegate") // DispatchedContinuation
|
||||||
private val resumeModeFieldRef = makeField("resumeMode")
|
private val resumeModeFieldRef = makeField("resumeMode")
|
||||||
@@ -169,7 +171,7 @@ class CancellableContinuationImpl(context: DefaultExecutionContext) :
|
|||||||
|
|
||||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfCancellableContinuationImpl? {
|
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfCancellableContinuationImpl? {
|
||||||
val decision = intValue(value, decisionFieldRef)
|
val decision = intValue(value, decisionFieldRef)
|
||||||
val dispatchedContinuation = dispatchedContinuationtMirror.mirror(objectValue(value, delegateFieldRef), context)
|
val dispatchedContinuation = dispatchedContinuationMirror.mirror(objectValue(value, delegateFieldRef), context)
|
||||||
val submissionTime = longValue(value, submissionTimeFieldRef)
|
val submissionTime = longValue(value, submissionTimeFieldRef)
|
||||||
val resumeMode = intValue(value, resumeModeFieldRef)
|
val resumeMode = intValue(value, resumeModeFieldRef)
|
||||||
val coroutineContext = objectValue(value, contextFieldRef)
|
val coroutineContext = objectValue(value, contextFieldRef)
|
||||||
@@ -183,7 +185,7 @@ data class MirrorOfCancellableContinuationImpl(
|
|||||||
val decision: Int?,
|
val decision: Int?,
|
||||||
val delegate: MirrorOfDispatchedContinuation?,
|
val delegate: MirrorOfDispatchedContinuation?,
|
||||||
val resumeMode: Int?,
|
val resumeMode: Int?,
|
||||||
val submissionTyme: Long?,
|
val submissionTime: Long?,
|
||||||
val jobContext: MirrorOfCoroutineContext?
|
val jobContext: MirrorOfCoroutineContext?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -45,7 +45,7 @@ class DebugMetadata private constructor(context: DefaultExecutionContext) :
|
|||||||
try {
|
try {
|
||||||
return DebugMetadata(context)
|
return DebugMetadata(context)
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
log.warn("Attempt to access DebugMetadata", e)
|
log.debug("Attempt to access DebugMetadata but none found.", e)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,8 @@ class BaseContinuationImpl(context: DefaultExecutionContext, private val debugMe
|
|||||||
val fieldVariables = getSpilledVariableFieldMapping(value, context)
|
val fieldVariables = getSpilledVariableFieldMapping(value, context)
|
||||||
val completionValue = objectValue(value, getCompletion, context)
|
val completionValue = objectValue(value, getCompletion, context)
|
||||||
val completion = if (completionValue != null && isCompatible(completionValue)) completionValue else null
|
val completion = if (completionValue != null && isCompatible(completionValue)) completionValue else null
|
||||||
val coroutineOwner = if (completionValue != null && DebugProbesImpl_CoroutineOwner.instanceOf(completionValue)) completionValue else null
|
val coroutineOwner =
|
||||||
|
if (completionValue != null && DebugProbesImplCoroutineOwner.instanceOf(completionValue)) completionValue else null
|
||||||
return MirrorOfBaseContinuationImpl(value, stackTraceElementMirror, fieldVariables, completion, coroutineOwner)
|
return MirrorOfBaseContinuationImpl(value, stackTraceElementMirror, fieldVariables, completion, coroutineOwner)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +85,7 @@ class BaseContinuationImpl(context: DefaultExecutionContext, private val debugMe
|
|||||||
val length = getSpilledVariableFieldMappingReference.length() / 2
|
val length = getSpilledVariableFieldMappingReference.length() / 2
|
||||||
val fieldVariables = ArrayList<FieldVariable>()
|
val fieldVariables = ArrayList<FieldVariable>()
|
||||||
for (index in 0 until length) {
|
for (index in 0 until length) {
|
||||||
var fieldVariable = getFieldVariableName(getSpilledVariableFieldMappingReference, index) ?: continue
|
val fieldVariable = getFieldVariableName(getSpilledVariableFieldMappingReference, index) ?: continue
|
||||||
fieldVariables.add(fieldVariable)
|
fieldVariables.add(fieldVariable)
|
||||||
}
|
}
|
||||||
return fieldVariables
|
return fieldVariables
|
||||||
|
|||||||
+5
-8
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
|||||||
|
|
||||||
class JavaLangMirror(context: DefaultExecutionContext) {
|
class JavaLangMirror(context: DefaultExecutionContext) {
|
||||||
// java.lang.Object
|
// java.lang.Object
|
||||||
val classClsRef = context.findClass("java.lang.Object") as ClassType
|
private val classClsRef = context.findClass("java.lang.Object") as ClassType
|
||||||
val toString: Method = classClsRef.concreteMethodByName("toString", "()Ljava/lang/String;")
|
val toString: Method = classClsRef.concreteMethodByName("toString", "()Ljava/lang/String;")
|
||||||
|
|
||||||
// java.util.List
|
// java.util.List
|
||||||
@@ -25,9 +25,6 @@ class JavaLangMirror(context: DefaultExecutionContext) {
|
|||||||
private val fileNameFieldRef: Field = stackTraceElementClsRef.fieldByName("fileName")
|
private val fileNameFieldRef: Field = stackTraceElementClsRef.fieldByName("fileName")
|
||||||
private val lineNumberFieldRef: Field = stackTraceElementClsRef.fieldByName("lineNumber")
|
private val lineNumberFieldRef: Field = stackTraceElementClsRef.fieldByName("lineNumber")
|
||||||
|
|
||||||
// java.lang.Class
|
|
||||||
val classType = context.findClass("java.lang.Class") as ClassType
|
|
||||||
|
|
||||||
fun string(state: ObjectReference, context: DefaultExecutionContext): String =
|
fun string(state: ObjectReference, context: DefaultExecutionContext): String =
|
||||||
(context.invokeMethod(state, toString, emptyList()) as StringReference).value()
|
(context.invokeMethod(state, toString, emptyList()) as StringReference).value()
|
||||||
|
|
||||||
@@ -63,14 +60,14 @@ class JavaLangMirror(context: DefaultExecutionContext) {
|
|||||||
|
|
||||||
class JavaUtilAbstractCollection(context: DefaultExecutionContext) :
|
class JavaUtilAbstractCollection(context: DefaultExecutionContext) :
|
||||||
BaseMirror<MirrorOfJavaLangAbstractCollection>("java.util.AbstractCollection", context) {
|
BaseMirror<MirrorOfJavaLangAbstractCollection>("java.util.AbstractCollection", context) {
|
||||||
val abstractList = JavaUtilAbstractList(context)
|
private val abstractList = JavaUtilAbstractList(context)
|
||||||
val sizeMethod = makeMethod("size")
|
private val sizeMethod = makeMethod("size")
|
||||||
|
|
||||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfJavaLangAbstractCollection? {
|
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfJavaLangAbstractCollection? {
|
||||||
val list = mutableListOf<ObjectReference>()
|
val list = mutableListOf<ObjectReference>()
|
||||||
val size = intValue(value, sizeMethod, context) ?: 0
|
val size = intValue(value, sizeMethod, context) ?: 0
|
||||||
for (index in 0 until size) {
|
for (index in 0 until size) {
|
||||||
val reference = abstractList.get(value, index, context) ?: continue
|
val reference = abstractList.get(value, index, context) ?: continue
|
||||||
list.add(reference)
|
list.add(reference)
|
||||||
}
|
}
|
||||||
return MirrorOfJavaLangAbstractCollection(value, list)
|
return MirrorOfJavaLangAbstractCollection(value, list)
|
||||||
@@ -81,7 +78,7 @@ class JavaUtilAbstractList(context: DefaultExecutionContext) :
|
|||||||
BaseMirror<ObjectReference>("java.util.AbstractList", context) {
|
BaseMirror<ObjectReference>("java.util.AbstractList", context) {
|
||||||
val getMethod = makeMethod("get")
|
val getMethod = makeMethod("get")
|
||||||
|
|
||||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext) =
|
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): Nothing? =
|
||||||
null
|
null
|
||||||
|
|
||||||
fun get(value: ObjectReference, index: Int, context: DefaultExecutionContext): ObjectReference? =
|
fun get(value: ObjectReference, index: Int, context: DefaultExecutionContext): ObjectReference? =
|
||||||
|
|||||||
+7
-7
@@ -20,7 +20,7 @@ class CoroutineFrameBuilder {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val log by logger
|
val log by logger
|
||||||
const val PRE_FETCH_FRAME_COUNT = 5
|
private const val PRE_FETCH_FRAME_COUNT = 5
|
||||||
|
|
||||||
fun build(coroutine: CoroutineInfoData, suspendContext: SuspendContextImpl): DoubleFrameList? =
|
fun build(coroutine: CoroutineInfoData, suspendContext: SuspendContextImpl): DoubleFrameList? =
|
||||||
when {
|
when {
|
||||||
@@ -81,10 +81,10 @@ class CoroutineFrameBuilder {
|
|||||||
frame: StackFrameProxyImpl
|
frame: StackFrameProxyImpl
|
||||||
): RunningCoroutineStackFrameItem? {
|
): RunningCoroutineStackFrameItem? {
|
||||||
val location = frame.location()
|
val location = frame.location()
|
||||||
if (!location.safeCoroutineExitPointLineNumber())
|
return if (!location.safeCoroutineExitPointLineNumber())
|
||||||
return RunningCoroutineStackFrameItem(frame, location)
|
RunningCoroutineStackFrameItem(frame, location)
|
||||||
else
|
else
|
||||||
return null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,7 +130,7 @@ class CoroutineFrameBuilder {
|
|||||||
else -> null
|
else -> null
|
||||||
} ?: return null
|
} ?: return null
|
||||||
|
|
||||||
val continuationHolder = ContinuationHolder.instance(context) ?: return null
|
val continuationHolder = ContinuationHolder.instance(context)
|
||||||
val coroutineInfo = continuationHolder.extractCoroutineInfoData(continuation) ?: return null
|
val coroutineInfo = continuationHolder.extractCoroutineInfoData(continuation) ?: return null
|
||||||
return preflight(frame, theFollowingFrames, coroutineInfo, mode)
|
return preflight(frame, theFollowingFrames, coroutineInfo, mode)
|
||||||
}
|
}
|
||||||
@@ -139,7 +139,7 @@ class CoroutineFrameBuilder {
|
|||||||
|
|
||||||
private fun lookForTheFollowingFrame(theFollowingFrames: List<StackFrameProxyImpl>): StackFrameProxyImpl? {
|
private fun lookForTheFollowingFrame(theFollowingFrames: List<StackFrameProxyImpl>): StackFrameProxyImpl? {
|
||||||
for (i in 0 until min(PRE_FETCH_FRAME_COUNT, theFollowingFrames.size)) { // pre-scan PRE_FETCH_FRAME_COUNT frames
|
for (i in 0 until min(PRE_FETCH_FRAME_COUNT, theFollowingFrames.size)) { // pre-scan PRE_FETCH_FRAME_COUNT frames
|
||||||
val nextFrame = theFollowingFrames.get(i)
|
val nextFrame = theFollowingFrames[i]
|
||||||
if (nextFrame.location().isPreFlight() == SuspendExitMode.SUSPEND_METHOD) {
|
if (nextFrame.location().isPreFlight() == SuspendExitMode.SUSPEND_METHOD) {
|
||||||
return nextFrame
|
return nextFrame
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ class CoroutineFrameBuilder {
|
|||||||
private fun getThisContinuation(frame: StackFrameProxyImpl?): ObjectReference? =
|
private fun getThisContinuation(frame: StackFrameProxyImpl?): ObjectReference? =
|
||||||
frame?.thisVariableValue()
|
frame?.thisVariableValue()
|
||||||
|
|
||||||
fun theFollowingFrames(frame: StackFrameProxyImpl): List<StackFrameProxyImpl>? {
|
private fun theFollowingFrames(frame: StackFrameProxyImpl): List<StackFrameProxyImpl>? {
|
||||||
val frames = frame.threadProxy().frames()
|
val frames = frame.threadProxy().frames()
|
||||||
val indexOfCurrentFrame = frames.indexOf(frame)
|
val indexOfCurrentFrame = frames.indexOf(frame)
|
||||||
if (indexOfCurrentFrame >= 0) {
|
if (indexOfCurrentFrame >= 0) {
|
||||||
|
|||||||
+3
-12
@@ -30,9 +30,6 @@ fun Method.isInvokeSuspend(): Boolean =
|
|||||||
fun Method.isInvoke(): Boolean =
|
fun Method.isInvoke(): Boolean =
|
||||||
name() == "invoke" && signature().contains("Ljava/lang/Object;)Ljava/lang/Object;")
|
name() == "invoke" && signature().contains("Ljava/lang/Object;)Ljava/lang/Object;")
|
||||||
|
|
||||||
fun Method.isContinuation() =
|
|
||||||
isInvokeSuspend() && declaringType().isContinuation() /* Perhaps need to check for "Lkotlin/coroutines/Continuation;)" in signature() ? */
|
|
||||||
|
|
||||||
fun Method.isSuspendLambda() =
|
fun Method.isSuspendLambda() =
|
||||||
isInvokeSuspend() && declaringType().isSuspendLambda()
|
isInvokeSuspend() && declaringType().isSuspendLambda()
|
||||||
|
|
||||||
@@ -79,16 +76,13 @@ fun StackFrameProxyImpl.variableValue(variableName: String): ObjectReference? {
|
|||||||
return getValue(continuationVariable) as? ObjectReference ?: return null
|
return getValue(continuationVariable) as? ObjectReference ?: return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun StackFrameProxyImpl.completionVariableValue(): ObjectReference? =
|
|
||||||
variableValue("completion")
|
|
||||||
|
|
||||||
fun StackFrameProxyImpl.continuationVariableValue(): ObjectReference? =
|
fun StackFrameProxyImpl.continuationVariableValue(): ObjectReference? =
|
||||||
variableValue("\$continuation")
|
variableValue("\$continuation")
|
||||||
|
|
||||||
fun StackFrameProxyImpl.thisVariableValue(): ObjectReference? =
|
fun StackFrameProxyImpl.thisVariableValue(): ObjectReference? =
|
||||||
this.thisObject()
|
this.thisObject()
|
||||||
|
|
||||||
private fun Method.isGetCOROUTINE_SUSPENDED() =
|
private fun Method.isGetCoroutineSuspended() =
|
||||||
signature() == "()Ljava/lang/Object;" && name() == "getCOROUTINE_SUSPENDED" && declaringType().name() == "kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsKt"
|
signature() == "()Ljava/lang/Object;" && name() == "getCOROUTINE_SUSPENDED" && declaringType().name() == "kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsKt"
|
||||||
|
|
||||||
fun DefaultExecutionContext.findCoroutineMetadataType() =
|
fun DefaultExecutionContext.findCoroutineMetadataType() =
|
||||||
@@ -101,7 +95,7 @@ fun DefaultExecutionContext.findCancellableContinuationImplReferenceType(): List
|
|||||||
vm.classesByName("kotlinx.coroutines.CancellableContinuationImpl")
|
vm.classesByName("kotlinx.coroutines.CancellableContinuationImpl")
|
||||||
|
|
||||||
fun hasGetCoroutineSuspended(frames: List<StackFrameProxyImpl>) =
|
fun hasGetCoroutineSuspended(frames: List<StackFrameProxyImpl>) =
|
||||||
frames.indexOfFirst { it.safeLocation()?.safeMethod()?.isGetCOROUTINE_SUSPENDED() == true }
|
frames.indexOfFirst { it.safeLocation()?.safeMethod()?.isGetCoroutineSuspended() == true }
|
||||||
|
|
||||||
fun StackTraceElement.isCreationSeparatorFrame() =
|
fun StackTraceElement.isCreationSeparatorFrame() =
|
||||||
className.startsWith(CREATION_STACK_TRACE_SEPARATOR)
|
className.startsWith(CREATION_STACK_TRACE_SEPARATOR)
|
||||||
@@ -112,9 +106,6 @@ fun StackTraceElement.findPosition(project: Project): XSourcePosition? =
|
|||||||
fun Location.findPosition(project: Project) =
|
fun Location.findPosition(project: Project) =
|
||||||
getPosition(project, declaringType().name(), lineNumber())
|
getPosition(project, declaringType().name(), lineNumber())
|
||||||
|
|
||||||
fun ClassType.completionField() =
|
|
||||||
fieldByName("completion")
|
|
||||||
|
|
||||||
private fun getPosition(project: Project, className: String, lineNumber: Int): XSourcePosition? {
|
private fun getPosition(project: Project, className: String, lineNumber: Int): XSourcePosition? {
|
||||||
val psiFacade = JavaPsiFacade.getInstance(project)
|
val psiFacade = JavaPsiFacade.getInstance(project)
|
||||||
val psiClass = psiFacade.findClass(
|
val psiClass = psiFacade.findClass(
|
||||||
@@ -130,7 +121,7 @@ private fun getPosition(project: Project, className: String, lineNumber: Int): X
|
|||||||
fun SuspendContextImpl.executionContext() =
|
fun SuspendContextImpl.executionContext() =
|
||||||
invokeInManagerThread { DefaultExecutionContext(EvaluationContextImpl(this, this.frameProxy)) }
|
invokeInManagerThread { DefaultExecutionContext(EvaluationContextImpl(this, this.frameProxy)) }
|
||||||
|
|
||||||
fun <T : Any> SuspendContextImpl.invokeInManagerThread(f: () -> T?) : T? =
|
fun <T : Any> SuspendContextImpl.invokeInManagerThread(f: () -> T?): T? =
|
||||||
debugProcess.invokeInManagerThread { f() }
|
debugProcess.invokeInManagerThread { f() }
|
||||||
|
|
||||||
fun ThreadReferenceProxyImpl.supportsEvaluation(): Boolean =
|
fun ThreadReferenceProxyImpl.supportsEvaluation(): Boolean =
|
||||||
|
|||||||
+1
-24
@@ -10,37 +10,16 @@ import com.intellij.debugger.jdi.StackFrameProxyImpl
|
|||||||
import com.intellij.debugger.memory.utils.StackFrameItem
|
import com.intellij.debugger.memory.utils.StackFrameItem
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.ui.MessageType
|
|
||||||
import com.intellij.openapi.util.registry.Registry
|
|
||||||
import com.intellij.psi.JavaPsiFacade
|
import com.intellij.psi.JavaPsiFacade
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.xdebugger.XDebuggerUtil
|
import com.intellij.xdebugger.XDebuggerUtil
|
||||||
import com.intellij.xdebugger.XSourcePosition
|
import com.intellij.xdebugger.XSourcePosition
|
||||||
import com.intellij.xdebugger.frame.XStackFrame
|
|
||||||
import com.intellij.xdebugger.impl.XDebuggerManagerImpl
|
|
||||||
import com.sun.jdi.Location
|
import com.sun.jdi.Location
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.ApplicationThreadExecutor
|
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.ApplicationThreadExecutor
|
||||||
import org.jetbrains.kotlin.idea.debugger.safeLineNumber
|
import org.jetbrains.kotlin.idea.debugger.safeLineNumber
|
||||||
import org.jetbrains.kotlin.idea.debugger.safeLocation
|
import org.jetbrains.kotlin.idea.debugger.safeLocation
|
||||||
import org.jetbrains.kotlin.idea.debugger.safeMethod
|
import org.jetbrains.kotlin.idea.debugger.safeMethod
|
||||||
|
|
||||||
fun getPosition(stackTraceElement: StackTraceElement, project: Project): XSourcePosition? {
|
|
||||||
val psiFacade = JavaPsiFacade.getInstance(project)
|
|
||||||
|
|
||||||
val psiClass = ApplicationThreadExecutor().readAction {
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
psiFacade.findClass(
|
|
||||||
stackTraceElement.className.substringBefore("$"), // find outer class, for which psi exists TODO
|
|
||||||
GlobalSearchScope.everythingScope(project)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val classFile = psiClass?.containingFile?.virtualFile
|
|
||||||
// to convert to 0-based line number or '-1' to do not move
|
|
||||||
val lineNumber = if (stackTraceElement.lineNumber > 0) stackTraceElement.lineNumber - 1 else return null
|
|
||||||
return XDebuggerUtil.getInstance().createPosition(classFile, lineNumber)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Location.format(): String {
|
fun Location.format(): String {
|
||||||
val method = safeMethod()
|
val method = safeMethod()
|
||||||
return "${method?.name() ?: "noname"}:${safeLineNumber()}, ${method?.declaringType()?.name() ?: "empty"}"
|
return "${method?.name() ?: "noname"}:${safeLineNumber()}, ${method?.declaringType()?.name() ?: "empty"}"
|
||||||
@@ -48,7 +27,7 @@ fun Location.format(): String {
|
|||||||
|
|
||||||
fun JavaStackFrame.format(): String {
|
fun JavaStackFrame.format(): String {
|
||||||
val location = descriptor.location
|
val location = descriptor.location
|
||||||
return location?.let { it.format() } ?: "emptyLocation"
|
return location?.format() ?: "emptyLocation"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun StackFrameItem.format(): String {
|
fun StackFrameItem.format(): String {
|
||||||
@@ -63,5 +42,3 @@ fun StackFrameProxyImpl.format(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isInUnitTest() = ApplicationManager.getApplication().isUnitTestMode
|
fun isInUnitTest() = ApplicationManager.getApplication().isUnitTestMode
|
||||||
|
|
||||||
fun coroutineDebuggerTraceEnabled() = Registry.`is`("kotlin.debugger.coroutines.trace") || isInUnitTest()
|
|
||||||
|
|||||||
+9
-7
@@ -5,27 +5,29 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.debugger.coroutine.util
|
package org.jetbrains.kotlin.idea.debugger.coroutine.util
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.diagnostic.DefaultLogger
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.xdebugger.XDebugSession
|
import com.intellij.xdebugger.XDebugSession
|
||||||
import com.intellij.xdebugger.XDebugSessionListener
|
import com.intellij.xdebugger.XDebugSessionListener
|
||||||
import org.apache.log4j.Level
|
|
||||||
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
|
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
import javax.swing.JComponent
|
import javax.swing.JComponent
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
interface CreateContentParamsProvider {
|
interface CreateContentParamsProvider {
|
||||||
fun createContentParams() : CreateContentParams
|
fun createContentParams(): CreateContentParams
|
||||||
}
|
}
|
||||||
|
|
||||||
data class CreateContentParams(val id: String, val component: JComponent, val displayName: String, val icon: Icon?, val parentComponent: JComponent)
|
data class CreateContentParams(
|
||||||
|
val id: String,
|
||||||
|
val component: JComponent,
|
||||||
|
val displayName: String,
|
||||||
|
val icon: Icon?,
|
||||||
|
val parentComponent: JComponent
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
interface XDebugSessionListenerProvider {
|
interface XDebugSessionListenerProvider {
|
||||||
fun debugSessionListener(session: XDebugSession) : XDebugSessionListener
|
fun debugSessionListener(session: XDebugSession): XDebugSessionListener
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+8
-11
@@ -45,7 +45,12 @@ import javax.swing.event.DocumentEvent
|
|||||||
/**
|
/**
|
||||||
* Panel with dump of coroutines
|
* Panel with dump of coroutines
|
||||||
*/
|
*/
|
||||||
class CoroutineDumpPanel(project: Project, consoleView: ConsoleView, toolbarActions: DefaultActionGroup, val dump: List<CoroutineInfoData>) :
|
class CoroutineDumpPanel(
|
||||||
|
project: Project,
|
||||||
|
consoleView: ConsoleView,
|
||||||
|
toolbarActions: DefaultActionGroup,
|
||||||
|
val dump: List<CoroutineInfoData>
|
||||||
|
) :
|
||||||
JPanel(BorderLayout()), DataProvider {
|
JPanel(BorderLayout()), DataProvider {
|
||||||
private var exporterToTextFile: ExporterToTextFile
|
private var exporterToTextFile: ExporterToTextFile
|
||||||
private var mergedDump = ArrayList<CoroutineInfoData>()
|
private var mergedDump = ArrayList<CoroutineInfoData>()
|
||||||
@@ -180,14 +185,6 @@ class CoroutineDumpPanel(project: Project, consoleView: ConsoleView, toolbarActi
|
|||||||
|
|
||||||
override fun getData(dataId: String): Any? = if (PlatformDataKeys.EXPORTER_TO_TEXT_FILE.`is`(dataId)) exporterToTextFile else null
|
override fun getData(dataId: String): Any? = if (PlatformDataKeys.EXPORTER_TO_TEXT_FILE.`is`(dataId)) exporterToTextFile else null
|
||||||
|
|
||||||
private fun getCoroutineStateIcon(infoData: CoroutineInfoData): Icon {
|
|
||||||
return when (infoData.key.state) {
|
|
||||||
State.RUNNING -> LayeredIcon(AllIcons.Actions.Resume, Daemon_sign)
|
|
||||||
State.SUSPENDED -> AllIcons.Actions.Pause
|
|
||||||
else -> EmptyIcon.create(6)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getAttributes(infoData: CoroutineInfoData): SimpleTextAttributes {
|
private fun getAttributes(infoData: CoroutineInfoData): SimpleTextAttributes {
|
||||||
return when {
|
return when {
|
||||||
infoData.isSuspended() -> SimpleTextAttributes.GRAY_ATTRIBUTES
|
infoData.isSuspended() -> SimpleTextAttributes.GRAY_ATTRIBUTES
|
||||||
@@ -296,9 +293,9 @@ class CoroutineDumpPanel(project: Project, consoleView: ConsoleView, toolbarActi
|
|||||||
|
|
||||||
private fun stringStackTrace(info: CoroutineInfoData) =
|
private fun stringStackTrace(info: CoroutineInfoData) =
|
||||||
buildString {
|
buildString {
|
||||||
appendln("\"${info.key.name}\", state: ${info.key.state}")
|
appendLine("\"${info.key.name}\", state: ${info.key.state}")
|
||||||
info.stackTrace.forEach {
|
info.stackTrace.forEach {
|
||||||
appendln("\t$it")
|
appendLine("\t$it")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -48,7 +48,7 @@ class CoroutineViewDebugSessionListener(
|
|||||||
renew(suspendContext)
|
renew(suspendContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun renew(suspendContext: XSuspendContext) {
|
private fun renew(suspendContext: XSuspendContext) {
|
||||||
if (suspendContext is SuspendContextImpl) {
|
if (suspendContext is SuspendContextImpl) {
|
||||||
DebuggerUIUtil.invokeLater {
|
DebuggerUIUtil.invokeLater {
|
||||||
xCoroutineView.renewRoot(suspendContext)
|
xCoroutineView.renewRoot(suspendContext)
|
||||||
|
|||||||
+11
-12
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.idea.debugger.coroutine.view
|
|||||||
import com.intellij.debugger.impl.DebuggerUtilsEx
|
import com.intellij.debugger.impl.DebuggerUtilsEx
|
||||||
import com.intellij.debugger.settings.ThreadsViewSettings
|
import com.intellij.debugger.settings.ThreadsViewSettings
|
||||||
import com.intellij.icons.AllIcons
|
import com.intellij.icons.AllIcons
|
||||||
import com.intellij.icons.AllIcons.General.Information
|
|
||||||
import com.intellij.openapi.editor.HighlighterColors
|
import com.intellij.openapi.editor.HighlighterColors
|
||||||
import com.intellij.openapi.editor.colors.TextAttributesKey
|
import com.intellij.openapi.editor.colors.TextAttributesKey
|
||||||
import com.intellij.ui.ColoredTextContainer
|
import com.intellij.ui.ColoredTextContainer
|
||||||
@@ -25,11 +24,11 @@ import org.jetbrains.kotlin.idea.debugger.coroutine.data.State
|
|||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
class SimpleColoredTextIcon(val icon: Icon?, val hasChildrens: Boolean) {
|
class SimpleColoredTextIcon(val icon: Icon?, val hasChildren: Boolean) {
|
||||||
val texts = mutableListOf<String>()
|
private val texts = mutableListOf<String>()
|
||||||
val textKeyAttributes = mutableListOf<TextAttributesKey>()
|
private val textKeyAttributes = mutableListOf<TextAttributesKey>()
|
||||||
|
|
||||||
constructor(icon: Icon?, hasChildrens: Boolean, text: String) : this(icon, hasChildrens) {
|
constructor(icon: Icon?, hasChildren: Boolean, text: String) : this(icon, hasChildren) {
|
||||||
append(text)
|
append(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,14 +42,14 @@ class SimpleColoredTextIcon(val icon: Icon?, val hasChildrens: Boolean) {
|
|||||||
textKeyAttributes.add(CoroutineDebuggerColors.VALUE_ATTRIBUTES)
|
textKeyAttributes.add(CoroutineDebuggerColors.VALUE_ATTRIBUTES)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun appendToComponent(component: ColoredTextContainer) {
|
private fun appendToComponent(component: ColoredTextContainer) {
|
||||||
val size: Int = texts.size
|
val size: Int = texts.size
|
||||||
for (i in 0 until size) {
|
for (i in 0 until size) {
|
||||||
val text: String = texts.get(i)
|
val text: String = texts[i]
|
||||||
val attribute: TextAttributesKey = textKeyAttributes.get(i)
|
val attribute: TextAttributesKey = textKeyAttributes[i]
|
||||||
val simpleTextAttrinbute = toSimpleTextAttribute(attribute)
|
val simpleTextAttribute = toSimpleTextAttribute(attribute)
|
||||||
|
|
||||||
component.append(text, simpleTextAttrinbute)
|
component.append(text, simpleTextAttribute)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +89,7 @@ class SimpleColoredTextIcon(val icon: Icon?, val hasChildrens: Boolean) {
|
|||||||
|
|
||||||
interface CoroutineDebuggerColors {
|
interface CoroutineDebuggerColors {
|
||||||
companion object {
|
companion object {
|
||||||
val REGULAR_ATTRIBUTES = HighlighterColors.TEXT
|
val REGULAR_ATTRIBUTES: TextAttributesKey = HighlighterColors.TEXT
|
||||||
val VALUE_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("KOTLIN_COROUTINE_DEBUGGER_VALUE", HighlighterColors.TEXT)
|
val VALUE_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("KOTLIN_COROUTINE_DEBUGGER_VALUE", HighlighterColors.TEXT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,7 +184,7 @@ class SimpleColoredTextIconPresentationRenderer {
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun renderErrorNode(error: String) =
|
fun renderErrorNode(error: String) =
|
||||||
SimpleColoredTextIcon(AllIcons.Actions.Lightning,false, KotlinDebuggerCoroutinesBundle.message(error))
|
SimpleColoredTextIcon(AllIcons.Actions.Lightning, false, KotlinDebuggerCoroutinesBundle.message(error))
|
||||||
|
|
||||||
fun renderInfoNode(text: String) =
|
fun renderInfoNode(text: String) =
|
||||||
SimpleColoredTextIcon(AllIcons.General.Information, false, KotlinDebuggerCoroutinesBundle.message(text))
|
SimpleColoredTextIcon(AllIcons.General.Information, false, KotlinDebuggerCoroutinesBundle.message(text))
|
||||||
|
|||||||
+9
-17
@@ -32,16 +32,12 @@ import org.jetbrains.kotlin.idea.debugger.coroutine.CoroutineDebuggerContentInfo
|
|||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.CoroutineDebuggerContentInfo.Companion.XCOROUTINE_POPUP_ACTION_GROUP
|
import org.jetbrains.kotlin.idea.debugger.coroutine.CoroutineDebuggerContentInfo.Companion.XCOROUTINE_POPUP_ACTION_GROUP
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
|
import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.VersionedImplementationProvider
|
import org.jetbrains.kotlin.idea.debugger.coroutine.VersionedImplementationProvider
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.CoroutineFrameBuilder
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineStackFrameItem
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineStackFrameItem
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CreationCoroutineStackFrameItem
|
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CreationCoroutineStackFrameItem
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.CoroutineDebugProbesProxy
|
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.CoroutineDebugProbesProxy
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.ManagerThreadExecutor
|
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.ManagerThreadExecutor
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.CreateContentParams
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.*
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.CreateContentParamsProvider
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.XDebugSessionListenerProvider
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
|
||||||
import java.awt.BorderLayout
|
import java.awt.BorderLayout
|
||||||
import javax.swing.JPanel
|
import javax.swing.JPanel
|
||||||
|
|
||||||
@@ -49,20 +45,20 @@ import javax.swing.JPanel
|
|||||||
class XCoroutineView(val project: Project, val session: XDebugSession) :
|
class XCoroutineView(val project: Project, val session: XDebugSession) :
|
||||||
Disposable, XDebugSessionListenerProvider, CreateContentParamsProvider {
|
Disposable, XDebugSessionListenerProvider, CreateContentParamsProvider {
|
||||||
val log by logger
|
val log by logger
|
||||||
val versionedImplementationProvider = VersionedImplementationProvider()
|
private val versionedImplementationProvider = VersionedImplementationProvider()
|
||||||
|
|
||||||
val mainPanel = JPanel(BorderLayout())
|
val mainPanel = JPanel(BorderLayout())
|
||||||
val someCombobox = ComboBox<String>()
|
val someCombobox = ComboBox<String>()
|
||||||
val panel = XDebuggerTreePanel(project, session.debugProcess.editorsProvider, this, null, XCOROUTINE_POPUP_ACTION_GROUP, null)
|
val panel = XDebuggerTreePanel(project, session.debugProcess.editorsProvider, this, null, XCOROUTINE_POPUP_ACTION_GROUP, null)
|
||||||
val alarm = SingleAlarm(Runnable { resetRoot() }, VIEW_CLEAR_DELAY, this)
|
val alarm = SingleAlarm({ resetRoot() }, VIEW_CLEAR_DELAY, this)
|
||||||
val renderer = SimpleColoredTextIconPresentationRenderer()
|
val renderer = SimpleColoredTextIconPresentationRenderer()
|
||||||
val managerThreadExecutor = ManagerThreadExecutor(session)
|
val managerThreadExecutor = ManagerThreadExecutor(session)
|
||||||
var treeState: XDebuggerTreeState? = null
|
private var treeState: XDebuggerTreeState? = null
|
||||||
private var restorer: XDebuggerTreeRestorer? = null
|
private var restorer: XDebuggerTreeRestorer? = null
|
||||||
private var selectedNodeListener: XDebuggerTreeSelectedNodeListener? = null
|
private var selectedNodeListener: XDebuggerTreeSelectedNodeListener? = null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val VIEW_CLEAR_DELAY = 100 //ms
|
private const val VIEW_CLEAR_DELAY = 100 //ms
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -97,7 +93,7 @@ class XCoroutineView(val project: Project, val session: XDebugSession) :
|
|||||||
|
|
||||||
fun saveState() {
|
fun saveState() {
|
||||||
DebuggerUIUtil.invokeLater {
|
DebuggerUIUtil.invokeLater {
|
||||||
if (!(panel.tree.root is EmptyNode)) {
|
if (panel.tree.root !is EmptyNode) {
|
||||||
treeState = XDebuggerTreeState.saveState(panel.tree)
|
treeState = XDebuggerTreeState.saveState(panel.tree)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,10 +120,6 @@ class XCoroutineView(val project: Project, val session: XDebugSession) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun forceClear() {
|
|
||||||
alarm.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun debugSessionListener(session: XDebugSession) =
|
override fun debugSessionListener(session: XDebugSession) =
|
||||||
CoroutineViewDebugSessionListener(session, this)
|
CoroutineViewDebugSessionListener(session, this)
|
||||||
|
|
||||||
@@ -155,10 +147,10 @@ class XCoroutineView(val project: Project, val session: XDebugSession) :
|
|||||||
val debugProbesProxy = CoroutineDebugProbesProxy(suspendContext)
|
val debugProbesProxy = CoroutineDebugProbesProxy(suspendContext)
|
||||||
|
|
||||||
val emptyDispatcherName = KotlinDebuggerCoroutinesBundle.message("coroutine.view.dispatcher.empty")
|
val emptyDispatcherName = KotlinDebuggerCoroutinesBundle.message("coroutine.view.dispatcher.empty")
|
||||||
var coroutineCache = debugProbesProxy.dumpCoroutines()
|
val coroutineCache = debugProbesProxy.dumpCoroutines()
|
||||||
if (coroutineCache.isOk()) {
|
if (coroutineCache.isOk()) {
|
||||||
val children = XValueChildrenList()
|
val children = XValueChildrenList()
|
||||||
var groups = coroutineCache.cache.groupBy { it.key.dispatcher }
|
val groups = coroutineCache.cache.groupBy { it.key.dispatcher }
|
||||||
for (dispatcher in groups.keys) {
|
for (dispatcher in groups.keys) {
|
||||||
children.add(CoroutineContainer(suspendContext, dispatcher ?: emptyDispatcherName, groups[dispatcher]))
|
children.add(CoroutineContainer(suspendContext, dispatcher ?: emptyDispatcherName, groups[dispatcher]))
|
||||||
}
|
}
|
||||||
@@ -248,7 +240,7 @@ class XCoroutineView(val project: Project, val session: XDebugSession) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun applyRenderer(node: XValueNode, presentation: SimpleColoredTextIcon) =
|
private fun applyRenderer(node: XValueNode, presentation: SimpleColoredTextIcon) =
|
||||||
node.setPresentation(presentation.icon, presentation.valuePresentation(), presentation.hasChildrens)
|
node.setPresentation(presentation.icon, presentation.valuePresentation(), presentation.hasChildren)
|
||||||
|
|
||||||
open inner class RendererContainer(val presentation: SimpleColoredTextIcon) : XNamedValue(presentation.simpleString()) {
|
open inner class RendererContainer(val presentation: SimpleColoredTextIcon) : XNamedValue(presentation.simpleString()) {
|
||||||
override fun computePresentation(node: XValueNode, place: XValuePlace) =
|
override fun computePresentation(node: XValueNode, place: XValuePlace) =
|
||||||
|
|||||||
+4
-1
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.inspections
|
|||||||
import com.intellij.codeInspection.ProblemsHolder
|
import com.intellij.codeInspection.ProblemsHolder
|
||||||
import com.intellij.psi.PsiElementVisitor
|
import com.intellij.psi.PsiElementVisitor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||||
import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor
|
import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor
|
||||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||||
@@ -46,4 +47,6 @@ abstract class AbstractPrimitiveRangeToInspection : AbstractKotlinInspection() {
|
|||||||
return constant.toConstantValue(getType(c) ?: return null)
|
return constant.toConstantValue(getType(c) ?: return null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var q = 12
|
||||||
Reference in New Issue
Block a user