diff --git a/platform/core-api/src/com/intellij/psi/SmartPointerManager.java b/platform/core-api/src/com/intellij/psi/SmartPointerManager.java index f6d6b87866b2..6c918ada8fde 100644 --- a/platform/core-api/src/com/intellij/psi/SmartPointerManager.java +++ b/platform/core-api/src/com/intellij/psi/SmartPointerManager.java @@ -60,4 +60,5 @@ public abstract class SmartPointerManager { * @return true if both pointers point to the same PSI element. */ public abstract boolean pointToTheSameElement(@NotNull SmartPsiElementPointer pointer1, @NotNull SmartPsiElementPointer pointer2); + public abstract boolean removePointer(@NotNull SmartPsiElementPointer pointer); } diff --git a/platform/core-api/src/com/intellij/psi/impl/ElementBase.java b/platform/core-api/src/com/intellij/psi/impl/ElementBase.java index 0492a3ac594d..c0f90eaccbb2 100644 --- a/platform/core-api/src/com/intellij/psi/impl/ElementBase.java +++ b/platform/core-api/src/com/intellij/psi/impl/ElementBase.java @@ -205,8 +205,9 @@ public abstract class ElementBase extends UserDataHolderBase implements Iconable @Nullable public PsiElement getElement() { if (myPointer.getProject().isDisposed()) return null; - - return myPointer.getElement(); + PsiElement element = myPointer.getElement(); + SmartPointerManager.getInstance(myPointer.getProject()).removePointer(myPointer); + return element; } @Iconable.IconFlags diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/ClsElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/ClsElementInfo.java index 296b2ace352c..980854022dc9 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/ClsElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/ClsElementInfo.java @@ -84,4 +84,9 @@ public class ClsElementInfo implements SmartPointerElementInfo { public Project getProject() { return myStubIndexReference.getProject(); } + + @Override + public void cleanup() { + + } } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java index 9650b4e2c874..a9f5bb8d6e07 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java @@ -94,4 +94,9 @@ class FileElementInfo implements SmartPointerElementInfo { public Project getProject() { return myProject; } + + @Override + public void cleanup() { + + } } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/HardElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/HardElementInfo.java index 99634f968822..fb45bffa6efd 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/HardElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/HardElementInfo.java @@ -80,4 +80,9 @@ class HardElementInfo implements SmartPointerElementInfo { public Project getProject() { return myProject; } + + @Override + public void cleanup() { + + } } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/InjectedSelfElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/InjectedSelfElementInfo.java index e548ade34f16..ccc543e5fc16 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/InjectedSelfElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/InjectedSelfElementInfo.java @@ -116,4 +116,10 @@ class InjectedSelfElementInfo extends SelfElementInfo { SmartPointerElementInfo oElementInfo = ((SmartPsiElementPointerImpl)((InjectedSelfElementInfo)other).myInjectedFileRangeInHostFile).getElementInfo(); return myElementInfo.pointsToTheSameElementAs(oElementInfo); } + + @Override + public void cleanup() { + super.cleanup(); + SmartPointerManager.getInstance(getProject()).removePointer(myInjectedFileRangeInHostFile); + } } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java index dfd7d3a899b4..784b0a345cc2 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java @@ -205,6 +205,15 @@ public class SelfElementInfo implements SmartPointerElementInfo { return ref == null ? null : ref.get(); } + @Override + public void cleanup() { + RangeMarker marker = getMarker(); + if (marker != null) marker.dispose(); + unfastenBelt(0); + setMarker(null); + mySyncMarkerIsValid = false; + } + private void setMarker(RangeMarker marker) { myMarkerRef = marker == null ? null : new SoftReference(marker); } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerElementInfo.java index 502096ed5e52..16c3ed55832a 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerElementInfo.java @@ -44,4 +44,6 @@ interface SmartPointerElementInfo { @Nullable Segment getRange(); @NotNull Project getProject(); + + void cleanup(); } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java index 1a7923ee127d..e91e769752b9 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java @@ -106,7 +106,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager { } } - private static final Key> CACHED_SMART_POINTER_KEY = Key.create("CACHED_SMART_POINTER_KEY"); + private static final Key> CACHED_SMART_POINTER_KEY = Key.create("CACHED_SMART_POINTER_KEY"); @Override @NotNull public SmartPsiElementPointer createSmartPsiElementPointer(@NotNull E element) { @@ -120,22 +120,26 @@ public class SmartPointerManagerImpl extends SmartPointerManager { if (containingFile != null && !containingFile.isValid() || containingFile == null && !element.isValid()) { LOG.error("Invalid element:" + element); } - SmartPsiElementPointer cachedPointer = getCachedPointer(element); + SmartPointerEx cachedPointer = getCachedPointer(element); if (cachedPointer != null) { + containingFile = containingFile == null ? element.getContainingFile() : containingFile; + if (containingFile != null && areBeltsFastened(containingFile)) { + cachedPointer.fastenBelt(0, null); + } return cachedPointer; } SmartPointerEx pointer = new SmartPsiElementPointerImpl(myProject, element, containingFile); initPointer(pointer, containingFile); - element.putUserData(CACHED_SMART_POINTER_KEY, new SoftReference(pointer)); + element.putUserData(CACHED_SMART_POINTER_KEY, new SoftReference(pointer)); return pointer; } - private static SmartPsiElementPointer getCachedPointer(@NotNull E element) { - Reference data = element.getUserData(CACHED_SMART_POINTER_KEY); - SmartPsiElementPointer cachedPointer = data == null ? null : data.get(); - if (cachedPointer instanceof SmartPointerEx) { - PsiElement cachedElement = ((SmartPointerEx)cachedPointer).getCachedElement(); + private static SmartPointerEx getCachedPointer(@NotNull E element) { + Reference data = element.getUserData(CACHED_SMART_POINTER_KEY); + SmartPointerEx cachedPointer = data == null ? null : data.get(); + if (cachedPointer != null) { + PsiElement cachedElement = cachedPointer.getCachedElement(); if (cachedElement != null && cachedElement != element) { return null; } @@ -160,7 +164,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager { synchronized (lock) { List pointers = getPointers(containingFile); if (pointers == null) { - pointers = new UnsafeWeakList(); // we synchronise access anyway by containingFile + pointers = new UnsafeWeakList(); // we synchronise access anyway containingFile.putUserData(SMART_POINTERS_IN_PSI_FILE_KEY, pointers); } pointers.add(pointer); @@ -171,14 +175,29 @@ public class SmartPointerManagerImpl extends SmartPointerManager { } } + @Override + public boolean removePointer(@NotNull SmartPsiElementPointer pointer) { + synchronized (lock) { + PsiFile containingFile = pointer.getContainingFile(); + if (containingFile == null) return false; + List pointers = getPointers(containingFile); + if (pointers == null) return false; + SmartPointerElementInfo info = ((SmartPsiElementPointerImpl)pointer).getElementInfo(); + info.cleanup(); + return pointers.remove(pointer); + } + } + private static List getPointers(@NotNull PsiFile containingFile) { return containingFile.getUserData(SMART_POINTERS_IN_PSI_FILE_KEY); } @TestOnly public int getPointersNumber(@NotNull PsiFile containingFile) { - List pointers = getPointers(containingFile); - return pointers == null ? 0 : pointers.size(); + synchronized (lock) { + List pointers = getPointers(containingFile); + return pointers == null ? 0 : pointers.size(); + } } private static boolean areBeltsFastened(@NotNull PsiFile file) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java index 2f6edc7dd8dc..134e18657638 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java @@ -98,9 +98,8 @@ public class CodeStyleManagerImpl extends CodeStyleManager { final PsiElement formatted = SourceTreeToPsiMap.treeElementToPsi(new CodeFormatterFacade(getSettings()).processElement(treeElement)); if (!canChangeWhiteSpacesOnly) { return postProcessElement(formatted); - } else { - return formatted; } + return formatted; } private PsiElement postProcessElement(@NotNull final PsiElement formatted) { @@ -234,6 +233,8 @@ public class CodeStyleManagerImpl extends CodeStyleManager { postProcessText(file, new TextRange(info.fromStart ? 0 : startElement.getTextRange().getStartOffset(), info.toEnd ? file.getTextLength() : endElement.getTextRange().getEndOffset())); } + if (info.startPointer != null) smartPointerManager.removePointer(info.startPointer); + if (info.endPointer != null) smartPointerManager.removePointer(info.endPointer); } if (editor == null) { @@ -794,11 +795,10 @@ public class CodeStyleManagerImpl extends CodeStyleManager { } private static class RangeFormatInfo{ - - public final SmartPsiElementPointer startPointer; - public final SmartPsiElementPointer endPointer; - public final boolean fromStart; - public final boolean toEnd; + private final SmartPsiElementPointer startPointer; + private final SmartPsiElementPointer endPointer; + private final boolean fromStart; + private final boolean toEnd; RangeFormatInfo(@Nullable SmartPsiElementPointer startPointer, @Nullable SmartPsiElementPointer endPointer, diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java index 1f9d74965957..dd90ecc66266 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java @@ -41,6 +41,8 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.SmartPointerManager; +import com.intellij.psi.SmartPsiElementPointer; import com.intellij.ui.*; import com.intellij.ui.components.JBTabbedPane; import com.intellij.ui.content.Content; @@ -1030,6 +1032,19 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra myModelTracker.removeListener(this); myUpdateAlarm.cancelAllRequests(); } + disposeSmartPointers(); + } + + private void disposeSmartPointers() { + SmartPointerManager pointerManager = SmartPointerManager.getInstance(getProject()); + for (Usage usage : myUsageNodes.keySet()) { + if (usage instanceof UsageInfo2UsageAdapter) { + SmartPsiElementPointer pointer = ((UsageInfo2UsageAdapter)usage).getUsageInfo().getSmartPointer(); + if (pointer != null) { + pointerManager.removePointer(pointer); + } + } + } } @Override