https://github.com/playerC updated https://github.com/llvm/llvm-project/pull/202267
>From 5ae898162a317c3b30c9cfa7ac580cf94fb16c86 Mon Sep 17 00:00:00 2001 From: player <[email protected]> Date: Mon, 8 Jun 2026 14:27:34 +0800 Subject: [PATCH] [clangd] Fix offset invalid on line. Fixed the offset invalid on line error,triggered by a `textDocument/didChange` notification when `range.end.character` exceeds the corresponding line's length. --- clang-tools-extra/clangd/SourceCode.cpp | 8 ++- .../clangd/unittests/SourceCodeTests.cpp | 55 ++++++++++++++++++- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp index 21c078fd2cdb9..60aba1da64559 100644 --- a/clang-tools-extra/clangd/SourceCode.cpp +++ b/clang-tools-extra/clangd/SourceCode.cpp @@ -1132,8 +1132,9 @@ llvm::Error applyChange(std::string &Contents, if (!StartIndex) return StartIndex.takeError(); + // End position may longer than current line . const Position &End = Change.range->end; - llvm::Expected<size_t> EndIndex = positionToOffset(Contents, End, false); + llvm::Expected<size_t> EndIndex = positionToOffset(Contents, End, true); inferFinalNewline(EndIndex, Contents, End); if (!EndIndex) return EndIndex.takeError(); @@ -1153,13 +1154,14 @@ llvm::Error applyChange(std::string &Contents, ssize_t ComputedRangeLength = lspLength(Contents.substr(*StartIndex, *EndIndex - *StartIndex)); - if (Change.rangeLength && ComputedRangeLength != *Change.rangeLength) + // CoumputedRangeLength may less equal than rangeLength. + if (Change.rangeLength && ComputedRangeLength > *Change.rangeLength) return error(llvm::errc::invalid_argument, "Change's rangeLength ({0}) doesn't match the " "computed range length ({1}).", *Change.rangeLength, ComputedRangeLength); - Contents.replace(*StartIndex, *EndIndex - *StartIndex, Change.text); + Contents.replace(*StartIndex, ComputedRangeLength, Change.text); return llvm::Error::success(); } diff --git a/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp b/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp index 801d535c1b9d0..c08e24e1e0961 100644 --- a/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp +++ b/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp @@ -968,10 +968,57 @@ TEST(ApplyEditsTest, WrongRangeLength) { Change.range->end.line = 0; Change.range->end.character = 2; Change.rangeLength = 10; + + // when rangeLength doesn't match, just use computed range length. + EXPECT_THAT_ERROR(applyChange(Code, Change), + llvm::Succeeded()); +} + +TEST(ApplyEditsTest, InvalidOffsetOfLine){ + std::string Code = "0123456789\n"; + + TextDocumentContentChangeEvent Change; + + // NOTE : just use range.start and end to emulate the computed range + // length. + + // computedRangeLength > rangeLength , expect error. + Change.range.emplace(); + Change.range->start.line = 0; + Change.range->start.character = 0; + Change.range->end.line = 0; + Change.range->end.character = 5; + Change.rangeLength = 2; EXPECT_THAT_ERROR(applyChange(Code, Change), - FailedWithMessage("Change's rangeLength (10) doesn't match " - "the computed range length (2).")); + FailedWithMessage("Change's rangeLength (2) doesn't match " + "the computed range length (5).")); + + // computedRangeLength < rangeLength ,use computed, expect success. + Change.range.emplace(); + Change.range->start.line = 0; + Change.range->start.character = 0; + Change.range->end.line = 0; + Change.range->end.character = 3; + Change.rangeLength = 6; + Change.text = "SIX"; + + EXPECT_THAT_ERROR(applyChange(Code, Change), + llvm::Succeeded()); + EXPECT_EQ(Code, "SIX3456789\n"); + + // computedRangeLength == rangeLength , expect success. + Change.range.emplace(); + Change.range->start.line = 0; + Change.range->start.character = 0; + Change.range->end.line = 0; + Change.range->end.character = 3; + Change.rangeLength = 3; + Change.text = "THREE"; + + EXPECT_THAT_ERROR(applyChange(Code, Change), + llvm::Succeeded()); + EXPECT_EQ(Code, "THREE3456789\n"); } // Test that we correct observed buggy edits from Neovim. @@ -1055,9 +1102,11 @@ TEST(ApplyEditsTest, EndCharOutOfRange) { Change.range->end.character = 100; Change.text = "foo"; + // OK to replace whole line. EXPECT_THAT_ERROR( applyChange(Code, Change), - FailedWithMessage("utf-16 offset 100 is invalid for line 0")); + llvm::Succeeded()); + EXPECT_EQ(Code, "foo\n"); } TEST(ApplyEditsTest, StartLineOutOfRange) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
