diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java index 2605c4f74852..876018fe447e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java @@ -19,6 +19,8 @@ import com.intellij.openapi.editor.*; import com.intellij.openapi.util.Key; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; +import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,6 +49,18 @@ abstract class FoldRegionsTree { }; private static final Comparator BY_END_OFFSET_REVERSE = Collections.reverseOrder(BY_END_OFFSET); + private static final TObjectHashingStrategy OFFSET_BASED_HASHING_STRATEGY = new TObjectHashingStrategy() { + @Override + public int computeHashCode(FoldRegion o) { + return o.getStartOffset() * 31 + o.getEndOffset(); + } + + @Override + public boolean equals(FoldRegion o1, FoldRegion o2) { + return o1.getStartOffset() == o2.getStartOffset() && o1.getEndOffset() == o2.getEndOffset(); + } + }; + void clear() { clearCachedValues(); @@ -67,11 +81,16 @@ abstract class FoldRegionsTree { List topLevels = new ArrayList(myRegions.size() / 2); List visible = new ArrayList(myRegions.size()); List allValid = new ArrayList(myRegions.size()); + Set distinctRegions = new THashSet(myRegions.size(), OFFSET_BASED_HASHING_STRATEGY); FoldRegion currentCollapsed = null; for (FoldRegion region : myRegions) { if (!region.isValid()) { continue; } + if (!distinctRegions.add(region)) { + region.dispose(); + continue; + } allValid.add(region); } @@ -134,9 +153,11 @@ abstract class FoldRegionsTree { rebuild(); return; } + + Set distinctRegions = new THashSet(visibleRegions.length, OFFSET_BASED_HASHING_STRATEGY); for (FoldRegion foldRegion : visibleRegions) { - if (!foldRegion.isValid()) { + if (!foldRegion.isValid() || !distinctRegions.add(foldRegion)) { rebuild(); return; } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/FoldingTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/FoldingTest.java index 30e7860638b6..f6dff65607ba 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/FoldingTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/FoldingTest.java @@ -22,6 +22,7 @@ import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.TestFileType; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertTrue; /** * @author max @@ -195,4 +196,24 @@ public class FoldingTest extends AbstractEditorTest { assertTrue(myModel.isOffsetCollapsed(5)); } + + public void testIdenticalRegionsAreRemoved() { + addFoldRegion(0, 5, "..."); + addFoldRegion(0, 4, "..."); + assertNumberOfValidFoldRegions(2); + + myEditor.getDocument().deleteString(4, 5); + + assertNumberOfValidFoldRegions(1); + } + + private void assertNumberOfValidFoldRegions(int expectedValue) { + int actualValue = 0; + for (FoldRegion region : myModel.getAllFoldRegions()) { + if (region.isValid()) { + actualValue++; + } + } + assertEquals(expectedValue, actualValue); + } }