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 bfd383134f78..bd1241c9f7c4 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 @@ -502,6 +502,20 @@ public final class FileManagerImpl implements FileManager { myVFileToPsiDirMap.set(null); } + @RequiresWriteLock + void removeInvalidFilesAndDirs(@NotNull Set<@NotNull VirtualFile> affectedFiles) { + Map fileToPsiFileMap = getVFileToViewProviderMap(); + ConcurrentMap fileToPsiDirMap = myVFileToPsiDirMap.get(); + + for (VirtualFile file : affectedFiles) { + fileToPsiDirMap.remove(file); + FileViewProvider viewProvider = fileToPsiFileMap.get(file); + if (viewProvider != null) { + clearPsiCaches(viewProvider); + } + } + } + @RequiresWriteLock void removeInvalidFilesAndDirs(boolean useFind) { removeInvalidDirs(); 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 889f509c9ce8..ed7ddcbeaeff 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 @@ -390,11 +390,15 @@ class PsiVFSListener internal constructor(private val project: Project) { val oldParentDirs = ArrayList(events.size) val newParentDirs = ArrayList(events.size) + var allMovedFilesAreRegularFiles = true + // find old directories before removing invalid ones for (e in events) { val event = e as VFileMoveEvent val vFile = event.file + allMovedFilesAreRegularFiles = allMovedFilesAreRegularFiles and !vFile.isDirectory + var oldParentDir = fileManager.findDirectory(event.oldParent) var newParentDir = fileManager.findDirectory(event.newParent) @@ -418,7 +422,27 @@ class PsiVFSListener internal constructor(private val project: Project) { oldParentDirs.add(oldParentDir) newParentDirs.add(newParentDir) } - fileManager.removeInvalidFilesAndDirs(true) + + if (allMovedFilesAreRegularFiles) { + /* + Optimization: + `myFileManager.removeInvalidFilesAndDirs` can execute heavy operations for each PSI file currently stored to remove all invalid + files and directories. + + If all files that were moved are regular files, and not directories, + all files that were *not* moved cannot become invalid, + so they can be skipped. + This is not the case if at least one moved file is a directory, since that also invalidates files in it. + */ + val movedFilesSet: MutableSet = HashSet() + for (e in events) { + val file = e.file ?: continue + movedFilesSet.add(file) + } + fileManager.removeInvalidFilesAndDirs(movedFilesSet) + } else { + fileManager.removeInvalidFilesAndDirs(true) + } for ((i, event) in events.withIndex()) { val vFile = event.file!!