diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -369,6 +369,10 @@ } } ParseInputs ParseInput{IP->Command, &TFS, IP->Contents.str()}; + // FIXME: Add traling new line if there is none at eof, workaround a crash, + // see https://github.com/clangd/clangd/issues/332 + if (!IP->Contents.endswith("\n")) + ParseInput.Contents.append("\n"); ParseInput.Index = Index; CodeCompleteOpts.MainFileSignals = IP->Signals; @@ -417,6 +421,10 @@ return CB(error("Failed to parse includes")); ParseInputs ParseInput{IP->Command, &TFS, IP->Contents.str()}; + // FIXME: Add traling new line if there is none at eof, workaround a crash, + // see https://github.com/clangd/clangd/issues/332 + if (!IP->Contents.endswith("\n")) + ParseInput.Contents.append("\n"); ParseInput.Index = Index; CB(clangd::signatureHelp(File, Pos, *PreambleData, ParseInput, DocumentationFormat)); diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -2474,6 +2474,26 @@ )cpp"); } +TEST(CompletionTest, NoCrashOnMissingNewLineAtEOF) { + auto FooCpp = testPath("foo.cpp"); + + MockCompilationDatabase CDB; + MockFS FS; + Annotations F("#pragma ^ // no new line"); + FS.Files[FooCpp] = F.code().str(); + ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); + runAddDocument(Server, FooCpp, F.code()); + // Run completion outside the file range. + EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, F.point(), + clangd::CodeCompleteOptions())) + .Completions, + IsEmpty()); + EXPECT_THAT(cantFail(runSignatureHelp(Server, FooCpp, F.point(), + MarkupKind::PlainText)) + .signatures, + IsEmpty()); +} + TEST(GuessCompletionPrefix, Filters) { for (llvm::StringRef Case : { "[[scope::]][[ident]]^",