ilya-biryukov created this revision.

https://reviews.llvm.org/D40486

Files:
  clangd/ClangdLSPServer.cpp
  clangd/ClangdServer.cpp
  clangd/ClangdServer.h
  clangd/ClangdUnit.cpp
  clangd/ClangdUnit.h
  clangd/ClangdUnitStore.cpp
  clangd/ClangdUnitStore.h
  clangd/GlobalCompilationDatabase.cpp
  clangd/GlobalCompilationDatabase.h
  clangd/JSONRPCDispatcher.cpp
  clangd/JSONRPCDispatcher.h
  clangd/Logger.cpp
  clangd/Logger.h
  clangd/Protocol.cpp
  clangd/Protocol.h
  clangd/ProtocolHandlers.cpp
  clangd/tool/ClangdMain.cpp
  unittests/clangd/ClangdTests.cpp

Index: unittests/clangd/ClangdTests.cpp
===================================================================
--- unittests/clangd/ClangdTests.cpp
+++ unittests/clangd/ClangdTests.cpp
@@ -9,7 +9,7 @@
 
 #include "ClangdLSPServer.h"
 #include "ClangdServer.h"
-#include "Logger.h"
+#include "Context.h"
 #include "clang/Basic/VirtualFileSystem.h"
 #include "clang/Config/config.h"
 #include "llvm/ADT/SmallVector.h"
@@ -133,8 +133,11 @@
 } // namespace vfs
 
 namespace clangd {
+
 namespace {
 
+Context emptyCtx() { return buildCtx(); }
+
 struct StringWithPos {
   std::string Text;
   clangd::Position MarkerPos;
@@ -333,8 +336,7 @@
     MockCompilationDatabase CDB(/*AddFreestandingFlag=*/true);
     ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
                         /*StorePreamblesInMemory=*/true,
-                        clangd::CodeCompleteOptions(),
-                        EmptyLogger::getInstance());
+                        clangd::CodeCompleteOptions());
     for (const auto &FileWithContents : ExtraFiles)
       FS.Files[getVirtualTestFilePath(FileWithContents.first)] =
           FileWithContents.second;
@@ -345,7 +347,8 @@
 
     // Have to sync reparses because requests are processed on the calling
     // thread.
-    auto AddDocFuture = Server.addDocument(SourceFilename, SourceContents);
+    auto AddDocFuture =
+        Server.addDocument(SourceFilename, SourceContents, emptyCtx());
 
     auto Result = dumpASTWithoutMemoryLocs(Server, SourceFilename);
 
@@ -398,8 +401,7 @@
   MockCompilationDatabase CDB(/*AddFreestandingFlag=*/true);
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
                       /*StorePreamblesInMemory=*/true,
-                      clangd::CodeCompleteOptions(),
-                      EmptyLogger::getInstance());
+                      clangd::CodeCompleteOptions());
 
   const auto SourceContents = R"cpp(
 #include "foo.h"
@@ -416,19 +418,19 @@
   // To sync reparses before checking for errors.
   std::future<void> ParseFuture;
 
-  ParseFuture = Server.addDocument(FooCpp, SourceContents);
+  ParseFuture = Server.addDocument(FooCpp, SourceContents, emptyCtx());
   auto DumpParse1 = dumpASTWithoutMemoryLocs(Server, FooCpp);
   ASSERT_EQ(ParseFuture.wait_for(DefaultFutureTimeout),
             std::future_status::ready);
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
 
-  ParseFuture = Server.addDocument(FooCpp, "");
+  ParseFuture = Server.addDocument(FooCpp, "", emptyCtx());
   auto DumpParseEmpty = dumpASTWithoutMemoryLocs(Server, FooCpp);
   ASSERT_EQ(ParseFuture.wait_for(DefaultFutureTimeout),
             std::future_status::ready);
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
 
-  ParseFuture = Server.addDocument(FooCpp, SourceContents);
+  ParseFuture = Server.addDocument(FooCpp, SourceContents, emptyCtx());
   auto DumpParse2 = dumpASTWithoutMemoryLocs(Server, FooCpp);
   ASSERT_EQ(ParseFuture.wait_for(DefaultFutureTimeout),
             std::future_status::ready);
@@ -445,8 +447,7 @@
 
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
                       /*StorePreamblesInMemory=*/true,
-                      clangd::CodeCompleteOptions(),
-                      EmptyLogger::getInstance());
+                      clangd::CodeCompleteOptions());
 
   const auto SourceContents = R"cpp(
 #include "foo.h"
@@ -463,21 +464,21 @@
   // To sync reparses before checking for errors.
   std::future<void> ParseFuture;
 
-  ParseFuture = Server.addDocument(FooCpp, SourceContents);
+  ParseFuture = Server.addDocument(FooCpp, SourceContents, emptyCtx());
   auto DumpParse1 = dumpASTWithoutMemoryLocs(Server, FooCpp);
   ASSERT_EQ(ParseFuture.wait_for(DefaultFutureTimeout),
             std::future_status::ready);
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
 
   FS.Files[FooH] = "";
-  ParseFuture = Server.forceReparse(FooCpp);
+  ParseFuture = Server.forceReparse(FooCpp, emptyCtx());
   auto DumpParseDifferent = dumpASTWithoutMemoryLocs(Server, FooCpp);
   ASSERT_EQ(ParseFuture.wait_for(DefaultFutureTimeout),
             std::future_status::ready);
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
 
   FS.Files[FooH] = "int a;";
-  ParseFuture = Server.forceReparse(FooCpp);
+  ParseFuture = Server.forceReparse(FooCpp, emptyCtx());
   auto DumpParse2 = dumpASTWithoutMemoryLocs(Server, FooCpp);
   EXPECT_EQ(ParseFuture.wait_for(DefaultFutureTimeout),
             std::future_status::ready);
@@ -495,8 +496,7 @@
   ClangdServer Server(CDB, DiagConsumer, FS,
                       /*AsyncThreadsCount=*/0,
                       /*StorePreamblesInMemory=*/true,
-                      clangd::CodeCompleteOptions(),
-                      EmptyLogger::getInstance());
+                      clangd::CodeCompleteOptions());
 
   auto FooCpp = getVirtualTestFilePath("foo.cpp");
   const auto SourceContents = "int a;";
@@ -506,14 +506,16 @@
   // No need to sync reparses, because requests are processed on the calling
   // thread.
   FS.Tag = "123";
-  Server.addDocument(FooCpp, SourceContents);
-  EXPECT_EQ(Server.codeComplete(FooCpp, Position{0, 0}).get().Tag, FS.Tag);
+  Server.addDocument(FooCpp, SourceContents, emptyCtx());
+  EXPECT_EQ(Server.codeComplete(FooCpp, Position{0, 0}, globalCtx()).get().Tag,
+            FS.Tag);
   EXPECT_EQ(DiagConsumer.lastVFSTag(), FS.Tag);
 
   FS.Tag = "321";
-  Server.addDocument(FooCpp, SourceContents);
+  Server.addDocument(FooCpp, SourceContents, emptyCtx());
   EXPECT_EQ(DiagConsumer.lastVFSTag(), FS.Tag);
-  EXPECT_EQ(Server.codeComplete(FooCpp, Position{0, 0}).get().Tag, FS.Tag);
+  EXPECT_EQ(Server.codeComplete(FooCpp, Position{0, 0}, globalCtx()).get().Tag,
+            FS.Tag);
 }
 
 // Only enable this test on Unix
@@ -531,8 +533,7 @@
   ClangdServer Server(CDB, DiagConsumer, FS,
                       /*AsyncThreadsCount=*/0,
                       /*StorePreamblesInMemory=*/true,
-                      clangd::CodeCompleteOptions(),
-                      EmptyLogger::getInstance());
+                      clangd::CodeCompleteOptions());
 
   // Just a random gcc version string
   SmallString<8> Version("4.9.3");
@@ -563,14 +564,14 @@
 
   // No need to sync reparses, because requests are processed on the calling
   // thread.
-  Server.addDocument(FooCpp, SourceContents);
+  Server.addDocument(FooCpp, SourceContents, emptyCtx());
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
 
   const auto SourceContentsWithError = R"cpp(
 #include <string>
 std::string x;
 )cpp";
-  Server.addDocument(FooCpp, SourceContentsWithError);
+  Server.addDocument(FooCpp, SourceContentsWithError, emptyCtx());
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
 }
 #endif // LLVM_ON_UNIX
@@ -582,8 +583,7 @@
   ClangdServer Server(CDB, DiagConsumer, FS,
                       /*AsyncThreadsCount=*/0,
                       /*StorePreamblesInMemory=*/true,
-                      clangd::CodeCompleteOptions(),
-                      EmptyLogger::getInstance());
+                      clangd::CodeCompleteOptions());
   // No need to sync reparses, because reparses are performed on the calling
   // thread to true.
 
@@ -602,26 +602,26 @@
 
   // First parse files in C mode and check they produce errors.
   CDB.ExtraClangFlags = {"-xc"};
-  Server.addDocument(FooCpp, SourceContents1);
+  Server.addDocument(FooCpp, SourceContents1, emptyCtx());
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
-  Server.addDocument(FooCpp, SourceContents2);
+  Server.addDocument(FooCpp, SourceContents2, emptyCtx());
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
 
   // Now switch to C++ mode.
   CDB.ExtraClangFlags = {"-xc++"};
   // Currently, addDocument never checks if CompileCommand has changed, so we
   // expect to see the errors.
-  Server.addDocument(FooCpp, SourceContents1);
+  Server.addDocument(FooCpp, SourceContents1, emptyCtx());
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
-  Server.addDocument(FooCpp, SourceContents2);
+  Server.addDocument(FooCpp, SourceContents2, emptyCtx());
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
   // But forceReparse should reparse the file with proper flags.
-  Server.forceReparse(FooCpp);
+  Server.forceReparse(FooCpp, emptyCtx());
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
   // Subsequent addDocument calls should finish without errors too.
-  Server.addDocument(FooCpp, SourceContents1);
+  Server.addDocument(FooCpp, SourceContents1, emptyCtx());
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
-  Server.addDocument(FooCpp, SourceContents2);
+  Server.addDocument(FooCpp, SourceContents2, emptyCtx());
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
 }
 
@@ -651,8 +651,7 @@
 
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
                       /*StorePreamblesInMemory=*/true,
-                      clangd::CodeCompleteOptions(),
-                      EmptyLogger::getInstance());
+                      clangd::CodeCompleteOptions());
 
   auto FooCpp = getVirtualTestFilePath("foo.cpp");
   const auto SourceContents = R"cpp(
@@ -675,19 +674,19 @@
 
   // No need to sync reparses here as there are no asserts on diagnostics (or
   // other async operations).
-  Server.addDocument(FooCpp, SourceContents);
+  Server.addDocument(FooCpp, SourceContents, emptyCtx());
 
   {
     auto CodeCompletionResults1 =
-        Server.codeComplete(FooCpp, CompletePos, None).get().Value;
+        Server.codeComplete(FooCpp, CompletePos, globalCtx(), None).get().Value;
     EXPECT_TRUE(ContainsItem(CodeCompletionResults1, "aba"));
     EXPECT_FALSE(ContainsItem(CodeCompletionResults1, "cbc"));
   }
 
   {
     auto CodeCompletionResultsOverriden =
         Server
-            .codeComplete(FooCpp, CompletePos,
+            .codeComplete(FooCpp, CompletePos, globalCtx(),
                           StringRef(OverridenSourceContents))
             .get()
             .Value;
@@ -697,7 +696,7 @@
 
   {
     auto CodeCompletionResults2 =
-        Server.codeComplete(FooCpp, CompletePos, None).get().Value;
+        Server.codeComplete(FooCpp, CompletePos, globalCtx(), None).get().Value;
     EXPECT_TRUE(ContainsItem(CodeCompletionResults2, "aba"));
     EXPECT_FALSE(ContainsItem(CodeCompletionResults2, "cbc"));
   }
@@ -711,8 +710,7 @@
   clangd::CodeCompleteOptions Opts;
   Opts.Limit = 2;
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
-                      /*StorePreamblesInMemory=*/true, Opts,
-                      EmptyLogger::getInstance());
+                      /*StorePreamblesInMemory=*/true, Opts);
 
   auto FooCpp = getVirtualTestFilePath("foo.cpp");
   FS.Files[FooCpp] = "";
@@ -726,11 +724,11 @@
 int main() { ClassWithMembers().{complete} }
       )cpp",
                                              "complete");
-  Server.addDocument(FooCpp, Completion.Text);
+  Server.addDocument(FooCpp, Completion.Text, emptyCtx());
 
   /// For after-dot completion we must always get consistent results.
   auto Results = Server
-                     .codeComplete(FooCpp, Completion.MarkerPos,
+                     .codeComplete(FooCpp, Completion.MarkerPos, globalCtx(),
                                    StringRef(Completion.Text))
                      .get()
                      .Value;
@@ -809,23 +807,23 @@
 
   auto TestWithOpts = [&](clangd::CodeCompleteOptions Opts) {
     ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
-                        /*StorePreamblesInMemory=*/true, Opts,
-                        EmptyLogger::getInstance());
+                        /*StorePreamblesInMemory=*/true, Opts);
     // No need to sync reparses here as there are no asserts on diagnostics (or
     // other async operations).
-    Server.addDocument(FooCpp, GlobalCompletion.Text);
+    Server.addDocument(FooCpp, GlobalCompletion.Text, emptyCtx());
 
     StringRef MethodItemText = Opts.EnableSnippets ? "method()" : "method";
     StringRef GlobalFuncItemText =
         Opts.EnableSnippets ? "global_func()" : "global_func";
 
     /// For after-dot completion we must always get consistent results.
     {
-      auto Results = Server
-                         .codeComplete(FooCpp, MemberCompletion.MarkerPos,
-                                       StringRef(MemberCompletion.Text))
-                         .get()
-                         .Value;
+      auto Results =
+          Server
+              .codeComplete(FooCpp, MemberCompletion.MarkerPos, globalCtx(),
+                            StringRef(MemberCompletion.Text))
+              .get()
+              .Value;
 
       // Class members. The only items that must be present in after-dor
       // completion.
@@ -857,11 +855,12 @@
     }
     // Global completion differs based on the Opts that were passed.
     {
-      auto Results = Server
-                         .codeComplete(FooCpp, GlobalCompletion.MarkerPos,
-                                       StringRef(GlobalCompletion.Text))
-                         .get()
-                         .Value;
+      auto Results =
+          Server
+              .codeComplete(FooCpp, GlobalCompletion.MarkerPos, globalCtx(),
+                            StringRef(GlobalCompletion.Text))
+              .get()
+              .Value;
 
       // Class members. Should never be present in global completions.
       EXPECT_FALSE(ContainsItem(Results, MethodItemText));
@@ -895,13 +894,13 @@
   };
 
   clangd::CodeCompleteOptions CCOpts;
-  for (bool IncludeMacros : {true, false}){
+  for (bool IncludeMacros : {true, false}) {
     CCOpts.IncludeMacros = IncludeMacros;
-    for (bool IncludeGlobals : {true, false}){
+    for (bool IncludeGlobals : {true, false}) {
       CCOpts.IncludeGlobals = IncludeGlobals;
-      for (bool IncludeBriefComments : {true, false}){
+      for (bool IncludeBriefComments : {true, false}) {
         CCOpts.IncludeBriefComments = IncludeBriefComments;
-        for (bool EnableSnippets : {true, false}){
+        for (bool EnableSnippets : {true, false}) {
           CCOpts.EnableSnippets = EnableSnippets;
           for (bool IncludeCodePatterns : {true, false}) {
             CCOpts.IncludeCodePatterns = IncludeCodePatterns;
@@ -1015,8 +1014,7 @@
     MockCompilationDatabase CDB(/*AddFreestandingFlag=*/true);
     ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
                         /*StorePreamblesInMemory=*/true,
-                        clangd::CodeCompleteOptions(),
-                        EmptyLogger::getInstance());
+                        clangd::CodeCompleteOptions());
 
     // Prepare some random distributions for the test.
     std::random_device RandGen;
@@ -1064,9 +1062,11 @@
 
     auto AddDocument = [&](unsigned FileIndex) {
       bool ShouldHaveErrors = ShouldHaveErrorsDist(RandGen);
-      auto Future = Server.addDocument(
-          FilePaths[FileIndex], ShouldHaveErrors ? SourceContentsWithErrors
-                                                 : SourceContentsWithoutErrors);
+      auto Future =
+          Server.addDocument(FilePaths[FileIndex],
+                             ShouldHaveErrors ? SourceContentsWithErrors
+                                              : SourceContentsWithoutErrors,
+                             emptyCtx());
       UpdateStatsOnAddDocument(FileIndex, ShouldHaveErrors, std::move(Future));
     };
 
@@ -1082,7 +1082,7 @@
       if (ReqStats[FileIndex].FileIsRemoved)
         AddDocument(FileIndex);
 
-      auto Future = Server.forceReparse(FilePaths[FileIndex]);
+      auto Future = Server.forceReparse(FilePaths[FileIndex], emptyCtx());
       UpdateStatsOnForceReparse(FileIndex, std::move(Future));
     };
 
@@ -1092,7 +1092,7 @@
       if (ReqStats[FileIndex].FileIsRemoved)
         AddDocument(FileIndex);
 
-      auto Future = Server.removeDocument(FilePaths[FileIndex]);
+      auto Future = Server.removeDocument(FilePaths[FileIndex], emptyCtx());
       UpdateStatsOnRemoveDocument(FileIndex, std::move(Future));
     };
 
@@ -1109,7 +1109,7 @@
       // requests as opposed to AddDocument/RemoveDocument, which are implicitly
       // cancelled by any subsequent AddDocument/RemoveDocument request to the
       // same file.
-      Server.codeComplete(FilePaths[FileIndex], Pos).wait();
+      Server.codeComplete(FilePaths[FileIndex], Pos, globalCtx()).wait();
     };
 
     auto FindDefinitionsRequest = [&]() {
@@ -1119,7 +1119,8 @@
         AddDocument(FileIndex);
 
       Position Pos{LineDist(RandGen), ColumnDist(RandGen)};
-      ASSERT_TRUE(!!Server.findDefinitions(FilePaths[FileIndex], Pos));
+      ASSERT_TRUE(
+          !!Server.findDefinitions(FilePaths[FileIndex], Pos, globalCtx()));
     };
 
     std::vector<std::function<void()>> AsyncRequests = {
@@ -1176,8 +1177,7 @@
 
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
                       /*StorePreamblesInMemory=*/true,
-                      clangd::CodeCompleteOptions(),
-                      EmptyLogger::getInstance());
+                      clangd::CodeCompleteOptions());
 
   auto SourceContents = R"cpp(
   #include "foo.h"
@@ -1303,12 +1303,12 @@
 
   MockCompilationDatabase CDB(/*AddFreestandingFlag=*/true);
   ClangdServer Server(CDB, DiagConsumer, FS, 4, /*StorePreamblesInMemory=*/true,
-                      clangd::CodeCompleteOptions(),
-                      EmptyLogger::getInstance());
-  Server.addDocument(FooCpp, SourceContentsWithErrors);
+                      clangd::CodeCompleteOptions());
+  Server.addDocument(FooCpp, SourceContentsWithErrors, emptyCtx());
   StartSecondReparse.wait();
 
-  auto Future = Server.addDocument(FooCpp, SourceContentsWithoutErrors);
+  auto Future =
+      Server.addDocument(FooCpp, SourceContentsWithoutErrors, emptyCtx());
   Future.wait();
 }
 
Index: clangd/tool/ClangdMain.cpp
===================================================================
--- clangd/tool/ClangdMain.cpp
+++ clangd/tool/ClangdMain.cpp
@@ -134,6 +134,8 @@
                  InputMirrorStream ? InputMirrorStream.getPointer() : nullptr,
                  PrettyPrint);
 
+  GlobalSession Session(buildCtx().add(Logger::CtxKey, &Out));
+
   // If --compile-commands-dir arg was invoked, check value and override default
   // path.
   llvm::Optional<Path> CompileCommandsDirPath;
@@ -172,8 +174,7 @@
   CCOpts.IncludeIneligibleResults = IncludeIneligibleResults;
   // Initialize and run ClangdLSPServer.
   ClangdLSPServer LSPServer(Out, WorkerThreadsCount, StorePreamblesInMemory,
-                            CCOpts, ResourceDirRef,
-                            CompileCommandsDirPath);
+                            CCOpts, ResourceDirRef, CompileCommandsDirPath);
   constexpr int NoShutdownRequestErrorCode = 1;
   llvm::set_thread_name("clangd.main");
   return LSPServer.run(std::cin) ? 0 : NoShutdownRequestErrorCode;
Index: clangd/ProtocolHandlers.cpp
===================================================================
--- clangd/ProtocolHandlers.cpp
+++ clangd/ProtocolHandlers.cpp
@@ -27,17 +27,16 @@
   void operator()(StringRef Method,
                   void (ProtocolCallbacks::*Handler)(RequestContext, Param)) {
     // Capture pointers by value, as the lambda will outlive this object.
-    auto *Out = this->Out;
     auto *Callbacks = this->Callbacks;
     Dispatcher.registerHandler(
         Method, [=](RequestContext C, llvm::yaml::MappingNode *RawParams) {
           if (auto P = [&] {
                 trace::Span Tracer("Parse");
-                return std::decay<Param>::type::parse(RawParams, *Out);
+                return std::decay<Param>::type::parse(RawParams, C.ctx());
               }()) {
             (Callbacks->*Handler)(std::move(C), *P);
           } else {
-            Out->log("Failed to decode " + Method + " request.\n");
+            log(C.ctx(), "Failed to decode " + Method + " request.\n");
           }
         });
   }
Index: clangd/Protocol.h
===================================================================
--- clangd/Protocol.h
+++ clangd/Protocol.h
@@ -21,6 +21,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_PROTOCOL_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PROTOCOL_H
 
+#include "Context.h"
 #include "JSONExpr.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/Support/YAMLParser.h"
@@ -75,7 +76,7 @@
   URI uri;
 
   static llvm::Optional<TextDocumentIdentifier>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 struct Position {
@@ -95,7 +96,7 @@
   }
 
   static llvm::Optional<Position> parse(llvm::yaml::MappingNode *Params,
-                                        clangd::Logger &Logger);
+                                        Context &Ctx);
   static json::Expr unparse(const Position &P);
 };
 
@@ -114,7 +115,7 @@
   }
 
   static llvm::Optional<Range> parse(llvm::yaml::MappingNode *Params,
-                                     clangd::Logger &Logger);
+                                     Context &Ctx);
   static json::Expr unparse(const Range &P);
 };
 
@@ -142,7 +143,7 @@
   std::vector<std::string> extraFlags;
 
   static llvm::Optional<Metadata> parse(llvm::yaml::MappingNode *Params,
-                                        clangd::Logger &Logger);
+                                        Context &Ctx);
 };
 
 struct TextEdit {
@@ -155,7 +156,7 @@
   std::string newText;
 
   static llvm::Optional<TextEdit> parse(llvm::yaml::MappingNode *Params,
-                                        clangd::Logger &Logger);
+                                        Context &Ctx);
   static json::Expr unparse(const TextEdit &P);
 };
 
@@ -173,7 +174,7 @@
   std::string text;
 
   static llvm::Optional<TextDocumentItem> parse(llvm::yaml::MappingNode *Params,
-                                                clangd::Logger &Logger);
+                                                Context &Ctx);
 };
 
 enum class TraceLevel {
@@ -184,7 +185,7 @@
 
 struct NoParams {
   static llvm::Optional<NoParams> parse(llvm::yaml::MappingNode *Params,
-                                        Logger &Logger) {
+                                        Context &Ctx) {
     return NoParams{};
   }
 };
@@ -219,7 +220,7 @@
   /// The initial trace setting. If omitted trace is disabled ('off').
   llvm::Optional<TraceLevel> trace;
   static llvm::Optional<InitializeParams> parse(llvm::yaml::MappingNode *Params,
-                                                clangd::Logger &Logger);
+                                                Context &Ctx);
 };
 
 struct DidOpenTextDocumentParams {
@@ -230,23 +231,23 @@
   llvm::Optional<Metadata> metadata;
 
   static llvm::Optional<DidOpenTextDocumentParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 struct DidCloseTextDocumentParams {
   /// The document that was closed.
   TextDocumentIdentifier textDocument;
 
   static llvm::Optional<DidCloseTextDocumentParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 struct TextDocumentContentChangeEvent {
   /// The new text of the document.
   std::string text;
 
   static llvm::Optional<TextDocumentContentChangeEvent>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 struct DidChangeTextDocumentParams {
@@ -259,7 +260,7 @@
   std::vector<TextDocumentContentChangeEvent> contentChanges;
 
   static llvm::Optional<DidChangeTextDocumentParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 enum class FileChangeType {
@@ -278,15 +279,15 @@
   FileChangeType type;
 
   static llvm::Optional<FileEvent> parse(llvm::yaml::MappingNode *Params,
-                                         clangd::Logger &Logger);
+                                         Context &Ctx);
 };
 
 struct DidChangeWatchedFilesParams {
   /// The actual file events.
   std::vector<FileEvent> changes;
 
   static llvm::Optional<DidChangeWatchedFilesParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 struct FormattingOptions {
@@ -297,7 +298,7 @@
   bool insertSpaces;
 
   static llvm::Optional<FormattingOptions>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
   static json::Expr unparse(const FormattingOptions &P);
 };
 
@@ -312,7 +313,7 @@
   FormattingOptions options;
 
   static llvm::Optional<DocumentRangeFormattingParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 struct DocumentOnTypeFormattingParams {
@@ -329,7 +330,7 @@
   FormattingOptions options;
 
   static llvm::Optional<DocumentOnTypeFormattingParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 struct DocumentFormattingParams {
@@ -340,7 +341,7 @@
   FormattingOptions options;
 
   static llvm::Optional<DocumentFormattingParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 struct Diagnostic {
@@ -373,15 +374,15 @@
   }
 
   static llvm::Optional<Diagnostic> parse(llvm::yaml::MappingNode *Params,
-                                          clangd::Logger &Logger);
+                                          Context &Ctx);
 };
 
 struct CodeActionContext {
   /// An array of diagnostics.
   std::vector<Diagnostic> diagnostics;
 
   static llvm::Optional<CodeActionContext>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 struct CodeActionParams {
@@ -395,7 +396,7 @@
   CodeActionContext context;
 
   static llvm::Optional<CodeActionParams> parse(llvm::yaml::MappingNode *Params,
-                                                clangd::Logger &Logger);
+                                                Context &Ctx);
 };
 
 struct WorkspaceEdit {
@@ -406,7 +407,7 @@
   /// no support for versioned edits.
 
   static llvm::Optional<WorkspaceEdit> parse(llvm::yaml::MappingNode *Params,
-                                             clangd::Logger &Logger);
+                                             Context &Ctx);
   static json::Expr unparse(const WorkspaceEdit &WE);
 };
 
@@ -430,7 +431,7 @@
   llvm::Optional<WorkspaceEdit> workspaceEdit;
 
   static llvm::Optional<ExecuteCommandParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 struct ApplyWorkspaceEditParams {
@@ -446,7 +447,7 @@
   Position position;
 
   static llvm::Optional<TextDocumentPositionParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(llvm::yaml::MappingNode *Params, Context &Ctx);
 };
 
 /// The kind of a completion entry.
@@ -612,7 +613,7 @@
   std::string newName;
 
   static llvm::Optional<RenameParams> parse(llvm::yaml::MappingNode *Params,
-                                            clangd::Logger &Logger);
+                                            Context &Ctx);
 };
 
 } // namespace clangd
Index: clangd/Protocol.cpp
===================================================================
--- clangd/Protocol.cpp
+++ clangd/Protocol.cpp
@@ -26,8 +26,8 @@
 using namespace clang::clangd;
 
 namespace {
-void logIgnoredField(llvm::StringRef KeyValue, clangd::Logger &Logger) {
-  Logger.log(llvm::formatv("Ignored unknown field \"{0}\"\n", KeyValue));
+void logIgnoredField(llvm::StringRef KeyValue, Context &Ctx) {
+  log(Ctx, llvm::formatv("Ignored unknown field \"{0}\"\n", KeyValue));
 }
 } // namespace
 
@@ -66,8 +66,7 @@
 json::Expr URI::unparse(const URI &U) { return U.uri; }
 
 llvm::Optional<TextDocumentIdentifier>
-TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params,
-                              clangd::Logger &Logger) {
+TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params, Context &Ctx) {
   TextDocumentIdentifier Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -86,14 +85,14 @@
     } else if (KeyValue == "version") {
       // FIXME: parse version, but only for VersionedTextDocumentIdentifiers.
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<Position> Position::parse(llvm::yaml::MappingNode *Params,
-                                         clangd::Logger &Logger) {
+                                         Context &Ctx) {
   Position Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -119,7 +118,7 @@
         return llvm::None;
       Result.character = Val;
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
@@ -133,7 +132,7 @@
 }
 
 llvm::Optional<Range> Range::parse(llvm::yaml::MappingNode *Params,
-                                   clangd::Logger &Logger) {
+                                   Context &Ctx) {
   Range Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -149,17 +148,17 @@
 
     llvm::SmallString<10> Storage;
     if (KeyValue == "start") {
-      auto Parsed = Position::parse(Value, Logger);
+      auto Parsed = Position::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.start = std::move(*Parsed);
     } else if (KeyValue == "end") {
-      auto Parsed = Position::parse(Value, Logger);
+      auto Parsed = Position::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.end = std::move(*Parsed);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
@@ -180,8 +179,7 @@
 }
 
 llvm::Optional<TextDocumentItem>
-TextDocumentItem::parse(llvm::yaml::MappingNode *Params,
-                        clangd::Logger &Logger) {
+TextDocumentItem::parse(llvm::yaml::MappingNode *Params, Context &Ctx) {
   TextDocumentItem Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -208,14 +206,14 @@
     } else if (KeyValue == "text") {
       Result.text = Value->getValue(Storage);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<Metadata> Metadata::parse(llvm::yaml::MappingNode *Params,
-                                         clangd::Logger &Logger) {
+                                         Context &Ctx) {
   Metadata Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -238,14 +236,14 @@
         Result.extraFlags.push_back(Node->getValue(Storage));
       }
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<TextEdit> TextEdit::parse(llvm::yaml::MappingNode *Params,
-                                         clangd::Logger &Logger) {
+                                         Context &Ctx) {
   TextEdit Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -261,7 +259,7 @@
       auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
       if (!Map)
         return llvm::None;
-      auto Parsed = Range::parse(Map, Logger);
+      auto Parsed = Range::parse(Map, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.range = std::move(*Parsed);
@@ -271,7 +269,7 @@
         return llvm::None;
       Result.newText = Node->getValue(Storage);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
@@ -285,26 +283,24 @@
 }
 
 namespace {
-TraceLevel getTraceLevel(llvm::StringRef TraceLevelStr,
-                         clangd::Logger &Logger) {
+TraceLevel getTraceLevel(llvm::StringRef TraceLevelStr, Context &Ctx) {
   if (TraceLevelStr == "off")
     return TraceLevel::Off;
   else if (TraceLevelStr == "messages")
     return TraceLevel::Messages;
   else if (TraceLevelStr == "verbose")
     return TraceLevel::Verbose;
 
-  Logger.log(llvm::formatv("Unknown trace level \"{0}\"\n", TraceLevelStr));
+  log(Ctx, llvm::formatv("Unknown trace level \"{0}\"\n", TraceLevelStr));
   return TraceLevel::Off;
 }
 } // namespace
 
 llvm::Optional<InitializeParams>
-InitializeParams::parse(llvm::yaml::MappingNode *Params,
-                        clangd::Logger &Logger) {
+InitializeParams::parse(llvm::yaml::MappingNode *Params, Context &Ctx) {
   // If we don't understand the params, proceed with default parameters.
   auto ParseFailure = [&] {
-    Logger.log("Failed to decode InitializeParams\n");
+    log(Ctx, "Failed to decode InitializeParams\n");
     return InitializeParams();
   };
   InitializeParams Result;
@@ -338,17 +334,17 @@
     } else if (KeyValue == "capabilities") {
       // Not used
     } else if (KeyValue == "trace") {
-      Result.trace = getTraceLevel(Value->getValue(KeyStorage), Logger);
+      Result.trace = getTraceLevel(Value->getValue(KeyStorage), Ctx);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<DidOpenTextDocumentParams>
 DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
-                                 clangd::Logger &Logger) {
+                                 Context &Ctx) {
   DidOpenTextDocumentParams Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -364,25 +360,25 @@
 
     llvm::SmallString<10> Storage;
     if (KeyValue == "textDocument") {
-      auto Parsed = TextDocumentItem::parse(Value, Logger);
+      auto Parsed = TextDocumentItem::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.textDocument = std::move(*Parsed);
     } else if (KeyValue == "metadata") {
-      auto Parsed = Metadata::parse(Value, Logger);
+      auto Parsed = Metadata::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.metadata = std::move(*Parsed);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<DidCloseTextDocumentParams>
 DidCloseTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
-                                  clangd::Logger &Logger) {
+                                  Context &Ctx) {
   DidCloseTextDocumentParams Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -397,20 +393,20 @@
       auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
       if (!Map)
         return llvm::None;
-      auto Parsed = TextDocumentIdentifier::parse(Map, Logger);
+      auto Parsed = TextDocumentIdentifier::parse(Map, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.textDocument = std::move(*Parsed);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<DidChangeTextDocumentParams>
 DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
-                                   clangd::Logger &Logger) {
+                                   Context &Ctx) {
   DidChangeTextDocumentParams Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -426,7 +422,7 @@
       auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
       if (!Map)
         return llvm::None;
-      auto Parsed = TextDocumentIdentifier::parse(Map, Logger);
+      auto Parsed = TextDocumentIdentifier::parse(Map, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.textDocument = std::move(*Parsed);
@@ -438,20 +434,20 @@
         auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
         if (!I)
           return llvm::None;
-        auto Parsed = TextDocumentContentChangeEvent::parse(I, Logger);
+        auto Parsed = TextDocumentContentChangeEvent::parse(I, Ctx);
         if (!Parsed)
           return llvm::None;
         Result.contentChanges.push_back(std::move(*Parsed));
       }
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<FileEvent> FileEvent::parse(llvm::yaml::MappingNode *Params,
-                                           clangd::Logger &Logger) {
+                                           Context &Ctx) {
   llvm::Optional<FileEvent> Result = FileEvent();
   for (auto &NextKeyValue : *Params) {
     // We have to consume the whole MappingNode because it doesn't support
@@ -487,15 +483,15 @@
           Result->type > FileChangeType::Deleted)
         Result.reset();
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<DidChangeWatchedFilesParams>
 DidChangeWatchedFilesParams::parse(llvm::yaml::MappingNode *Params,
-                                   clangd::Logger &Logger) {
+                                   Context &Ctx) {
   DidChangeWatchedFilesParams Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -515,22 +511,22 @@
         auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
         if (!I)
           return llvm::None;
-        auto Parsed = FileEvent::parse(I, Logger);
+        auto Parsed = FileEvent::parse(I, Ctx);
         if (Parsed)
           Result.changes.push_back(std::move(*Parsed));
         else
-          Logger.log("Failed to decode a FileEvent.\n");
+          log(Ctx, "Failed to decode a FileEvent.\n");
       }
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<TextDocumentContentChangeEvent>
 TextDocumentContentChangeEvent::parse(llvm::yaml::MappingNode *Params,
-                                      clangd::Logger &Logger) {
+                                      Context &Ctx) {
   TextDocumentContentChangeEvent Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -548,15 +544,14 @@
     if (KeyValue == "text") {
       Result.text = Value->getValue(Storage);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<FormattingOptions>
-FormattingOptions::parse(llvm::yaml::MappingNode *Params,
-                         clangd::Logger &Logger) {
+FormattingOptions::parse(llvm::yaml::MappingNode *Params, Context &Ctx) {
   FormattingOptions Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -589,7 +584,7 @@
       }
       Result.insertSpaces = Val;
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
@@ -604,7 +599,7 @@
 
 llvm::Optional<DocumentRangeFormattingParams>
 DocumentRangeFormattingParams::parse(llvm::yaml::MappingNode *Params,
-                                     clangd::Logger &Logger) {
+                                     Context &Ctx) {
   DocumentRangeFormattingParams Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -620,30 +615,30 @@
 
     llvm::SmallString<10> Storage;
     if (KeyValue == "textDocument") {
-      auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
+      auto Parsed = TextDocumentIdentifier::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.textDocument = std::move(*Parsed);
     } else if (KeyValue == "range") {
-      auto Parsed = Range::parse(Value, Logger);
+      auto Parsed = Range::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.range = std::move(*Parsed);
     } else if (KeyValue == "options") {
-      auto Parsed = FormattingOptions::parse(Value, Logger);
+      auto Parsed = FormattingOptions::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.options = std::move(*Parsed);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<DocumentOnTypeFormattingParams>
 DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params,
-                                      clangd::Logger &Logger) {
+                                      Context &Ctx) {
   DocumentOnTypeFormattingParams Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -668,30 +663,29 @@
     if (!Value)
       return llvm::None;
     if (KeyValue == "textDocument") {
-      auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
+      auto Parsed = TextDocumentIdentifier::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.textDocument = std::move(*Parsed);
     } else if (KeyValue == "position") {
-      auto Parsed = Position::parse(Value, Logger);
+      auto Parsed = Position::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.position = std::move(*Parsed);
     } else if (KeyValue == "options") {
-      auto Parsed = FormattingOptions::parse(Value, Logger);
+      auto Parsed = FormattingOptions::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.options = std::move(*Parsed);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<DocumentFormattingParams>
-DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params,
-                                clangd::Logger &Logger) {
+DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params, Context &Ctx) {
   DocumentFormattingParams Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -707,24 +701,24 @@
 
     llvm::SmallString<10> Storage;
     if (KeyValue == "textDocument") {
-      auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
+      auto Parsed = TextDocumentIdentifier::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.textDocument = std::move(*Parsed);
     } else if (KeyValue == "options") {
-      auto Parsed = FormattingOptions::parse(Value, Logger);
+      auto Parsed = FormattingOptions::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.options = std::move(*Parsed);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<Diagnostic> Diagnostic::parse(llvm::yaml::MappingNode *Params,
-                                             clangd::Logger &Logger) {
+                                             Context &Ctx) {
   Diagnostic Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -740,7 +734,7 @@
           dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
       if (!Value)
         return llvm::None;
-      auto Parsed = Range::parse(Value, Logger);
+      auto Parsed = Range::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.range = std::move(*Parsed);
@@ -764,15 +758,14 @@
         return llvm::None;
       Result.message = Value->getValue(Storage);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<CodeActionContext>
-CodeActionContext::parse(llvm::yaml::MappingNode *Params,
-                         clangd::Logger &Logger) {
+CodeActionContext::parse(llvm::yaml::MappingNode *Params, Context &Ctx) {
   CodeActionContext Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -792,21 +785,20 @@
         auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
         if (!I)
           return llvm::None;
-        auto Parsed = Diagnostic::parse(I, Logger);
+        auto Parsed = Diagnostic::parse(I, Ctx);
         if (!Parsed)
           return llvm::None;
         Result.diagnostics.push_back(std::move(*Parsed));
       }
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<CodeActionParams>
-CodeActionParams::parse(llvm::yaml::MappingNode *Params,
-                        clangd::Logger &Logger) {
+CodeActionParams::parse(llvm::yaml::MappingNode *Params, Context &Ctx) {
   CodeActionParams Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -822,30 +814,29 @@
 
     llvm::SmallString<10> Storage;
     if (KeyValue == "textDocument") {
-      auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
+      auto Parsed = TextDocumentIdentifier::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.textDocument = std::move(*Parsed);
     } else if (KeyValue == "range") {
-      auto Parsed = Range::parse(Value, Logger);
+      auto Parsed = Range::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.range = std::move(*Parsed);
     } else if (KeyValue == "context") {
-      auto Parsed = CodeActionContext::parse(Value, Logger);
+      auto Parsed = CodeActionContext::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.context = std::move(*Parsed);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
 }
 
 llvm::Optional<std::map<std::string, std::vector<TextEdit>>>
-parseWorkspaceEditChange(llvm::yaml::MappingNode *Params,
-                         clangd::Logger &Logger) {
+parseWorkspaceEditChange(llvm::yaml::MappingNode *Params, Context &Ctx) {
   std::map<std::string, std::vector<TextEdit>> Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -855,7 +846,7 @@
     llvm::SmallString<10> KeyStorage;
     StringRef KeyValue = KeyString->getValue(KeyStorage);
     if (Result.count(KeyValue)) {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
       continue;
     }
 
@@ -867,7 +858,7 @@
       auto *ItemValue = dyn_cast_or_null<llvm::yaml::MappingNode>(&Item);
       if (!ItemValue)
         return llvm::None;
-      auto Parsed = TextEdit::parse(ItemValue, Logger);
+      auto Parsed = TextEdit::parse(ItemValue, Ctx);
       if (!Parsed)
         return llvm::None;
 
@@ -879,7 +870,7 @@
 }
 
 llvm::Optional<WorkspaceEdit>
-WorkspaceEdit::parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger) {
+WorkspaceEdit::parse(llvm::yaml::MappingNode *Params, Context &Ctx) {
   WorkspaceEdit Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -895,12 +886,12 @@
           dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
       if (!Value)
         return llvm::None;
-      auto Parsed = parseWorkspaceEditChange(Value, Logger);
+      auto Parsed = parseWorkspaceEditChange(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.changes = std::move(*Parsed);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
@@ -910,8 +901,7 @@
     "clangd.applyFix";
 
 llvm::Optional<ExecuteCommandParams>
-ExecuteCommandParams::parse(llvm::yaml::MappingNode *Params,
-                            clangd::Logger &Logger) {
+ExecuteCommandParams::parse(llvm::yaml::MappingNode *Params, Context &Ctx) {
   ExecuteCommandParams Result;
   // Depending on which "command" we parse, we will use this function to parse
   // the command "arguments".
@@ -935,8 +925,8 @@
       llvm::SmallString<10> Storage;
       Result.command = ScalarValue->getValue(Storage);
       if (Result.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
-        ArgParser = [&Result, &Logger](llvm::yaml::MappingNode *Params) {
-          auto WE = WorkspaceEdit::parse(Params, Logger);
+        ArgParser = [&Result, &Ctx](llvm::yaml::MappingNode *Params) {
+          auto WE = WorkspaceEdit::parse(Params, Ctx);
           if (WE)
             Result.workspaceEdit = WE;
           return WE.hasValue();
@@ -957,7 +947,7 @@
           return llvm::None;
       }
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   if (Result.command.empty())
@@ -982,7 +972,7 @@
 
 llvm::Optional<TextDocumentPositionParams>
 TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params,
-                                  clangd::Logger &Logger) {
+                                  Context &Ctx) {
   TextDocumentPositionParams Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -998,17 +988,17 @@
 
     llvm::SmallString<10> Storage;
     if (KeyValue == "textDocument") {
-      auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
+      auto Parsed = TextDocumentIdentifier::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.textDocument = std::move(*Parsed);
     } else if (KeyValue == "position") {
-      auto Parsed = Position::parse(Value, Logger);
+      auto Parsed = Position::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.position = std::move(*Parsed);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
@@ -1082,7 +1072,7 @@
 }
 
 llvm::Optional<RenameParams>
-RenameParams::parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger) {
+RenameParams::parse(llvm::yaml::MappingNode *Params, Context &Ctx) {
   RenameParams Result;
   for (auto &NextKeyValue : *Params) {
     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -1100,16 +1090,16 @@
       auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
       if (!Map)
         return llvm::None;
-      auto Parsed = TextDocumentIdentifier::parse(Map, Logger);
+      auto Parsed = TextDocumentIdentifier::parse(Map, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.textDocument = std::move(*Parsed);
     } else if (KeyValue == "position") {
       auto *Value =
           dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
       if (!Value)
         continue;
-      auto Parsed = Position::parse(Value, Logger);
+      auto Parsed = Position::parse(Value, Ctx);
       if (!Parsed)
         return llvm::None;
       Result.position = std::move(*Parsed);
@@ -1123,7 +1113,7 @@
       llvm::SmallString<10> Storage;
       Result.newName = Node->getValue(Storage);
     } else {
-      logIgnoredField(KeyValue, Logger);
+      logIgnoredField(KeyValue, Ctx);
     }
   }
   return Result;
Index: clangd/Logger.h
===================================================================
--- clangd/Logger.h
+++ clangd/Logger.h
@@ -10,29 +10,24 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_LOGGER_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_LOGGER_H
 
+#include "Context.h"
 #include "llvm/ADT/Twine.h"
 
 namespace clang {
 namespace clangd {
 
+/// Main logging function. Logs messages to a Logger inside \p Ctx.
+void log(Context &Ctx, const llvm::Twine &Message);
+
 /// Interface to allow custom logging in clangd.
 class Logger {
 public:
+  static PtrKey<Logger> CtxKey;
+
   virtual ~Logger() = default;
 
   /// Implementations of this method must be thread-safe.
-  virtual void log(const llvm::Twine &Message) = 0;
-};
-
-/// Logger implementation that ignores all messages.
-class EmptyLogger : public Logger {
-public:
-  static EmptyLogger &getInstance();
-
-  void log(const llvm::Twine &Message) override;
-
-private:
-  EmptyLogger() = default;
+  virtual void logImpl(Context &Ctx, const llvm::Twine &Message) = 0;
 };
 
 } // namespace clangd
Index: clangd/Logger.cpp
===================================================================
--- clangd/Logger.cpp
+++ clangd/Logger.cpp
@@ -9,11 +9,17 @@
 
 #include "Logger.h"
 
-using namespace clang::clangd;
+namespace clang {
+namespace clangd {
 
-EmptyLogger &EmptyLogger::getInstance() {
-  static EmptyLogger Logger;
-  return Logger;
+PtrKey<Logger> Logger::CtxKey;
+
+void log(Context &Ctx, const llvm::Twine &Message) {
+  Logger *Logger = Ctx.get(Logger::CtxKey);
+  if (!Logger)
+    return;
+  Logger->logImpl(Ctx, Message);
 }
 
-void EmptyLogger::log(const llvm::Twine &Message) {}
+} // namespace clangd
+} // namespace clang
Index: clangd/JSONRPCDispatcher.h
===================================================================
--- clangd/JSONRPCDispatcher.h
+++ clangd/JSONRPCDispatcher.h
@@ -10,6 +10,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSONRPCDISPATCHER_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSONRPCDISPATCHER_H
 
+#include "Context.h"
 #include "JSONExpr.h"
 #include "Logger.h"
 #include "Protocol.h"
@@ -37,7 +38,7 @@
 
   /// Write to the logging stream.
   /// No newline is implicitly added. (TODO: we should fix this!)
-  void log(const Twine &Message) override;
+  void logImpl(Context &Ctx, const Twine &Message) override;
 
   /// Mirror \p Message into InputMirror stream. Does nothing if InputMirror is
   /// null.
@@ -56,9 +57,9 @@
 /// Context object passed to handlers to allow replies.
 class RequestContext {
 public:
-  RequestContext(JSONOutput &Out, StringRef Method,
+  RequestContext(Context Ctx, JSONOutput &Out, StringRef Method,
                  llvm::Optional<json::Expr> ID)
-      : Out(Out), ID(std::move(ID)),
+      : Ctx(std::move(Ctx)), Out(Out), ID(std::move(ID)),
         Tracer(llvm::make_unique<trace::Span>(Method)) {
     if (this->ID)
       SPAN_ATTACH(tracer(), "ID", *this->ID);
@@ -72,8 +73,10 @@
   void call(llvm::StringRef Method, json::Expr &&Params);
 
   trace::Span &tracer() { return *Tracer; }
+  Context &ctx() { return Ctx; }
 
 private:
+  Context Ctx;
   JSONOutput &Out;
   llvm::Optional<json::Expr> ID;
   std::unique_ptr<trace::Span> Tracer;
Index: clangd/JSONRPCDispatcher.cpp
===================================================================
--- clangd/JSONRPCDispatcher.cpp
+++ clangd/JSONRPCDispatcher.cpp
@@ -39,7 +39,8 @@
   Outs.flush();
 }
 
-void JSONOutput::log(const Twine &Message) {
+void JSONOutput::logImpl(Context &Ctx, const Twine &Message) {
+  // FIXME(ibiryukov): get rid of trace::log here.
   trace::log(Message);
   std::lock_guard<std::mutex> Guard(StreamMutex);
   Logs << Message;
@@ -56,7 +57,7 @@
 
 void RequestContext::reply(json::Expr &&Result) {
   if (!ID) {
-    Out.log("Attempted to reply to a notification!\n");
+    log(Ctx, "Attempted to reply to a notification!\n");
     return;
   }
   SPAN_ATTACH(tracer(), "Reply", Result);
@@ -69,7 +70,7 @@
 
 void RequestContext::replyError(ErrorCode code,
                                 const llvm::StringRef &Message) {
-  Out.log("Error " + Twine(static_cast<int>(code)) + ": " + Message + "\n");
+  log(Ctx, "Error " + Twine(static_cast<int>(code)) + ": " + Message + "\n");
   SPAN_ATTACH(tracer(), "Error",
               (json::obj{{"code", static_cast<int>(code)},
                          {"message", Message.str()}}));
@@ -110,7 +111,9 @@
   llvm::StringRef MethodStr = Method->getValue(MethodStorage);
   auto I = Handlers.find(MethodStr);
   auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;
-  Handler(RequestContext(Out, MethodStr, std::move(ID)), Params);
+  Handler(
+      RequestContext(buildCtx(), Out, MethodStr, std::move(ID)),
+      Params);
 }
 
 bool JSONRPCDispatcher::call(StringRef Content, JSONOutput &Out) const {
@@ -224,9 +227,10 @@
       // The end of headers is signified by an empty line.
       if (LineRef.consume_front("Content-Length: ")) {
         if (ContentLength != 0) {
-          Out.log("Warning: Duplicate Content-Length header received. "
-                  "The previous value for this message (" +
-                  std::to_string(ContentLength) + ") was ignored.\n");
+          log(globalCtx(), "Warning: Duplicate Content-Length header received. "
+                           "The previous value for this message (" +
+                               std::to_string(ContentLength) +
+                               ") was ignored.\n");
         }
 
         llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength);
@@ -245,8 +249,8 @@
     // and we don't want to crash downstream because of it.
     if (ContentLength > 1 << 30) { // 1024M
       In.ignore(ContentLength);
-      Out.log("Skipped overly large message of " + Twine(ContentLength) +
-              " bytes.\n");
+      log(globalCtx(), "Skipped overly large message of " +
+                           Twine(ContentLength) + " bytes.\n");
       continue;
     }
 
@@ -262,28 +266,30 @@
         // If the stream is aborted before we read ContentLength bytes, In
         // will have eofbit and failbit set.
         if (!In) {
-          Out.log("Input was aborted. Read only " +
-                  std::to_string(In.gcount()) + " bytes of expected " +
-                  std::to_string(ContentLength) + ".\n");
+          log(globalCtx(), "Input was aborted. Read only " +
+                               std::to_string(In.gcount()) +
+                               " bytes of expected " +
+                               std::to_string(ContentLength) + ".\n");
           break;
         }
 
         JSONRef = StringRef(JSON.data(), ContentLength);
       }
 
       // Log the message.
-      Out.log("<-- " + JSONRef + "\n");
+      log(globalCtx(), "<-- " + JSONRef + "\n");
 
       // Finally, execute the action for this JSON message.
       if (!Dispatcher.call(JSONRef, Out))
-        Out.log("JSON dispatch failed!\n");
+        log(globalCtx(), "JSON dispatch failed!\n");
 
       // If we're done, exit the loop.
       if (IsDone)
         break;
     } else {
-      Out.log("Warning: Missing Content-Length header, or message has zero "
-              "length.\n");
+      log(globalCtx(),
+          "Warning: Missing Content-Length header, or message has zero "
+          "length.\n");
     }
   }
 }
Index: clangd/GlobalCompilationDatabase.h
===================================================================
--- clangd/GlobalCompilationDatabase.h
+++ clangd/GlobalCompilationDatabase.h
@@ -48,7 +48,7 @@
     : public GlobalCompilationDatabase {
 public:
   DirectoryBasedGlobalCompilationDatabase(
-      clangd::Logger &Logger, llvm::Optional<Path> CompileCommandsDir);
+      llvm::Optional<Path> CompileCommandsDir);
 
   std::vector<tooling::CompileCommand>
   getCompileCommands(PathRef File) override;
@@ -67,8 +67,6 @@
 
   /// Stores extra flags per file.
   llvm::StringMap<std::vector<std::string>> ExtraFlagsForFile;
-  /// Used for logging.
-  clangd::Logger &Logger;
   /// Used for command argument pointing to folder where compile_commands.json
   /// is located.
   llvm::Optional<Path> CompileCommandsDir;
Index: clangd/GlobalCompilationDatabase.cpp
===================================================================
--- clangd/GlobalCompilationDatabase.cpp
+++ clangd/GlobalCompilationDatabase.cpp
@@ -39,8 +39,8 @@
 
 DirectoryBasedGlobalCompilationDatabase::
     DirectoryBasedGlobalCompilationDatabase(
-        clangd::Logger &Logger, llvm::Optional<Path> CompileCommandsDir)
-    : Logger(Logger), CompileCommandsDir(std::move(CompileCommandsDir)) {}
+        llvm::Optional<Path> CompileCommandsDir)
+    : CompileCommandsDir(std::move(CompileCommandsDir)) {}
 
 std::vector<tooling::CompileCommand>
 DirectoryBasedGlobalCompilationDatabase::getCompileCommands(PathRef File) {
@@ -99,9 +99,9 @@
     tooling::CompilationDatabase *ReturnValue =
         tryLoadDatabaseFromPath(CompileCommandsDir.getValue());
     if (ReturnValue == nullptr)
-      Logger.log("Failed to find compilation database for " + Twine(File) +
-                 "in overriden directory " + CompileCommandsDir.getValue() +
-                 "\n");
+      log(globalCtx(), "Failed to find compilation database for " +
+                           Twine(File) + "in overriden directory " +
+                           CompileCommandsDir.getValue() + "\n");
     return ReturnValue;
   }
 
@@ -114,7 +114,8 @@
     return CDB;
   }
 
-  Logger.log("Failed to find compilation database for " + Twine(File) + "\n");
+  log(globalCtx(),
+      "Failed to find compilation database for " + Twine(File) + "\n");
   return nullptr;
 }
 
Index: clangd/ClangdUnitStore.h
===================================================================
--- clangd/ClangdUnitStore.h
+++ clangd/ClangdUnitStore.h
@@ -14,6 +14,7 @@
 
 #include "ClangdUnit.h"
 #include "GlobalCompilationDatabase.h"
+#include "Logger.h"
 #include "Path.h"
 #include "clang/Tooling/CompilationDatabase.h"
 
@@ -28,8 +29,7 @@
   std::shared_ptr<CppFile>
   getOrCreateFile(PathRef File, PathRef ResourceDir,
                   GlobalCompilationDatabase &CDB, bool StorePreamblesInMemory,
-                  std::shared_ptr<PCHContainerOperations> PCHs,
-                  clangd::Logger &Logger) {
+                  std::shared_ptr<PCHContainerOperations> PCHs) {
     std::lock_guard<std::mutex> Lock(Mutex);
 
     auto It = OpenedFiles.find(File);
@@ -39,7 +39,7 @@
       It = OpenedFiles
                .try_emplace(File, CppFile::Create(File, std::move(Command),
                                                   StorePreamblesInMemory,
-                                                  std::move(PCHs), Logger))
+                                                  std::move(PCHs)))
                .first;
     }
     return It->second;
@@ -61,8 +61,8 @@
   /// will be returned in RecreateResult.RemovedFile.
   RecreateResult recreateFileIfCompileCommandChanged(
       PathRef File, PathRef ResourceDir, GlobalCompilationDatabase &CDB,
-      bool StorePreamblesInMemory, std::shared_ptr<PCHContainerOperations> PCHs,
-      clangd::Logger &Logger);
+      bool StorePreamblesInMemory,
+      std::shared_ptr<PCHContainerOperations> PCHs);
 
   std::shared_ptr<CppFile> getFile(PathRef File) {
     std::lock_guard<std::mutex> Lock(Mutex);
Index: clangd/ClangdUnitStore.cpp
===================================================================
--- clangd/ClangdUnitStore.cpp
+++ clangd/ClangdUnitStore.cpp
@@ -29,8 +29,7 @@
 CppFileCollection::RecreateResult
 CppFileCollection::recreateFileIfCompileCommandChanged(
     PathRef File, PathRef ResourceDir, GlobalCompilationDatabase &CDB,
-    bool StorePreamblesInMemory, std::shared_ptr<PCHContainerOperations> PCHs,
-    clangd::Logger &Logger) {
+    bool StorePreamblesInMemory, std::shared_ptr<PCHContainerOperations> PCHs) {
   auto NewCommand = getCompileCommand(CDB, File, ResourceDir);
 
   std::lock_guard<std::mutex> Lock(Mutex);
@@ -42,14 +41,13 @@
     It = OpenedFiles
              .try_emplace(File, CppFile::Create(File, std::move(NewCommand),
                                                 StorePreamblesInMemory,
-                                                std::move(PCHs), Logger))
+                                                std::move(PCHs)))
              .first;
   } else if (!compileCommandsAreEqual(It->second->getCompileCommand(),
                                       NewCommand)) {
     Result.RemovedFile = std::move(It->second);
-    It->second =
-        CppFile::Create(File, std::move(NewCommand), StorePreamblesInMemory,
-                        std::move(PCHs), Logger);
+    It->second = CppFile::Create(File, std::move(NewCommand),
+                                 StorePreamblesInMemory, std::move(PCHs));
   }
   Result.FileInCollection = It->second;
   return Result;
Index: clangd/ClangdUnit.h
===================================================================
--- clangd/ClangdUnit.h
+++ clangd/ClangdUnit.h
@@ -10,6 +10,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
 
+#include "Context.h"
 #include "Function.h"
 #include "Path.h"
 #include "Protocol.h"
@@ -40,8 +41,6 @@
 
 namespace clangd {
 
-class Logger;
-
 /// A diagnostic with its FixIts.
 struct DiagWithFixIts {
   clangd::Diagnostic Diag;
@@ -69,7 +68,7 @@
         std::shared_ptr<const PreambleData> Preamble,
         std::unique_ptr<llvm::MemoryBuffer> Buffer,
         std::shared_ptr<PCHContainerOperations> PCHs,
-        IntrusiveRefCntPtr<vfs::FileSystem> VFS, clangd::Logger &Logger);
+        IntrusiveRefCntPtr<vfs::FileSystem> VFS, Context &Ctx);
 
   ParsedAST(ParsedAST &&Other);
   ParsedAST &operator=(ParsedAST &&Other);
@@ -146,12 +145,12 @@
   static std::shared_ptr<CppFile>
   Create(PathRef FileName, tooling::CompileCommand Command,
          bool StorePreamblesInMemory,
-         std::shared_ptr<PCHContainerOperations> PCHs, clangd::Logger &Logger);
+         std::shared_ptr<PCHContainerOperations> PCHs);
 
 private:
   CppFile(PathRef FileName, tooling::CompileCommand Command,
           bool StorePreamblesInMemory,
-          std::shared_ptr<PCHContainerOperations> PCHs, clangd::Logger &Logger);
+          std::shared_ptr<PCHContainerOperations> PCHs);
 
 public:
   CppFile(CppFile const &) = delete;
@@ -173,7 +172,8 @@
   /// requested in parallel (effectively cancelling this rebuild) before
   /// diagnostics were produced.
   llvm::Optional<std::vector<DiagWithFixIts>>
-  rebuild(StringRef NewContents, IntrusiveRefCntPtr<vfs::FileSystem> VFS);
+  rebuild(StringRef NewContents, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+          Context &Ctx);
 
   /// Schedule a rebuild and return a deferred computation that will finish the
   /// rebuild, that can be called on a different thread.
@@ -189,7 +189,7 @@
   /// The future to finish rebuild returns a list of diagnostics built during
   /// reparse, or None, if another deferRebuild was called before this
   /// rebuild was finished.
-  UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>()>
+  UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>(Context &)>
   deferRebuild(StringRef NewContents, IntrusiveRefCntPtr<vfs::FileSystem> VFS);
 
   /// Returns a future to get the most fresh PreambleData for a file. The
@@ -252,8 +252,6 @@
   std::shared_ptr<const PreambleData> LatestAvailablePreamble;
   /// Utility class, required by clang.
   std::shared_ptr<PCHContainerOperations> PCHs;
-  /// Used for logging various messages.
-  clangd::Logger &Logger;
 };
 
 struct CodeCompleteOptions {
@@ -291,29 +289,28 @@
 };
 
 /// Get code completions at a specified \p Pos in \p FileName.
-CompletionList
-codeComplete(PathRef FileName, const tooling::CompileCommand &Command,
-             PrecompiledPreamble const *Preamble, StringRef Contents,
-             Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
-             std::shared_ptr<PCHContainerOperations> PCHs,
-             clangd::CodeCompleteOptions Opts, clangd::Logger &Logger);
-
-/// Get signature help at a specified \p Pos in \p FileName.
-SignatureHelp signatureHelp(PathRef FileName,
+CompletionList codeComplete(PathRef FileName,
                             const tooling::CompileCommand &Command,
                             PrecompiledPreamble const *Preamble,
                             StringRef Contents, Position Pos,
                             IntrusiveRefCntPtr<vfs::FileSystem> VFS,
                             std::shared_ptr<PCHContainerOperations> PCHs,
-                            clangd::Logger &Logger);
+                            clangd::CodeCompleteOptions Opts, Context &Ctx);
+
+/// Get signature help at a specified \p Pos in \p FileName.
+SignatureHelp
+signatureHelp(PathRef FileName, const tooling::CompileCommand &Command,
+              PrecompiledPreamble const *Preamble, StringRef Contents,
+              Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+              std::shared_ptr<PCHContainerOperations> PCHs, Context &Ctx);
 
 /// Get the beginning SourceLocation at a specified \p Pos.
 SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos,
                                         const FileEntry *FE);
 
 /// Get definition of symbol at a specified \p Pos.
 std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
-                                      clangd::Logger &Logger);
+                                      Context &Ctx);
 
 /// For testing/debugging purposes. Note that this method deserializes all
 /// unserialized Decls, so use with care.
Index: clangd/ClangdUnit.cpp
===================================================================
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -762,7 +762,7 @@
                         PrecompiledPreamble const *Preamble, StringRef Contents,
                         Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
                         std::shared_ptr<PCHContainerOperations> PCHs,
-                        clangd::Logger &Logger) {
+                        Context &Ctx) {
   std::vector<const char *> ArgStrs;
   for (const auto &S : Command.CommandLine)
     ArgStrs.push_back(S.c_str());
@@ -807,12 +807,12 @@
 
   SyntaxOnlyAction Action;
   if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
-    Logger.log("BeginSourceFile() failed when running codeComplete for " +
-               FileName);
+    log(Ctx,
+        "BeginSourceFile() failed when running codeComplete for " + FileName);
     return false;
   }
   if (!Action.Execute()) {
-    Logger.log("Execute() failed when running codeComplete for " + FileName);
+    log(Ctx, "Execute() failed when running codeComplete for " + FileName);
     return false;
   }
 
@@ -839,7 +839,7 @@
                      PrecompiledPreamble const *Preamble, StringRef Contents,
                      Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
                      std::shared_ptr<PCHContainerOperations> PCHs,
-                     clangd::CodeCompleteOptions Opts, clangd::Logger &Logger) {
+                     clangd::CodeCompleteOptions Opts, Context &Ctx) {
   CompletionList Results;
   std::unique_ptr<CodeCompleteConsumer> Consumer;
   if (Opts.EnableSnippets) {
@@ -851,25 +851,25 @@
   }
   invokeCodeComplete(std::move(Consumer), Opts.getClangCompleteOpts(), FileName,
                      Command, Preamble, Contents, Pos, std::move(VFS),
-                     std::move(PCHs), Logger);
+                     std::move(PCHs), Ctx);
   return Results;
 }
 
 SignatureHelp
 clangd::signatureHelp(PathRef FileName, const tooling::CompileCommand &Command,
                       PrecompiledPreamble const *Preamble, StringRef Contents,
                       Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
                       std::shared_ptr<PCHContainerOperations> PCHs,
-                      clangd::Logger &Logger) {
+                      Context &Ctx) {
   SignatureHelp Result;
   clang::CodeCompleteOptions Options;
   Options.IncludeGlobals = false;
   Options.IncludeMacros = false;
   Options.IncludeCodePatterns = false;
   Options.IncludeBriefComments = true;
   invokeCodeComplete(llvm::make_unique<SignatureHelpCollector>(Options, Result),
                      Options, FileName, Command, Preamble, Contents, Pos,
-                     std::move(VFS), std::move(PCHs), Logger);
+                     std::move(VFS), std::move(PCHs), Ctx);
   return Result;
 }
 
@@ -882,8 +882,7 @@
                  std::shared_ptr<const PreambleData> Preamble,
                  std::unique_ptr<llvm::MemoryBuffer> Buffer,
                  std::shared_ptr<PCHContainerOperations> PCHs,
-                 IntrusiveRefCntPtr<vfs::FileSystem> VFS,
-                 clangd::Logger &Logger) {
+                 IntrusiveRefCntPtr<vfs::FileSystem> VFS, Context &Ctx) {
 
   std::vector<DiagWithFixIts> ASTDiags;
   StoreDiagsConsumer UnitDiagsConsumer(/*ref*/ ASTDiags);
@@ -901,12 +900,12 @@
   auto Action = llvm::make_unique<ClangdFrontendAction>();
   const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0];
   if (!Action->BeginSourceFile(*Clang, MainInput)) {
-    Logger.log("BeginSourceFile() failed when building AST for " +
-               MainInput.getFile());
+    log(Ctx, "BeginSourceFile() failed when building AST for " +
+                 MainInput.getFile());
     return llvm::None;
   }
   if (!Action->Execute())
-    Logger.log("Execute() failed when building AST for " + MainInput.getFile());
+    log(Ctx, "Execute() failed when building AST for " + MainInput.getFile());
 
   // UnitDiagsConsumer is local, we can not store it in CompilerInstance that
   // has a longer lifetime.
@@ -1032,7 +1031,7 @@
 } // namespace
 
 std::vector<Location> clangd::findDefinitions(ParsedAST &AST, Position Pos,
-                                              clangd::Logger &Logger) {
+                                              Context &Ctx) {
   const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
   const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
   if (!FE)
@@ -1135,20 +1134,17 @@
 std::shared_ptr<CppFile>
 CppFile::Create(PathRef FileName, tooling::CompileCommand Command,
                 bool StorePreamblesInMemory,
-                std::shared_ptr<PCHContainerOperations> PCHs,
-                clangd::Logger &Logger) {
-  return std::shared_ptr<CppFile>(new CppFile(FileName, std::move(Command),
-                                              StorePreamblesInMemory,
-                                              std::move(PCHs), Logger));
+                std::shared_ptr<PCHContainerOperations> PCHs) {
+  return std::shared_ptr<CppFile>(new CppFile(
+      FileName, std::move(Command), StorePreamblesInMemory, std::move(PCHs)));
 }
 
 CppFile::CppFile(PathRef FileName, tooling::CompileCommand Command,
                  bool StorePreamblesInMemory,
-                 std::shared_ptr<PCHContainerOperations> PCHs,
-                 clangd::Logger &Logger)
+                 std::shared_ptr<PCHContainerOperations> PCHs)
     : FileName(FileName), Command(std::move(Command)),
       StorePreamblesInMemory(StorePreamblesInMemory), RebuildCounter(0),
-      RebuildInProgress(false), PCHs(std::move(PCHs)), Logger(Logger) {
+      RebuildInProgress(false), PCHs(std::move(PCHs)) {
 
   std::lock_guard<std::mutex> Lock(Mutex);
   LatestAvailablePreamble = nullptr;
@@ -1200,12 +1196,12 @@
 }
 
 llvm::Optional<std::vector<DiagWithFixIts>>
-CppFile::rebuild(StringRef NewContents,
-                 IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
-  return deferRebuild(NewContents, std::move(VFS))();
+CppFile::rebuild(StringRef NewContents, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+                 Context &Ctx) {
+  return deferRebuild(NewContents, std::move(VFS))(Ctx);
 }
 
-UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>()>
+UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>(Context &)>
 CppFile::deferRebuild(StringRef NewContents,
                       IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
   std::shared_ptr<const PreambleData> OldPreamble;
@@ -1242,9 +1238,10 @@
   // Don't let this CppFile die before rebuild is finished.
   std::shared_ptr<CppFile> That = shared_from_this();
   auto FinishRebuild = [OldPreamble, VFS, RequestRebuildCounter, PCHs,
-                        That](std::string NewContents) mutable // 'mutable' to
-                                                               // allow changing
-                                                               // OldPreamble.
+                        That](std::string NewContents,
+                              Context &Ctx) mutable // 'mutable' to
+                                                    // allow changing
+                                                    // OldPreamble.
       -> llvm::Optional<std::vector<DiagWithFixIts>> {
     // Only one execution of this method is possible at a time.
     // RebuildGuard will wait for any ongoing rebuilds to finish and will put us
@@ -1337,9 +1334,8 @@
     {
       trace::Span Tracer("Build");
       SPAN_ATTACH(Tracer, "File", That->FileName);
-      NewAST =
-          ParsedAST::Build(std::move(CI), std::move(NewPreamble),
-                           std::move(ContentsBuffer), PCHs, VFS, That->Logger);
+      NewAST = ParsedAST::Build(std::move(CI), std::move(NewPreamble),
+                                std::move(ContentsBuffer), PCHs, VFS, Ctx);
     }
 
     if (NewAST) {
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -36,8 +36,6 @@
 
 namespace clangd {
 
-class Logger;
-
 /// Turn a [line, column] pair into an offset in Code.
 size_t positionToOffset(StringRef Code, Position P);
 
@@ -204,14 +202,11 @@
   ///
   /// \p StorePreamblesInMemory defines whether the Preambles generated by
   /// clangd are stored in-memory or on disk.
-  ///
-  /// Various messages are logged using \p Logger.
   ClangdServer(GlobalCompilationDatabase &CDB,
                DiagnosticsConsumer &DiagConsumer,
                FileSystemProvider &FSProvider, unsigned AsyncThreadsCount,
                bool StorePreamblesInMemory,
                const clangd::CodeCompleteOptions &CodeCompleteOpts,
-               clangd::Logger &Logger,
                llvm::Optional<StringRef> ResourceDir = llvm::None);
 
   /// Set the root path of the workspace.
@@ -223,17 +218,17 @@
   /// constructor will receive onDiagnosticsReady callback.
   /// \return A future that will become ready when the rebuild (including
   /// diagnostics) is finished.
-  std::future<void> addDocument(PathRef File, StringRef Contents);
+  std::future<void> addDocument(PathRef File, StringRef Contents, Context Ctx);
   /// Remove \p File from list of tracked files, schedule a request to free
   /// resources associated with it.
   /// \return A future that will become ready when the file is removed and all
   /// associated resources are freed.
-  std::future<void> removeDocument(PathRef File);
+  std::future<void> removeDocument(PathRef File, Context Ctx);
   /// Force \p File to be reparsed using the latest contents.
   /// Will also check if CompileCommand, provided by GlobalCompilationDatabase
   /// for \p File has changed. If it has, will remove currently stored Preamble
   /// and AST and rebuild them from scratch.
-  std::future<void> forceReparse(PathRef File);
+  std::future<void> forceReparse(PathRef File, Context Ctx);
 
   /// DEPRECATED. Please use a callback-based version, this API is deprecated
   /// and will soon be removed.
@@ -252,15 +247,20 @@
   /// This method should only be called for currently tracked files. However, it
   /// is safe to call removeDocument for \p File after this method returns, even
   /// while returned future is not yet ready.
+  ///
+  /// The callers are responsible for making sure \p Ctx stays alive until
+  /// std::future<> is ready (i.e. wait() or get() returns)
   std::future<Tagged<CompletionList>>
-  codeComplete(PathRef File, Position Pos,
+  codeComplete(PathRef File, Position Pos, Context &Ctx,
                llvm::Optional<StringRef> OverridenContents = llvm::None,
                IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
 
   /// A version of `codeComplete` that runs \p Callback on the processing thread
   /// when codeComplete results become available.
+  /// The callers are responsible for making sure \p Ctx stays alive until \p
+  /// Callback is executed.
   void codeComplete(UniqueFunction<void(Tagged<CompletionList>)> Callback,
-                    PathRef File, Position Pos,
+                    PathRef File, Position Pos, Context &Ctx,
                     llvm::Optional<StringRef> OverridenContents = llvm::None,
                     IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
 
@@ -272,13 +272,13 @@
   /// vfs::FileSystem used for signature help. This method should only be called
   /// for currently tracked files.
   llvm::Expected<Tagged<SignatureHelp>>
-  signatureHelp(PathRef File, Position Pos,
+  signatureHelp(PathRef File, Position Pos, Context &Ctx,
                 llvm::Optional<StringRef> OverridenContents = llvm::None,
                 IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
 
   /// Get definition of symbol at a specified \p Line and \p Column in \p File.
-  llvm::Expected<Tagged<std::vector<Location>>> findDefinitions(PathRef File,
-                                                                Position Pos);
+  llvm::Expected<Tagged<std::vector<Location>>>
+  findDefinitions(PathRef File, Position Pos, Context &Ctx);
 
   /// Helper function that returns a path to the corresponding source file when
   /// given a header file and vice versa.
@@ -309,14 +309,13 @@
   void onFileEvent(const DidChangeWatchedFilesParams &Params);
 
 private:
-  std::future<void>
-  scheduleReparseAndDiags(PathRef File, VersionedDraft Contents,
-                          std::shared_ptr<CppFile> Resources,
-                          Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS);
+  std::future<void> scheduleReparseAndDiags(
+      PathRef File, VersionedDraft Contents, std::shared_ptr<CppFile> Resources,
+      Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS, Context Ctx);
 
-  std::future<void> scheduleCancelRebuild(std::shared_ptr<CppFile> Resources);
+  std::future<void> scheduleCancelRebuild(std::shared_ptr<CppFile> Resources,
+                                          Context Ctx);
 
-  clangd::Logger &Logger;
   GlobalCompilationDatabase &CDB;
   DiagnosticsConsumer &DiagConsumer;
   FileSystemProvider &FSProvider;
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -175,10 +175,8 @@
                            unsigned AsyncThreadsCount,
                            bool StorePreamblesInMemory,
                            const clangd::CodeCompleteOptions &CodeCompleteOpts,
-                           clangd::Logger &Logger,
                            llvm::Optional<StringRef> ResourceDir)
-    : Logger(Logger), CDB(CDB), DiagConsumer(DiagConsumer),
-      FSProvider(FSProvider),
+    : CDB(CDB), DiagConsumer(DiagConsumer), FSProvider(FSProvider),
       ResourceDir(ResourceDir ? ResourceDir->str() : getStandardResourceDir()),
       PCHs(std::make_shared<PCHContainerOperations>()),
       StorePreamblesInMemory(StorePreamblesInMemory),
@@ -191,41 +189,45 @@
     this->RootPath = NewRootPath;
 }
 
-std::future<void> ClangdServer::addDocument(PathRef File, StringRef Contents) {
+std::future<void> ClangdServer::addDocument(PathRef File, StringRef Contents,
+                                            Context Ctx) {
   DocVersion Version = DraftMgr.updateDraft(File, Contents);
 
   auto TaggedFS = FSProvider.getTaggedFileSystem(File);
   std::shared_ptr<CppFile> Resources = Units.getOrCreateFile(
-      File, ResourceDir, CDB, StorePreamblesInMemory, PCHs, Logger);
+      File, ResourceDir, CDB, StorePreamblesInMemory, PCHs);
   return scheduleReparseAndDiags(File, VersionedDraft{Version, Contents.str()},
-                                 std::move(Resources), std::move(TaggedFS));
+                                 std::move(Resources), std::move(TaggedFS),
+                                 std::move(Ctx));
 }
 
-std::future<void> ClangdServer::removeDocument(PathRef File) {
+std::future<void> ClangdServer::removeDocument(PathRef File, Context Ctx) {
   DraftMgr.removeDraft(File);
   std::shared_ptr<CppFile> Resources = Units.removeIfPresent(File);
-  return scheduleCancelRebuild(std::move(Resources));
+  return scheduleCancelRebuild(std::move(Resources), std::move(Ctx));
 }
 
-std::future<void> ClangdServer::forceReparse(PathRef File) {
+std::future<void> ClangdServer::forceReparse(PathRef File, Context Ctx) {
   auto FileContents = DraftMgr.getDraft(File);
   assert(FileContents.Draft &&
          "forceReparse() was called for non-added document");
 
   auto TaggedFS = FSProvider.getTaggedFileSystem(File);
   auto Recreated = Units.recreateFileIfCompileCommandChanged(
-      File, ResourceDir, CDB, StorePreamblesInMemory, PCHs, Logger);
+      File, ResourceDir, CDB, StorePreamblesInMemory, PCHs);
 
-  // Note that std::future from this cleanup action is ignored.
-  scheduleCancelRebuild(std::move(Recreated.RemovedFile));
+  // Note that std::future from this cleanup action.
+  // FIXME(ibiryukov): We use a global context here, should not fork the action
+  // instead.
+  scheduleCancelRebuild(std::move(Recreated.RemovedFile), buildCtx());
   // Schedule a reparse.
   return scheduleReparseAndDiags(File, std::move(FileContents),
                                  std::move(Recreated.FileInCollection),
-                                 std::move(TaggedFS));
+                                 std::move(TaggedFS), std::move(Ctx));
 }
 
 std::future<Tagged<CompletionList>>
-ClangdServer::codeComplete(PathRef File, Position Pos,
+ClangdServer::codeComplete(PathRef File, Position Pos, Context &Ctx,
                            llvm::Optional<StringRef> OverridenContents,
                            IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS) {
   using ResultType = Tagged<CompletionList>;
@@ -239,13 +241,13 @@
 
   std::future<ResultType> ResultFuture = ResultPromise.get_future();
   codeComplete(BindWithForward(Callback, std::move(ResultPromise)), File, Pos,
-               OverridenContents, UsedFS);
+               Ctx, OverridenContents, UsedFS);
   return ResultFuture;
 }
 
 void ClangdServer::codeComplete(
     UniqueFunction<void(Tagged<CompletionList>)> Callback, PathRef File,
-    Position Pos, llvm::Optional<StringRef> OverridenContents,
+    Position Pos, Context &Ctx, llvm::Optional<StringRef> OverridenContents,
     IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS) {
   using CallbackType = UniqueFunction<void(Tagged<CompletionList>)>;
 
@@ -276,7 +278,7 @@
   // A task that will be run asynchronously.
   auto Task =
       // 'mutable' to reassign Preamble variable.
-      [=](CallbackType Callback) mutable {
+      [=, &Ctx](CallbackType Callback) mutable {
         if (!Preamble) {
           // Maybe we built some preamble before processing this request.
           Preamble = Resources->getPossiblyStalePreamble();
@@ -287,16 +289,16 @@
         CompletionList Result = clangd::codeComplete(
             File, Resources->getCompileCommand(),
             Preamble ? &Preamble->Preamble : nullptr, Contents, Pos,
-            TaggedFS.Value, PCHs, CodeCompleteOpts, Logger);
+            TaggedFS.Value, PCHs, CodeCompleteOpts, Ctx);
 
         Callback(make_tagged(std::move(Result), std::move(TaggedFS.Tag)));
       };
 
   WorkScheduler.addToFront(std::move(Task), std::move(Callback));
 }
 
 llvm::Expected<Tagged<SignatureHelp>>
-ClangdServer::signatureHelp(PathRef File, Position Pos,
+ClangdServer::signatureHelp(PathRef File, Position Pos, Context &Ctx,
                             llvm::Optional<StringRef> OverridenContents,
                             IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS) {
   std::string DraftStorage;
@@ -322,10 +324,10 @@
         llvm::errc::invalid_argument);
 
   auto Preamble = Resources->getPossiblyStalePreamble();
-  auto Result = clangd::signatureHelp(File, Resources->getCompileCommand(),
-                                      Preamble ? &Preamble->Preamble : nullptr,
-                                      *OverridenContents, Pos, TaggedFS.Value,
-                                      PCHs, Logger);
+  auto Result =
+      clangd::signatureHelp(File, Resources->getCompileCommand(),
+                            Preamble ? &Preamble->Preamble : nullptr,
+                            *OverridenContents, Pos, TaggedFS.Value, PCHs, Ctx);
   return make_tagged(std::move(Result), TaggedFS.Tag);
 }
 
@@ -430,7 +432,7 @@
 }
 
 llvm::Expected<Tagged<std::vector<Location>>>
-ClangdServer::findDefinitions(PathRef File, Position Pos) {
+ClangdServer::findDefinitions(PathRef File, Position Pos, Context &Ctx) {
   auto TaggedFS = FSProvider.getTaggedFileSystem(File);
 
   std::shared_ptr<CppFile> Resources = Units.getFile(File);
@@ -440,10 +442,10 @@
         llvm::errc::invalid_argument);
 
   std::vector<Location> Result;
-  Resources->getAST().get()->runUnderLock([Pos, &Result, this](ParsedAST *AST) {
+  Resources->getAST().get()->runUnderLock([Pos, &Result, &Ctx](ParsedAST *AST) {
     if (!AST)
       return;
-    Result = clangd::findDefinitions(*AST, Pos, Logger);
+    Result = clangd::findDefinitions(*AST, Pos, Ctx);
   });
   return make_tagged(std::move(Result), TaggedFS.Tag);
 }
@@ -509,10 +511,10 @@
 
 std::future<void> ClangdServer::scheduleReparseAndDiags(
     PathRef File, VersionedDraft Contents, std::shared_ptr<CppFile> Resources,
-    Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS) {
+    Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS, Context Ctx) {
 
   assert(Contents.Draft && "Draft must have contents");
-  UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>()>
+  UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>(Context &)>
       DeferredRebuild =
           Resources->deferRebuild(*Contents.Draft, TaggedFS.Value);
   std::promise<void> DonePromise;
@@ -522,17 +524,17 @@
   Path FileStr = File;
   VFSTag Tag = TaggedFS.Tag;
   auto ReparseAndPublishDiags =
-      [this, FileStr, Version,
-       Tag](UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>()>
-                DeferredRebuild,
-            std::promise<void> DonePromise) -> void {
+      [this, FileStr, Version, Tag](
+          UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>(Context &)>
+              DeferredRebuild,
+          std::promise<void> DonePromise, Context Ctx) -> void {
     FulfillPromiseGuard Guard(DonePromise);
 
     auto CurrentVersion = DraftMgr.getVersion(FileStr);
     if (CurrentVersion != Version)
       return; // This request is outdated
 
-    auto Diags = DeferredRebuild();
+    auto Diags = DeferredRebuild(Ctx);
     if (!Diags)
       return; // A new reparse was requested before this one completed.
 
@@ -553,12 +555,14 @@
   };
 
   WorkScheduler.addToFront(std::move(ReparseAndPublishDiags),
-                           std::move(DeferredRebuild), std::move(DonePromise));
+                           std::move(DeferredRebuild), std::move(DonePromise),
+                           std::move(Ctx));
   return DoneFuture;
 }
 
 std::future<void>
-ClangdServer::scheduleCancelRebuild(std::shared_ptr<CppFile> Resources) {
+ClangdServer::scheduleCancelRebuild(std::shared_ptr<CppFile> Resources,
+                                    Context Ctx) {
   std::promise<void> DonePromise;
   std::future<void> DoneFuture = DonePromise.get_future();
   if (!Resources) {
@@ -569,12 +573,13 @@
 
   UniqueFunction<void()> DeferredCancel = Resources->deferCancelRebuild();
   auto CancelReparses = [Resources](std::promise<void> DonePromise,
-                                    UniqueFunction<void()> DeferredCancel) {
+                                    UniqueFunction<void()> DeferredCancel,
+                                    Context Ctx) {
     FulfillPromiseGuard Guard(DonePromise);
     DeferredCancel();
   };
   WorkScheduler.addToFront(std::move(CancelReparses), std::move(DonePromise),
-                           std::move(DeferredCancel));
+                           std::move(DeferredCancel), std::move(Ctx));
   return DoneFuture;
 }
 
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -32,6 +32,12 @@
   return Edits;
 }
 
+Context destroyAndTakeContext(RequestContext Ctx) {
+  // FIXME(ibiryukov): We move the Context out of RequestContext. This works,
+  // but it's shaky. Maybe we should rather keep the RequestContext alive?
+  return std::move(Ctx.ctx());
+}
+
 } // namespace
 
 void ClangdLSPServer::onInitialize(Ctx C, InitializeParams &Params) {
@@ -82,7 +88,8 @@
   if (Params.metadata && !Params.metadata->extraFlags.empty())
     CDB.setExtraFlagsForFile(Params.textDocument.uri.file,
                              std::move(Params.metadata->extraFlags));
-  Server.addDocument(Params.textDocument.uri.file, Params.textDocument.text);
+  Server.addDocument(Params.textDocument.uri.file, Params.textDocument.text,
+                     destroyAndTakeContext(std::move(C)));
 }
 
 void ClangdLSPServer::onDocumentDidChange(Ctx C,
@@ -92,7 +99,8 @@
                         "can only apply one change at a time");
   // We only support full syncing right now.
   Server.addDocument(Params.textDocument.uri.file,
-                     Params.contentChanges[0].text);
+                     Params.contentChanges[0].text,
+                     destroyAndTakeContext(std::move(C)));
 }
 
 void ClangdLSPServer::onFileEvent(Ctx C, DidChangeWatchedFilesParams &Params) {
@@ -145,7 +153,8 @@
 
 void ClangdLSPServer::onDocumentDidClose(Ctx C,
                                          DidCloseTextDocumentParams &Params) {
-  Server.removeDocument(Params.textDocument.uri.file);
+  Server.removeDocument(Params.textDocument.uri.file,
+                        destroyAndTakeContext(std::move(C)));
 }
 
 void ClangdLSPServer::onDocumentOnTypeFormatting(
@@ -197,19 +206,18 @@
   auto List = Server
                   .codeComplete(
                       Params.textDocument.uri.file,
-                      Position{Params.position.line, Params.position.character})
-                  .get() // FIXME(ibiryukov): This could be made async if we
-                         // had an API that would allow to attach callbacks to
-                         // futures returned by ClangdServer.
+                      Position{Params.position.line, Params.position.character},
+                      C.ctx())
+                  .get() // FIXME(ibiryukov): This could be made async.
                   .Value;
   C.reply(List);
 }
 
 void ClangdLSPServer::onSignatureHelp(Ctx C,
                                       TextDocumentPositionParams &Params) {
   auto SignatureHelp = Server.signatureHelp(
       Params.textDocument.uri.file,
-      Position{Params.position.line, Params.position.character});
+      Position{Params.position.line, Params.position.character}, C.ctx());
   if (!SignatureHelp)
     return C.replyError(ErrorCode::InvalidParams,
                         llvm::toString(SignatureHelp.takeError()));
@@ -220,7 +228,7 @@
                                        TextDocumentPositionParams &Params) {
   auto Items = Server.findDefinitions(
       Params.textDocument.uri.file,
-      Position{Params.position.line, Params.position.character});
+      Position{Params.position.line, Params.position.character}, C.ctx());
   if (!Items)
     return C.replyError(ErrorCode::InvalidParams,
                         llvm::toString(Items.takeError()));
@@ -239,10 +247,9 @@
                                  const clangd::CodeCompleteOptions &CCOpts,
                                  llvm::Optional<StringRef> ResourceDir,
                                  llvm::Optional<Path> CompileCommandsDir)
-    : Out(Out), CDB(/*Logger=*/Out, std::move(CompileCommandsDir)),
+    : Out(Out), CDB(std::move(CompileCommandsDir)),
       Server(CDB, /*DiagConsumer=*/*this, FSProvider, AsyncThreadsCount,
-             StorePreamblesInMemory, CCOpts,
-             /*Logger=*/Out, ResourceDir) {}
+             StorePreamblesInMemory, CCOpts, ResourceDir) {}
 
 bool ClangdLSPServer::run(std::istream &In) {
   assert(!IsDone && "Run was called before");
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to