private void switchToTree() {
PsiElement element = restoreElement();
- if (element != null) {
- PsiElement anchor = AnchorElementInfoFactory.getAnchor(element);
- if (anchor == null) anchor = element;
- myType = AnchorTypeInfo.obtainInfo(anchor, myType.getFileLanguage());
- setRange(anchor.getTextRange());
- MarkerCache cache = myManager.getMarkerCache(getVirtualFile());
- if (cache != null) {
- cache.rangeChanged();
- }
- myStubElementTypeAndId = pack(-1, null);
+ SmartPointerTracker tracker = myManager.getTracker(getVirtualFile());
+ if (element != null && tracker != null) {
+ tracker.switchStubToAst(this, element);
}
}
+ void switchToTreeRange(@NotNull PsiElement element) {
+ PsiElement anchor = AnchorElementInfoFactory.getAnchor(element);
+ if (anchor == null) anchor = element;
+ myType = AnchorTypeInfo.obtainInfo(anchor, myType.getFileLanguage());
+ setRange(anchor.getTextRange());
+ myStubElementTypeAndId = pack(-1, null);
+ }
+
@Override
public Segment getRange() {
if (getStubId() != -1) {
}
};
private final SmartPointerTracker myPointers;
- private volatile UpdatedRanges myUpdatedRanges;
+ private UpdatedRanges myUpdatedRanges;
MarkerCache(SmartPointerTracker pointers) {
myPointers = pointers;
UpdatedRanges cache = myUpdatedRanges;
if (cache != null && cache.myEventCount == eventCount) return cache;
- //noinspection SynchronizeOnThis
- synchronized (this) {
- cache = myUpdatedRanges;
- if (cache != null && cache.myEventCount == eventCount) return cache;
-
- UpdatedRanges answer;
- if (cache != null && cache.myEventCount < eventCount) {
- // apply only the new events
- answer = applyEvents(events.subList(cache.myEventCount, eventCount), cache);
- }
- else {
- List<SelfElementInfo> infos = myPointers.getSortedInfos();
- ManualRangeMarker[] markers = createMarkers(infos);
- answer = applyEvents(events, new UpdatedRanges(0, frozen, infos, markers));
- }
-
- myUpdatedRanges = answer;
- return answer;
+ UpdatedRanges answer;
+ if (cache != null && cache.myEventCount < eventCount) {
+ // apply only the new events
+ answer = applyEvents(events.subList(cache.myEventCount, eventCount), cache);
}
+ else {
+ List<SelfElementInfo> infos = myPointers.getSortedInfos();
+ ManualRangeMarker[] markers = createMarkers(infos);
+ answer = applyEvents(events, new UpdatedRanges(0, frozen, infos, markers));
+ }
+
+ myUpdatedRanges = answer;
+ return answer;
}
@NotNull
return new UpdatedRanges(struct.myEventCount + events.size(), frozen, struct.mySortedInfos, resultMarkers);
}
- synchronized void updateMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
+ boolean updateMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
UpdatedRanges updated = getUpdatedMarkers(frozen, events);
boolean sorted = true;
}
}
- if (!sorted) {
- myPointers.markUnsorted();
- }
-
myUpdatedRanges = null;
+ return sorted;
}
@Nullable
void rangeChanged() {
myUpdatedRanges = null;
- myPointers.markUnsorted();
}
private static class UpdatedRanges {
PsiDocumentManagerBase documentManager = myManager.getPsiDocumentManager();
List<DocumentEvent> events = documentManager.getEventsSinceCommit(document);
if (!events.isEmpty()) {
- MarkerCache markerCache = myManager.getMarkerCache(getVirtualFile());
- if (markerCache != null) {
- return markerCache.getUpdatedRange(this, (FrozenDocument)documentManager.getLastCommittedDocument(document), events);
+ SmartPointerTracker tracker = myManager.getTracker(getVirtualFile());
+ if (tracker != null) {
+ return tracker.getUpdatedRange(this, (FrozenDocument)documentManager.getLastCommittedDocument(document), events);
}
}
}
import com.intellij.openapi.editor.impl.FrozenDocument;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.*;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.ProperTextRange;
+import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiDocumentManagerBase;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.reference.SoftReference;
-import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
}
public void fastenBelts(@NotNull VirtualFile file) {
- SmartPointerTracker.processQueue();
- SmartPointerTracker pointers = getPointers(file);
- if (pointers != null) {
- pointers.processAlivePointers(new Processor<SmartPsiElementPointerImpl>() {
- @Override
- public boolean process(SmartPsiElementPointerImpl pointer) {
- pointer.getElementInfo().fastenBelt();
- return true;
- }
- });
- }
+ SmartPointerTracker pointers = getTracker(file);
+ if (pointers != null) pointers.fastenBelts();
}
private static final Key<Reference<SmartPsiElementPointerImpl>> CACHED_SMART_POINTER_KEY = Key.create("CACHED_SMART_POINTER_KEY");
SmartPointerTracker.PointerReference reference = new SmartPointerTracker.PointerReference(pointer, containingFile, POINTERS_KEY);
while (true) {
- SmartPointerTracker pointers = getPointers(containingFile);
+ SmartPointerTracker pointers = getTracker(containingFile);
if (pointers == null) {
pointers = containingFile.putUserDataIfAbsent(POINTERS_KEY, new SmartPointerTracker());
}
- if (pointers.addReference(reference)) {
- if (((SelfElementInfo)info).hasRange()) {
- pointers.markerCache.rangeChanged();
- }
+ if (pointers.addReference(reference, pointer)) {
break;
}
}
if (containingFile == null) return;
VirtualFile vFile = containingFile.getViewProvider().getVirtualFile();
- SmartPointerTracker pointers = getPointers(vFile);
+ SmartPointerTracker pointers = getTracker(vFile);
SmartPointerTracker.PointerReference reference = ((SmartPsiElementPointerImpl)pointer).pointerReference;
if (pointers != null && reference != null) {
pointers.removeReference(reference);
}
@Nullable
- private SmartPointerTracker getPointers(@NotNull VirtualFile containingFile) {
+ SmartPointerTracker getTracker(@NotNull VirtualFile containingFile) {
return containingFile.getUserData(POINTERS_KEY);
}
- @Nullable
- MarkerCache getMarkerCache(@NotNull VirtualFile file) {
- SmartPointerTracker pointers = getPointers(file);
- return pointers == null ? null : pointers.markerCache;
- }
-
@TestOnly
public int getPointersNumber(@NotNull PsiFile containingFile) {
VirtualFile file = containingFile.getViewProvider().getVirtualFile();
- SmartPointerTracker pointers = getPointers(file);
+ SmartPointerTracker pointers = getTracker(file);
return pointers == null ? 0 : pointers.getSize();
}
public void updatePointers(Document document, FrozenDocument frozen, List<DocumentEvent> events) {
VirtualFile file = FileDocumentManager.getInstance().getFile(document);
- SmartPointerTracker list = file == null ? null : getPointers(file);
- if (list == null) return;
-
- list.markerCache.updateMarkers(frozen, events);
+ SmartPointerTracker list = file == null ? null : getTracker(file);
+ if (list != null) list.updateMarkers(frozen, events);
}
public void updatePointerTargetsAfterReparse(@NotNull VirtualFile file) {
- SmartPointerTracker list = getPointers(file);
- if (list == null) return;
-
- list.processAlivePointers(new Processor<SmartPsiElementPointerImpl>() {
- @Override
- public boolean process(SmartPsiElementPointerImpl pointer) {
- if (!(pointer instanceof SmartPsiFileRangePointerImpl)) {
- updatePointerTarget(pointer, pointer.getPsiRange());
- }
- return true;
- }
- });
+ SmartPointerTracker list = getTracker(file);
+ if (list != null) list.updatePointerTargetsAfterReparse();
}
- // after reparse and its complex tree diff, the element might have "moved" to other range
- // but if an element of the same type can still be found at the old range, let's point there
- private static <E extends PsiElement> void updatePointerTarget(@NotNull SmartPsiElementPointerImpl<E> pointer, @Nullable Segment pointerRange) {
- E cachedElement = pointer.getCachedElement();
- if (cachedElement == null || cachedElement.isValid() && pointerRange != null && pointerRange.equals(cachedElement.getTextRange())) {
- return;
- }
-
- pointer.cacheElement(pointer.doRestoreElement());
- }
-
-
Project getProject() {
return myProject;
}
package com.intellij.psi.impl.smartPointers;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.event.DocumentEvent;
+import com.intellij.openapi.editor.impl.FrozenDocument;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.LowMemoryWatcher;
+import com.intellij.openapi.util.Segment;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
import com.intellij.util.CommonProcessors;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.lang.ref.ReferenceQueue;
private int nextAvailableIndex;
private int size;
private PointerReference[] references = new PointerReference[10];
- final MarkerCache markerCache = new MarkerCache(this);
+ private final MarkerCache markerCache = new MarkerCache(this);
private boolean mySorted;
static {
}, ApplicationManager.getApplication());
}
- synchronized boolean addReference(@NotNull PointerReference reference) {
+ synchronized boolean addReference(@NotNull PointerReference reference, @NotNull SmartPsiElementPointerImpl pointer) {
if (!isActual(reference.file, reference.key)) {
// this pointer list has been removed by another thread; clients should get/create an up-to-date list and try adding to it
return false;
storePointerReference(references, nextAvailableIndex++, reference);
size++;
mySorted = false;
+ if (((SelfElementInfo)pointer.getElementInfo()).hasRange()) {
+ markerCache.rangeChanged();
+ }
return true;
}
}
}
- synchronized void processAlivePointers(@NotNull Processor<SmartPsiElementPointerImpl> processor) {
+ private void processAlivePointers(@NotNull Processor<SmartPsiElementPointerImpl> processor) {
for (int i = 0; i < nextAvailableIndex; i++) {
PointerReference ref = references[i];
if (ref == null) continue;
}
}
+ synchronized void updateMarkers(FrozenDocument frozen, List<DocumentEvent> events) {
+ boolean stillSorted = markerCache.updateMarkers(frozen, events);
+ if (!stillSorted) {
+ mySorted = false;
+ }
+ }
+
+ @Nullable
+ synchronized Segment getUpdatedRange(SelfElementInfo info, FrozenDocument document, List<DocumentEvent> events) {
+ return markerCache.getUpdatedRange(info, document, events);
+ }
+
+ synchronized void switchStubToAst(AnchorElementInfo info, PsiElement element) {
+ info.switchToTreeRange(element);
+ markerCache.rangeChanged();
+ mySorted = false;
+ }
+
+ synchronized void fastenBelts() {
+ processQueue();
+ processAlivePointers(new Processor<SmartPsiElementPointerImpl>() {
+ @Override
+ public boolean process(SmartPsiElementPointerImpl pointer) {
+ pointer.getElementInfo().fastenBelt();
+ return true;
+ }
+ });
+ }
+
+ synchronized void updatePointerTargetsAfterReparse() {
+ processAlivePointers(new Processor<SmartPsiElementPointerImpl>() {
+ @Override
+ public boolean process(SmartPsiElementPointerImpl pointer) {
+ if (!(pointer instanceof SmartPsiFileRangePointerImpl)) {
+ updatePointerTarget(pointer, pointer.getPsiRange());
+ }
+ return true;
+ }
+ });
+ }
+
+ // after reparse and its complex tree diff, the element might have "moved" to other range
+ // but if an element of the same type can still be found at the old range, let's point there
+ private static <E extends PsiElement> void updatePointerTarget(@NotNull SmartPsiElementPointerImpl<E> pointer, @Nullable Segment pointerRange) {
+ E cachedElement = pointer.getCachedElement();
+ if (cachedElement == null || cachedElement.isValid() && pointerRange != null && pointerRange.equals(cachedElement.getTextRange())) {
+ return;
+ }
+
+ pointer.cacheElement(pointer.doRestoreElement());
+ }
+
private static void storePointerReference(PointerReference[] references, int index, PointerReference ref) {
references[index] = ref;
ref.index = index;
return size;
}
- synchronized void markUnsorted() {
- mySorted = false;
- }
-
static class PointerReference extends WeakReference<SmartPsiElementPointerImpl> {
@NotNull private final VirtualFile file;
@NotNull private final Key<SmartPointerTracker> key;