From 06c2cde8d09ea15c858fb5d51901bd1c6a122c2a Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 4 Sep 2013 13:46:00 +0400 Subject: [PATCH] removing of smart pointers fixed --- .../SmartPsiElementPointersTest.java | 44 +++++++++++++++++- .../SmartPointerManagerImpl.java | 46 +++++++++++++------ .../SmartPsiElementPointerImpl.java | 6 +++ 3 files changed, 80 insertions(+), 16 deletions(-) rename java/java-tests/testSrc/com/intellij/psi/{ => impl/smartPointers}/SmartPsiElementPointersTest.java (88%) diff --git a/java/java-tests/testSrc/com/intellij/psi/SmartPsiElementPointersTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java similarity index 88% rename from java/java-tests/testSrc/com/intellij/psi/SmartPsiElementPointersTest.java rename to java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java index b716b539768d..7d0aaa65f947 100644 --- a/java/java-tests/testSrc/com/intellij/psi/SmartPsiElementPointersTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.psi; +package com.intellij.psi.impl.smartPointers; import com.intellij.JavaTestUtil; import com.intellij.codeInsight.CodeInsightTestCase; +import com.intellij.ide.highlighter.JavaFileType; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.event.DocumentEvent; @@ -26,6 +27,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; import com.intellij.psi.impl.source.PsiFileImpl; import com.intellij.psi.impl.source.tree.FileElement; import com.intellij.psi.search.GlobalSearchScope; @@ -38,6 +40,7 @@ import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.FileContentUtil; import gnu.trove.THashSet; +import org.junit.Assert; import java.io.IOException; import java.util.Collections; @@ -374,4 +377,43 @@ public class SmartPsiElementPointersTest extends CodeInsightTestCase { assertFalse(SmartPointerManager.getInstance(myProject).pointToTheSameElement(pointer1, pointer2)); } + + public void testPointersRefCount() throws Exception { + PsiFile file = configureByText(JavaFileType.INSTANCE, "class X{}"); + PsiClass aClass = ((PsiClassOwner)file).getClasses()[0]; + SmartPointerManagerImpl smartPointerManager = (SmartPointerManagerImpl)SmartPointerManager.getInstance(myProject); + SmartPsiElementPointer pointer1 = smartPointerManager.createSmartPsiElementPointer(aClass); + SmartPsiElementPointer pointer2 = smartPointerManager.createSmartPsiElementPointer(aClass); + assertSame(pointer1, pointer2); + + assertNotNull(pointer1.getRange()); + + boolean removed2 = smartPointerManager.removePointer(pointer2); + assertFalse(removed2); + assertNotNull(pointer1.getRange()); + + boolean removed1 = smartPointerManager.removePointer(pointer1); + assertTrue(removed1); + assertNull(pointer1.getRange()); + } + + public void testPointersRefCountSaturated() throws Exception { + PsiFile file = configureByText(JavaFileType.INSTANCE, "class X{}"); + PsiClass aClass = ((PsiClassOwner)file).getClasses()[0]; + SmartPointerManagerImpl smartPointerManager = (SmartPointerManagerImpl)SmartPointerManager.getInstance(myProject); + SmartPsiElementPointerImpl pointer1 = (SmartPsiElementPointerImpl)smartPointerManager.createSmartPsiElementPointer(aClass); + for (int i=0; i<1000; i++) { + SmartPsiElementPointer pointer2 = smartPointerManager.createSmartPsiElementPointer(aClass); + assertSame(pointer1, pointer2); + } + + assertNotNull(pointer1.getRange()); + assertEquals(Byte.MAX_VALUE, pointer1.incrementAndGetReferenceCount(0)); + + for (int i=0; i<1100; i++) { + boolean removed1 = smartPointerManager.removePointer(pointer1); + assertFalse(removed1); + Assert.assertNotNull(pointer1.getRange()); + } + } } 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 e91e769752b9..7346f4256f62 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 @@ -120,19 +120,25 @@ public class SmartPointerManagerImpl extends SmartPointerManager { if (containingFile != null && !containingFile.isValid() || containingFile == null && !element.isValid()) { LOG.error("Invalid element:" + element); } - SmartPointerEx cachedPointer = getCachedPointer(element); - if (cachedPointer != null) { + SmartPointerEx pointer = getCachedPointer(element); + if (pointer != null) { containingFile = containingFile == null ? element.getContainingFile() : containingFile; if (containingFile != null && areBeltsFastened(containingFile)) { - cachedPointer.fastenBelt(0, null); + pointer.fastenBelt(0, null); + } + } + else { + pointer = new SmartPsiElementPointerImpl(myProject, element, containingFile); + initPointer(pointer, containingFile); + element.putUserData(CACHED_SMART_POINTER_KEY, new SoftReference(pointer)); + } + if (pointer instanceof SmartPsiElementPointerImpl) { + synchronized (lock) { + ((SmartPsiElementPointerImpl)pointer).incrementAndGetReferenceCount(1); } - return cachedPointer; } - - SmartPointerEx pointer = new SmartPsiElementPointerImpl(myProject, element, containingFile); - initPointer(pointer, containingFile); - element.putUserData(CACHED_SMART_POINTER_KEY, new SoftReference(pointer)); return pointer; + } private static SmartPointerEx getCachedPointer(@NotNull E element) { @@ -178,14 +184,24 @@ 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); + if (pointer instanceof SmartPsiElementPointerImpl) { + int refCount = ((SmartPsiElementPointerImpl)pointer).incrementAndGetReferenceCount(-1); + if (refCount == 0) { + PsiElement element = ((SmartPointerEx)pointer).getCachedElement(); + if (element != null) { + element.putUserData(CACHED_SMART_POINTER_KEY, null); + } + 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); + } + } } + return false; } private static List getPointers(@NotNull PsiFile containingFile) { diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java index be4e693f11cd..656635c803bc 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java @@ -39,6 +39,7 @@ class SmartPsiElementPointerImpl implements SmartPointerEx private Reference myElement; private final SmartPointerElementInfo myElementInfo; private final Class myElementClass; + private byte myReferenceCount; public SmartPsiElementPointerImpl(@NotNull Project project, @NotNull E element, @Nullable PsiFile containingFile) { this(element, createElementInfo(project, element, containingFile), element.getClass()); @@ -193,4 +194,9 @@ class SmartPsiElementPointerImpl implements SmartPointerEx } return Comparing.equal(pointer1.getElement(), pointer2.getElement()); } + + int incrementAndGetReferenceCount(int delta) { + if (myReferenceCount == Byte.MAX_VALUE) return Byte.MAX_VALUE; // saturated + return myReferenceCount += delta; + } }