From 686da7797105a93035cfbc7edbf2a8e8f8adf0ec Mon Sep 17 00:00:00 2001 From: Christoph Cullmann 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(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