smart pointers should survive on DocumentEx.moveText

This commit is contained in:
peter
2015-08-16 18:12:40 +02:00
parent 86632606fe
commit 9e268c2e39
5 changed files with 125 additions and 9 deletions
@@ -27,6 +27,7 @@ import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.editor.event.EditorEventMulticaster;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.PlainTextFileType;
import com.intellij.openapi.fileTypes.StdFileTypes;
@@ -716,6 +717,33 @@ public class SmartPsiElementPointersTest extends CodeInsightTestCase {
assertEquals(TextRange.create(1, 2), range2.getRange());
}
public void testMoveText() {
PsiJavaFile file = (PsiJavaFile)configureByText(JavaFileType.INSTANCE, "class C1{}\nclass C2 {}");
DocumentEx document = (DocumentEx)file.getViewProvider().getDocument();
SmartPsiElementPointer<PsiClass> pointer1 =
SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(file.getClasses()[0]);
SmartPsiElementPointer<PsiClass> pointer2 =
SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(file.getClasses()[1]);
assertEquals("C1", pointer1.getElement().getName());
assertEquals("C2", pointer2.getElement().getName());
PlatformTestUtil.tryGcSoftlyReachableObjects();
assertNull(((SmartPointerEx) pointer1).getCachedElement());
assertNull(((SmartPointerEx) pointer2).getCachedElement());
TextRange range = file.getClasses()[1].getTextRange();
document.moveText(range.getStartOffset(), range.getEndOffset(), 0);
System.out.println(pointer1.getRange());
System.out.println(pointer2.getRange());
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
assertEquals("C1", pointer1.getElement().getName());
assertEquals("C2", pointer2.getElement().getName());
}
public void testNonPhysicalFile() {
PsiJavaFile file = (PsiJavaFile)myJavaFacade.findClass("AClass", GlobalSearchScope.allScope(getProject())).getContainingFile().copy();
SmartPsiFileRange pointer = SmartPointerManager.getInstance(myProject).createSmartPsiFileRangePointer(file, TextRange.create(1, 2));
@@ -16,6 +16,7 @@
package com.intellij.openapi.editor.impl;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.impl.event.RetargetRangeMarkers;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.ProperTextRange;
import org.jetbrains.annotations.NotNull;
@@ -57,6 +58,14 @@ public class ManualRangeMarker {
@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()));
}
}
if (myLinesCols != null) {
return PersistentRangeMarker
.applyChange(event, myRange, myRange.getStartOffset(), myRange.getEndOffset(), myGreedyLeft, myGreedyRight, myLinesCols);
@@ -0,0 +1,48 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.editor.impl.event;
import com.intellij.openapi.editor.Document;
import org.jetbrains.annotations.NotNull;
/**
* @author peter
*/
public class RetargetRangeMarkers extends DocumentEventImpl {
private final int myStartOffset;
private final int myEndOffset;
private final int myMoveDestinationOffset;
public RetargetRangeMarkers(@NotNull Document document,
int startOffset, int endOffset, int moveDestinationOffset) {
super(document, startOffset, "", "", 0, false);
myStartOffset = startOffset;
myEndOffset = endOffset;
myMoveDestinationOffset = moveDestinationOffset;
}
public int getStartOffset() {
return myStartOffset;
}
public int getEndOffset() {
return myEndOffset;
}
public int getMoveDestinationOffset() {
return myMoveDestinationOffset;
}
}
@@ -24,11 +24,15 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.ex.PrioritizedInternalDocumentListener;
import com.intellij.openapi.editor.impl.DocumentImpl;
import com.intellij.openapi.editor.impl.EditorDocumentPriorities;
import com.intellij.openapi.editor.impl.FrozenDocument;
import com.intellij.openapi.editor.impl.event.RetargetRangeMarkers;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
@@ -667,10 +671,6 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
if (myStopTrackingDocuments || myProject.isDisposed()) return;
final Document document = event.getDocument();
if (document instanceof DocumentImpl) {
myUncommittedInfos.get(document).myEvents.add(event);
}
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
boolean isRelevant = virtualFile != null && isRelevant(virtualFile);
@@ -767,6 +767,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);
}
return info;
}
@@ -841,6 +842,9 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
@TestOnly
public void clearUncommittedDocuments() {
for (UncommittedInfo info : myUncommittedInfos.values()) {
Disposer.dispose(info);
}
myUncommittedInfos.clear();
myUncommittedDocuments.clear();
mySynchronizer.cleanupForNextTest();
@@ -863,7 +867,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
return mySynchronizer;
}
private static class UncommittedInfo {
private static class UncommittedInfo extends DocumentAdapter implements PrioritizedInternalDocumentListener, Disposable {
final DocumentImpl myOriginal;
final FrozenDocument myFrozen;
final List<DocumentEvent> myEvents = ContainerUtil.newArrayList();
@@ -871,8 +875,27 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
public UncommittedInfo(DocumentImpl original) {
myOriginal = original;
myFrozen = original.freeze();
myOriginal.addDocumentListener(this, this);
}
@Override
public int getPriority() {
return EditorDocumentPriorities.RANGE_MARKER;
}
@Override
public void documentChanged(DocumentEvent e) {
myEvents.add(e);
}
@Override
public void moveTextHappened(int start, int end, int base) {
myEvents.add(new RetargetRangeMarkers(myOriginal, start, end, base));
}
@Override
public void dispose() {
}
}
}
@@ -19,6 +19,7 @@ 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.editor.impl.event.DocumentEventImpl;
import com.intellij.openapi.editor.impl.event.RetargetRangeMarkers;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.openapi.util.Trinity;
import com.intellij.util.NullableFunction;
@@ -114,10 +115,17 @@ class MarkerCache {
@NotNull List<DocumentEvent> events,
Map<RangeKey, ManualRangeMarker> map) {
for (DocumentEvent event : events) {
frozen = frozen.applyEvent(event, 0);
final DocumentEvent corrected =
new DocumentEventImpl(frozen, event.getOffset(), event.getOldFragment(), event.getNewFragment(), event.getOldTimeStamp(),
event.isWholeTextReplaced());
DocumentEvent corrected;
if ((event instanceof RetargetRangeMarkers)) {
RetargetRangeMarkers retarget = (RetargetRangeMarkers)event;
corrected = new RetargetRangeMarkers(frozen, retarget.getStartOffset(), retarget.getEndOffset(), retarget.getMoveDestinationOffset());
}
else {
frozen = frozen.applyEvent(event, 0);
corrected = new DocumentEventImpl(frozen, event.getOffset(), event.getOldFragment(), event.getNewFragment(), event.getOldTimeStamp(),
event.isWholeTextReplaced());
}
for (Map.Entry<RangeKey, ManualRangeMarker> entry : map.entrySet()) {
ManualRangeMarker currentRange = entry.getValue();
if (currentRange != null) {