mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
make smart pointers occupy less memory:
create ManualRangeMarker-s (now immutable) only for non-committed documents store only PSI ranges in the pointers
This commit is contained in:
@@ -23,27 +23,23 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A range marker that has to be manually updated with {@link #getUpdatedRange(DocumentEvent)} and {@link #applyState(ManualRangeMarker)}.
|
||||
* A range marker that has to be manually updated with {@link #getUpdatedRange(DocumentEvent)}.
|
||||
* Can hold PSI-based range and be updated when the document is committed.
|
||||
*/
|
||||
public class ManualRangeMarker {
|
||||
private static int ourCount = 0;
|
||||
|
||||
private ProperTextRange myRange;
|
||||
private boolean myValid = true;
|
||||
private final ProperTextRange myRange;
|
||||
private final boolean myGreedyLeft;
|
||||
private final boolean myGreedyRight;
|
||||
@SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") private final int myHash = ourCount++;
|
||||
private PersistentRangeMarker.LinesCols myLinesCols;
|
||||
private final PersistentRangeMarker.LinesCols myLinesCols;
|
||||
|
||||
public ManualRangeMarker(@NotNull FrozenDocument document, @NotNull ProperTextRange range, boolean greedyLeft, boolean greedyRight, boolean surviveOnExternalChange) {
|
||||
this(range, greedyLeft, greedyRight, surviveOnExternalChange ? PersistentRangeMarker.storeLinesAndCols(range, document) : null);
|
||||
}
|
||||
|
||||
private ManualRangeMarker(ProperTextRange range,
|
||||
boolean greedyLeft,
|
||||
boolean greedyRight,
|
||||
PersistentRangeMarker.LinesCols linesCols) {
|
||||
private ManualRangeMarker(@NotNull ProperTextRange range,
|
||||
boolean greedyLeft,
|
||||
boolean greedyRight,
|
||||
@Nullable PersistentRangeMarker.LinesCols linesCols) {
|
||||
myRange = range;
|
||||
myGreedyLeft = greedyLeft;
|
||||
myGreedyRight = greedyRight;
|
||||
@@ -52,67 +48,32 @@ public class ManualRangeMarker {
|
||||
|
||||
@Nullable
|
||||
public ManualRangeMarker getUpdatedRange(@NotNull DocumentEvent event) {
|
||||
Pair<ProperTextRange, PersistentRangeMarker.LinesCols> pair = getUpdatedState(event);
|
||||
return pair == null ? null : new ManualRangeMarker(pair.first, myGreedyLeft, myGreedyRight, pair.second);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<ProperTextRange, PersistentRangeMarker.LinesCols> getUpdatedState(@NotNull DocumentEvent event) {
|
||||
if (event instanceof RetargetRangeMarkers) {
|
||||
int start = ((RetargetRangeMarkers)event).getStartOffset();
|
||||
if (myRange.getStartOffset() >= start && myRange.getEndOffset() <= ((RetargetRangeMarkers)event).getEndOffset()) {
|
||||
ProperTextRange range = myRange.shiftRight(((RetargetRangeMarkers)event).getMoveDestinationOffset() - start);
|
||||
return Pair.create(range, myLinesCols == null ? null : PersistentRangeMarker.storeLinesAndCols(range, event.getDocument()));
|
||||
return new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, myLinesCols == null ? null : PersistentRangeMarker.storeLinesAndCols(range, event.getDocument()));
|
||||
}
|
||||
}
|
||||
|
||||
if (myLinesCols != null) {
|
||||
return PersistentRangeMarker
|
||||
Pair<ProperTextRange, PersistentRangeMarker.LinesCols> pair = PersistentRangeMarker
|
||||
.applyChange(event, myRange, myRange.getStartOffset(), myRange.getEndOffset(), myGreedyLeft, myGreedyRight, myLinesCols);
|
||||
return pair == null ? null : new ManualRangeMarker(pair.first, myGreedyLeft, myGreedyRight, pair.second);
|
||||
}
|
||||
|
||||
ProperTextRange range = RangeMarkerImpl.applyChange(event, myRange.getStartOffset(), myRange.getEndOffset(), myGreedyLeft, myGreedyRight);
|
||||
return range == null ? null : new Pair<ProperTextRange, PersistentRangeMarker.LinesCols>(range, null);
|
||||
return range == null ? null : new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, null);
|
||||
}
|
||||
|
||||
public void applyState(@Nullable ManualRangeMarker updated) {
|
||||
if (updated == null || !updated.myValid) {
|
||||
myValid = false;
|
||||
}
|
||||
if (!myValid) return;
|
||||
|
||||
myRange = updated.myRange;
|
||||
myLinesCols = updated.myLinesCols;
|
||||
}
|
||||
|
||||
public boolean isGreedyLeft() {
|
||||
return myGreedyLeft;
|
||||
}
|
||||
|
||||
public boolean isGreedyRight() {
|
||||
return myGreedyRight;
|
||||
}
|
||||
|
||||
public boolean isSurviveOnExternalChange() {
|
||||
return myLinesCols != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
public ProperTextRange getRange() {
|
||||
return myValid ? myRange : null;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return myValid;
|
||||
return myRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ManualRangeMarker" + (myValid ? myRange.toString() : " invalid");
|
||||
return "ManualRangeMarker" + myRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myHash;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,6 +317,12 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
|
||||
final boolean synchronously) {
|
||||
if (myProject.isDisposed()) return false;
|
||||
assert !(document instanceof DocumentWindow);
|
||||
|
||||
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
|
||||
if (virtualFile != null) {
|
||||
((SmartPointerManagerImpl)SmartPointerManager.getInstance(myProject)).fastenBelts(virtualFile);
|
||||
}
|
||||
|
||||
myIsCommitInProgress = true;
|
||||
boolean success = true;
|
||||
try {
|
||||
@@ -635,9 +641,6 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
|
||||
|
||||
if (document instanceof DocumentImpl && !myUncommittedInfos.containsKey(document)) {
|
||||
myUncommittedInfos.put(document, new UncommittedInfo((DocumentImpl)document));
|
||||
if (isRelevant) {
|
||||
((SmartPointerManagerImpl)SmartPointerManager.getInstance(myProject)).fastenBelts(virtualFile);
|
||||
}
|
||||
}
|
||||
|
||||
final FileViewProvider viewProvider = getCachedViewProvider(document);
|
||||
@@ -769,7 +772,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
|
||||
UncommittedInfo info = myUncommittedInfos.remove(document);
|
||||
if (info != null) {
|
||||
((SmartPointerManagerImpl)SmartPointerManager.getInstance(myProject)).updatePointers(document, info.myFrozen, info.myEvents);
|
||||
Disposer.dispose(info);
|
||||
info.removeListener();
|
||||
}
|
||||
return info;
|
||||
}
|
||||
@@ -845,7 +848,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
|
||||
@VisibleForTesting
|
||||
public void clearUncommittedDocuments() {
|
||||
for (UncommittedInfo info : myUncommittedInfos.values()) {
|
||||
Disposer.dispose(info);
|
||||
info.removeListener();
|
||||
}
|
||||
myUncommittedInfos.clear();
|
||||
myUncommittedDocuments.clear();
|
||||
@@ -892,7 +895,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
|
||||
return mySynchronizer;
|
||||
}
|
||||
|
||||
private static class UncommittedInfo extends DocumentAdapter implements PrioritizedInternalDocumentListener, Disposable {
|
||||
private static class UncommittedInfo extends DocumentAdapter implements PrioritizedInternalDocumentListener {
|
||||
final DocumentImpl myOriginal;
|
||||
final FrozenDocument myFrozen;
|
||||
final List<DocumentEvent> myEvents = ContainerUtil.newArrayList();
|
||||
@@ -900,7 +903,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
|
||||
public UncommittedInfo(DocumentImpl original) {
|
||||
myOriginal = original;
|
||||
myFrozen = original.freeze();
|
||||
myOriginal.addDocumentListener(this, this);
|
||||
myOriginal.addDocumentListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -918,8 +921,8 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
|
||||
myEvents.add(new RetargetRangeMarkers(myOriginal, start, end, base));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
public void removeListener() {
|
||||
myOriginal.removeDocumentListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,8 @@ class AnchorElementInfo extends SelfElementInfo {
|
||||
// switch to tree
|
||||
myStubElementTypeAndId = pack(-1, null);
|
||||
PsiElement anchor = AnchorElementInfoFactory.getAnchor(element);
|
||||
setRange((anchor == null ? element : anchor).getTextRange(), document);
|
||||
TextRange range = (anchor == null ? element : anchor).getTextRange();
|
||||
setRange(ProperTextRange.create(range));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,65 +24,39 @@ import com.intellij.openapi.util.ProperTextRange;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.util.NullableFunction;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.WeakHashMap;
|
||||
import com.intellij.util.containers.WeakValueHashMap;
|
||||
import gnu.trove.TLongObjectHashMap;
|
||||
import gnu.trove.TLongObjectProcedure;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
class MarkerCache {
|
||||
private final Set<ManualRangeMarker> myMarkerSet = Collections.newSetFromMap(new WeakHashMap<ManualRangeMarker, Boolean>());
|
||||
private WeakValueHashMap<RangeKey, ManualRangeMarker> myByRange = new WeakValueHashMap<RangeKey, ManualRangeMarker>();
|
||||
private volatile Trinity<Integer, Map<RangeKey, ManualRangeMarker>, FrozenDocument> myUpdatedRanges;
|
||||
private final SmartPointerManagerImpl.FilePointersList myPointers;
|
||||
private volatile Trinity<Integer, TLongObjectHashMap<ManualRangeMarker>, FrozenDocument> myUpdatedRanges;
|
||||
|
||||
@Nullable
|
||||
private static RangeKey keyOf(@NotNull ManualRangeMarker marker) {
|
||||
ProperTextRange range = marker.getRange();
|
||||
return range == null ? null : new RangeKey(range, marker.isGreedyLeft(), marker.isGreedyRight(), marker.isSurviveOnExternalChange());
|
||||
MarkerCache(SmartPointerManagerImpl.FilePointersList pointers) {
|
||||
myPointers = pointers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
synchronized ManualRangeMarker obtainMarker(@NotNull ProperTextRange range, @NotNull FrozenDocument frozen, boolean greedyLeft, boolean greedyRight, boolean persistent) {
|
||||
WeakValueHashMap<RangeKey, ManualRangeMarker> byRange = getByRangeCache();
|
||||
RangeKey key = new RangeKey(range, greedyLeft, greedyRight, persistent);
|
||||
ManualRangeMarker marker = byRange.get(key);
|
||||
if (marker == null) {
|
||||
marker = new ManualRangeMarker(frozen, range, greedyLeft, greedyRight, persistent);
|
||||
myMarkerSet.add(marker);
|
||||
byRange.put(key, marker);
|
||||
myUpdatedRanges = null;
|
||||
}
|
||||
return marker;
|
||||
private static long keyOf(@NotNull ProperTextRange range, boolean forInjected) {
|
||||
long start = range.getStartOffset();
|
||||
assert start >= 0;
|
||||
assert start < Integer.MAX_VALUE;
|
||||
|
||||
long packed = (start + 1) | ((long)range.getEndOffset() << 32);
|
||||
assert packed > 0;
|
||||
return forInjected ? -packed : packed;
|
||||
}
|
||||
|
||||
private WeakValueHashMap<RangeKey, ManualRangeMarker> getByRangeCache() {
|
||||
if (myByRange == null) {
|
||||
myByRange = new WeakValueHashMap<RangeKey, ManualRangeMarker>();
|
||||
for (ManualRangeMarker marker : myMarkerSet) {
|
||||
RangeKey key = keyOf(marker);
|
||||
if (key != null) {
|
||||
myByRange.put(key, marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
return myByRange;
|
||||
}
|
||||
|
||||
private Map<RangeKey, ManualRangeMarker> getUpdatedMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
|
||||
if (myMarkerSet.isEmpty()) return Collections.emptyMap();
|
||||
|
||||
private TLongObjectHashMap<ManualRangeMarker> getUpdatedMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
|
||||
int eventCount = events.size();
|
||||
assert eventCount > 0;
|
||||
|
||||
Trinity<Integer, Map<RangeKey, ManualRangeMarker>, FrozenDocument> cache = myUpdatedRanges;
|
||||
Trinity<Integer, TLongObjectHashMap<ManualRangeMarker>, FrozenDocument> cache = myUpdatedRanges;
|
||||
if (cache != null && cache.first.intValue() == eventCount) return cache.second;
|
||||
|
||||
//noinspection SynchronizeOnThis
|
||||
@@ -90,17 +64,19 @@ class MarkerCache {
|
||||
cache = myUpdatedRanges;
|
||||
if (cache != null && cache.first.intValue() == eventCount) return cache.second;
|
||||
|
||||
Map<RangeKey, ManualRangeMarker> answer = ContainerUtil.newHashMap();
|
||||
TLongObjectHashMap<ManualRangeMarker> answer;
|
||||
if (cache != null && cache.first < eventCount) {
|
||||
// apply only the new events
|
||||
answer.putAll(cache.second);
|
||||
answer = cache.second.clone();
|
||||
frozen = applyEvents(cache.third, events.subList(cache.first, eventCount), answer);
|
||||
}
|
||||
else {
|
||||
for (ManualRangeMarker marker : myMarkerSet) {
|
||||
RangeKey key = keyOf(marker);
|
||||
if (key != null) {
|
||||
answer.put(key, marker);
|
||||
answer = new TLongObjectHashMap<ManualRangeMarker>();
|
||||
for (SelfElementInfo info : getInfos()) {
|
||||
ProperTextRange range = info.getPsiRange();
|
||||
if (range != null) {
|
||||
boolean forInjected = info.isForInjected();
|
||||
answer.put(keyOf(range, forInjected), new ManualRangeMarker(frozen, range, forInjected, forInjected, !forInjected));
|
||||
}
|
||||
}
|
||||
frozen = applyEvents(frozen, events, answer);
|
||||
@@ -112,10 +88,10 @@ class MarkerCache {
|
||||
}
|
||||
|
||||
private static FrozenDocument applyEvents(@NotNull FrozenDocument frozen,
|
||||
@NotNull List<DocumentEvent> events,
|
||||
Map<RangeKey, ManualRangeMarker> map) {
|
||||
@NotNull List<DocumentEvent> events,
|
||||
final TLongObjectHashMap<ManualRangeMarker> map) {
|
||||
for (DocumentEvent event : events) {
|
||||
DocumentEvent corrected;
|
||||
final DocumentEvent corrected;
|
||||
if ((event instanceof RetargetRangeMarkers)) {
|
||||
RetargetRangeMarkers retarget = (RetargetRangeMarkers)event;
|
||||
corrected = new RetargetRangeMarkers(frozen, retarget.getStartOffset(), retarget.getEndOffset(), retarget.getMoveDestinationOffset());
|
||||
@@ -126,102 +102,55 @@ class MarkerCache {
|
||||
event.isWholeTextReplaced());
|
||||
}
|
||||
|
||||
for (Map.Entry<RangeKey, ManualRangeMarker> entry : map.entrySet()) {
|
||||
ManualRangeMarker currentRange = entry.getValue();
|
||||
if (currentRange != null) {
|
||||
entry.setValue(currentRange.getUpdatedRange(corrected));
|
||||
map.forEachEntry(new TLongObjectProcedure<ManualRangeMarker>() {
|
||||
@Override
|
||||
public boolean execute(long key, ManualRangeMarker currentRange) {
|
||||
if (currentRange != null) {
|
||||
map.put(key, currentRange.getUpdatedRange(corrected));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return frozen;
|
||||
}
|
||||
|
||||
synchronized void updateMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events, @NotNull List<SmartPsiElementPointerImpl> pointers) {
|
||||
List<SelfElementInfo> infos = ContainerUtil.findAll(ContainerUtil.map(pointers, new NullableFunction<SmartPsiElementPointerImpl, SmartPointerElementInfo>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public SmartPointerElementInfo fun(SmartPsiElementPointerImpl pointer) {
|
||||
return pointer.getElementInfo();
|
||||
}
|
||||
}), SelfElementInfo.class);
|
||||
synchronized void updateMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
|
||||
TLongObjectHashMap<ManualRangeMarker> updated = getUpdatedMarkers(frozen, events);
|
||||
|
||||
Map<RangeKey, ManualRangeMarker> updated = getUpdatedMarkers(frozen, events);
|
||||
Map<ManualRangeMarker, ManualRangeMarker> newStates = ContainerUtil.newHashMap();
|
||||
for (SelfElementInfo info : infos) {
|
||||
ManualRangeMarker marker = info.getRangeMarker();
|
||||
RangeKey key = marker == null ? null : keyOf(marker);
|
||||
if (key != null) {
|
||||
newStates.put(marker, updated.get(key));
|
||||
for (SelfElementInfo info : getInfos()) {
|
||||
ProperTextRange range = info.getPsiRange();
|
||||
if (range != null) {
|
||||
ManualRangeMarker newRange = updated.get(keyOf(range, info.isForInjected()));
|
||||
info.setRange(newRange == null ? null : newRange.getRange());
|
||||
}
|
||||
}
|
||||
|
||||
myMarkerSet.clear();
|
||||
for (Map.Entry<ManualRangeMarker, ManualRangeMarker> entry : newStates.entrySet()) {
|
||||
ManualRangeMarker marker = entry.getKey();
|
||||
marker.applyState(entry.getValue());
|
||||
if (marker.isValid()) {
|
||||
myMarkerSet.add(marker); //re-add only alive markers
|
||||
}
|
||||
}
|
||||
myByRange = null;
|
||||
myUpdatedRanges = null;
|
||||
}
|
||||
|
||||
for (SelfElementInfo info : infos) {
|
||||
info.updateValidity();
|
||||
}
|
||||
@NotNull
|
||||
private List<SelfElementInfo> getInfos() {
|
||||
return ContainerUtil.findAll(ContainerUtil.map(myPointers.getAlivePointers(), new NullableFunction<SmartPsiElementPointerImpl, SmartPointerElementInfo>() {
|
||||
@Override
|
||||
public SmartPointerElementInfo fun(SmartPsiElementPointerImpl pointer) {
|
||||
return pointer.getElementInfo();
|
||||
}
|
||||
}), SelfElementInfo.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
ProperTextRange getUpdatedRange(@NotNull ManualRangeMarker marker, @NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
|
||||
ManualRangeMarker updated = getUpdatedMarkers(frozen, events).get(keyOf(marker));
|
||||
ProperTextRange getUpdatedRange(SelfElementInfo info, @NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
|
||||
ProperTextRange range = info.getPsiRange();
|
||||
if (range == null) return null;
|
||||
|
||||
ManualRangeMarker updated = getUpdatedMarkers(frozen, events).get(keyOf(range, info.isForInjected()));
|
||||
return updated == null ? null : updated.getRange();
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
synchronized int getMarkerCount() {
|
||||
return myMarkerSet.size();
|
||||
}
|
||||
|
||||
private static class RangeKey {
|
||||
final int start;
|
||||
final int end;
|
||||
final int flags;
|
||||
|
||||
RangeKey(ProperTextRange range, boolean greedyLeft, boolean greedyRight, boolean persistent) {
|
||||
start = range.getStartOffset();
|
||||
end = range.getEndOffset();
|
||||
flags = (persistent ? 4 : 0) + (greedyLeft ? 2 : 0) + (greedyRight ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof RangeKey)) return false;
|
||||
|
||||
RangeKey key = (RangeKey)o;
|
||||
|
||||
if (start != key.start) return false;
|
||||
if (end != key.end) return false;
|
||||
if (flags != key.flags) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = start;
|
||||
result = 31 * result + end;
|
||||
result = 31 * result + flags;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RangeKey{" +
|
||||
"start=" + start +
|
||||
", end=" + end +
|
||||
", flags=" + flags +
|
||||
'}';
|
||||
synchronized void rangeChanged(@NotNull ProperTextRange range, boolean forInjected) {
|
||||
if (myUpdatedRanges != null && !myUpdatedRanges.second.contains(keyOf(range, forInjected))) {
|
||||
myUpdatedRanges = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,8 @@ package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.impl.FrozenDocument;
|
||||
import com.intellij.openapi.editor.impl.ManualRangeMarker;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.*;
|
||||
@@ -37,7 +34,6 @@ import java.util.List;
|
||||
* User: cdr
|
||||
*/
|
||||
public class SelfElementInfo extends SmartPointerElementInfo {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.smartPointers.SelfElementInfo");
|
||||
private static final FileDocumentManager ourFileDocManager = FileDocumentManager.getInstance();
|
||||
@NotNull private final VirtualFile myVirtualFile;
|
||||
private final Class myType;
|
||||
@@ -45,7 +41,6 @@ public class SelfElementInfo extends SmartPointerElementInfo {
|
||||
private final Language myLanguage;
|
||||
private final MarkerCache myMarkerCache;
|
||||
private final boolean myForInjected;
|
||||
@Nullable private ManualRangeMarker myRangeMarker;
|
||||
@Nullable private ProperTextRange myPsiRange;
|
||||
private final PsiDocumentManagerBase myPsiDocManager;
|
||||
|
||||
@@ -65,17 +60,18 @@ public class SelfElementInfo extends SmartPointerElementInfo {
|
||||
myPsiRange = range;
|
||||
myMarkerCache = ((SmartPointerManagerImpl)SmartPointerManager.getInstance(project)).getMarkerCache(myVirtualFile);
|
||||
myPsiDocManager = (PsiDocumentManagerBase)PsiDocumentManager.getInstance(myProject);
|
||||
setRange(range);
|
||||
}
|
||||
|
||||
Document document = myPsiDocManager.getCachedDocument(containingFile);
|
||||
if (document != null) {
|
||||
setRange(range, document);
|
||||
void setRange(@Nullable ProperTextRange range) {
|
||||
myPsiRange = range;
|
||||
if (range != null) {
|
||||
myMarkerCache.rangeChanged(range, myForInjected);
|
||||
}
|
||||
}
|
||||
|
||||
void setRange(@NotNull TextRange range, @NotNull Document document) {
|
||||
myPsiRange = null;
|
||||
FrozenDocument frozenDocument = myPsiDocManager.getLastCommittedDocument(document);
|
||||
myRangeMarker = myMarkerCache.obtainMarker(ProperTextRange.create(range), frozenDocument, myForInjected, myForInjected, !myForInjected);
|
||||
boolean isForInjected() {
|
||||
return myForInjected;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,23 +79,6 @@ public class SelfElementInfo extends SmartPointerElementInfo {
|
||||
return ourFileDocManager.getCachedDocument(myVirtualFile);
|
||||
}
|
||||
|
||||
// before change
|
||||
@Override
|
||||
public void fastenBelt() {
|
||||
if (myRangeMarker != null) return; // already tracks changes
|
||||
if (myPsiRange == null) return; // invalid
|
||||
|
||||
Document document = ourFileDocManager.getDocument(myVirtualFile);
|
||||
if (document == null || !myPsiDocManager.isCommitted(document)) {
|
||||
// we only have PSI range and now they say the document is uncommitted, so this PSI range is useless
|
||||
// so, just invalidate
|
||||
myPsiRange = null;
|
||||
return;
|
||||
}
|
||||
|
||||
setRange(myPsiRange, document);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement restoreElement() {
|
||||
Segment segment = getPsiRange();
|
||||
@@ -112,8 +91,8 @@ public class SelfElementInfo extends SmartPointerElementInfo {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Segment getPsiRange() {
|
||||
return myRangeMarker != null ? myRangeMarker.getRange() : myPsiRange;
|
||||
protected ProperTextRange getPsiRange() {
|
||||
return myPsiRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -149,21 +128,9 @@ public class SelfElementInfo extends SmartPointerElementInfo {
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
myRangeMarker = null;
|
||||
myPsiRange = null;
|
||||
}
|
||||
|
||||
void updateValidity() {
|
||||
if (myPsiRange != null) {
|
||||
LOG.error("Non-fastened smart pointer " + this + " " + myRangeMarker);
|
||||
myPsiRange = null;
|
||||
myRangeMarker = null;
|
||||
}
|
||||
if (myRangeMarker != null && !myRangeMarker.isValid()) {
|
||||
myRangeMarker = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiFile restoreFileFromVirtual(@NotNull final VirtualFile virtualFile, @NotNull final Project project, @Nullable final Language language) {
|
||||
return ApplicationManager.getApplication().runReadAction(new NullableComputable<PsiFile>() {
|
||||
@@ -252,16 +219,15 @@ public class SelfElementInfo extends SmartPointerElementInfo {
|
||||
@Override
|
||||
@Nullable
|
||||
public Segment getRange() {
|
||||
if (myRangeMarker != null) {
|
||||
if (myPsiRange != null) {
|
||||
Document document = getDocumentToSynchronize();
|
||||
if (document != null) {
|
||||
PsiDocumentManagerBase documentManager = myPsiDocManager;
|
||||
List<DocumentEvent> events = documentManager.getEventsSinceCommit(document);
|
||||
if (!events.isEmpty()) {
|
||||
return myMarkerCache.getUpdatedRange(myRangeMarker, documentManager.getLastCommittedDocument(document), events);
|
||||
return myMarkerCache.getUpdatedRange(this, documentManager.getLastCommittedDocument(document), events);
|
||||
}
|
||||
}
|
||||
return myRangeMarker.getRange();
|
||||
}
|
||||
return myPsiRange;
|
||||
}
|
||||
@@ -272,8 +238,4 @@ public class SelfElementInfo extends SmartPointerElementInfo {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
ManualRangeMarker getRangeMarker() {
|
||||
return myRangeMarker;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-12
@@ -230,14 +230,6 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public int getMarkerCount(@NotNull Document document) {
|
||||
synchronized (lock) {
|
||||
VirtualFile file = FileDocumentManager.getInstance().getFile(document);
|
||||
return file == null ? 0 : getMarkerCache(file).getMarkerCount();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pointToTheSameElement(@NotNull SmartPsiElementPointer pointer1, @NotNull SmartPsiElementPointer pointer2) {
|
||||
return SmartPsiElementPointerImpl.pointsToTheSameElementAs(pointer1, pointer2);
|
||||
@@ -248,7 +240,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
FilePointersList list = file == null ? null : getPointers(file);
|
||||
if (list == null) return;
|
||||
|
||||
list.markerCache.updateMarkers(frozen, events, list.getAlivePointers());
|
||||
list.markerCache.updateMarkers(frozen, events);
|
||||
}
|
||||
|
||||
private static class PointerReference extends WeakReference<SmartPointerEx> {
|
||||
@@ -265,11 +257,11 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static class FilePointersList {
|
||||
static class FilePointersList {
|
||||
private int nextAvailableIndex;
|
||||
private int size;
|
||||
private PointerReference[] references = new PointerReference[10];
|
||||
private final MarkerCache markerCache = new MarkerCache();
|
||||
private final MarkerCache markerCache = new MarkerCache(this);
|
||||
|
||||
private void add(@NotNull PointerReference reference) {
|
||||
if (nextAvailableIndex >= references.length || nextAvailableIndex > size*2) { // overflow or too many dead refs
|
||||
@@ -316,7 +308,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<SmartPsiElementPointerImpl> getAlivePointers() {
|
||||
List<SmartPsiElementPointerImpl> getAlivePointers() {
|
||||
return ContainerUtil.mapNotNull(references, new Function<PointerReference, SmartPsiElementPointerImpl>() {
|
||||
@Override
|
||||
public SmartPsiElementPointerImpl fun(PointerReference reference) {
|
||||
|
||||
Reference in New Issue
Block a user