removing of smart pointers fixed

This commit is contained in:
Alexey Kudravtsev
2013-09-04 14:17:54 +04:00
parent 2a8f1fb0e5
commit 06c2cde8d0
3 changed files with 80 additions and 16 deletions
@@ -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<PsiClass> 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());
}
}
}
@@ -120,19 +120,25 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
if (containingFile != null && !containingFile.isValid() || containingFile == null && !element.isValid()) {
LOG.error("Invalid element:" + element);
}
SmartPointerEx<E> cachedPointer = getCachedPointer(element);
if (cachedPointer != null) {
SmartPointerEx<E> 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<E>(myProject, element, containingFile);
initPointer(pointer, containingFile);
element.putUserData(CACHED_SMART_POINTER_KEY, new SoftReference<SmartPointerEx>(pointer));
}
if (pointer instanceof SmartPsiElementPointerImpl) {
synchronized (lock) {
((SmartPsiElementPointerImpl)pointer).incrementAndGetReferenceCount(1);
}
return cachedPointer;
}
SmartPointerEx<E> pointer = new SmartPsiElementPointerImpl<E>(myProject, element, containingFile);
initPointer(pointer, containingFile);
element.putUserData(CACHED_SMART_POINTER_KEY, new SoftReference<SmartPointerEx>(pointer));
return pointer;
}
private static <E extends PsiElement> SmartPointerEx<E> 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<SmartPointerEx> 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<SmartPointerEx> pointers = getPointers(containingFile);
if (pointers == null) return false;
SmartPointerElementInfo info = ((SmartPsiElementPointerImpl)pointer).getElementInfo();
info.cleanup();
return pointers.remove(pointer);
}
}
}
return false;
}
private static List<SmartPointerEx> getPointers(@NotNull PsiFile containingFile) {
@@ -39,6 +39,7 @@ class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx
private Reference<E> myElement;
private final SmartPointerElementInfo myElementInfo;
private final Class<? extends PsiElement> 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<E extends PsiElement> 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;
}
}