Index: clangd/ClangdLSPServer.h =================================================================== --- clangd/ClangdLSPServer.h +++ clangd/ClangdLSPServer.h @@ -39,7 +39,9 @@ /// opened in binary mode. Output will be written using Out variable passed to /// class constructor. This method must not be executed more than once for /// each instance of ClangdLSPServer. - void run(std::istream &In); + /// + /// \return Wether we received a 'shutdown' request before an 'exit' request + bool run(std::istream &In); private: // Implement DiagnosticsConsumer. @@ -50,6 +52,7 @@ // Implement ProtocolCallbacks. void onInitialize(Ctx C, InitializeParams &Params) override; void onShutdown(Ctx C, ShutdownParams &Params) override; + void onExit(Ctx C, ExitParams& Params) override; void onDocumentDidOpen(Ctx C, DidOpenTextDocumentParams &Params) override; void onDocumentDidChange(Ctx C, DidChangeTextDocumentParams &Params) override; void onDocumentDidClose(Ctx C, DidCloseTextDocumentParams &Params) override; @@ -79,6 +82,10 @@ JSONOutput &Out; /// Used to indicate that the 'shutdown' request was received from the /// Language Server client. + bool ShutdownRequestReceived = false; + + /// Used to indicate that the 'exit' notification was received from the + /// Language Server client. /// It's used to break out of the LSP parsing loop. bool IsDone = false; Index: clangd/ClangdLSPServer.cpp =================================================================== --- clangd/ClangdLSPServer.cpp +++ clangd/ClangdLSPServer.cpp @@ -56,9 +56,14 @@ } void ClangdLSPServer::onShutdown(Ctx C, ShutdownParams &Params) { - IsDone = true; + // Before we reply, we could serialize the preambles to disk. For now, let's + // just say we're ready to exit. + ShutdownRequestReceived = true; + C.reply("null"); } +void ClangdLSPServer::onExit(Ctx C, ExitParams &Params) { IsDone = true; } + void ClangdLSPServer::onDocumentDidOpen(Ctx C, DidOpenTextDocumentParams &Params) { if (Params.metadata && !Params.metadata->extraFlags.empty()) @@ -195,7 +200,7 @@ Server(CDB, /*DiagConsumer=*/*this, FSProvider, AsyncThreadsCount, SnippetCompletions, /*Logger=*/Out, ResourceDir) {} -void ClangdLSPServer::run(std::istream &In) { +bool ClangdLSPServer::run(std::istream &In) { assert(!IsDone && "Run was called before"); // Set up JSONRPCDispatcher. @@ -211,6 +216,8 @@ // Make sure IsDone is set to true after this method exits to ensure assertion // at the start of the method fires if it's ever executed again. IsDone = true; + + return ShutdownRequestReceived; } std::vector Index: clangd/Protocol.h =================================================================== --- clangd/Protocol.h +++ clangd/Protocol.h @@ -173,6 +173,7 @@ } }; using ShutdownParams = NoParams; +using ExitParams = NoParams; struct InitializeParams { /// The process Id of the parent process that started Index: clangd/ProtocolHandlers.h =================================================================== --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -34,6 +34,7 @@ virtual void onInitialize(Ctx C, InitializeParams &Params) = 0; virtual void onShutdown(Ctx C, ShutdownParams &Params) = 0; + virtual void onExit(Ctx C, ExitParams& Params) = 0; virtual void onDocumentDidOpen(Ctx C, DidOpenTextDocumentParams &Params) = 0; virtual void onDocumentDidChange(Ctx C, DidChangeTextDocumentParams &Params) = 0; Index: clangd/ProtocolHandlers.cpp =================================================================== --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -52,6 +52,7 @@ Register("initialize", &ProtocolCallbacks::onInitialize); Register("shutdown", &ProtocolCallbacks::onShutdown); + Register("exit", &ProtocolCallbacks::onExit); Register("textDocument/didOpen", &ProtocolCallbacks::onDocumentDidOpen); Register("textDocument/didClose", &ProtocolCallbacks::onDocumentDidClose); Register("textDocument/didChange", &ProtocolCallbacks::onDocumentDidChange); Index: clangd/tool/ClangdMain.cpp =================================================================== --- clangd/tool/ClangdMain.cpp +++ clangd/tool/ClangdMain.cpp @@ -114,5 +114,5 @@ /// Initialize and run ClangdLSPServer. ClangdLSPServer LSPServer(Out, WorkerThreadsCount, EnableSnippets, ResourceDirRef, CompileCommandsDirPath); - LSPServer.run(std::cin); + return LSPServer.run(std::cin) ? 0 : 1; } Index: test/clangd/authority-less-uri.test =================================================================== --- test/clangd/authority-less-uri.test +++ test/clangd/authority-less-uri.test @@ -30,3 +30,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":3,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":3,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/completion-priorities.test =================================================================== --- test/clangd/completion-priorities.test +++ test/clangd/completion-priorities.test @@ -34,3 +34,7 @@ Content-Length: 58 {"jsonrpc":"2.0","id":4,"method":"shutdown","params":null} +# CHECK: {"jsonrpc":"2.0","id":4,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/completion-qualifiers.test =================================================================== --- test/clangd/completion-qualifiers.test +++ test/clangd/completion-qualifiers.test @@ -16,3 +16,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":4,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":4,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/completion-snippet.test =================================================================== --- test/clangd/completion-snippet.test +++ test/clangd/completion-snippet.test @@ -52,3 +52,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":4,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":4,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/completion.test =================================================================== --- test/clangd/completion.test +++ test/clangd/completion.test @@ -52,3 +52,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":4,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":4,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/definitions.test =================================================================== --- test/clangd/definitions.test +++ test/clangd/definitions.test @@ -166,3 +166,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":3,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":3,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/diagnostics-preamble.test =================================================================== --- test/clangd/diagnostics-preamble.test +++ test/clangd/diagnostics-preamble.test @@ -13,3 +13,7 @@ Content-Length: 58 {"jsonrpc":"2.0","id":2,"method":"shutdown","params":null} +# CHECK: {"jsonrpc":"2.0","id":2,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/diagnostics.test =================================================================== --- test/clangd/diagnostics.test +++ test/clangd/diagnostics.test @@ -15,3 +15,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":5,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":5,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/did-change-watch-files.test =================================================================== --- test/clangd/did-change-watch-files.test +++ test/clangd/did-change-watch-files.test @@ -59,3 +59,6 @@ Content-Length: 44 {"jsonrpc":"2.0","id":3,"method":"shutdown"} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/extra-flags.test =================================================================== --- test/clangd/extra-flags.test +++ test/clangd/extra-flags.test @@ -18,5 +18,9 @@ Content-Length: 44 {"jsonrpc":"2.0","id":5,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":5,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/fixits.test =================================================================== --- test/clangd/fixits.test +++ test/clangd/fixits.test @@ -26,3 +26,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":3,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":3,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/formatting.test =================================================================== --- test/clangd/formatting.test +++ test/clangd/formatting.test @@ -65,3 +65,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":6,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":6,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/initialize-params-invalid.test =================================================================== --- test/clangd/initialize-params-invalid.test +++ test/clangd/initialize-params-invalid.test @@ -20,3 +20,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":3,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":3,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/initialize-params.test =================================================================== --- test/clangd/initialize-params.test +++ test/clangd/initialize-params.test @@ -20,3 +20,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":3,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":3,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/input-mirror.test =================================================================== --- test/clangd/input-mirror.test +++ test/clangd/input-mirror.test @@ -152,3 +152,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":3,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":3,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/signature-help.test =================================================================== --- test/clangd/signature-help.test +++ test/clangd/signature-help.test @@ -40,3 +40,7 @@ Content-Length: 49 {"jsonrpc":"2.0","id":100000,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":100000,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"} Index: test/clangd/unsupported-method.test =================================================================== --- test/clangd/unsupported-method.test +++ test/clangd/unsupported-method.test @@ -17,3 +17,7 @@ Content-Length: 44 {"jsonrpc":"2.0","id":2,"method":"shutdown"} +# CHECK: {"jsonrpc":"2.0","id":2,"result":null} +Content-Length: 33 + +{"jsonrpc":"2.0":"method":"exit"}