diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index cd13e013aa502..b4a5cf337296e 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -518,6 +518,7 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params, if (Params.capabilities.WorkDoneProgress) BackgroundIndexProgressState = BackgroundIndexProgress::Empty; BackgroundIndexSkipCreate = Params.capabilities.ImplicitProgressCreation; + Opts.ImplicitCancellation = !Params.capabilities.CancelsStaleRequests; llvm::json::Object ServerCaps{ {"textDocumentSync", diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 164e387bd4548..e9724e7516aae 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -150,6 +150,8 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB, DynamicIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex() : nullptr), ClangTidyProvider(Opts.ClangTidyProvider), WorkspaceRoot(Opts.WorkspaceRoot), + Transient(Opts.ImplicitCancellation ? TUScheduler::InvalidateOnUpdate + : TUScheduler::NoInvalidation), DirtyFS(std::make_unique(TFS, DraftMgr)) { // Pass a callback into `WorkScheduler` to extract symbols from a newly // parsed file and rebuild the file index synchronously each time an AST @@ -593,7 +595,7 @@ void ClangdServer::enumerateTweaks( }; WorkScheduler->runWithAST("EnumerateTweaks", File, std::move(Action), - TUScheduler::InvalidateOnUpdate); + Transient); } void ClangdServer::applyTweak(PathRef File, Range Sel, StringRef TweakID, @@ -683,8 +685,7 @@ void ClangdServer::findDocumentHighlights( CB(clangd::findDocumentHighlights(InpAST->AST, Pos)); }; - WorkScheduler->runWithAST("Highlights", File, std::move(Action), - TUScheduler::InvalidateOnUpdate); + WorkScheduler->runWithAST("Highlights", File, std::move(Action), Transient); } void ClangdServer::findHover(PathRef File, Position Pos, @@ -698,8 +699,7 @@ void ClangdServer::findHover(PathRef File, Position Pos, CB(clangd::getHover(InpAST->AST, Pos, std::move(Style), Index)); }; - WorkScheduler->runWithAST("Hover", File, std::move(Action), - TUScheduler::InvalidateOnUpdate); + WorkScheduler->runWithAST("Hover", File, std::move(Action), Transient); } void ClangdServer::typeHierarchy(PathRef File, Position Pos, int Resolve, @@ -771,7 +771,7 @@ void ClangdServer::documentSymbols(llvm::StringRef File, CB(clangd::getDocumentSymbols(InpAST->AST)); }; WorkScheduler->runWithAST("DocumentSymbols", File, std::move(Action), - TUScheduler::InvalidateOnUpdate); + Transient); } void ClangdServer::foldingRanges(llvm::StringRef File, @@ -783,7 +783,7 @@ void ClangdServer::foldingRanges(llvm::StringRef File, CB(clangd::getFoldingRanges(InpAST->AST)); }; WorkScheduler->runWithAST("FoldingRanges", File, std::move(Action), - TUScheduler::InvalidateOnUpdate); + Transient); } void ClangdServer::findImplementations( @@ -850,7 +850,7 @@ void ClangdServer::documentLinks(PathRef File, CB(clangd::getDocumentLinks(InpAST->AST)); }; WorkScheduler->runWithAST("DocumentLinks", File, std::move(Action), - TUScheduler::InvalidateOnUpdate); + Transient); } void ClangdServer::semanticHighlights( @@ -862,7 +862,7 @@ void ClangdServer::semanticHighlights( CB(clangd::getSemanticHighlightings(InpAST->AST)); }; WorkScheduler->runWithAST("SemanticHighlights", File, std::move(Action), - TUScheduler::InvalidateOnUpdate); + Transient); } void ClangdServer::getAST(PathRef File, Range R, diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h index e76ef65922ee0..b633d31396837 100644 --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -146,6 +146,12 @@ class ClangdServer { /*RebuildRatio=*/1, }; + /// Cancel certain requests if the file changes before they begin running. + /// This is useful for "transient" actions like enumerateTweaks that were + /// likely implicitly generated, and avoids redundant work if clients forget + /// to cancel. Clients that always cancel stale requests should clear this. + bool ImplicitCancellation = true; + /// Clangd will execute compiler drivers matching one of these globs to /// fetch system include path. std::vector QueryDriverGlobs; @@ -391,6 +397,8 @@ class ClangdServer { llvm::Optional WorkspaceRoot; llvm::Optional WorkScheduler; + // Invalidation policy used for actions that we assume are "transient". + TUScheduler::ASTActionInvalidation Transient; // Store of the current versions of the open documents. // Only written from the main thread (despite being threadsafe). diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp index b3ff124df4de7..42ca721ebcbb5 100644 --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -414,6 +414,12 @@ bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R, if (auto Implicit = Window->getBoolean("implicitWorkDoneProgressCreate")) R.ImplicitProgressCreation = *Implicit; } + if (auto *General = O->getObject("general")) { + if (auto *StaleRequestSupport = General->getObject("staleRequestSupport")) { + if (auto Cancel = StaleRequestSupport->getBoolean("cancel")) + R.CancelsStaleRequests = *Cancel; + } + } if (auto *OffsetEncoding = O->get("offsetEncoding")) { R.offsetEncoding.emplace(); if (!fromJSON(*OffsetEncoding, *R.offsetEncoding, diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index c6074abcb04e9..1334ddf4b5ce7 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -475,6 +475,10 @@ struct ClientCapabilities { /// window.implicitWorkDoneProgressCreate bool ImplicitProgressCreation = false; + /// Whether the client claims to cancel stale requests. + /// general.staleRequestSupport.cancel + bool CancelsStaleRequests = false; + /// Whether the client implementation supports a refresh request sent from the /// server to the client. bool SemanticTokenRefreshSupport = false;