IJPL-218636 [psi] send property-change events for all psi trees on file rename

GitOrigin-RevId: 50ae722ddb683f8b3450fe30b843be8249d7f9ae
This commit is contained in:
Max Medvedev
2025-11-18 14:32:05 +00:00
committed by intellij-monorepo-bot
parent cd3ddb7e5e
commit 7a7ead7ff0
2 changed files with 64 additions and 21 deletions
@@ -176,8 +176,6 @@ private class PsiVFSListener(private val project: Project) {
}
ApplicationManager.getApplication().runWriteAction(ExternalChangeActionUtil.externalChangeAction {
val treeEvent = PsiTreeChangeEventImpl(manager)
treeEvent.parent = parentDir
if (propertyName == VirtualFile.PROP_NAME) {
if (parentDir == null) {
return@externalChangeAction
@@ -188,6 +186,8 @@ private class PsiVFSListener(private val project: Project) {
val psiDir = fileManager.findDirectory(vFile)
if (psiDir != null) {
if (!FileTypeManager.getInstance().isFileIgnored(newName)) {
val treeEvent = PsiTreeChangeEventImpl(manager)
treeEvent.parent = parentDir
treeEvent.child = psiDir
treeEvent.propertyName = PsiTreeChangeEvent.PROP_DIRECTORY_NAME
treeEvent.oldValue = vFile.name
@@ -195,45 +195,62 @@ private class PsiVFSListener(private val project: Project) {
manager.beforePropertyChange(treeEvent)
}
else {
val treeEvent = PsiTreeChangeEventImpl(manager)
treeEvent.parent = parentDir
treeEvent.child = psiDir
manager.beforeChildRemoval(treeEvent)
}
}
else {
if ((!Registry.`is`("ide.hide.excluded.files") || !isExcludeRoot(vFile)) && !FileTypeManager.getInstance().isFileIgnored(newName)) {
val treeEvent = PsiTreeChangeEventImpl(manager)
treeEvent.parent = parentDir
manager.beforeChildAddition(treeEvent)
}
}
}
else {
val psiFile = fileManager.findViewProvider(vFile).getPsi(fileManager.findViewProvider(vFile).baseLanguage)
val psiFile1 = createFileCopyWithNewName(vFile, newName)
val viewProviders = fileManager.findCachedViewProviders(vFile).ifEmpty { listOf(fileManager.findViewProvider(vFile)) }
for (viewProvider in viewProviders) {
val psiFile = viewProvider.getPsi(fileManager.findViewProvider(vFile).baseLanguage)
val psiFile1 = createFileCopyWithNewName(vFile, newName)
if (psiFile != null) {
if (psiFile1 == null) {
treeEvent.child = psiFile
manager.beforeChildRemoval(treeEvent)
if (psiFile != null) {
if (psiFile1 == null) {
val treeEvent = PsiTreeChangeEventImpl(manager)
treeEvent.parent = parentDir
treeEvent.child = psiFile
manager.beforeChildRemoval(treeEvent)
}
else if (psiFile1.javaClass != psiFile.javaClass) {
val treeEvent = PsiTreeChangeEventImpl(manager)
treeEvent.parent = parentDir
treeEvent.oldChild = psiFile
manager.beforeChildReplacement(treeEvent)
}
else {
val treeEvent = PsiTreeChangeEventImpl(manager)
treeEvent.parent = parentDir
treeEvent.child = psiFile
treeEvent.propertyName = PsiTreeChangeEvent.PROP_FILE_NAME
treeEvent.oldValue = vFile.name
treeEvent.newValue = newName
manager.beforePropertyChange(treeEvent)
}
}
else if (psiFile1.javaClass != psiFile.javaClass) {
treeEvent.oldChild = psiFile
manager.beforeChildReplacement(treeEvent)
else if (psiFile1 != null) {
val treeEvent = PsiTreeChangeEventImpl(manager)
treeEvent.parent = parentDir
manager.beforeChildAddition(treeEvent)
}
else {
treeEvent.child = psiFile
treeEvent.propertyName = PsiTreeChangeEvent.PROP_FILE_NAME
treeEvent.oldValue = vFile.name
treeEvent.newValue = newName
manager.beforePropertyChange(treeEvent)
}
}
else if (psiFile1 != null) {
manager.beforeChildAddition(treeEvent)
}
}
}
else if (propertyName == VirtualFile.PROP_WRITABLE) {
// todo IJPL-339 implement proper event for multiple files
val psiFile = fileManager.getCachedPsiFileInner(vFile, anyContext()) ?: return@externalChangeAction
val treeEvent = PsiTreeChangeEventImpl(manager)
treeEvent.parent = parentDir
treeEvent.element = psiFile
treeEvent.propertyName = PsiTreeChangeEvent.PROP_WRITABLE
treeEvent.oldValue = event.oldValue
@@ -82,6 +82,32 @@ internal class MultiversePsiEventTest {
expectedEventNumber = 2
)
@Test
fun `test we receive 2 before-property-change rename events on renaming file with 2 psi files`() = doChangeTest(
listenerFactory = { counter ->
object : PsiTreeChangeAdapter() {
override fun beforePropertyChange(event: PsiTreeChangeEvent) {
counter.incrementAndGet()
}
}
},
updateBlock = { file -> file.rename(this, "B.java") },
expectedEventNumber = 2
)
@Test
fun `test we receive 2 property-change rename events on renaming file with 2 psi files`() = doChangeTest(
listenerFactory = { counter ->
object : PsiTreeChangeAdapter() {
override fun propertyChanged(event: PsiTreeChangeEvent) {
counter.incrementAndGet()
}
}
},
updateBlock = { file -> file.rename(this, "B.java") },
expectedEventNumber = 2
)
private fun doChangeTest(
listenerFactory: (AtomicInteger) -> PsiTreeChangeListener,
updateBlock: (file: VirtualFile) -> Unit,