From b3c25f5b860adea42bb91149a765103bbcd568fc Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Sat, 15 Nov 2025 11:52:12 +0100 Subject: [PATCH] Revert "IJPL-339 [psi] send all corresponding events on file move" This reverts commit f01d04dfa24253edd62c28e4da63106a5c753c0b. GitOrigin-RevId: cad910659a8857bf30893fa1b330899d1cdfe50e --- .../psi/impl/file/impl/FileManagerImpl.java | 8 +-- .../psi/impl/file/impl/PsiVFSListener.kt | 63 +++++++------------ .../impl/file/impl/MultiversePsiEventTest.kt | 46 -------------- 3 files changed, 28 insertions(+), 89 deletions(-) diff --git a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java index e3f28ee6f68b..bbbba2033dd9 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java @@ -673,13 +673,13 @@ public final class FileManagerImpl implements FileManagerEx { myVFileToViewProviderMap.clear(); } - // When some file is moved to another directory, its contexts might change. - // So, view providers associated with irrelevant contexts should be processed. + // When some file is moved to another directory, its contexts might change + // So, view providers associated with irrelevant contexts should be processed // The best way to deal with such view providers is just to invalidate them. // But PSI clients are not usually ready for that. - // So we try to preserve one of the view providers, clearing the context of this lucky view provider and setting its context to `any`. + // So we try to preserve one of them, clearing the context of this lucky view provider and setting its context to `any`. // It is possible to do that if there are no other relevant view providers for this file left. - // Also, if there's a view provider with `any` context, there can be no other view providers for this file, so we don't need to do anything for this file. + // Also, if there's a view provider with `any` context, there can be no other view providers for this file, so we can silently accept them here. Set filesHavingRelevantViewProviders = new HashSet<>(); Map irrelevantViewProviders = new LinkedHashMap<>(); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.kt b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.kt index ec7fc8e53fdf..4b38f03b4dc4 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.kt +++ b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.kt @@ -1,6 +1,7 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.psi.impl.file.impl +import com.intellij.codeInsight.multiverse.anyContext import com.intellij.ide.PsiCopyPasteManager import com.intellij.ide.impl.ProjectUtilCore import com.intellij.ide.plugins.DynamicPluginListener @@ -490,7 +491,7 @@ private class PsiVFSListener(private val project: Project) { // optimization: call fileManager.removeInvalidFilesAndDirs() once for a group of move events, instead of once for each event private fun filesMoved(events: List) { - val allOldElements = ArrayList>(events.size) + val allOldElements = ArrayList(events.size) val allOldParentDirs = ArrayList(events.size) val allNewParentDirs = ArrayList(events.size) @@ -502,11 +503,12 @@ private class PsiVFSListener(private val project: Project) { var oldParentDir = fileManager.findDirectory(event.oldParent) var newParentDir = fileManager.findDirectory(event.newParent) - var oldElements = if (vFile.isDirectory) { - listOfNotNull(fileManager.getCachedDirectory(vFile)) + var oldElement: PsiElement? = if (vFile.isDirectory) { + fileManager.getCachedDirectory(vFile) } else { - fileManager.getCachedPsiFilesInner(vFile) + // todo IJPL-339 implement proper event for multiple files + fileManager.getCachedPsiFileInner(vFile, anyContext()) } val oldProject = ProjectLocator.getInstance().guessProjectForFile(vFile) if (oldProject != null && oldProject !== project) { @@ -514,11 +516,11 @@ private class PsiVFSListener(private val project: Project) { fileManager.removeFilesAndDirsRecursively(vFile) // avoiding crashes in filePointer.getElement() PsiCopyPasteManager.getInstance().fileMovedOutsideProject(vFile) - oldElements = emptyList() + oldElement = null oldParentDir = null newParentDir = null } - allOldElements.add(oldElements) + allOldElements.add(oldElement) allOldParentDirs.add(oldParentDir) allNewParentDirs.add(newParentDir) } @@ -533,7 +535,7 @@ private class PsiVFSListener(private val project: Project) { continue } - val oldElements = allOldElements[i] + val oldElement = allOldElements[i] var newElement: PsiElement? var newViewProvider: FileViewProvider? if (vFile.isDirectory) { @@ -545,16 +547,16 @@ private class PsiVFSListener(private val project: Project) { newElement = newViewProvider.getPsi(fileManager.findViewProvider(vFile).baseLanguage) } - if (oldElements.isEmpty() && newElement == null) { + if (oldElement == null && newElement == null) { continue } ApplicationManager.getApplication().runWriteAction(ExternalChangeActionUtil.externalChangeAction { - if (oldElements.isEmpty()) { + val treeEvent = PsiTreeChangeEventImpl(manager) + if (oldElement == null) { if (newViewProvider != null) { fileManager.changeViewProvider(vFile, newViewProvider) } - val treeEvent = PsiTreeChangeEventImpl(manager) treeEvent.parent = newParentDir treeEvent.child = newElement manager.childAdded(treeEvent) @@ -562,41 +564,24 @@ private class PsiVFSListener(private val project: Project) { else { if (newElement == null) { clearViewProvider(vFile, "PSI moved") - - for (oldElement in oldElements) { - val treeEvent = PsiTreeChangeEventImpl(manager) - treeEvent.parent = oldParentDir - treeEvent.child = oldElement - manager.childRemoved(treeEvent) - } + treeEvent.parent = oldParentDir + treeEvent.child = oldElement + manager.childRemoved(treeEvent) } else { if (newElement is PsiDirectory || - FileManagerImpl.areViewProvidersEquivalent(newViewProvider!!, (oldElements.first() as PsiFile).viewProvider)) { - - for (oldElement in oldElements) { - val treeEvent = PsiTreeChangeEventImpl(manager) - treeEvent.oldParent = oldParentDir - treeEvent.newParent = newParentDir - treeEvent.child = oldElement - if (oldElement.isValid) { // fileManager.removeInvalidFilesAndDirs(true) must have already invalided all old elements that must die. - manager.childMoved(treeEvent) - } - else { - manager.childRemoved(treeEvent) - } - } + FileManagerImpl.areViewProvidersEquivalent(newViewProvider!!, (oldElement as PsiFile).viewProvider)) { + treeEvent.oldParent = oldParentDir + treeEvent.newParent = newParentDir + treeEvent.child = oldElement + manager.childMoved(treeEvent) } else { fileManager.changeViewProvider(vFile, newViewProvider) - - for (oldElement in oldElements) { - val treeRemoveEvent = PsiTreeChangeEventImpl(manager) - treeRemoveEvent.parent = oldParentDir - treeRemoveEvent.child = oldElement - manager.childRemoved(treeRemoveEvent) - } - + val treeRemoveEvent = PsiTreeChangeEventImpl(manager) + treeRemoveEvent.parent = oldParentDir + treeRemoveEvent.child = oldElement + manager.childRemoved(treeRemoveEvent) val treeAddEvent = PsiTreeChangeEventImpl(manager) treeAddEvent.parent = newParentDir treeAddEvent.child = newElement diff --git a/platform/lang-impl/testSources/com/intellij/psi/impl/file/impl/MultiversePsiEventTest.kt b/platform/lang-impl/testSources/com/intellij/psi/impl/file/impl/MultiversePsiEventTest.kt index cc0bc8ec19ba..2fb168bfb88c 100644 --- a/platform/lang-impl/testSources/com/intellij/psi/impl/file/impl/MultiversePsiEventTest.kt +++ b/platform/lang-impl/testSources/com/intellij/psi/impl/file/impl/MultiversePsiEventTest.kt @@ -41,7 +41,6 @@ internal class MultiversePsiEventTest { private val sourceRoot = sharedSourceRootFixture(module1, module2) private val sourceRoot2 = sharedSourceRootFixture(module1, module2) - private val m1sourceRoot = module1.sourceRootFixture() @Suppress("unused") private val registerFakeLang = testFixture { @@ -283,51 +282,6 @@ internal class MultiversePsiEventTest { expectedEventNumber = 2 ) - @Test - fun `test we receive 2 child moved events on moving a file with 2 psi files`() = doChangeTest( - listenerFactory = { counter -> - object : PsiTreeChangeAdapter() { - override fun childMoved(event: PsiTreeChangeEvent) { - counter.incrementAndGet() - } - } - }, - updateBlock = { file -> - file.move(this, sourceRoot2.get().virtualFile) - }, - expectedEventNumber = 2 - ) - - @Test - fun `test we receive 1 child moved event (and 1 child removed event) on moving a file with 2 psi files to a directory where only 1 context exists`() = doChangeTest( - listenerFactory = { counter -> - object : PsiTreeChangeAdapter() { - override fun childMoved(event: PsiTreeChangeEvent) { - counter.incrementAndGet() - } - } - }, - updateBlock = { file -> - file.move(this, m1sourceRoot.get().virtualFile) - }, - expectedEventNumber = 1 - ) - - @Test - fun `test we receive (1 child moved event and) 1 child removed event on moving a file with 2 psi files to a directory where only 1 context exists`() = doChangeTest( - listenerFactory = { counter -> - object : PsiTreeChangeAdapter() { - override fun childRemoved(event: PsiTreeChangeEvent) { - counter.incrementAndGet() - } - } - }, - updateBlock = { file -> - file.move(this, m1sourceRoot.get().virtualFile) - }, - expectedEventNumber = 1 - ) - private fun doChangeTest( listenerFactory: (AtomicInteger) -> PsiTreeChangeListener, updateBlock: (file: VirtualFile) -> Unit,