diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java index e012f11af497..a26a4596abd3 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java @@ -373,10 +373,12 @@ public class RangeMarkerTree extends IntervalTreeImpl> affected = new ArrayList>(); collectNodesToRetarget(getRoot(), start, end, affected); if (affected.isEmpty()) return; - - int shift = newBase - start; + // remove all first because findOrInsert can remove gced nodes which could interfere with not-yet-removed nodes for (IntervalNode node : affected) { removeNode(node); + } + int shift = newBase - start; + for (IntervalNode node : affected) { node.setLeft(null); node.setRight(null); node.setParent(null); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java index 4ec550153256..ac385362b9b7 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java @@ -1203,4 +1203,19 @@ public class RangeMarkerTest extends LightPlatformTestCase { assertValidMarker(marker, 0, 9); } + public void testMoveTextCrashes() { + DocumentEx doc = new DocumentImpl(StringUtil.repeat("blah", 1000)); + Random random = new Random(); + for(int i = 0; i < 10000; i++) { + int limit = doc.getTextLength() + 1; + int offset = random.nextInt(limit); + doc.createRangeMarker(offset, offset); + int startOffset = random.nextInt(limit); + int endOffset = random.nextInt(limit); + int targetOffset = random.nextInt(limit); + if (endOffset > startOffset && (targetOffset < startOffset || targetOffset > endOffset)) { + doc.moveText(startOffset, endOffset, targetOffset); + } + } + } }