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 954250d963df..4a5ef259382b 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 @@ -451,24 +451,38 @@ private class PsiVFSListener(private val project: Project) { } ApplicationManager.getApplication().runWriteAction(ExternalChangeActionUtil.externalChangeAction { - val treeEvent = PsiTreeChangeEventImpl(manager) val isExcluded = vFile.isDirectory && Registry.`is`("ide.hide.excluded.files") && myProjectRootManager.fileIndex.isExcluded(vFile) if (oldParentDir != null && !isExcluded) { - val eventChild = if (vFile.isDirectory) fileManager.findDirectory(vFile) else fileManager.findFile(vFile) - treeEvent.child = eventChild - if (newParentDir != null) { - treeEvent.oldParent = oldParentDir - treeEvent.newParent = newParentDir - manager.beforeChildMovement(treeEvent) + + // a list of: + // - one or several not-null PsiFiles + // - one not-null PsiDirectory + // - single 'null' if corresponding PsiDirectory or PsiFile cannot be created + val eventChildren: List = if (vFile.isDirectory) { + listOf(fileManager.findDirectory(vFile)) } else { - treeEvent.parent = oldParentDir - manager.beforeChildRemoval(treeEvent) + fileManager.getCachedPsiFiles(vFile).ifEmpty { listOf(fileManager.findFile(vFile)) } + } + + for (eventChild in eventChildren) { + val treeEvent = PsiTreeChangeEventImpl(manager) + treeEvent.child = eventChild + if (newParentDir != null) { + treeEvent.oldParent = oldParentDir + treeEvent.newParent = newParentDir + manager.beforeChildMovement(treeEvent) + } + else { + treeEvent.parent = oldParentDir + manager.beforeChildRemoval(treeEvent) + } } } else { // checked above LOG.assertTrue(newParentDir != null) + val treeEvent = PsiTreeChangeEventImpl(manager) treeEvent.parent = newParentDir manager.beforeChildAddition(treeEvent) } 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 2c6d06d84b95..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 @@ -40,6 +40,7 @@ internal class MultiversePsiEventTest { private val module2 = projectFixture.moduleFixture("m2") private val sourceRoot = sharedSourceRootFixture(module1, module2) + private val sourceRoot2 = sharedSourceRootFixture(module1, module2) @Suppress("unused") private val registerFakeLang = testFixture { @@ -266,6 +267,21 @@ internal class MultiversePsiEventTest { expectedEventNumber = 2 ) + @Test + fun `test we receive 2 before-child-moved events on moving a file with 2 psi files`() = doChangeTest( + listenerFactory = { counter -> + object : PsiTreeChangeAdapter() { + override fun beforeChildMovement(event: PsiTreeChangeEvent) { + counter.incrementAndGet() + } + } + }, + updateBlock = { file -> + file.move(this, sourceRoot2.get().virtualFile) + }, + expectedEventNumber = 2 + ) + private fun doChangeTest( listenerFactory: (AtomicInteger) -> PsiTreeChangeListener, updateBlock: (file: VirtualFile) -> Unit,