smartPointer.get(Psi)Range should be not-null for valid pointers; fix related data race (EA-74922 - assert: TextRange.<init>)

This commit is contained in:
peter
2015-10-29 11:27:40 +01:00
parent c56a594100
commit 5ce2ec9cb2
3 changed files with 48 additions and 19 deletions
@@ -877,4 +877,23 @@ public class SmartPsiElementPointersTest extends CodeInsightTestCase {
private <T extends PsiElement> SmartPointerEx<T> createPointer(T element) {
return (SmartPointerEx<T>)getPointerManager().createSmartPsiElementPointer(element);
}
public void testAnchorInfoHasRange() throws Exception {
PsiJavaFile file = (PsiJavaFile)createFile("a.java", "class C1{}");
assertNotNull(((PsiFileImpl) file).getStubTree());
PsiClass psiClass = file.getClasses()[0];
Segment range = createPointer(psiClass).getRange();
assertNotNull(range);
assertEquals(psiClass.getNameIdentifier().getTextRange(), TextRange.create(range));
file = (PsiJavaFile)createFile("b.java", "class C2{}");
assertNotNull(((PsiFileImpl) file).getStubTree());
psiClass = file.getClasses()[0];
range = createPointer(psiClass).getPsiRange();
assertNotNull(range);
assertEquals(psiClass.getNameIdentifier().getTextRange(), TextRange.create(range));
}
}
@@ -16,9 +16,9 @@
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.util.*;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.openapi.util.Segment;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiAnchor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -102,16 +102,17 @@ class AnchorElementInfo extends SelfElementInfo {
@Override
public boolean pointsToTheSameElementAs(@NotNull final SmartPointerElementInfo other) {
if (other instanceof AnchorElementInfo) {
AnchorElementInfo otherAnchor = (AnchorElementInfo)other;
if ((getStubId() == -1) != (otherAnchor.getStubId() == -1)) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return Comparing.equal(restoreElement(), other.restoreElement());
}
});
if (!getVirtualFile().equals(other.getVirtualFile())) return false;
long packed1 = myStubElementTypeAndId;
long packed2 = ((AnchorElementInfo)other).myStubElementTypeAndId;
if (packed1 != -1 && packed2 != -1) {
return packed1 == packed2;
}
if (packed1 != -1 || packed2 != -1) {
return areRestoredElementsEqual(other);
}
if (myStubElementTypeAndId != otherAnchor.myStubElementTypeAndId) return false;
}
return super.pointsToTheSameElementAs(other);
}
@@ -126,9 +127,7 @@ class AnchorElementInfo extends SelfElementInfo {
private void switchToTree() {
PsiElement element = restoreElement();
Document document = getDocumentToSynchronize();
if (element != null && document != null) {
// switch to tree
if (element != null) {
PsiElement anchor = AnchorElementInfoFactory.getAnchor(element);
if (anchor == null) anchor = element;
myType = AnchorTypeInfo.obtainInfo(anchor, myType.getFileLanguage());
@@ -146,4 +145,12 @@ class AnchorElementInfo extends SelfElementInfo {
return super.getRange();
}
@Nullable
@Override
public ProperTextRange getPsiRange() {
if (getStubId() != -1) {
switchToTree();
}
return super.getPsiRange();
}
}
@@ -232,16 +232,19 @@ public class SelfElementInfo extends SmartPointerElementInfo {
public boolean pointsToTheSameElementAs(@NotNull final SmartPointerElementInfo other) {
if (other instanceof SelfElementInfo) {
SelfElementInfo otherInfo = (SelfElementInfo)other;
if (!getVirtualFile().equals(other.getVirtualFile()) || myType != otherInfo.myType) return false;
Segment range1 = getPsiRange();
Segment range2 = otherInfo.getPsiRange();
return Comparing.equal(getVirtualFile(), otherInfo.getVirtualFile())
&& myType == otherInfo.myType
&& range1 != null
&& range2 != null
return range1 != null && range2 != null
&& range1.getStartOffset() == range2.getStartOffset()
&& range1.getEndOffset() == range2.getEndOffset()
;
}
return areRestoredElementsEqual(other);
}
protected boolean areRestoredElementsEqual(@NotNull final SmartPointerElementInfo other) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {