psi->document sync when doc is gc-ed (IDEA-131067)

This commit is contained in:
peter
2014-10-21 19:17:25 +02:00
parent 434d71b1c0
commit 1807d294d7
3 changed files with 26 additions and 5 deletions
@@ -23,6 +23,7 @@ import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.psi.impl.source.tree.LazyParseableElement;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
@@ -297,4 +298,23 @@ public class MiscPsiTest extends LightCodeInsightFixtureTestCase {
assertFalse(leaf.isValid());
assertNotSame(leaf, file.findElementAt(5));
}
public void testPsiModificationsWithNoDocumentDocument() {
final PsiJavaFile file = (PsiJavaFile)myFixture.addFileToProject("a.java", "class A{}");
PsiClass aClass = file.getClasses()[0];
aClass.getNode();
assertNotNull(PsiDocumentManager.getInstance(getProject()).getCachedDocument(file));
PlatformTestUtil.tryGcSoftlyReachableObjects();
assertNull(PsiDocumentManager.getInstance(getProject()).getCachedDocument(file));
aClass.add(JavaPsiFacade.getElementFactory(getProject()).createMethodFromText("void foo(){}", null));
assertNotNull(PsiDocumentManager.getInstance(getProject()).getCachedDocument(file));
PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting();
assertTrue(file.getText(), file.getText().contains("foo() {\n"));
}
}
@@ -300,7 +300,8 @@ public class PomModelImpl extends UserDataHolderBase implements PomModel {
LOG.assertTrue(changeScope != null);
final PsiFile containingFileByTree = getContainingFileByTree(changeScope);
if (changeScope.isPhysical() && synchronizer.toProcessPsiEvent() && isDocumentUncommitted(containingFileByTree)) {
boolean physical = changeScope.isPhysical();
if (physical && synchronizer.toProcessPsiEvent() && isDocumentUncommitted(containingFileByTree)) {
// fail-fast to prevent any psi modifications that would cause psi/document text mismatch
// PsiToDocumentSynchronizer assertions happen inside event processing and are logged by PsiManagerImpl.fireEvent instead of being rethrown
// so it's important to throw something outside event processing
@@ -308,7 +309,9 @@ public class PomModelImpl extends UserDataHolderBase implements PomModel {
}
BlockSupportImpl.sendBeforeChildrenChangeEvent((PsiManagerImpl)PsiManager.getInstance(myProject), changeScope, true);
Document document = containingFileByTree == null ? null : manager.getCachedDocument(containingFileByTree);
Document document = containingFileByTree == null ? null :
physical ? manager.getDocument(containingFileByTree) :
manager.getCachedDocument(containingFileByTree);
if(document != null) {
synchronizer.startTransaction(myProject, document, changeScope);
}
@@ -74,9 +74,7 @@ public class PsiToDocumentSynchronizer extends PsiTreeChangeAdapter {
final PsiFile psiFile = event.getFile();
if (psiFile == null || psiFile.getNode() == null) return;
boolean forceDocument = !psiFile.getViewProvider().isPhysical();
final Document document = forceDocument ? myPsiDocumentManager.getDocument(psiFile)
: myPsiDocumentManager.getCachedDocument(psiFile);
final Document document = myPsiDocumentManager.getCachedDocument(psiFile);
if (document != null && myPsiDocumentManager.isUncommited(document)) {
throw new IllegalStateException("Attempt to modify PSI for non-committed Document!");
}