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 index 8ea8d3a77112..2461a4601eba 100644 --- 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 @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.psi.impl.file.impl; @@ -640,4 +655,90 @@ public class PsiEventsTest extends PsiTestCase { getPsiManager().removePsiTreeChangeListener(listener); } } + + public void testPsiEventsComeWhenDocumentAlreadyCommitted() throws Exception { + myFile = createFile("A.java", "class A { int i; }"); + getPsiManager().addPsiTreeChangeListener(new PsiTreeChangeListener() { + @Override + public void beforeChildAddition(@NotNull PsiTreeChangeEvent event) { + // did not decide whether the doc should be committed at this point + //checkCommitted(false, event); + } + + @Override + public void beforeChildRemoval(@NotNull PsiTreeChangeEvent event) { + // did not decide whether the doc should be committed at this point + //checkCommitted(false, event); + } + + @Override + public void beforeChildReplacement(@NotNull PsiTreeChangeEvent event) { + // did not decide whether the doc should be committed at this point + //checkCommitted(false, event); + } + + @Override + public void beforeChildMovement(@NotNull PsiTreeChangeEvent event) { + // did not decide whether the doc should be committed at this point + //checkCommitted(false, event); + } + + @Override + public void beforeChildrenChange(@NotNull PsiTreeChangeEvent event) { + // did not decide whether the doc should be committed at this point + //checkCommitted(false, event); + } + + @Override + public void beforePropertyChange(@NotNull PsiTreeChangeEvent event) { + // did not decide whether the doc should be committed at this point + //checkCommitted(false, event); + } + + @Override + public void childAdded(@NotNull PsiTreeChangeEvent event) { + checkCommitted(true, event); + } + + @Override + public void childRemoved(@NotNull PsiTreeChangeEvent event) { + checkCommitted(true, event); + } + + @Override + public void childReplaced(@NotNull PsiTreeChangeEvent event) { + checkCommitted(true, event); + } + + @Override + public void childrenChanged(@NotNull PsiTreeChangeEvent event) { + checkCommitted(true, event); + } + + @Override + public void childMoved(@NotNull PsiTreeChangeEvent event) { + checkCommitted(true, event); + } + + @Override + public void propertyChanged(@NotNull PsiTreeChangeEvent event) { + checkCommitted(true, event); + } + }, myTestRootDisposable); + + PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getProject()); + Document document = documentManager.getDocument(getFile()); + assertTrue(documentManager.isCommitted(document)); + + document.setText(""); + documentManager.commitAllDocuments(); + assertTrue(documentManager.isCommitted(document)); + } + + private void checkCommitted(boolean shouldBeCommitted, PsiTreeChangeEvent event) { + PsiFile file = event.getFile(); + PsiDocumentManager documentManager = PsiDocumentManager.getInstance(file.getProject()); + Document document = documentManager.getDocument(file); + assertEquals(shouldBeCommitted, documentManager.isCommitted(document)); + } } diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java index 2d81a3d39581..f631ce1b3898 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java @@ -85,6 +85,16 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen mySmartPointerManager = (SmartPointerManagerImpl)smartPointerManager; mySynchronizer = new PsiToDocumentSynchronizer(this, bus); myPsiManager.addPsiTreeChangeListener(mySynchronizer); + bus.connect().subscribe(PsiDocumentTransactionListener.TOPIC, new PsiDocumentTransactionListener() { + @Override + public void transactionStarted(@NotNull Document document, @NotNull PsiFile file) { + myUncommittedDocuments.remove(document); + } + + @Override + public void transactionCompleted(@NotNull Document document, @NotNull PsiFile file) { + } + }); } @Override @@ -384,8 +394,9 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen runnable.run(); } else { - LOG.assertTrue(!ApplicationManager.getApplication().isReadAccessAllowed(), - "Don't call commitAndRunReadAction inside ReadAction, it will cause a deadlock otherwise."); + if (ApplicationManager.getApplication().isReadAccessAllowed()) { + LOG.error("Don't call commitAndRunReadAction inside ReadAction, it will cause a deadlock otherwise. "+Thread.currentThread()); + } final Semaphore s1 = new Semaphore(); final Semaphore s2 = new Semaphore();