[debugger] Coroutine View: fixed coroutine job hierarchy.

Bugs: IDEA-371866, IDEA-366085

Only show the jobs corresponding to the coroutines captured in the dump.

GitOrigin-RevId: c163cdcdc9c4ba4d1e25a01daa940ff174af263b
This commit is contained in:
Maria Sokolova
2025-05-19 07:58:29 +00:00
committed by intellij-monorepo-bot
parent 35763ae892
commit fd088c015e
3 changed files with 32 additions and 26 deletions
@@ -5,9 +5,7 @@ import com.intellij.rt.debugger.JsonUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.*;
public final class CoroutinesDebugHelper {
@@ -170,7 +168,9 @@ public final class CoroutinesDebugHelper {
/**
* This method takes the array of {@link kotlinx.coroutines.debug.internal.DebugCoroutineInfo} instances
* and for each coroutine requests it's job, and it's first parent.
* and for each coroutine finds it's job and the first parent, which corresponds to some coroutine, captured in the dump.
* That means that parent jobs corresponding to ScopeCoroutines (coroutineScope) or DispatchedCoroutine (withContext)
* will be skipped. Their frames will be seen in the async stack trace.
*
* @return an array of Strings of size (debugCoroutineInfos.size * 2), where
* (2 * i)-th element is a String representation of the job and
@@ -178,7 +178,6 @@ public final class CoroutinesDebugHelper {
*/
public static String[] getJobsAndParentsForCoroutines(Object ... debugCoroutineInfos) throws ReflectiveOperationException {
if (debugCoroutineInfos.length == 0) return new String[]{};
String[] jobsWithParents = new String[debugCoroutineInfos.length * 2];
ClassLoader loader = debugCoroutineInfos[0].getClass().getClassLoader();
Class<?> debugCoroutineInfoClass = Class.forName(DEBUG_COROUTINE_INFO_FQN, false, loader);
Class<?> coroutineContext = Class.forName(COROUTINE_CONTEXT_FQN, false, loader);
@@ -189,20 +188,33 @@ public final class CoroutinesDebugHelper {
Method getParentJob = coroutineJobClass.getMethod("getParent");
Method getContext = debugCoroutineInfoClass.getMethod("getContext");
for (int i = 0; i < debugCoroutineInfos.length * 2; i += 2) {
Object info = debugCoroutineInfos[i / 2];
if (info == null) {
jobsWithParents[i] = null;
jobsWithParents[i + 1] = null;
continue;
}
String[] jobToCapturedParent = new String[debugCoroutineInfos.length * 2];
Set<String> capturedJobs = new HashSet<>();
for(Object info : debugCoroutineInfos) {
Object context = invoke(info, getContext);
Object job = invoke(context, coroutineContextGet, coroutineJobKey);
Object parent = invoke(job, getParentJob);
jobsWithParents[i] = (job == null) ? null : job.toString();
jobsWithParents[i + 1] = (parent == null) ? null : parent.toString();
capturedJobs.add(job.toString());
}
return jobsWithParents;
for (int i = 0; i < debugCoroutineInfos.length * 2; i += 2) {
Object info = debugCoroutineInfos[i / 2];
Object context = invoke(info, getContext);
Object job = invoke(context, coroutineContextGet, coroutineJobKey);
if (job == null) {
jobToCapturedParent[i] = null;
jobToCapturedParent[i + 1] = null;
continue;
}
jobToCapturedParent[i] = job.toString();
Object parent = invoke(job, getParentJob);
while (parent != null) {
if (capturedJobs.contains(parent.toString())) {
jobToCapturedParent[i + 1] = parent.toString();
break;
}
parent = invoke(parent, getParentJob);
}
}
return jobToCapturedParent;
}
private static Object getField(Object object, String fieldName) throws ReflectiveOperationException {