void (@NotNull PsiTreeChangeEvent e) { PsiFile file = e.getFile(); if (file != null) { // local change scheduleMarkFileAsDirtyAndUpdateTree(file); return; } PsiElement child = e.getChild(); if (child instanceof PsiFile psiFile) { // file was moved if (canContainTodoItems(psiFile)) { // moved file contains TODOs scheduleMarkFileAsDirtyAndUpdateTree(psiFile); } return; } if (child instanceof PsiDirectory psiDirectory) { // directory was moved. mark all its files as dirty. ArrayList<VirtualFile> files = new ArrayList<>(); for (Iterator<? extends PsiFile> i = getAllFiles(); i.hasNext(); ) { PsiFile psiFile = i.next(); if (psiFile == null || // skip invalid PSI files !psiFile.isValid() || !PsiTreeUtil.isAncestor(psiDirectory, psiFile, true)) { continue; } VirtualFile virtualFile = psiFile.getVirtualFile(); if (virtualFile != null) { files.add(virtualFile); } } myCoroutineHelper.scheduleMarkFilesAsDirtyAndUpdateTree(files); } }