From fa1bf0583e2f360de83fd0696a74d92eff8384e8 Mon Sep 17 00:00:00 2001 From: Sergei Vorobyov Date: Fri, 20 Sep 2024 18:42:38 +0200 Subject: [PATCH] [PSI] new: added collecting uncommited documents traces when they become uncommited This collection process is disabled by default. It is enabled by the `ide.activity.tracking.enable.debug` registry key. GitOrigin-RevId: 9f9959f33cab6922869b57204f478f24ef82c198 --- .../intellij/testFramework/TestObservation.kt | 18 ++++++++++++++++++ .../psi/impl/PsiDocumentManagerBase.java | 14 ++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/java/testFramework/src/com/intellij/testFramework/TestObservation.kt b/java/testFramework/src/com/intellij/testFramework/TestObservation.kt index 950cd7527b38..7c0182788bcd 100644 --- a/java/testFramework/src/com/intellij/testFramework/TestObservation.kt +++ b/java/testFramework/src/com/intellij/testFramework/TestObservation.kt @@ -6,7 +6,10 @@ import com.intellij.diagnostic.dumpCoroutines import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.project.Project +import com.intellij.openapi.util.registry.Registry import com.intellij.platform.backend.observation.Observation +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.impl.PsiDocumentManagerBase import com.intellij.testFramework.concurrency.waitForPromiseAndPumpEdt import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.TimeoutCancellationException @@ -42,6 +45,7 @@ object TestObservation { } catch (_: TimeoutCancellationException) { val activityDump = Observation.dumpAwaitedActivitiesToString() + val uncommitedDocuments = dumpUncommitedDocumentsWithTracesToString(project) val coroutineDump = dumpCoroutines() val threadDump = dumpThreadsToString() @@ -50,6 +54,9 @@ object TestObservation { |------ Operation log begin ------ |$operationLog |------- Operation log end ------- + |--- Uncommited documents begin -- + |$uncommitedDocuments + |---- Uncommited documents end --- |------ Activity dump begin ------ |$activityDump |------- Activity dump end ------- @@ -64,6 +71,17 @@ object TestObservation { } } + private fun dumpUncommitedDocumentsWithTracesToString(project: Project): String { + if (!Registry.`is`("ide.activity.tracking.enable.debug")) { + return "Enable 'ide.activity.tracking.enable.debug' registry option to collect uncommited document traces" + } + val psiDocumentManager = PsiDocumentManager.getInstance(project) as PsiDocumentManagerBase + return psiDocumentManager.uncommitedDocumentsWithTraces.entries + .joinToString("\n") { + it.key.toString() + ": " + it.value.stackTraceToString() + } + } + @Service(Service.Level.PROJECT) private class CoroutineScopeService(private val coroutineScope: CoroutineScope) { companion object { diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java index 9f281afa224b..679fdc37552a 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java @@ -28,6 +28,7 @@ import com.intellij.openapi.progress.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.*; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -66,6 +67,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen private final DocumentCommitProcessor myDocumentCommitProcessor; final Set myUncommittedDocuments = Collections.newSetFromMap(CollectionFactory.createConcurrentWeakMap()); + private final Map myUncommittedDocumentTraces = CollectionFactory.createConcurrentWeakMap(); private final Map myUncommittedInfos = new ConcurrentHashMap<>(); private /*non-static*/ final Key FREE_THREADED_UNCOMMITTED_INFO = Key.create("FREE_THREADED_UNCOMMITTED_INFO"); @@ -440,6 +442,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen finally { if (success.get()) { myUncommittedDocuments.remove(document); + myUncommittedDocumentTraces.remove(document); } } }); @@ -508,6 +511,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen PsiFile psiFile = getPsiFile(document); if (psiFile == null) { myUncommittedDocuments.remove(document); + myUncommittedDocumentTraces.remove(document); runAfterCommitActions(document); return true; // the project must be closing or file deleted } @@ -865,6 +869,11 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen return ArrayUtil.stripTrailingNulls(documents); } + @ApiStatus.Internal + public @NotNull Map getUncommitedDocumentsWithTraces() { + return Collections.unmodifiableMap(myUncommittedDocumentTraces); + } + boolean isInUncommittedSet(@NotNull Document document) { return myUncommittedDocuments.contains(getTopLevelDocument(document)); } @@ -973,6 +982,9 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen if (commitNecessary) { assert !(document instanceof DocumentWindow); myUncommittedDocuments.add(document); + if (Registry.is("ide.activity.tracking.enable.debug")) { + myUncommittedDocumentTraces.put(document, new Throwable()); + } if (forceCommit) { commitDocument(document); } @@ -1029,6 +1041,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen } myUncommittedDocuments.remove(document); + myUncommittedDocumentTraces.remove(document); if (!myProject.isInitialized() || myProject.isDisposed() || myProject.isDefault()) { return; @@ -1138,6 +1151,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen public void clearUncommittedDocuments() { myUncommittedInfos.clear(); myUncommittedDocuments.clear(); + myUncommittedDocumentTraces.clear(); mySynchronizer.cleanupForNextTest(); }