don't expose whole document text through subsequences in document change events (IDEA-131780)

This commit is contained in:
peter
2014-10-23 11:43:13 +02:00
parent 1869ad4cb0
commit 086d2083e8
2 changed files with 18 additions and 8 deletions
@@ -493,7 +493,9 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
throwGuardedFragment(marker, offset, null, s.toString());
}
updateText(myText.insert(offset, ImmutableText.valueOf(s)), offset, null, s, false, LocalTimeCounter.currentTime());
myText = myText.ensureChunked();
ImmutableText newText = myText.insert(offset, ImmutableText.valueOf(s));
updateText(newText, offset, null, newText.subtext(offset, offset + s.length()), false, LocalTimeCounter.currentTime());
trimToSize();
}
@@ -511,14 +513,13 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
if (!isWritable()) throw new ReadOnlyModificationException(this);
if (startOffset == endOffset) return;
CharSequence sToDelete = myText.subSequence(startOffset, endOffset);
RangeMarker marker = getRangeGuard(startOffset, endOffset);
if (marker != null) {
throwGuardedFragment(marker, startOffset, sToDelete.toString(), null);
throwGuardedFragment(marker, startOffset, myText.subSequence(startOffset, endOffset).toString(), null);
}
updateText(myText.delete(startOffset, endOffset), startOffset, sToDelete, null, false, LocalTimeCounter.currentTime());
myText = myText.ensureChunked();
updateText(myText.delete(startOffset, endOffset), startOffset, myText.subtext(startOffset, endOffset), null, false, LocalTimeCounter.currentTime());
}
@Override
@@ -582,7 +583,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
}
CharSequence changedPart = s.subSequence(newStartInString, newEndInString);
CharSequence sToDelete = myText.subSequence(startOffset, endOffset);
CharSequence sToDelete = myText.subtext(startOffset, endOffset);
RangeMarker guard = getRangeGuard(startOffset, endOffset);
if (guard != null) {
throwGuardedFragment(guard, startOffset, sToDelete.toString(), changedPart.toString());
@@ -593,7 +594,9 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
newText = (ImmutableText)s;
}
else {
myText = myText.ensureChunked();
newText = myText.delete(startOffset, endOffset).insert(startOffset, changedPart);
changedPart = newText.subtext(startOffset, startOffset + changedPart.length());
}
updateText(newText, startOffset, sToDelete, changedPart, wholeTextReplaced, newModificationStamp);
trimToSize();
@@ -96,7 +96,14 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
return new ImmutableText(new LeafNode(chars));
}
private ImmutableText ensureChunked() {
/**
* When first loaded, ImmutableText contents are stored as a single large array. This saves memory but isn't
* modification-friendly as it disallows slightly changed texts to retain most of the internal structure of the
* original document. Whoever retains old non-chunked version will use more memory than really needed.
*
* @return a copy of this text better prepared for small modifications to fully enable structure-sharing capabilities
*/
public ImmutableText ensureChunked() {
if (length() > BLOCK_SIZE && myNode instanceof LeafNode) {
return new ImmutableText(nodeOf(((LeafNode)myNode)._data, 0, length()));
}
@@ -292,7 +299,7 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
* @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0) ||
* (start > end) || (end > this.length())</code>
*/
private ImmutableText subtext(int start, int end) {
public ImmutableText subtext(int start, int end) {
if ((start < 0) || (start > end) || (end > length()))
throw new IndexOutOfBoundsException();
if ((start == 0) && (end == length()))