import com.intellij.psi.impl.source.tree.FileElement;
import com.intellij.psi.templateLanguages.OuterLanguageElement;
import com.intellij.util.ConcurrencyUtil;
+import com.intellij.util.NullableFunction;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
return myRoots.get(target);
}
+ @Override
+ public List<PsiFile> getCachedPsiFiles() {
+ return ContainerUtil.mapNotNull(myRoots.keySet(), new NullableFunction<Language, PsiFile>() {
+ @Nullable
+ @Override
+ public PsiFile fun(Language language) {
+ return getCachedPsi(language);
+ }
+ });
+ }
+
@NotNull
@Override
- public FileElement[] getKnownTreeRoots() {
+ public List<FileElement> getKnownTreeRoots() {
List<FileElement> files = new ArrayList<FileElement>(myRoots.size());
for (PsiFile file : myRoots.values()) {
final FileElement treeElement = ((PsiFileImpl)file).getTreeElement();
}
}
- return files.toArray(new FileElement[files.size()]);
+ return files;
}
@TestOnly
import com.intellij.openapi.vfs.PersistentFSConstants;
import com.intellij.openapi.vfs.VFileProperty;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.impl.PsiManagerEx;
-import com.intellij.psi.impl.PsiManagerImpl;
+import com.intellij.psi.impl.*;
import com.intellij.psi.impl.file.PsiBinaryFileImpl;
import com.intellij.psi.impl.file.PsiLargeFileImpl;
import com.intellij.psi.impl.file.impl.FileManager;
@Override
public void contentsSynchronized() {
- if (!(myContent instanceof PsiFileContent)) return;
- setContent(new VirtualFileContent());
+ if (myContent instanceof PsiFileContent) {
+ setContent(new VirtualFileContent());
+ }
+ checkLengthConsistency();
}
public void beforeDocumentChanged(@Nullable PsiFile psiCause) {
PsiFile psiFile = psiCause != null ? psiCause : getPsi(getBaseLanguage());
if (psiFile instanceof PsiFileImpl) {
setContent(new PsiFileContent((PsiFileImpl)psiFile, psiCause == null ? getModificationStamp() : LocalTimeCounter.currentTime()));
+ checkLengthConsistency();
}
}
+ public final void onContentReload() {
+ List<PsiFile> files = getCachedPsiFiles();
+ List<PsiTreeChangeEventImpl> events = ContainerUtil.newArrayList();
+ List<PsiTreeChangeEventImpl> genericEvents = ContainerUtil.newArrayList();
+ for (PsiFile file : files) {
+ genericEvents.add(createChildrenChangeEvent(file, true));
+ events.add(createChildrenChangeEvent(file, false));
+ }
+
+ beforeContentsSynchronized();
+
+ for (PsiTreeChangeEventImpl event : genericEvents) {
+ ((PsiManagerImpl)getManager()).beforeChildrenChange(event);
+ }
+ for (PsiTreeChangeEventImpl event : events) {
+ ((PsiManagerImpl)getManager()).beforeChildrenChange(event);
+ }
+
+ for (PsiFile psiFile : files) {
+ if (psiFile instanceof PsiFileEx) {
+ ((PsiFileEx)psiFile).onContentReload();
+ }
+ }
+
+ for (PsiTreeChangeEventImpl event : events) {
+ ((PsiManagerImpl)getManager()).childrenChanged(event);
+ }
+ for (PsiTreeChangeEventImpl event : genericEvents) {
+ ((PsiManagerImpl)getManager()).childrenChanged(event);
+ }
+
+ contentsSynchronized();
+ }
+
+ private PsiTreeChangeEventImpl createChildrenChangeEvent(PsiFile file, boolean generic) {
+ PsiTreeChangeEventImpl event = new PsiTreeChangeEventImpl(myManager);
+ event.setParent(file);
+ event.setFile(file);
+ event.setGenericChange(generic);
+ if (file instanceof PsiFileImpl && ((PsiFileImpl)file).isContentsLoaded()) {
+ event.setOffset(0);
+ event.setOldLength(file.getTextLength());
+ }
+ return event;
+ }
+
@Override
public void rootChanged(@NotNull PsiFile psiFile) {
if (psiFile instanceof PsiFileImpl && ((PsiFileImpl)psiFile).isContentsLoaded()) {
return file == PsiUtilCore.NULL_PSI_FILE ? null : file;
}
+ public List<PsiFile> getCachedPsiFiles() {
+ return ContainerUtil.createMaybeSingletonList(getCachedPsi(myBaseLanguage));
+ }
+
@NotNull
- public FileElement[] getKnownTreeRoots() {
+ public List<FileElement> getKnownTreeRoots() {
PsiFile psiFile = getCachedPsi(myBaseLanguage);
- if (!(psiFile instanceof PsiFileImpl)) return FileElement.EMPTY_ARRAY;
- if (((PsiFileImpl)psiFile).getTreeElement() == null) return FileElement.EMPTY_ARRAY;
- return new FileElement[]{(FileElement)psiFile.getNode()};
+ if (!(psiFile instanceof PsiFileImpl)) return Collections.emptyList();
+ FileElement element = ((PsiFileImpl)psiFile).getTreeElement();
+ return ContainerUtil.createMaybeSingletonList(element);
}
private PsiFile createFile() {
}
private void setContent(@NotNull Content content) {
- Content prevContent = myContent;
myContent = content;
- if (prevContent instanceof PsiFileContent && content instanceof VirtualFileContent) {
- int fileLength = content.getText().length();
- for (FileElement fileElement : getKnownTreeRoots()) {
- int nodeLength = fileElement.getTextLength();
- if (nodeLength != fileLength) {
- LOG.error("Inconsistent " + fileElement.getElementType() + " tree in " + this + "; nodeLength=" + nodeLength + "; fileLength=" + fileLength);
- }
+ }
+
+ private void checkLengthConsistency() {
+ Document document = getCachedDocument();
+ if (document != null &&
+ ((PsiDocumentManagerBase)PsiDocumentManager.getInstance(myManager.getProject())).getSynchronizer().isInSynchronization(document)) {
+ return;
+ }
+
+ List<FileElement> knownTreeRoots = getKnownTreeRoots();
+ if (knownTreeRoots.isEmpty()) return;
+
+ int fileLength = myContent.getText().length();
+ for (FileElement fileElement : knownTreeRoots) {
+ int nodeLength = fileElement.getTextLength();
+ if (nodeLength != fileLength) {
+ // exceptions here should be assigned to peter
+ LOG.error("Inconsistent " + fileElement.getElementType() + " tree in " + this + "; nodeLength=" + nodeLength + "; fileLength=" + fileLength);
}
}
-
}
@NonNls
ApplicationManager.getApplication().runWriteAction(new ExternalChangeAction() {
@Override
public void run() {
- psiFile.getViewProvider().beforeContentsSynchronized();
- synchronized (PsiLock.LOCK) {
- final int oldLength = prevInfo.myFrozen.getTextLength();
- PsiManagerImpl manager = (PsiManagerImpl)psiFile.getManager();
- BlockSupportImpl.sendBeforeChildrenChangeEvent(manager, psiFile, true);
- BlockSupportImpl.sendBeforeChildrenChangeEvent(manager, psiFile, false);
- if (psiFile instanceof PsiFileImpl) {
- ((PsiFileImpl)psiFile).onContentReload();
- }
- BlockSupportImpl.sendAfterChildrenChangedEvent(manager, psiFile, oldLength, false);
- BlockSupportImpl.sendAfterChildrenChangedEvent(manager, psiFile, oldLength, true);
+ FileViewProvider viewProvider = psiFile.getViewProvider();
+ if (viewProvider instanceof SingleRootFileViewProvider) {
+ ((SingleRootFileViewProvider)viewProvider).onContentReload();
+ } else {
+ LOG.error("Invalid view provider: " + viewProvider + " of " + viewProvider.getClass());
}
- psiFile.getViewProvider().contentsSynchronized();
}
});
}
return;
}
- PsiTreeChangeEventImpl event = new PsiTreeChangeEventImpl(myManager);
- event.setParent(file);
- event.setFile(file);
- if (file instanceof PsiFileImpl && ((PsiFileImpl)file).isContentsLoaded()) {
- event.setOffset(0);
- event.setOldLength(file.getTextLength());
- }
- myManager.beforeChildrenChange(event);
-
- if (file instanceof PsiFileEx) {
- ((PsiFileEx)file).onContentReload();
+ FileViewProvider viewProvider = file.getViewProvider();
+ if (viewProvider instanceof SingleRootFileViewProvider) {
+ ((SingleRootFileViewProvider)viewProvider).onContentReload();
+ } else {
+ LOG.error("Invalid view provider: " + viewProvider + " of " + viewProvider.getClass());
}
-
- myManager.childrenChanged(event);
}
}
}
return treeElement;
}
- public void unloadContent() {
- ApplicationManager.getApplication().assertWriteAccessAllowed();
- clearCaches();
- myViewProvider.beforeContentsSynchronized();
- synchronized (PsiLock.LOCK) {
- FileElement treeElement = derefTreeElement();
- DebugUtil.startPsiModification("unloadContent");
- try {
- if (treeElement != null) {
- myTreeElementPointer = null;
- treeElement.detachFromFile();
- DebugUtil.onInvalidated(treeElement);
- }
- clearStub("unloadContent");
- }
- finally {
- DebugUtil.finishPsiModification();
- }
- }
- myViewProvider.contentsSynchronized();
- }
-
private void clearStub(@NotNull String reason) {
StubTree stubHolder = SoftReference.dereference(myStub);
if (stubHolder != null) {
@Override
public void onContentReload() {
- subtreeChanged(); // important! otherwise cached information is not released
- if (isContentsLoaded()) {
- unloadContent();
+ ApplicationManager.getApplication().assertWriteAccessAllowed();
+
+ FileElement treeElement = derefTreeElement();
+ DebugUtil.startPsiModification("onContentReload");
+ try {
+ if (treeElement != null) {
+ myTreeElementPointer = null;
+ treeElement.detachFromFile();
+ DebugUtil.onInvalidated(treeElement);
+ }
+ clearStub("onContentReload");
+ }
+ finally {
+ DebugUtil.finishPsiModification();
}
+ clearCaches();
}
@Nullable
import com.intellij.openapi.project.DumbServiceImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiDocumentManager;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiManager;
+import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubUpdatingIndex;
import com.intellij.psi.util.QualifiedName;
+import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.TestDataPath;
import com.intellij.util.indexing.FileBasedIndex;
import com.jetbrains.python.fixtures.PyTestCase;
StubElement fileStub = fileImpl.getStub();
assertNull("There should be no stub if file holds tree element", fileStub);
- FileBasedIndex.getInstance().ensureUpToDate(StubUpdatingIndex.INDEX_ID, myFixture.getProject(), null);
new WriteCommandAction(myFixture.getProject(), fileImpl) {
@Override
protected void run(@NotNull Result result) throws Throwable {
- fileImpl.unloadContent();
+ ((SingleRootFileViewProvider)fileImpl.getViewProvider()).onContentReload();
}
}.execute();
- assertNull(fileImpl.getTreeElement()); // Test unload successed.
+ assertNull(fileImpl.getTreeElement()); // Test unload succeeded.
- fileStub = fileImpl.getStub();
- assertNotNull("After tree element have been unloaded we must be able to create updated stub", fileStub);
-
- final PyClassStub newclassstub = (PyClassStub)fileStub.getChildrenStubs().get(0);
- assertEquals("RenamedClass", newclassstub.getName());
+ assertEquals("RenamedClass", fileImpl.getTopLevelClasses().get(0).getName());
}
public void testImportStatement() {