Author: Krzysztof Jędruczyk
Date: 2026-05-07T16:18:13+03:00
New Revision: 540859c2d45b935e6f055663f0d243d2ecc68233
URL: https://github.com/llvm/llvm-project/commit/540859c2d45b935e6f055663f0d243d2ecc68233
DIFF: https://github.com/llvm/llvm-project/commit/540859c2d45b935e6f055663f0d243d2ecc68233.diff
LOG: [clangd] Fix crash on completion with out-of-range position (#196112)
shouldRunCompletion() checked the Expected<> from positionToOffset() via
operator!() but never consumed the error with takeError(). This caused
an assertion failure when a TriggerCharacter completion request had a
position beyond the document bounds.
LLM was used to generate the unit test.
Fixes: #196072
Added:
Modified:
clang-tools-extra/clangd/ClangdLSPServer.cpp
clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 245419dda9151..6e40a5278502c 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -1797,9 +1797,9 @@ bool ClangdLSPServer::shouldRunCompletion(
auto Offset = positionToOffset(*Code, Params.position,
/*AllowColumnsBeyondLineLength=*/false);
if (!Offset) {
- vlog("could not convert position '{0}' to offset for file '{1}'",
- Params.position, Params.textDocument.uri.file());
- return true;
+ elog("could not convert position '{0}' to offset for file '{1}': {2}",
+ Params.position, Params.textDocument.uri.file(), Offset.takeError());
+ return false;
}
return allowImplicitCompletion(*Code, *Offset);
}
diff --git a/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp b/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp
index 95bf5e54fc792..0aca1433614dc 100644
--- a/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp
@@ -492,6 +492,26 @@ TEST_F(LSPTest, DiagModuleTest) {
EXPECT_THAT(Client.diagnostics("foo.cpp"),
llvm::ValueIs(testing::ElementsAre(diagMessage(DiagMsg))));
}
+
+// Regression test for https://github.com/llvm/llvm-project/issues/196072.
+TEST_F(LSPTest, CompletionOutOfRangePosition) {
+ auto &Client = start();
+ Client.didOpen("foo.cpp", "int x;");
+ auto &Reply = Client.call(
+ "textDocument/completion",
+ llvm::json::Object{
+ {"textDocument", Client.documentID("foo.cpp")},
+ {"position", llvm::json::Object{{"line", 97}, {"character", 0}}},
+ {"context",
+ llvm::json::Object{
+ {"triggerKind", 2},
+ {"triggerCharacter", ">"},
+ }},
+ });
+ auto Result = Reply.take();
+ ASSERT_TRUE(!!Result) << "Expected a response, not a server crash";
+}
+
} // namespace
} // namespace clangd
} // namespace clang