smart pointers on import lists should survive adding new imports (IDEA-161409)

This commit is contained in:
peter
2017-01-27 17:54:56 +01:00
parent beeb5920b1
commit 2204579e00
7 changed files with 55 additions and 20 deletions
@@ -30,16 +30,14 @@ public class JavaAnchorProvider extends SmartPointerAnchorProvider {
return null;
}
if (element instanceof PsiClass) {
if (element instanceof PsiAnonymousClass) {
return ((PsiAnonymousClass)element).getBaseClassReference().getReferenceNameElement();
} else {
return ((PsiClass)element).getNameIdentifier();
}
} else if (element instanceof PsiMethod) {
return ((PsiMethod)element).getNameIdentifier();
} else if (element instanceof PsiVariable) {
return ((PsiVariable)element).getNameIdentifier();
if (element instanceof PsiAnonymousClass) {
return ((PsiAnonymousClass)element).getBaseClassReference().getReferenceNameElement();
}
if (element instanceof PsiClass || element instanceof PsiMethod || element instanceof PsiVariable) {
return ((PsiNameIdentifierOwner)element).getNameIdentifier();
}
if (element instanceof PsiImportList) {
return element.getContainingFile();
}
return null;
}
@@ -55,6 +53,9 @@ public class JavaAnchorProvider extends SmartPointerAnchorProvider {
return parent;
}
if (anchor instanceof PsiJavaFile) {
return ((PsiJavaFile)anchor).getImportList();
}
return null;
}
}
@@ -996,7 +996,7 @@ class Foo {
assertTopLevelFoldRegionsState "[FoldRegion +(49:92), placeholder='otherMethod() → { ', FoldRegion +(113:123), placeholder=' }']"
}
public void "disabled - test imports remain collapsed when new item is added at the end"() {
public void "test imports remain collapsed when new item is added at the end"() {
boolean oldValue = CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY
CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = true
DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(true); // tests disable this by default
@@ -931,4 +931,26 @@ public class SmartPsiElementPointersTest extends CodeInsightTestCase {
assertFalse(createPointer(clazz).hashCode() == createPointer(clazz.getMethods()[0]).hashCode());
}
public void testImportListPointerSurvivesImportAddition() throws Exception {
PsiJavaFile file = (PsiJavaFile)createFile("a.java", "import foo.Bar;\nclass Foo {}");
SmartPointerEx<PsiImportList> pointer = createPointer(file.getImportList());
Document document = file.getViewProvider().getDocument();
WriteCommandAction.runWriteCommandAction(myProject, () -> {
document.insertString(document.getText().indexOf("class"), "import foo.Goo;\n");
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
});
assertEquals(file.getImportList(), pointer.getElement());
assertSize(2, file.getImportList().getImportStatements());
WriteCommandAction.runWriteCommandAction(myProject, () -> {
document.insertString(0, " ");
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
document.deleteString(0, document.getText().indexOf("\nimport"));
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
});
assertEquals(file.getImportList(), pointer.getElement());
assertSize(1, file.getImportList().getImportStatements());
}
}
@@ -36,7 +36,6 @@ class AnchorElementInfo extends SelfElementInfo {
AnchorElementInfo(@NotNull PsiElement anchor, @NotNull PsiFile containingFile, Identikit.ByAnchor identikit) {
super(containingFile.getProject(), ProperTextRange.create(anchor.getTextRange()), identikit, containingFile, false);
assert !(anchor instanceof PsiFile) : "FileElementInfo must be used for file: "+anchor;
myStubElementTypeAndId = pack(-1, null);
}
// will restore by stub index until file tree get loaded
@@ -22,6 +22,7 @@ import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.IFileElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.containers.WeakInterner;
@@ -41,6 +42,8 @@ public abstract class Identikit {
@NotNull
public abstract Language getFileLanguage();
public abstract boolean isForPsiFile();
public static ByType fromPsi(@NotNull PsiElement element, @NotNull Language fileLanguage) {
return fromTypes(element.getClass(), PsiUtilCore.getElementType(element), fileLanguage);
}
@@ -156,6 +159,11 @@ public abstract class Identikit {
return myFileLanguage;
}
@Override
public boolean isForPsiFile() {
return myElementType instanceof IFileElementType;
}
private boolean isAcceptable(@NotNull PsiElement element) {
return myElementClass == element.getClass() && myElementType == PsiUtilCore.getElementType(element);
}
@@ -204,6 +212,11 @@ public abstract class Identikit {
public Language getFileLanguage() {
return myAnchorInfo.getFileLanguage();
}
@Override
public boolean isForPsiFile() {
return myAnchorInfo.isForPsiFile();
}
}
}
@@ -45,7 +45,7 @@ class MarkerCache {
o2 = info2.getPsiEndOffset();
if (o1 != o2) return o1 > o2 ? 1 : -1;
return (info1.isForInjected() ? 1 : 0) - (info2.isForInjected() ? 1 : 0);
return (info1.isGreedy() ? 1 : 0) - (info2.isGreedy() ? 1 : 0);
}
};
private final SmartPointerTracker myPointers;
@@ -83,13 +83,13 @@ class MarkerCache {
int i = 0;
while (i < markers.length) {
SelfElementInfo info = infos.get(i);
boolean forInjected = info.isForInjected();
boolean greedy = info.isGreedy();
int start = info.getPsiStartOffset();
int end = info.getPsiEndOffset();
markers[i] = new ManualRangeMarker(start, end, forInjected, forInjected, !forInjected, null);
markers[i] = new ManualRangeMarker(start, end, greedy, greedy, !greedy, null);
i++;
while (i < markers.length && rangeEquals(infos.get(i), start, end, forInjected)) {
while (i < markers.length && rangeEquals(infos.get(i), start, end, greedy)) {
markers[i] = markers[i - 1];
i++;
}
@@ -97,8 +97,8 @@ class MarkerCache {
return markers;
}
private static boolean rangeEquals(SelfElementInfo info, int start, int end, boolean injected) {
return start == info.getPsiStartOffset() && end == info.getPsiEndOffset() && injected == info.isForInjected();
private static boolean rangeEquals(SelfElementInfo info, int start, int end, boolean greedy) {
return start == info.getPsiStartOffset() && end == info.getPsiEndOffset() && greedy == info.isGreedy();
}
private static UpdatedRanges applyEvents(@NotNull List<DocumentEvent> events, final UpdatedRanges struct) {
@@ -89,8 +89,8 @@ public class SelfElementInfo extends SmartPointerElementInfo {
return myEndOffset;
}
boolean isForInjected() {
return myForInjected;
boolean isGreedy() {
return myForInjected || myIdentikit.isForPsiFile();
}
@Override