diff --git a/java/java-tests/testData/psi/java/cls/Clazz.class b/java/java-tests/testData/psi/java/cls/Clazz.class new file mode 100644 index 000000000000..117efbebbcd9 Binary files /dev/null and b/java/java-tests/testData/psi/java/cls/Clazz.class differ diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/EventsTestListener.java b/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/EventsTestListener.java new file mode 100644 index 000000000000..c8dfde3442c1 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/EventsTestListener.java @@ -0,0 +1,75 @@ +package com.intellij.psi.impl.file.impl; + +import com.intellij.psi.PsiTreeChangeEvent; +import com.intellij.psi.PsiTreeChangeListener; + +/** + * @author dsl + */ +class EventsTestListener implements PsiTreeChangeListener { + StringBuffer myBuffer = new StringBuffer(); + + public String getEventsString() { + return myBuffer.toString(); + } + + @Override + public void beforeChildAddition(PsiTreeChangeEvent event) { + myBuffer.append("beforeChildAddition\n"); + } + + @Override + public void beforeChildRemoval(PsiTreeChangeEvent event) { + myBuffer.append("beforeChildRemoval\n"); + } + + @Override + public void beforeChildReplacement(PsiTreeChangeEvent event) { + myBuffer.append("beforeChildReplacement\n"); + } + + @Override + public void beforeChildMovement(PsiTreeChangeEvent event) { + myBuffer.append("beforeChildMovement\n"); + } + + @Override + public void beforeChildrenChange(PsiTreeChangeEvent event) { + myBuffer.append("beforeChildrenChange\n"); + } + + @Override + public void beforePropertyChange(PsiTreeChangeEvent event) { + myBuffer.append("beforePropertyChange\n"); + } + + @Override + public void childAdded(PsiTreeChangeEvent event) { + myBuffer.append("childAdded\n"); + } + + @Override + public void childRemoved(PsiTreeChangeEvent event) { + myBuffer.append("childRemoved\n"); + } + + @Override + public void childReplaced(PsiTreeChangeEvent event) { + myBuffer.append("childReplaced\n"); + } + + @Override + public void childrenChanged(PsiTreeChangeEvent event) { + myBuffer.append("childrenChanged\n"); + } + + @Override + public void childMoved(PsiTreeChangeEvent event) { + myBuffer.append("childMoved\n"); + } + + @Override + public void propertyChanged(PsiTreeChangeEvent event) { + myBuffer.append("propertyChanged\n"); + } +} diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/InvalidateClassFileTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/InvalidateClassFileTest.java new file mode 100644 index 000000000000..ac79a1761d87 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/InvalidateClassFileTest.java @@ -0,0 +1,90 @@ +package com.intellij.psi.impl.file.impl; + +import com.intellij.JavaTestUtil; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiTreeChangeAdapter; +import com.intellij.psi.PsiTreeChangeEvent; +import com.intellij.testFramework.PsiTestCase; + +import java.io.File; + +/** + * @author ven + */ +public class InvalidateClassFileTest extends PsiTestCase { + private File myRoot; + + private static final String BASE_PATH = "/psi/java/cls/"; + + + @Override + protected void setUp() throws Exception { + super.setUp(); + myRoot = createTempDirectory(); + myFilesToDelete.add(myRoot); + } + + public void test1() throws Exception { + String srcPath = JavaTestUtil.getJavaTestDataPath() + BASE_PATH + "Clazz.class"; + final File srcFile = new File(srcPath); + final File dstFile = new File(myRoot, "Clazz.class"); + assertFalse(dstFile.exists()); + FileUtil.copy(srcFile, dstFile); + + final VirtualFile rootVFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(myRoot); + + assertNotNull(rootVFile); + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + Module module = myModule; + final ModuleRootManager rootManager = ModuleRootManager.getInstance(module); + final ModifiableRootModel rootModel = rootManager.getModifiableModel(); + final Library library = rootModel.getModuleLibraryTable().createLibrary(); + final Library.ModifiableModel libraryModel = library.getModifiableModel(); + libraryModel.addRoot(rootVFile.getUrl(), OrderRootType.CLASSES); + libraryModel.commit(); + rootModel.commit(); + } + }); + + + PsiClass clazz = getJavaFacade().findClass("Clazz"); + assertNotNull(clazz); + final boolean[] notified = new boolean[] {false}; + final PsiTreeChangeAdapter listener = new PsiTreeChangeAdapter() { + @Override + public void childRemoved(PsiTreeChangeEvent event) { + notified[0] = true; + } + + @Override + public void childrenChanged(PsiTreeChangeEvent event) { + notified[0] = true; + } + }; + getPsiManager().addPsiTreeChangeListener(listener); + + try { + dstFile.setLastModified(System.currentTimeMillis()); + VirtualFileManager.getInstance().refresh(false); + assertTrue("No event sent!", notified[0]); + } + finally { + getPsiManager().removePsiTreeChangeListener(listener); + } + + assertFalse(clazz.isValid()); + assertNotNull(getJavaFacade().findClass("Clazz")); + } +} diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/PsiEventsTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/PsiEventsTest.java new file mode 100644 index 000000000000..884e0388d0a5 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/psi/impl/file/impl/PsiEventsTest.java @@ -0,0 +1,666 @@ +package com.intellij.psi.impl.file.impl; + + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx; +import com.intellij.openapi.roots.ContentEntry; +import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.impl.PsiTreeChangeEventImpl; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.testFramework.PsiTestCase; +import com.intellij.util.io.ReadOnlyAttributeUtil; +import com.intellij.util.WaitFor; + +import java.io.File; +import java.io.IOException; + +public class PsiEventsTest extends PsiTestCase { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.file.impl.PsiEventsTest"); + + private VirtualFile myPrjDir1; + private VirtualFile myPrjDir2; + private VirtualFile myPrjDir3; + private VirtualFile mySrcDir1; + private VirtualFile mySrcDir2; + private VirtualFile mySrcDir3; + private VirtualFile mySrcDir4; + private VirtualFile myClsDir1; + private VirtualFile myExcludedDir1; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + final File root = FileUtil.createTempFile(getName(), ""); + root.delete(); + root.mkdir(); + myFilesToDelete.add(root); + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + try { + VirtualFile rootVFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(root); + + myPrjDir1 = rootVFile.createChildDirectory(null, "prj1"); + mySrcDir1 = myPrjDir1.createChildDirectory(null, "src1"); + mySrcDir2 = myPrjDir1.createChildDirectory(null, "src2"); + + myPrjDir2 = rootVFile.createChildDirectory(null, "prj2"); + mySrcDir3 = myPrjDir2; + + + myClsDir1 = myPrjDir1.createChildDirectory(null, "cls1"); + + myExcludedDir1 = mySrcDir1.createChildDirectory(null, "excluded"); + + final ModifiableRootModel rootModel = ModuleRootManager.getInstance(myModule).getModifiableModel(); + final ContentEntry contentEntry1 = rootModel.addContentEntry(myPrjDir1); + contentEntry1.addSourceFolder(mySrcDir1, false); + contentEntry1.addSourceFolder(mySrcDir2, false); + contentEntry1.addExcludeFolder(myExcludedDir1); + final Library.ModifiableModel libraryModel = rootModel.getModuleLibraryTable().createLibrary().getModifiableModel(); + libraryModel.addRoot(myClsDir1, OrderRootType.CLASSES); + libraryModel.commit(); + final ContentEntry contentEntry2 = rootModel.addContentEntry(myPrjDir2); + contentEntry2.addSourceFolder(mySrcDir3, false); + rootModel.commit(); + } catch (IOException e) { + LOG.error(e); + } + } + }); + + //((PsiManagerImpl)myPsiManager).getFileManager().disbleVFSEventsProcessing(); + } + + public void testCreateFile() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + PsiDirectory psiDir = fileManager.findDirectory(myPrjDir1); + myPrjDir1.createChildData(null, "a.txt"); + + String string = listener.getEventsString(); + String expected = + "beforeChildAddition\n" + + "childAdded\n"; + assertEquals(expected, string); + } + + public void testCreateDirectory() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + PsiDirectory psiDir = fileManager.findDirectory(myPrjDir1); + myPrjDir1.createChildDirectory(null, "aaa"); + + String string = listener.getEventsString(); + String expected = + "beforeChildAddition\n" + + "childAdded\n"; + assertEquals(expected, string); + } + + public void testDeleteFile() throws Exception { + VirtualFile file = myPrjDir1.createChildData(null, "a.txt"); + + FileManager fileManager = myPsiManager.getFileManager(); + PsiFile psiFile = fileManager.findFile(file);//it's important to hold the reference + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.delete(null); + + String string = listener.getEventsString(); + String expected = + "beforeChildRemoval\n" + + "childRemoved\n"; + assertEquals(expected, string); + } + + public void testDeleteDirectory() throws Exception { + VirtualFile file = myPrjDir1.createChildDirectory(null, "aaa"); + + FileManager fileManager = myPsiManager.getFileManager(); + PsiDirectory psiDirectory = fileManager.findDirectory(file); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.delete(null); + + String string = listener.getEventsString(); + String expected = + "beforeChildRemoval\n" + + "childRemoved\n"; + assertEquals(expected, string); + } + + public void testRenameFile1() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildData(null, "a.txt"); + PsiFile psiFile = fileManager.findFile(file); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.rename(null, "b.txt"); + + String string = listener.getEventsString(); + String expected = + "beforePropertyChange\n" + + "propertyChanged\n"; + assertEquals(expected, string); + } + + public void testRenameFile2() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildData(null, "a.txt"); + PsiFile psiFile = fileManager.findFile(file); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.rename(null, "b.xml"); + + String string = listener.getEventsString(); + String expected = + "beforeChildReplacement\n" + + "childReplaced\n"; + assertEquals(expected, string); + } + + public void testRenameFile3() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildData(null, "a.txt"); + PsiFile psiFile = fileManager.findFile(file); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.rename(null, "CVS"); + + String string = listener.getEventsString(); + String expected = + "beforeChildRemoval\n" + + "childRemoved\n"; + assertEquals(expected, string); + assertNull(fileManager.findFile(file)); + } + + public void testRenameFile4() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildData(null, "CVS"); + PsiDirectory psiDirectory = fileManager.findDirectory(file.getParent()); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.rename(null, "aaa.txt"); + + String string = listener.getEventsString(); + String expected = + "beforeChildAddition\n" + + "childAdded\n"; + assertEquals(expected, string); + } + + public void testRenameDirectory1() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildDirectory(null, "dir1"); + PsiDirectory psiDirectory = fileManager.findDirectory(file); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.rename(null, "dir2"); + + String string = listener.getEventsString(); + String expected = + "beforePropertyChange\n" + + "propertyChanged\n"; + assertEquals(expected, string); + } + + public void testRenameDirectory2() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildDirectory(null, "dir1"); + PsiDirectory psiDirectory = fileManager.findDirectory(file); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.rename(null, "CVS"); + + String string = listener.getEventsString(); + String expected = + "beforeChildRemoval\n" + + "childRemoved\n"; + assertEquals(expected, string); + assertNull(fileManager.findDirectory(file)); + } + + public void testRenameDirectory3() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildDirectory(null, "CVS"); + PsiDirectory psiDirectory = fileManager.findDirectory(file.getParent()); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.rename(null, "dir"); + + String string = listener.getEventsString(); + String expected = + "beforeChildAddition\n" + + "childAdded\n"; + assertEquals(expected, string); + } + + public void testMakeFileReadOnly() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildData(null, "a.txt"); + PsiFile psiFile = fileManager.findFile(file); + + final EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + ReadOnlyAttributeUtil.setReadOnlyAttribute(file, true); + + String string = listener.getEventsString(); + final String expected = + "beforePropertyChange\n" + + "propertyChanged\n"; + + new WaitFor(500){ + @Override + protected boolean condition() { + return expected.equals(listener.getEventsString()); + } + }.assertCompleted(expected); + + ReadOnlyAttributeUtil.setReadOnlyAttribute(file, false); + } + + public void testMoveFile1() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildData(null, "a.txt"); + PsiFile psiFile = fileManager.findFile(file); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.move(null, myPrjDir1.getParent()); + + String string = listener.getEventsString(); + String expected = + "beforeChildMovement\n" + + "childMoved\n"; + assertEquals(expected, string); + } + + public void testMoveFile2() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildData(null, "a.txt"); + PsiFile psiFile = fileManager.findFile(file); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.move(null, myExcludedDir1); + + String string = listener.getEventsString(); + String expected = + "beforeChildRemoval\n" + + "childRemoved\n"; + assertEquals(expected, string); + assertNull(fileManager.findFile(file)); + } + + public void testMoveFile3() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myExcludedDir1.createChildData(null, "a.txt"); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.move(null, myPrjDir1); + + String string = listener.getEventsString(); + String expected = + "beforeChildAddition\n" + + "childAdded\n"; + assertEquals(expected, string); + } + + public void testMoveFile4() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myExcludedDir1.createChildData(null, "a.txt"); + VirtualFile subdir = myExcludedDir1.createChildDirectory(null, "subdir"); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.move(null, subdir); + + String string = listener.getEventsString(); + String expected = ""; + assertEquals(expected, string); + } + + public void testMoveDirectory1() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildDirectory(null, "dir"); + PsiDirectory psiDirectory = fileManager.findDirectory(file); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.move(null, myPrjDir1.getParent()); + + String string = listener.getEventsString(); + String expected = + "beforeChildMovement\n" + + "childMoved\n"; + assertEquals(expected, string); + } + + public void testMoveDirectory2() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildDirectory(null, "dir"); + PsiDirectory psiDirectory = fileManager.findDirectory(file); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.move(null, myExcludedDir1); + + String string = listener.getEventsString(); + String expected = + "beforeChildRemoval\n" + + "childRemoved\n"; + assertEquals(expected, string); + assertNull(fileManager.findDirectory(file)); + } + + public void testMoveDirectory3() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myExcludedDir1.createChildDirectory(null, "dir"); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.move(null, myPrjDir1); + + String string = listener.getEventsString(); + String expected = + "beforeChildAddition\n" + + "childAdded\n"; + assertEquals(expected, string); + } + + public void testMoveDirectory4() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myExcludedDir1.createChildDirectory(null, "dir"); + VirtualFile subdir = myExcludedDir1.createChildDirectory(null, "subdir"); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + file.move(null, subdir); + + String string = listener.getEventsString(); + String expected = ""; + assertEquals(expected, string); + } + + public void testChangeFile() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + VirtualFile file = myPrjDir1.createChildData(null, "a.txt"); + VfsUtil.saveText(file, "aaa"); + PsiFile psiFile = fileManager.findFile(file); + psiFile.getText(); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + VfsUtil.saveText(file, "bbb"); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + + /* + assertEquals("", listener.getEventsString()); + + PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + */ + + assertEquals( + "beforeChildrenChange\n" + + "beforeChildReplacement\n" + + "childReplaced\n"+ + "childrenChanged\n", + listener.getEventsString()); + } + + public void testAddExcludeRoot() throws IOException { + final VirtualFile dir = myPrjDir1.createChildDirectory(null, "aaa"); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + final ModifiableRootModel rootModel = ModuleRootManager.getInstance(myModule).getModifiableModel(); + final ContentEntry contentEntry1 = rootModel.getContentEntries()[0]; + contentEntry1.addExcludeFolder(dir); + rootModel.commit(); + } + }); + + + String string = listener.getEventsString(); + String expected = + "beforePropertyChange\n" + + "propertyChanged\n"; + assertEquals(expected, string); + } + + public void testAddSourceRoot() throws IOException { + final VirtualFile dir = myPrjDir1.createChildDirectory(null, "aaa"); + + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + final ModifiableRootModel rootModel = ModuleRootManager.getInstance(myModule).getModifiableModel(); + final ContentEntry contentEntry1 = rootModel.getContentEntries()[0]; + contentEntry1.addSourceFolder(dir, false); + rootModel.commit(); + } + }); + + + String string = listener.getEventsString(); + String expected = + "beforePropertyChange\n" + + "propertyChanged\n"; + assertEquals(expected, string); + } + + public void testModifyFileTypes() throws Exception { + FileManager fileManager = myPsiManager.getFileManager(); + EventsTestListener listener = new EventsTestListener(); + myPsiManager.addPsiTreeChangeListener(listener,getTestRootDisposable()); + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + ((FileTypeManagerEx)FileTypeManager.getInstance()).fireBeforeFileTypesChanged(); + ((FileTypeManagerEx)FileTypeManager.getInstance()).fireFileTypesChanged(); + } + }); + + + String string = listener.getEventsString(); + String expected = + "beforePropertyChange\n" + + "propertyChanged\n"; + assertEquals(expected, string); + } + + public void testCyclicDispatching() throws Throwable { + final VirtualFile virtualFile = createFile("a.xml", "").getVirtualFile(); + final PsiTreeChangeAdapter listener = new PsiTreeChangeAdapter() { + @Override + public void propertyChanged(PsiTreeChangeEvent event) { + getJavaFacade().findClass("XXX", GlobalSearchScope.allScope(myProject)); + } + }; + getPsiManager().addPsiTreeChangeListener(listener,getTestRootDisposable()); + virtualFile.rename(this, "b.xml"); + } + + String newText; + String original; + String eventsFired = ""; + PsiTreeChangeListener listener; + public void testBeforeAfterChildrenChange() throws Throwable { + listener = new PsiTreeChangeListener() { + @Override + public void beforeChildAddition(PsiTreeChangeEvent event) { + logEvent(event); + } + + @Override + public void beforeChildRemoval(PsiTreeChangeEvent event) { + logEvent(event); + } + + @Override + public void beforeChildReplacement(PsiTreeChangeEvent event) { + logEvent(event); + } + + @Override + public void beforeChildMovement(PsiTreeChangeEvent event) { + logEvent(event); + } + + @Override + public void beforeChildrenChange(PsiTreeChangeEvent event) { + logEvent(event); + } + + @Override + public void beforePropertyChange(PsiTreeChangeEvent event) { + logEvent(event); + } + + @Override + public void childAdded(PsiTreeChangeEvent event) { + logEvent(event); + assertBeforeEventFired(event); + } + + @Override + public void childRemoved(PsiTreeChangeEvent event) { + logEvent(event); + assertBeforeEventFired(event); + } + + @Override + public void childReplaced(PsiTreeChangeEvent event) { + logEvent(event); + assertBeforeEventFired(event); + } + + @Override + public void childrenChanged(PsiTreeChangeEvent event) { + logEvent(event); + assertBeforeEventFired(event); + } + + @Override + public void childMoved(PsiTreeChangeEvent event) { + logEvent(event); + assertBeforeEventFired(event); + } + + @Override + public void propertyChanged(PsiTreeChangeEvent event) { + logEvent(event); + assertBeforeEventFired(event); + } + }; + + myFile = createFile("A.java", "class A { int i; }"); + doTestEvents("class A { }"); + //doTestEvents("class A { int i; int j; }"); //todo: f*(&&ing compactChanges() in TreeChangeEventImpl garbles afterXXX events so that they don't match beforeXXX + doTestEvents("class A { int k; }"); + doTestEvents("class A { int k; int i; }"); + doTestEvents("class A { void foo(){} }"); + doTestEvents("xxxxxx"); + doTestEvents(""); + } + + private void logEvent(PsiTreeChangeEvent event) { + PsiTreeChangeEventImpl.PsiEventType code = ((PsiTreeChangeEventImpl)event).getCode(); + eventsFired += eventText(event, code); + } + + private static String eventText(PsiTreeChangeEvent event, PsiTreeChangeEventImpl.PsiEventType code) { + PsiElement parent = event.getParent(); + PsiElement oldChild = event.getOldChild(); + if (oldChild == null) oldChild = event.getChild(); + PsiElement newChild = event.getNewChild(); + return code + ":" + + (parent == null ? null : parent.getNode().getElementType()) + "/" + + (oldChild == null ? null : oldChild.getNode().getElementType()) + "->" + + (newChild == null ? null : newChild.getNode().getElementType()) + + ";"; + } + + private void assertBeforeEventFired(PsiTreeChangeEvent afterEvent) { + PsiTreeChangeEventImpl.PsiEventType code = ((PsiTreeChangeEventImpl)afterEvent).getCode(); + assertFalse(code.name(), code.name().startsWith("BEFORE_")); + PsiTreeChangeEventImpl.PsiEventType beforeCode = PsiTreeChangeEventImpl.PsiEventType.values()[code.ordinal() - 1]; + assertTrue(beforeCode.name(), beforeCode.name().startsWith("BEFORE_")); + String beforeText = eventText(afterEvent, beforeCode); + int i = eventsFired.indexOf(beforeText); + assertTrue("Event '" + beforeText + "' must be fired. Events so far: " + eventsFired, i >= 0); + } + private void doTestEvents(String newText) { + try { + getPsiManager().addPsiTreeChangeListener(listener); + eventsFired = ""; + this.newText = newText; + original = getFile().getText(); + Document document = PsiDocumentManager.getInstance(getProject()).getDocument(getFile()); + document.setText(newText); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + + document.setText(original); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + } + finally { + getPsiManager().removePsiTreeChangeListener(listener); + } + } +}