From 686da7797105a93035cfbc7edbf2a8e8f8adf0ec Mon Sep 17 00:00:00 2001
From: Christoph Cullmann <cullmann@kde.org>
Date: Wed, 17 Feb 2021 20:51:12 +0100
Subject: [PATCH] ensure rangesForLine caching is correcly updated
during fixing a segfault, as invalid range pointer were kept
in the rangesForLine cache, too many ranges were purged
properly update the cache before potential invalidation
add unit test to avoid regressions in the future
---
autotests/src/movingrange_test.cpp | 33 ++++++++++++++++++++++++++++++
autotests/src/movingrange_test.h | 1 +
src/buffer/katetextblock.cpp | 10 +++++++++
3 files changed, 44 insertions(+)
diff --git a/autotests/src/movingrange_test.cpp b/autotests/src/movingrange_test.cpp
index 66393ae7..81a85b1a 100644
--- a/autotests/src/movingrange_test.cpp
+++ b/autotests/src/movingrange_test.cpp
@@ -459,3 +459,36 @@ void MovingRangeTest::testLineRemoved()
auto r = doc.buffer().rangesForLine(1, view, true);
QVERIFY(r.isEmpty());
}
+
+void MovingRangeTest::testLineWrapOrUnwrapUpdateRangeForLineCache()
+{
+ KTextEditor::DocumentPrivate doc;
+ doc.setText(
+ QStringLiteral("abcd\n"
+ "efgh\n"
+ "hijk\n"));
+
+ // add range to line 2, it shall be in rangeForLine for the right lines after each update!
+ // must be single line range to be in the cache!
+ auto range = static_cast<Kate::TextRange *>(doc.newMovingRange({2, 1, 2, 3},
+ KTextEditor::MovingRange::ExpandLeft | KTextEditor::MovingRange::ExpandRight,
+ KTextEditor::MovingRange::InvalidateIfEmpty));
+
+ // range shall be in the lookup cache for line 2
+ QVERIFY(doc.buffer().rangesForLine(0, nullptr, false).isEmpty());
+ QVERIFY(doc.buffer().rangesForLine(1, nullptr, false).isEmpty());
+ QVERIFY(doc.buffer().rangesForLine(2, nullptr, false).contains(range));
+
+ // wrap line 1 => range should move to line 3
+ doc.editWrapLine(1, 1);
+ QVERIFY(doc.buffer().rangesForLine(0, nullptr, false).isEmpty());
+ QVERIFY(doc.buffer().rangesForLine(1, nullptr, false).isEmpty());
+ QVERIFY(doc.buffer().rangesForLine(2, nullptr, false).isEmpty());
+ QVERIFY(doc.buffer().rangesForLine(3, nullptr, false).contains(range));
+
+ // unwrap line 1 => range should back move to line 2
+ doc.editUnWrapLine(1);
+ QVERIFY(doc.buffer().rangesForLine(0, nullptr, false).isEmpty());
+ QVERIFY(doc.buffer().rangesForLine(1, nullptr, false).isEmpty());
+ QVERIFY(doc.buffer().rangesForLine(2, nullptr, false).contains(range));
+}
diff --git a/autotests/src/movingrange_test.h b/autotests/src/movingrange_test.h
index 6f8c057d..016655f7 100644
--- a/autotests/src/movingrange_test.h
+++ b/autotests/src/movingrange_test.h
@@ -24,6 +24,7 @@ private Q_SLOTS:
void testFeedbackCaret();
void testFeedbackMouse();
void testLineRemoved();
+ void testLineWrapOrUnwrapUpdateRangeForLineCache();
};
#endif // KATE_MOVINGRANGE_TEST_H
diff --git a/src/buffer/katetextblock.cpp b/src/buffer/katetextblock.cpp
index 43d137e4..246897b4 100644
--- a/src/buffer/katetextblock.cpp
+++ b/src/buffer/katetextblock.cpp
@@ -167,6 +167,11 @@ void TextBlock::wrapLine(const KTextEditor::Cursor &position, int fixStartLinesS
// we might need to invalidate ranges or notify about their changes
// checkValidity might trigger delete of the range!
for (TextRange *range : qAsConst(changedRanges)) {
+ // we need to do updateRange to ALWAYS ensure the line => range and back cache is updated
+ // see MovingRangeTest::testLineWrapOrUnwrapUpdateRangeForLineCache
+ updateRange(range);
+
+ // in addition: ensure that we really invalidate bad ranges!
range->checkValidity(range->toLineRange());
}
}
@@ -333,6 +338,11 @@ void TextBlock::unwrapLine(int line, TextBlock *previousBlock, int fixStartLines
// we might need to invalidate ranges or notify about their changes
// checkValidity might trigger delete of the range!
for (TextRange *range : qAsConst(changedRanges)) {
+ // we need to do updateRange to ALWAYS ensure the line => range and back cache is updated
+ // see MovingRangeTest::testLineWrapOrUnwrapUpdateRangeForLineCache
+ updateRange(range);
+
+ // in addition: ensure that we really invalidate bad ranges!
range->checkValidity(range->toLineRange());
}
}
--
GitLab