From 8262d4e658af9d87c0f324a544680f2333bb4abd Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 20 Aug 2018 14:19:30 +0300 Subject: [PATCH] lst: release trackers on VirtualFile invalidation Fix issue with duplicated trackers registered in ChangeListWorker, if one VirtualFile was moved on top of another VirtualFile. EA-116756 - assert: ChangeListWorker.registerChangeTracker EA-116749 - assert: ChangeListWorker.unregisterChangeTracker --- .../vcs/impl/LineStatusTrackerManager.kt | 38 +++++++++++----- .../vcs/LineStatusTrackerManagerTest.kt | 45 +++++++++++++++++++ 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt index a1f52df8c4ed..60a638eb854c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt @@ -641,21 +641,37 @@ class LineStatusTrackerManager( if (!partialChangeListsEnabled) return synchronized(LOCK) { - if (file.isDirectory) { - for (data in trackers.values) { - if (VfsUtil.isAncestor(file, data.tracker.virtualFile, false)) { - reregisterTrackerInCLM(data) - } - } - } - else { - val document = fileDocumentManager.getCachedDocument(file) ?: return - val data = trackers[document] ?: return - + forEachTrackerUnder(file) { data -> reregisterTrackerInCLM(data) } } } + + override fun fileDeleted(event: VirtualFileEvent) { + if (!partialChangeListsEnabled) return + + synchronized(LOCK) { + forEachTrackerUnder(event.file) { data -> + releaseTracker(data.tracker.document) + } + } + } + + private fun forEachTrackerUnder(file: VirtualFile, action: (TrackerData) -> Unit) { + if (file.isDirectory) { + for (data in trackers.values) { + if (VfsUtil.isAncestor(file, data.tracker.virtualFile, false)) { + action(data) + } + } + } + else { + val document = fileDocumentManager.getCachedDocument(file) ?: return + val data = trackers[document] ?: return + + action(data) + } + } } private inner class MyDocumentListener : DocumentListener { diff --git a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerManagerTest.kt b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerManagerTest.kt index 9089dce81f67..74f10d0f3b3a 100644 --- a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerManagerTest.kt +++ b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerManagerTest.kt @@ -236,6 +236,51 @@ class LineStatusTrackerManagerTest : BaseLineStatusTrackerManagerTest() { } } + fun `test tracker when file is moved on top of another file`() { + createChangelist("Test #1") + createChangelist("Test #2") + + val file1 = addLocalFile(FILE_1, "a_b_c_d_e") + val file2 = addLocalFile(FILE_2, "a_b_c_d_e") + setBaseVersion(FILE_1, "a1_b_c_d_e1") + setBaseVersion(FILE_2, "a1_b_c_d_e1") + refreshCLM() + + + file1.withOpenedEditor { + val tracker = file1.tracker as PartialLocalLineStatusTracker + lstm.waitUntilBaseContentsLoaded() + + val ranges = tracker.getRanges()!! + tracker.moveToChangelist(ranges[0], "Test #2".asListNameToList()) + } + + file2.withOpenedEditor { + val tracker = file2.tracker as PartialLocalLineStatusTracker + lstm.waitUntilBaseContentsLoaded() + + val ranges = tracker.getRanges()!! + tracker.moveToChangelist(ranges[1], "Test #2".asListNameToList()) + } + + releaseUnneededTrackers() + assertNotNull(file1.tracker) + assertNotNull(file2.tracker) + + runWriteAction { + file1.delete(this) + file2.rename(this, file1.name) + } + assertNull(file1.tracker) + + refreshCLM() + lstm.waitUntilBaseContentsLoaded() + + file2.moveAllChangesTo("Test #1") + releaseUnneededTrackers() + assertNull(file2.tracker) + } + fun `test tracker changes moves - empty tracker`() { createChangelist("Test #1") createChangelist("Test #2")