smart pointer cleanup

This commit is contained in:
peter
2015-08-10 08:20:12 +02:00
parent 26e53b0175
commit 8563043ac2
15 changed files with 35 additions and 266 deletions
@@ -28,8 +28,6 @@ import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.editor.event.EditorEventMulticaster;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileTypes.PlainTextFileType;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.util.Segment;
@@ -672,35 +670,6 @@ public class SmartPsiElementPointersTest extends CodeInsightTestCase {
assertNotNull(node);
}
public void testSmartPointersForOpenFilesAreFastened() {
PsiJavaFile file = (PsiJavaFile)myJavaFacade.findClass("AClass", GlobalSearchScope.allScope(getProject())).getContainingFile();
SmartPointerManagerImpl manager = (SmartPointerManagerImpl)SmartPointerManager.getInstance(myProject);
VirtualFile virtualFile = file.getVirtualFile();
assertFalse(manager.areBeltsFastened(virtualFile));
FileEditor[] editors = FileEditorManager.getInstance(myProject).openFile(virtualFile, true);
assertTrue(editors.length != 0);
assertTrue(manager.areBeltsFastened(virtualFile));
FileEditorManager.getInstance(myProject).closeFile(virtualFile);
assertFalse(manager.areBeltsFastened(virtualFile));
SmartPsiElementPointer<PsiClass> pointer = manager.createSmartPsiElementPointer(file.getClasses()[0]);
assertFalse(manager.areBeltsFastened(virtualFile));
editors = FileEditorManager.getInstance(myProject).openFile(virtualFile, true);
assertTrue(editors.length != 0);
assertTrue(manager.areBeltsFastened(virtualFile));
FileEditorManager.getInstance(myProject).closeFile(virtualFile);
assertFalse(manager.areBeltsFastened(virtualFile));
assertEquals(file.getClasses()[0], pointer.getElement()); // retain pointer from gc
}
public void testLargeFileWithManyChanges() {
configureByText(PlainTextFileType.INSTANCE, StringUtil.repeat("foo foo \n", 50000));
final TextRange range = TextRange.from(10, 10);
@@ -18,7 +18,6 @@ package com.intellij.psi.impl.smartPointers;
import com.intellij.lang.LanguageUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.util.*;
import com.intellij.psi.PsiAnchor;
import com.intellij.psi.PsiElement;
@@ -110,11 +109,11 @@ class AnchorElementInfo extends SelfElementInfo {
}
@Override
public void fastenBelt(int offset, RangeMarker[] cachedRangeMarker) {
public void fastenBelt() {
if (getStubId() != -1) {
switchToTree();
}
super.fastenBelt(offset, cachedRangeMarker);
super.fastenBelt();
}
private void switchToTree() {
@@ -15,8 +15,6 @@
*/
package com.intellij.psi.impl.smartPointers;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Segment;
@@ -29,28 +27,13 @@ import org.jetbrains.annotations.NotNull;
/**
* User: cdr
*/
public class ClsElementInfo implements SmartPointerElementInfo {
public class ClsElementInfo extends SmartPointerElementInfo {
private final PsiAnchor.StubIndexReference myStubIndexReference;
public ClsElementInfo(@NotNull PsiAnchor.StubIndexReference stubReference) {
myStubIndexReference = stubReference;
}
@Override
public Document getDocumentToSynchronize() {
return null;
}
// before change
@Override
public void fastenBelt(int offset, RangeMarker[] cachedRangeMarker) {
}
// after change
@Override
public void unfastenBelt(int offset) {
}
@Override
public PsiElement restoreElement() {
return myStubIndexReference.retrieve();
@@ -85,11 +68,6 @@ public class ClsElementInfo implements SmartPointerElementInfo {
return myStubIndexReference.getProject();
}
@Override
public void cleanup() {
}
@Override
public PsiFile restoreFile() {
return myStubIndexReference.getFile();
@@ -16,8 +16,6 @@
package com.intellij.psi.impl.smartPointers;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Segment;
@@ -30,7 +28,7 @@ import org.jetbrains.annotations.NotNull;
/**
* User: cdr
*/
class FileElementInfo implements SmartPointerElementInfo {
class FileElementInfo extends SmartPointerElementInfo {
protected final VirtualFile myVirtualFile;
protected final Project myProject;
protected final Language myLanguage;
@@ -48,19 +46,6 @@ class FileElementInfo implements SmartPointerElementInfo {
myLanguage = lang;
}
@Override
public Document getDocumentToSynchronize() {
return null;
}
@Override
public void fastenBelt(int offset, RangeMarker[] cachedRangeMarker) {
}
@Override
public void unfastenBelt(int offset) {
}
@Override
public PsiElement restoreElement() {
return SelfElementInfo.restoreFileFromVirtual(myVirtualFile, myProject, myLanguage);
@@ -105,8 +90,4 @@ class FileElementInfo implements SmartPointerElementInfo {
return myProject;
}
@Override
public void cleanup() {
}
}
@@ -15,8 +15,6 @@
*/
package com.intellij.psi.impl.smartPointers;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Segment;
@@ -29,7 +27,7 @@ import org.jetbrains.annotations.NotNull;
/**
* User: cdr
*/
class HardElementInfo implements SmartPointerElementInfo {
class HardElementInfo extends SmartPointerElementInfo {
@NotNull
private final PsiElement myElement;
@NotNull
@@ -40,19 +38,6 @@ class HardElementInfo implements SmartPointerElementInfo {
myProject = project;
}
@Override
public Document getDocumentToSynchronize() {
return null;
}
@Override
public void fastenBelt(int offset, RangeMarker[] cachedRangeMarker) {
}
@Override
public void unfastenBelt(int offset) {
}
@Override
public PsiElement restoreElement() {
return myElement;
@@ -89,8 +74,4 @@ class HardElementInfo implements SmartPointerElementInfo {
return myProject;
}
@Override
public void cleanup() {
}
}
@@ -20,7 +20,6 @@ import com.intellij.injected.editor.VirtualFileWindow;
import com.intellij.lang.Language;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.ProperTextRange;
@@ -39,7 +38,7 @@ import java.util.List;
/**
* User: cdr
*/
class InjectedSelfElementInfo implements SmartPointerElementInfo {
class InjectedSelfElementInfo extends SmartPointerElementInfo {
private final SmartPsiFileRange myInjectedFileRangeInHostFile;
private final Class<? extends PsiElement> anchorClass;
private final Language anchorLanguage;
@@ -193,16 +192,6 @@ class InjectedSelfElementInfo implements SmartPointerElementInfo {
return ((SmartPsiElementPointerImpl)myHostContext).getElementInfo().getDocumentToSynchronize();
}
@Override
public void fastenBelt(int offset, RangeMarker[] cachedRangeMarkers) {
}
@Override
public void unfastenBelt(int offset) {
}
@Override
public int elementHashCode() {
return ((SmartPsiElementPointerImpl)myHostContext).getElementInfo().elementHashCode();
@@ -18,7 +18,6 @@ package com.intellij.psi.impl.smartPointers;
import com.intellij.lang.Language;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.impl.FrozenDocument;
import com.intellij.openapi.editor.impl.ManualRangeMarker;
@@ -38,7 +37,7 @@ import java.util.Set;
/**
* User: cdr
*/
public class SelfElementInfo implements SmartPointerElementInfo {
public class SelfElementInfo extends SmartPointerElementInfo {
private final VirtualFile myVirtualFile;
private final Class myType;
private final Project myProject;
@@ -81,7 +80,7 @@ public class SelfElementInfo implements SmartPointerElementInfo {
// before change
@Override
public void fastenBelt(int offset, @Nullable RangeMarker[] cachedRangeMarkers) {
public void fastenBelt() {
if (myRangeMarker != null) return; // already tracks changes
if (myPsiRange == null) return; // invalid
@@ -96,11 +95,6 @@ public class SelfElementInfo implements SmartPointerElementInfo {
setRange(myPsiRange, document);
}
// after change
@Override
public void unfastenBelt(int offset) {
}
@Override
public PsiElement restoreElement() {
Segment segment = getPsiRange();
@@ -17,7 +17,6 @@
package com.intellij.psi.impl.smartPointers;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Segment;
import com.intellij.openapi.vfs.VirtualFile;
@@ -26,27 +25,30 @@ import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
interface SmartPointerElementInfo {
abstract class SmartPointerElementInfo {
@Nullable
Document getDocumentToSynchronize();
public Document getDocumentToSynchronize() {
return null;
}
void fastenBelt(int offset, @Nullable RangeMarker[] cachedRangeMarkers);
void unfastenBelt(int offset);
public void fastenBelt() {
}
@Nullable
PsiElement restoreElement();
public abstract PsiElement restoreElement();
PsiFile restoreFile();
public abstract PsiFile restoreFile();
int elementHashCode(); // must be immutable
boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other);
public abstract int elementHashCode(); // must be immutable
public abstract boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other);
VirtualFile getVirtualFile();
public abstract VirtualFile getVirtualFile();
@Nullable
Segment getRange();
@NotNull Project getProject();
public abstract Segment getRange();
@NotNull
public abstract Project getProject();
void cleanup();
public void cleanup() {
}
}
@@ -15,15 +15,13 @@
*/
package com.intellij.psi.impl.smartPointers;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.psi.PsiElement;
import com.intellij.psi.SmartPsiElementPointer;
import org.jetbrains.annotations.Nullable;
interface SmartPointerEx<E extends PsiElement> extends SmartPsiElementPointer<E> {
void fastenBelt(int offset, @Nullable RangeMarker[] cachedRangeMarkers);
void unfastenBelt(int offset);
void fastenBelt();
@Nullable
PsiElement getCachedElement();
}
@@ -16,12 +16,9 @@
package com.intellij.psi.impl.smartPointers;
import com.intellij.injected.editor.DocumentWindow;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.impl.FrozenDocument;
import com.intellij.openapi.editor.impl.ManualRangeMarker;
@@ -34,7 +31,6 @@ import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiDocumentManagerBase;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.reference.SoftReference;
import com.intellij.util.ArrayUtil;
@@ -65,12 +61,10 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
private final Project myProject;
private final Key<FilePointersList> POINTERS_KEY;
private final Key<Boolean> POINTERS_ARE_FASTENED_KEY;
public SmartPointerManagerImpl(Project project) {
myProject = project;
POINTERS_KEY = Key.create("SMART_POINTERS for "+project);
POINTERS_ARE_FASTENED_KEY = Key.create("SMART_POINTERS_ARE_FASTENED for "+project);
}
private static void processQueue() {
@@ -89,50 +83,22 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
}
}
public void fastenBelts(@NotNull VirtualFile file, int offset, @Nullable RangeMarker[] cachedRangeMarkers) {
public void fastenBelts(@NotNull VirtualFile file) {
ApplicationManager.getApplication().assertIsDispatchThread();
processQueue();
synchronized (lock) {
if (getAndFasten(file)) return;
FilePointersList pointers = getPointers(file);
if (pointers != null && !pointers.isEmpty()) {
for (PointerReference ref : pointers.references) {
SmartPointerEx pointer = SoftReference.dereference(ref);
if (pointer != null) {
pointer.fastenBelt(offset, cachedRangeMarkers);
pointer.fastenBelt();
}
}
}
}
}
public void unfastenBelts(@NotNull VirtualFile file, int offset) {
ApplicationManager.getApplication().assertIsDispatchThread();
processQueue();
synchronized (lock) {
if (!getAndUnfasten(file)) return;
FilePointersList pointers = getPointers(file);
if (pointers != null && !pointers.isEmpty()) {
for (PointerReference ref : pointers.references) {
SmartPointerEx pointer = SoftReference.dereference(ref);
if (pointer != null) {
pointer.unfastenBelt(offset);
}
}
}
PsiFile psiFile = ((PsiManagerEx)PsiManager.getInstance(myProject)).getFileManager().getCachedPsiFile(file);
if (psiFile != null) {
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(myProject);
for (DocumentWindow injectedDoc : InjectedLanguageManager.getInstance(myProject).getCachedInjectedDocuments(psiFile)) {
PsiFile injectedFile = psiDocumentManager.getPsiFile(injectedDoc);
if (injectedFile == null) continue;
unfastenBelts(injectedFile.getViewProvider().getVirtualFile(), 0);
}
}
}
}
private static final Key<Reference<SmartPointerEx>> CACHED_SMART_POINTER_KEY = Key.create("CACHED_SMART_POINTER_KEY");
@Override
@NotNull
@@ -158,11 +124,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
element.putUserData(CACHED_SMART_POINTER_KEY, new SoftReference<SmartPointerEx>(pointer));
}
else {
containingFile = containingFile == null ? element.getContainingFile() : containingFile;
synchronized (lock) {
if (containingFile != null && areBeltsFastened(containingFile.getViewProvider().getVirtualFile())) {
pointer.fastenBelt(0, null);
}
if (pointer instanceof SmartPsiElementPointerImpl) {
((SmartPsiElementPointerImpl)pointer).incrementAndGetReferenceCount(1);
}
@@ -273,20 +235,6 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
}
}
private boolean getAndFasten(@NotNull VirtualFile file) {
boolean fastened = areBeltsFastened(file);
file.putUserData(POINTERS_ARE_FASTENED_KEY, Boolean.TRUE);
return fastened;
}
private boolean getAndUnfasten(@NotNull VirtualFile file) {
boolean fastened = areBeltsFastened(file);
file.putUserData(POINTERS_ARE_FASTENED_KEY, null);
return fastened;
}
boolean areBeltsFastened(@NotNull VirtualFile file) {
return file.getUserData(POINTERS_ARE_FASTENED_KEY) == Boolean.TRUE;
}
@Override
public boolean pointToTheSameElement(@NotNull SmartPsiElementPointer pointer1, @NotNull SmartPsiElementPointer pointer2) {
return SmartPsiElementPointerImpl.pointsToTheSameElementAs(pointer1, pointer2);
@@ -20,7 +20,6 @@ import com.intellij.lang.LanguageUtil;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
@@ -178,13 +177,8 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
}
@Override
public void unfastenBelt(int offset) {
myElementInfo.unfastenBelt(offset);
}
@Override
public void fastenBelt(int offset, @Nullable RangeMarker[] cachedRangeMarkers) {
myElementInfo.fastenBelt(offset, cachedRangeMarkers);
public void fastenBelt() {
myElementInfo.fastenBelt();
}
@NotNull
@@ -1,25 +0,0 @@
/*
* Copyright 2000-2013 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.source.tree;
import com.intellij.openapi.editor.RangeMarker;
import org.jetbrains.annotations.NotNull;
public interface MarkersHolderFileViewProvider {
@NotNull
RangeMarker[] getCachedMarkers();
}
@@ -60,20 +60,12 @@ public class SmartPointerEditorTracker extends AbstractProjectComponent implemen
boolean isRelevant = virtualFile != null && isRelevant(virtualFile);
if (!isBulk && isRelevant && shouldNotifySmartPointers(virtualFile)) {
mySmartPointerManager.fastenBelts(virtualFile, event.getOffset(), null);
mySmartPointerManager.fastenBelts(virtualFile);
}
}
@Override
public void documentChanged(DocumentEvent event) {
final Document document = event.getDocument();
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
boolean isBulk = document instanceof DocumentEx && ((DocumentEx)document).isInBulkUpdate();
boolean isRelevant = virtualFile != null && isRelevant(virtualFile);
if (!isBulk && isRelevant && shouldNotifySmartPointers(virtualFile)) {
mySmartPointerManager.unfastenBelts(virtualFile, event.getOffset());
}
}
@Override
@@ -86,22 +78,12 @@ public class SmartPointerEditorTracker extends AbstractProjectComponent implemen
final VirtualFile virtualFile = psiFile.getVirtualFile();
// materialize all range markers and do not let them to be collected to improve responsiveness
if (virtualFile != null) {
mySmartPointerManager.fastenBelts(virtualFile, 0, null);
mySmartPointerManager.fastenBelts(virtualFile);
}
}
@Override
public void editorReleased(@NotNull EditorFactoryEvent event) {
final Editor editor = event.getEditor();
if (editor.getProject() != null && editor.getProject() != myProject || myProject.isDisposed()) return;
final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(editor.getDocument());
if (psiFile == null) return;
final VirtualFile virtualFile = psiFile.getVirtualFile();
// allow range markers in smart pointers to be collected
// beware there maybe other editors still open for that file
if (virtualFile != null && virtualFile.isValid() && shouldNotifySmartPointers(virtualFile)) {
mySmartPointerManager.unfastenBelts(virtualFile, 0);
}
}
private boolean shouldNotifySmartPointers(@NotNull VirtualFile virtualFile) {
@@ -116,16 +98,12 @@ public class SmartPointerEditorTracker extends AbstractProjectComponent implemen
public void updateStarted(@NotNull Document document) {
final VirtualFile virtualFile = getVirtualFile(document);
if (virtualFile != null && isRelevant(virtualFile) && shouldNotifySmartPointers(virtualFile)) {
mySmartPointerManager.fastenBelts(virtualFile, 0, null);
mySmartPointerManager.fastenBelts(virtualFile);
}
}
@Override
public void updateFinished(@NotNull Document document) {
final VirtualFile virtualFile = getVirtualFile(document);
if (virtualFile != null && isRelevant(virtualFile) && shouldNotifySmartPointers(virtualFile)) {
mySmartPointerManager.unfastenBelts(virtualFile, 0);
}
}
private static VirtualFile getVirtualFile(@NotNull Document document) {
@@ -42,7 +42,6 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.PsiTreeChangeEventImpl;
import com.intellij.psi.impl.smartPointers.SmartPointerManagerImpl;
import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.util.FileContentUtilCore;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NotNull;
@@ -365,7 +364,7 @@ public class PsiVFSListener extends VirtualFileAdapter {
}
}
((SmartPointerManagerImpl)SmartPointerManager.getInstance(myManager.getProject())).fastenBelts(vFile, 0, null);
((SmartPointerManagerImpl)SmartPointerManager.getInstance(myManager.getProject())).fastenBelts(vFile);
ApplicationManager.getApplication().runWriteAction(
new ExternalChangeAction() {
@Override
@@ -22,7 +22,6 @@ import com.intellij.injected.editor.VirtualFileWindow;
import com.intellij.lang.Language;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Ref;
@@ -32,8 +31,6 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.FreeThreadedFileViewProvider;
import com.intellij.psi.impl.source.tree.MarkersHolderFileViewProvider;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -42,8 +39,7 @@ import java.util.List;
/**
* @author cdr
*/
public class InjectedFileViewProvider extends SingleRootFileViewProvider implements FreeThreadedFileViewProvider,
MarkersHolderFileViewProvider {
public class InjectedFileViewProvider extends SingleRootFileViewProvider implements FreeThreadedFileViewProvider {
private Project myProject;
private final Object myLock = new Object();
private final DocumentWindowImpl myDocumentWindow;
@@ -205,16 +201,4 @@ public class InjectedFileViewProvider extends SingleRootFileViewProvider impleme
myPatchingLeaves = patchingLeaves;
}
@Override
@NotNull
public RangeMarker[] getCachedMarkers() {
List<RangeMarker> markers = new SmartList<RangeMarker>();
for (PsiLanguageInjectionHost.Shred shred : myDocumentWindow.getShreds()) {
RangeMarker marker = (RangeMarker)shred.getHostRangeMarker();
if (marker != null) {
markers.add(marker);
}
}
return markers.toArray(new RangeMarker[markers.size()]);
}
}