void (@NotNull List<? extends VFileEvent> events) { List<PsiElement> oldElements = new ArrayList<>(events.size()); List<PsiDirectory> oldParentDirs = new ArrayList<>(events.size()); List<PsiDirectory> newParentDirs = new ArrayList<>(events.size()); // find old directories before removing invalid ones for (VFileEvent e : events) { VFileMoveEvent event = (VFileMoveEvent)e; VirtualFile vFile = event.getFile(); PsiDirectory oldParentDir = myFileManager.findDirectory(event.getOldParent()); PsiDirectory newParentDir = myFileManager.findDirectory(event.getNewParent()); PsiElement oldElement = vFile.isDirectory() ? myFileManager.getCachedDirectory(vFile) : myFileManager.getCachedPsiFileInner(vFile); Project oldProject = ProjectLocator.getInstance().guessProjectForFile(vFile); if (oldProject != null && oldProject != myProject) { // file moved between projects, remove all associations to the old project myFileManager.removeFilesAndDirsRecursively(vFile); // avoiding crashes in filePointer.getElement() PsiCopyPasteManager.getInstance().fileMovedOutsideProject(vFile); oldElement = null; oldParentDir = null; newParentDir = null; } oldElements.add(oldElement); oldParentDirs.add(oldParentDir); newParentDirs.add(newParentDir); } myFileManager.removeInvalidFilesAndDirs(true); for (int i = 0; i < events.size(); i++) { VFileMoveEvent event = (VFileMoveEvent)events.get(i); VirtualFile vFile = event.getFile(); PsiDirectory oldParentDir = oldParentDirs.get(i); PsiDirectory newParentDir = newParentDirs.get(i); if (oldParentDir == null && newParentDir == null) continue; PsiElement oldElement = oldElements.get(i); PsiElement newElement; FileViewProvider newViewProvider; if (vFile.isDirectory()) { newElement = myFileManager.findDirectory(vFile); newViewProvider = null; } else { newViewProvider = myFileManager.createFileViewProvider(vFile, true); newElement = newViewProvider.getPsi(myFileManager.findViewProvider(vFile).getBaseLanguage()); } if (oldElement == null && newElement == null) continue; ApplicationManager.getApplication().runWriteAction( (ExternalChangeAction)() -> { PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager); if (oldElement == null) { myFileManager.setViewProvider(vFile, newViewProvider); treeEvent.setParent(newParentDir); treeEvent.setChild(newElement); myManager.childAdded(treeEvent); } else { if (newElement == null) { clearViewProvider(vFile, "PSI moved"); treeEvent.setParent(oldParentDir); treeEvent.setChild(oldElement); myManager.childRemoved(treeEvent); } else { if (newElement instanceof PsiDirectory || FileManagerImpl.areViewProvidersEquivalent(newViewProvider, ((PsiFile)oldElement).getViewProvider())) { treeEvent.setOldParent(oldParentDir); treeEvent.setNewParent(newParentDir); treeEvent.setChild(oldElement); myManager.childMoved(treeEvent); } else { myFileManager.setViewProvider(vFile, newViewProvider); PsiTreeChangeEventImpl treeRemoveEvent = new PsiTreeChangeEventImpl(myManager); treeRemoveEvent.setParent(oldParentDir); treeRemoveEvent.setChild(oldElement); myManager.childRemoved(treeRemoveEvent); PsiTreeChangeEventImpl treeAddEvent = new PsiTreeChangeEventImpl(myManager); treeAddEvent.setParent(newParentDir); treeAddEvent.setChild(newElement); myManager.childAdded(treeAddEvent); } } } } ); } }