Index: clangd/ClangdLSPServer.h =================================================================== --- clangd/ClangdLSPServer.h +++ clangd/ClangdLSPServer.h @@ -113,6 +113,10 @@ void reparseOpenedFiles(); void applyConfiguration(const ConfigurationSettings &Settings); + /// Sends a "publishDiagnostics" notification to the LSP client. + void publishDiagnostics(const URIForFile &File, + std::vector Diagnostics); + /// Used to indicate that the 'shutdown' request was received from the /// Language Server client. bool ShutdownRequestReceived = false; Index: clangd/ClangdLSPServer.cpp =================================================================== --- clangd/ClangdLSPServer.cpp +++ clangd/ClangdLSPServer.cpp @@ -536,6 +536,17 @@ PathRef File = Params.textDocument.uri.file(); DraftMgr.removeDraft(File); Server->removeDocument(File); + + { + std::lock_guard Lock(FixItsMutex); + FixItsMap.erase(File); + } + // clangd will not send updates for this file anymore, so we empty out the + // list of diagnostics shown on the client (e.g. in the "Problems" pane of + // VSCode). Note that this cannot race with actual diagnostics responses + // because removeDocument() guarantees no diagnostic callbacks will be + // executed after it returns. + publishDiagnostics(URIForFile::canonicalize(File, /*TUPath=*/File), {}); } void ClangdLSPServer::onDocumentOnTypeFormatting( @@ -836,6 +847,16 @@ reparseOpenedFiles(); } +void ClangdLSPServer::publishDiagnostics( + const URIForFile &File, std::vector Diagnostics) { + // Publish diagnostics. + notify("textDocument/publishDiagnostics", + llvm::json::Object{ + {"uri", File}, + {"diagnostics", std::move(Diagnostics)}, + }); +} + // FIXME: This function needs to be properly tested. void ClangdLSPServer::onChangeConfiguration( const DidChangeConfigurationParams &Params) { @@ -978,17 +999,12 @@ // Cache FixIts { - // FIXME(ibiryukov): should be deleted when documents are removed std::lock_guard Lock(FixItsMutex); FixItsMap[File] = LocalFixIts; } - // Publish diagnostics. - notify("textDocument/publishDiagnostics", - llvm::json::Object{ - {"uri", URI}, - {"diagnostics", std::move(LSPDiagnostics)}, - }); + // Send a notification to the LSP client. + publishDiagnostics(URI, std::move(LSPDiagnostics)); } void ClangdLSPServer::onFileUpdated(PathRef File, const TUStatus &Status) { Index: test/clangd/diagnostics.test =================================================================== --- test/clangd/diagnostics.test +++ test/clangd/diagnostics.test @@ -23,6 +23,15 @@ # CHECK-NEXT: "uri": "file://{{.*}}/foo.c" # CHECK-NEXT: } --- +{"jsonrpc":"2.0","id":2,"method":"sync","params":null} +--- +{"jsonrpc":"2.0","method":"textDocument/didClose","params":{"textDocument":{"uri":"test:///foo.c"}}} +# CHECK: "method": "textDocument/publishDiagnostics", +# CHECK-NEXT: "params": { +# CHECK-NEXT: "diagnostics": [], +# CHECK-NEXT: "uri": "file://{{.*}}/foo.c" +# CHECK-NEXT: } +--- {"jsonrpc":"2.0","id":5,"method":"shutdown"} --- {"jsonrpc":"2.0","method":"exit"}