ilya-biryukov updated this revision to Diff 125545.
ilya-biryukov added a comment.
Herald added a subscriber: klimek.

- Updated to match the new Context implementation.
- Logger is now stored in a global variable instead of the global Context.
- Removed json-specific RequestContext, now storing all required information in 
Context.
- `reply`,`replyError` and `call` are freestanding functions now.


Repository:
  rCTE Clang Tools Extra

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/CodeComplete.cpp
  clangd/CodeComplete.h
  clangd/GlobalCompilationDatabase.cpp
  clangd/GlobalCompilationDatabase.h
  clangd/JSONRPCDispatcher.cpp
  clangd/JSONRPCDispatcher.h
  clangd/Logger.cpp
  clangd/Logger.h
  clangd/Protocol.h
  clangd/ProtocolHandlers.cpp
  clangd/ProtocolHandlers.h
  clangd/tool/ClangdMain.cpp
  unittests/clangd/ClangdTests.cpp
  unittests/clangd/CodeCompleteTests.cpp

Index: unittests/clangd/CodeCompleteTests.cpp
===================================================================
--- unittests/clangd/CodeCompleteTests.cpp
+++ unittests/clangd/CodeCompleteTests.cpp
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 #include "ClangdServer.h"
 #include "Compiler.h"
+#include "Context.h"
 #include "Protocol.h"
 #include "TestFS.h"
 #include "gtest/gtest.h"
@@ -74,8 +75,7 @@
   MockCompilationDatabase CDB;
 
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
-                      /*StorePreamblesInMemory=*/true,
-                      EmptyLogger::getInstance());
+                      /*StorePreamblesInMemory=*/true);
 
   auto FooCpp = getVirtualTestFilePath("foo.cpp");
   const auto SourceContents = R"cpp(
@@ -101,29 +101,33 @@
 
   // 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, buildCtx());
 
   {
     auto CodeCompletionResults1 =
-        Server.codeComplete(FooCpp, CompletePos, CCOpts, None).get().Value;
+        Server.codeComplete(FooCpp, CompletePos, CCOpts, buildCtx(), None)
+            .get()
+            .first.Value;
     EXPECT_TRUE(ContainsItem(CodeCompletionResults1, "aba"));
     EXPECT_FALSE(ContainsItem(CodeCompletionResults1, "cbc"));
   }
 
   {
     auto CodeCompletionResultsOverriden =
         Server
-            .codeComplete(FooCpp, CompletePos, CCOpts,
+            .codeComplete(FooCpp, CompletePos, CCOpts, buildCtx(),
                           StringRef(OverridenSourceContents))
             .get()
-            .Value;
+            .first.Value;
     EXPECT_TRUE(ContainsItem(CodeCompletionResultsOverriden, "cbc"));
     EXPECT_FALSE(ContainsItem(CodeCompletionResultsOverriden, "aba"));
   }
 
   {
     auto CodeCompletionResults2 =
-        Server.codeComplete(FooCpp, CompletePos, CCOpts, None).get().Value;
+        Server.codeComplete(FooCpp, CompletePos, CCOpts, buildCtx(), None)
+            .get()
+            .first.Value;
     EXPECT_TRUE(ContainsItem(CodeCompletionResults2, "aba"));
     EXPECT_FALSE(ContainsItem(CodeCompletionResults2, "cbc"));
   }
@@ -135,8 +139,7 @@
   CDB.ExtraClangFlags.push_back("-xc++");
   IgnoreDiagnostics DiagConsumer;
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
-                      /*StorePreamblesInMemory=*/true,
-                      EmptyLogger::getInstance());
+                      /*StorePreamblesInMemory=*/true);
 
   auto FooCpp = getVirtualTestFilePath("foo.cpp");
   FS.Files[FooCpp] = "";
@@ -150,17 +153,17 @@
 int main() { ClassWithMembers().{complete} }
       )cpp",
                                              "complete");
-  Server.addDocument(FooCpp, Completion.Text);
+  Server.addDocument(FooCpp, Completion.Text, buildCtx());
 
   clangd::CodeCompleteOptions Opts;
   Opts.Limit = 2;
 
   /// For after-dot completion we must always get consistent results.
   auto Results = Server
                      .codeComplete(FooCpp, Completion.MarkerPos, Opts,
-                                   StringRef(Completion.Text))
+                                   buildCtx(), StringRef(Completion.Text))
                      .get()
-                     .Value;
+                     .first.Value;
 
   EXPECT_TRUE(Results.isIncomplete);
   EXPECT_EQ(Opts.Limit, Results.items.size());
@@ -175,8 +178,7 @@
   CDB.ExtraClangFlags.push_back("-xc++");
   IgnoreDiagnostics DiagConsumer;
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
-                      /*StorePreamblesInMemory=*/true,
-                      EmptyLogger::getInstance());
+                      /*StorePreamblesInMemory=*/true);
 
   auto FooCpp = getVirtualTestFilePath("foo.cpp");
   FS.Files[FooCpp] = "";
@@ -194,12 +196,13 @@
     StringWithPos Completion = parseTextMarker(
         formatv("{0} int main() { {1}{{complete}} }", Body, Query).str(),
         "complete");
-    Server.addDocument(FooCpp, Completion.Text);
+    Server.addDocument(FooCpp, Completion.Text, buildCtx());
     return Server
         .codeComplete(FooCpp, Completion.MarkerPos,
-                      clangd::CodeCompleteOptions(), StringRef(Completion.Text))
+                      clangd::CodeCompleteOptions(), buildCtx(),
+                      StringRef(Completion.Text))
         .get()
-        .Value;
+        .first.Value;
   };
 
   auto Foba = Complete("S().Foba");
@@ -291,23 +294,23 @@
 
   auto TestWithOpts = [&](clangd::CodeCompleteOptions Opts) {
     ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
-                        /*StorePreamblesInMemory=*/true,
-                        EmptyLogger::getInstance());
+                        /*StorePreamblesInMemory=*/true);
     // 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, buildCtx());
 
     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, Opts,
-                                       StringRef(MemberCompletion.Text))
-                         .get()
-                         .Value;
+      auto Results =
+          Server
+              .codeComplete(FooCpp, MemberCompletion.MarkerPos, Opts,
+                            buildCtx(), StringRef(MemberCompletion.Text))
+              .get()
+              .first.Value;
 
       // Class members. The only items that must be present in after-dor
       // completion.
@@ -339,11 +342,12 @@
     }
     // Global completion differs based on the Opts that were passed.
     {
-      auto Results = Server
-                         .codeComplete(FooCpp, GlobalCompletion.MarkerPos, Opts,
-                                       StringRef(GlobalCompletion.Text))
-                         .get()
-                         .Value;
+      auto Results =
+          Server
+              .codeComplete(FooCpp, GlobalCompletion.MarkerPos, Opts,
+                            buildCtx(), StringRef(GlobalCompletion.Text))
+              .get()
+              .first.Value;
 
       // Class members. Should never be present in global completions.
       EXPECT_FALSE(ContainsItem(Results, MethodItemText));
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 "TestFS.h"
 #include "clang/Config/config.h"
 #include "llvm/ADT/SmallVector.h"
@@ -28,6 +28,7 @@
 
 namespace clang {
 namespace clangd {
+
 namespace {
 
 // Don't wait for async ops in clangd test more than that to avoid blocking
@@ -123,8 +124,7 @@
     ErrorCheckingDiagConsumer DiagConsumer;
     MockCompilationDatabase CDB;
     ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
-                        /*StorePreamblesInMemory=*/true,
-                        EmptyLogger::getInstance());
+                        /*StorePreamblesInMemory=*/true);
     for (const auto &FileWithContents : ExtraFiles)
       FS.Files[getVirtualTestFilePath(FileWithContents.first)] =
           FileWithContents.second;
@@ -135,7 +135,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, buildCtx());
 
     auto Result = dumpASTWithoutMemoryLocs(Server, SourceFilename);
 
@@ -187,8 +188,7 @@
   ErrorCheckingDiagConsumer DiagConsumer;
   MockCompilationDatabase CDB;
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
-                      /*StorePreamblesInMemory=*/true,
-                      EmptyLogger::getInstance());
+                      /*StorePreamblesInMemory=*/true);
 
   const auto SourceContents = R"cpp(
 #include "foo.h"
@@ -203,21 +203,21 @@
   FS.ExpectedFile = FooCpp;
 
   // To sync reparses before checking for errors.
-  std::future<void> ParseFuture;
+  std::future<Context> ParseFuture;
 
-  ParseFuture = Server.addDocument(FooCpp, SourceContents);
+  ParseFuture = Server.addDocument(FooCpp, SourceContents, buildCtx());
   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, "", buildCtx());
   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, buildCtx());
   auto DumpParse2 = dumpASTWithoutMemoryLocs(Server, FooCpp);
   ASSERT_EQ(ParseFuture.wait_for(DefaultFutureTimeout),
             std::future_status::ready);
@@ -233,8 +233,7 @@
   MockCompilationDatabase CDB;
 
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
-                      /*StorePreamblesInMemory=*/true,
-                      EmptyLogger::getInstance());
+                      /*StorePreamblesInMemory=*/true);
 
   const auto SourceContents = R"cpp(
 #include "foo.h"
@@ -249,23 +248,23 @@
   FS.ExpectedFile = FooCpp;
 
   // To sync reparses before checking for errors.
-  std::future<void> ParseFuture;
+  std::future<Context> ParseFuture;
 
-  ParseFuture = Server.addDocument(FooCpp, SourceContents);
+  ParseFuture = Server.addDocument(FooCpp, SourceContents, buildCtx());
   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, buildCtx());
   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, buildCtx());
   auto DumpParse2 = dumpASTWithoutMemoryLocs(Server, FooCpp);
   EXPECT_EQ(ParseFuture.wait_for(DefaultFutureTimeout),
             std::future_status::ready);
@@ -282,8 +281,7 @@
   // Run ClangdServer synchronously.
   ClangdServer Server(CDB, DiagConsumer, FS,
                       /*AsyncThreadsCount=*/0,
-                      /*StorePreamblesInMemory=*/true,
-                      EmptyLogger::getInstance());
+                      /*StorePreamblesInMemory=*/true);
 
   auto FooCpp = getVirtualTestFilePath("foo.cpp");
   const auto SourceContents = "int a;";
@@ -296,15 +294,19 @@
   // 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}, CCOpts).get().Tag,
+  Server.addDocument(FooCpp, SourceContents, buildCtx());
+  EXPECT_EQ(Server.codeComplete(FooCpp, Position{0, 0}, CCOpts, buildCtx())
+                .get()
+                .first.Tag,
             FS.Tag);
   EXPECT_EQ(DiagConsumer.lastVFSTag(), FS.Tag);
 
   FS.Tag = "321";
-  Server.addDocument(FooCpp, SourceContents);
+  Server.addDocument(FooCpp, SourceContents, buildCtx());
   EXPECT_EQ(DiagConsumer.lastVFSTag(), FS.Tag);
-  EXPECT_EQ(Server.codeComplete(FooCpp, Position{0, 0}, CCOpts).get().Tag,
+  EXPECT_EQ(Server.codeComplete(FooCpp, Position{0, 0}, CCOpts, buildCtx())
+                .get()
+                .first.Tag,
             FS.Tag);
 }
 
@@ -322,8 +324,7 @@
   // Run ClangdServer synchronously.
   ClangdServer Server(CDB, DiagConsumer, FS,
                       /*AsyncThreadsCount=*/0,
-                      /*StorePreamblesInMemory=*/true,
-                      EmptyLogger::getInstance());
+                      /*StorePreamblesInMemory=*/true);
 
   // Just a random gcc version string
   SmallString<8> Version("4.9.3");
@@ -354,14 +355,14 @@
 
   // No need to sync reparses, because requests are processed on the calling
   // thread.
-  Server.addDocument(FooCpp, SourceContents);
+  Server.addDocument(FooCpp, SourceContents, buildCtx());
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
 
   const auto SourceContentsWithError = R"cpp(
 #include <string>
 std::string x;
 )cpp";
-  Server.addDocument(FooCpp, SourceContentsWithError);
+  Server.addDocument(FooCpp, SourceContentsWithError, buildCtx());
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
 }
 #endif // LLVM_ON_UNIX
@@ -372,11 +373,10 @@
   MockCompilationDatabase CDB;
   ClangdServer Server(CDB, DiagConsumer, FS,
                       /*AsyncThreadsCount=*/0,
-                      /*StorePreamblesInMemory=*/true,
-                      EmptyLogger::getInstance());
-  // No need to sync reparses, because reparses are performed on the calling
-  // thread to true.
+                      /*StorePreamblesInMemory=*/true);
 
+  // No need to sync reparses, because reparses are performed on the calling
+  // thread.
   auto FooCpp = getVirtualTestFilePath("foo.cpp");
   const auto SourceContents1 = R"cpp(
 template <class T>
@@ -392,26 +392,26 @@
 
   // First parse files in C mode and check they produce errors.
   CDB.ExtraClangFlags = {"-xc"};
-  Server.addDocument(FooCpp, SourceContents1);
+  Server.addDocument(FooCpp, SourceContents1, buildCtx());
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
-  Server.addDocument(FooCpp, SourceContents2);
+  Server.addDocument(FooCpp, SourceContents2, buildCtx());
   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, buildCtx());
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
-  Server.addDocument(FooCpp, SourceContents2);
+  Server.addDocument(FooCpp, SourceContents2, buildCtx());
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
   // But forceReparse should reparse the file with proper flags.
-  Server.forceReparse(FooCpp);
+  Server.forceReparse(FooCpp, buildCtx());
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
   // Subsequent addDocument calls should finish without errors too.
-  Server.addDocument(FooCpp, SourceContents1);
+  Server.addDocument(FooCpp, SourceContents1, buildCtx());
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
-  Server.addDocument(FooCpp, SourceContents2);
+  Server.addDocument(FooCpp, SourceContents2, buildCtx());
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
 }
 
@@ -501,7 +501,7 @@
     unsigned RequestsWithErrors = 0;
     bool LastContentsHadErrors = false;
     bool FileIsRemoved = true;
-    std::future<void> LastRequestFuture;
+    std::future<Context> LastRequestFuture;
   };
 
   std::vector<RequestStats> ReqStats;
@@ -513,8 +513,7 @@
   {
     MockCompilationDatabase CDB;
     ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
-                        /*StorePreamblesInMemory=*/true,
-                        EmptyLogger::getInstance());
+                        /*StorePreamblesInMemory=*/true);
 
     // Prepare some random distributions for the test.
     std::random_device RandGen;
@@ -529,7 +528,7 @@
 
     // Some helpers.
     auto UpdateStatsOnAddDocument = [&](unsigned FileIndex, bool HadErrors,
-                                        std::future<void> Future) {
+                                        std::future<Context> Future) {
       auto &Stats = ReqStats[FileIndex];
 
       if (HadErrors)
@@ -542,15 +541,15 @@
     };
 
     auto UpdateStatsOnRemoveDocument = [&](unsigned FileIndex,
-                                           std::future<void> Future) {
+                                           std::future<Context> Future) {
       auto &Stats = ReqStats[FileIndex];
 
       Stats.FileIsRemoved = true;
       Stats.LastRequestFuture = std::move(Future);
     };
 
     auto UpdateStatsOnForceReparse = [&](unsigned FileIndex,
-                                         std::future<void> Future) {
+                                         std::future<Context> Future) {
       auto &Stats = ReqStats[FileIndex];
 
       Stats.LastRequestFuture = std::move(Future);
@@ -562,9 +561,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,
+                             buildCtx());
       UpdateStatsOnAddDocument(FileIndex, ShouldHaveErrors, std::move(Future));
     };
 
@@ -580,7 +581,7 @@
       if (ReqStats[FileIndex].FileIsRemoved)
         AddDocument(FileIndex);
 
-      auto Future = Server.forceReparse(FilePaths[FileIndex]);
+      auto Future = Server.forceReparse(FilePaths[FileIndex], buildCtx());
       UpdateStatsOnForceReparse(FileIndex, std::move(Future));
     };
 
@@ -590,7 +591,7 @@
       if (ReqStats[FileIndex].FileIsRemoved)
         AddDocument(FileIndex);
 
-      auto Future = Server.removeDocument(FilePaths[FileIndex]);
+      auto Future = Server.removeDocument(FilePaths[FileIndex], buildCtx());
       UpdateStatsOnRemoveDocument(FileIndex, std::move(Future));
     };
 
@@ -609,7 +610,7 @@
       // same file.
       Server
           .codeComplete(FilePaths[FileIndex], Pos,
-                        clangd::CodeCompleteOptions())
+                        clangd::CodeCompleteOptions(), buildCtx())
           .wait();
     };
 
@@ -620,7 +621,8 @@
         AddDocument(FileIndex);
 
       Position Pos{LineDist(RandGen), ColumnDist(RandGen)};
-      ASSERT_TRUE(!!Server.findDefinitions(FilePaths[FileIndex], Pos));
+      ASSERT_TRUE(
+          !!Server.findDefinitions(FilePaths[FileIndex], Pos, emptyCtx()));
     };
 
     std::vector<std::function<void()>> AsyncRequests = {
@@ -676,8 +678,7 @@
   MockCompilationDatabase CDB;
 
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
-                      /*StorePreamblesInMemory=*/true,
-                      EmptyLogger::getInstance());
+                      /*StorePreamblesInMemory=*/true);
 
   auto SourceContents = R"cpp(
   #include "foo.h"
@@ -802,12 +803,13 @@
       std::move(StartSecondReparsePromise));
 
   MockCompilationDatabase CDB;
-  ClangdServer Server(CDB, DiagConsumer, FS, 4, /*StorePreamblesInMemory=*/true,
-                      EmptyLogger::getInstance());
-  Server.addDocument(FooCpp, SourceContentsWithErrors);
+  ClangdServer Server(CDB, DiagConsumer, FS, 4,
+                      /*StorePreamblesInMemory=*/true);
+  Server.addDocument(FooCpp, SourceContentsWithErrors, buildCtx());
   StartSecondReparse.wait();
 
-  auto Future = Server.addDocument(FooCpp, SourceContentsWithoutErrors);
+  auto Future =
+      Server.addDocument(FooCpp, SourceContentsWithoutErrors, buildCtx());
   Future.wait();
 }
 
Index: clangd/tool/ClangdMain.cpp
===================================================================
--- clangd/tool/ClangdMain.cpp
+++ clangd/tool/ClangdMain.cpp
@@ -134,6 +134,8 @@
                  InputMirrorStream ? InputMirrorStream.getPointer() : nullptr,
                  PrettyPrint);
 
+  clangd::LoggingSession LoggingSession(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.h
===================================================================
--- clangd/ProtocolHandlers.h
+++ clangd/ProtocolHandlers.h
@@ -29,7 +29,7 @@
 // The interface implemented by ClangLSPServer to handle incoming requests.
 class ProtocolCallbacks {
 public:
-  using Ctx = RequestContext;
+  using Ctx = Context;
   virtual ~ProtocolCallbacks() = default;
 
   virtual void onInitialize(Ctx C, InitializeParams &Params) = 0;
Index: clangd/ProtocolHandlers.cpp
===================================================================
--- clangd/ProtocolHandlers.cpp
+++ clangd/ProtocolHandlers.cpp
@@ -25,17 +25,16 @@
 struct HandlerRegisterer {
   template <typename Param>
   void operator()(StringRef Method,
-                  void (ProtocolCallbacks::*Handler)(RequestContext, Param)) {
+                  void (ProtocolCallbacks::*Handler)(Context, 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, const json::Expr &RawParams) {
+        Method, [=](Context C, const json::Expr &RawParams) {
           typename std::remove_reference<Param>::type P;
           if (fromJSON(RawParams, P)) {
             (Callbacks->*Handler)(std::move(C), P);
           } else {
-            Out->log("Failed to decode " + Method + " request.");
+            log(C, "Failed to decode " + Method + " request.");
           }
         });
   }
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 <string>
Index: clangd/Logger.h
===================================================================
--- clangd/Logger.h
+++ clangd/Logger.h
@@ -10,29 +10,37 @@
 #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 globalLogger().
+void log(Context &Ctx, const llvm::Twine &Message);
+
 /// Interface to allow custom logging in clangd.
 class Logger {
 public:
   virtual ~Logger() = default;
 
   /// Implementations of this method must be thread-safe.
-  virtual void log(const llvm::Twine &Message) = 0;
+  virtual void logImpl(Context &Ctx, const llvm::Twine &Message) = 0;
 };
 
-/// Logger implementation that ignores all messages.
-class EmptyLogger : public Logger {
+Logger &globalLogger();
+
+/// Only one LoggingSession can be active at a time.
+class LoggingSession {
 public:
-  static EmptyLogger &getInstance();
+  LoggingSession(clangd::Logger &Instance);
+  ~LoggingSession();
 
-  void log(const llvm::Twine &Message) override;
+  LoggingSession(LoggingSession &&) = delete;
+  LoggingSession &operator=(LoggingSession &&) = delete;
 
-private:
-  EmptyLogger() = default;
+  LoggingSession(LoggingSession const &) = delete;
+  LoggingSession &operator=(LoggingSession const &) = delete;
 };
 
 } // namespace clangd
Index: clangd/Logger.cpp
===================================================================
--- clangd/Logger.cpp
+++ clangd/Logger.cpp
@@ -9,11 +9,34 @@
 
 #include "Logger.h"
 
-using namespace clang::clangd;
+namespace clang {
+namespace clangd {
 
-EmptyLogger &EmptyLogger::getInstance() {
-  static EmptyLogger Logger;
-  return Logger;
+namespace {
+class EmptyLogger : public Logger {
+public:
+  void logImpl(Context &Ctx, const llvm::Twine &Message) override {}
+};
+
+EmptyLogger Empty;
+Logger *GlobalLogger = &Empty;
+} // namespace
+
+Logger &globalLogger() {
+  assert(GlobalLogger);
+  return *GlobalLogger;
+}
+
+LoggingSession::LoggingSession(clangd::Logger &Instance) {
+  assert(GlobalLogger == &Empty);
+  GlobalLogger = &Instance;
+}
+
+LoggingSession::~LoggingSession() { GlobalLogger = &Empty; }
+
+void log(Context &Ctx, const llvm::Twine &Message) {
+  globalLogger().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"
@@ -35,7 +36,7 @@
   void writeMessage(const json::Expr &Result);
 
   /// Write a line to the logging stream.
-  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.
@@ -53,38 +54,22 @@
   std::mutex StreamMutex;
 };
 
-/// Context object passed to handlers to allow replies.
-class RequestContext {
-public:
-  RequestContext(JSONOutput &Out, StringRef Method,
-                 llvm::Optional<json::Expr> ID)
-      : Out(Out), ID(std::move(ID)),
-        Tracer(llvm::make_unique<trace::Span>(Method)) {
-    if (this->ID)
-      SPAN_ATTACH(tracer(), "ID", *this->ID);
-  }
-
-  /// Sends a successful reply.
-  void reply(json::Expr &&Result);
-  /// Sends an error response to the client, and logs it.
-  void replyError(ErrorCode code, const llvm::StringRef &Message);
-  /// Sends a request to the client.
-  void call(llvm::StringRef Method, json::Expr &&Params);
-
-  trace::Span &tracer() { return *Tracer; }
-
-private:
-  JSONOutput &Out;
-  llvm::Optional<json::Expr> ID;
-  std::unique_ptr<trace::Span> Tracer;
-};
+/// Sends a successful reply. \p Ctx must either be the Context accepted by
+/// JSONRPCDispatcher::Handler or be derived from it.
+void reply(Context &Ctx, json::Expr &&Result);
+/// Sends an error response to the client, and logs it. \p Ctx must either be
+/// the Context accepted by JSONRPCDispatcher::Handler or be derived from it.
+void replyError(Context &Ctx, ErrorCode code, const llvm::StringRef &Message);
+/// Sends a request to the client. \p Ctx must either be the Context accepted by
+/// JSONRPCDispatcher::Handler or be derived from it.
+void call(Context &Ctx, llvm::StringRef Method, json::Expr &&Params);
 
 /// Main JSONRPC entry point. This parses the JSONRPC "header" and calls the
 /// registered Handler for the method received.
 class JSONRPCDispatcher {
 public:
   // A handler responds to requests for a particular method name.
-  using Handler = std::function<void(RequestContext, const json::Expr &)>;
+  using Handler = std::function<void(Context, const json::Expr &)>;
 
   /// Create a new JSONRPCDispatcher. UnknownHandler is called when an unknown
   /// method is received.
Index: clangd/JSONRPCDispatcher.cpp
===================================================================
--- clangd/JSONRPCDispatcher.cpp
+++ clangd/JSONRPCDispatcher.cpp
@@ -19,6 +19,12 @@
 using namespace clang;
 using namespace clangd;
 
+namespace {
+static Key<std::unique_ptr<trace::Span>> TracerKey;
+static Key<json::Expr> IDKey;
+static Key<JSONOutput *> OutKey;
+} // namespace
+
 void JSONOutput::writeMessage(const json::Expr &Message) {
   std::string S;
   llvm::raw_string_ostream OS(S);
@@ -38,7 +44,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 << '\n';
@@ -53,41 +60,44 @@
   InputMirror->flush();
 }
 
-void RequestContext::reply(json::Expr &&Result) {
+void clangd::reply(Context &Ctx, json::Expr &&Result) {
+  auto ID = Ctx->get(IDKey);
   if (!ID) {
-    Out.log("Attempted to reply to a notification!");
+    log(Ctx, "Attempted to reply to a notification!");
     return;
   }
-  SPAN_ATTACH(tracer(), "Reply", Result);
-  Out.writeMessage(json::obj{
+
+  SPAN_ATTACH(*Ctx->getExisting(TracerKey), "Reply", Result);
+  Ctx->getPtr(OutKey)->writeMessage(json::obj{
       {"jsonrpc", "2.0"},
       {"id", *ID},
       {"result", std::move(Result)},
   });
 }
 
-void RequestContext::replyError(ErrorCode code,
-                                const llvm::StringRef &Message) {
-  Out.log("Error " + Twine(static_cast<int>(code)) + ": " + Message);
-  SPAN_ATTACH(tracer(), "Error",
+void clangd::replyError(Context &Ctx, ErrorCode code,
+                        const llvm::StringRef &Message) {
+  log(Ctx, "Error " + Twine(static_cast<int>(code)) + ": " + Message);
+  SPAN_ATTACH(*Ctx->getExisting(TracerKey), "Error",
               (json::obj{{"code", static_cast<int>(code)},
                          {"message", Message.str()}}));
-  if (ID) {
-    Out.writeMessage(json::obj{
+
+  if (auto ID = Ctx->get(IDKey)) {
+    Ctx->getPtr(OutKey)->writeMessage(json::obj{
         {"jsonrpc", "2.0"},
         {"id", *ID},
         {"error",
          json::obj{{"code", static_cast<int>(code)}, {"message", Message}}},
     });
   }
 }
 
-void RequestContext::call(StringRef Method, json::Expr &&Params) {
+void clangd::call(Context &Ctx, StringRef Method, json::Expr &&Params) {
   // FIXME: Generate/Increment IDs for every request so that we can get proper
   // replies once we need to.
-  SPAN_ATTACH(tracer(), "Call",
+  SPAN_ATTACH(*Ctx->getExisting(TracerKey), "Call",
               (json::obj{{"method", Method.str()}, {"params", Params}}));
-  Out.writeMessage(json::obj{
+  Ctx->getPtr(OutKey)->writeMessage(json::obj{
       {"jsonrpc", "2.0"},
       {"id", 1},
       {"method", Method},
@@ -120,8 +130,17 @@
 
   auto I = Handlers.find(*Method);
   auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;
-  RequestContext Ctx(Out, *Method, std::move(ID));
-  SPAN_ATTACH(Ctx.tracer(), "Params", Params);
+
+  auto Tracer = llvm::make_unique<trace::Span>(*Method);
+  if (ID)
+    SPAN_ATTACH(*Tracer, "ID", *ID);
+  SPAN_ATTACH(*Tracer, "Params", Params);
+
+  auto Ctx = buildCtx()
+                 .addOpt(IDKey, ID)
+                 .add(OutKey, &Out)
+                 .add(TracerKey, std::move(Tracer));
+
   Handler(std::move(Ctx), std::move(Params));
   return true;
 }
@@ -164,9 +183,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.");
+          log(emptyCtx(), "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);
@@ -185,8 +205,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.");
+      log(emptyCtx(), "Skipped overly large message of " +
+                          Twine(ContentLength) + " bytes.\n");
       continue;
     }
 
@@ -200,34 +220,37 @@
         // 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) + ".");
+          log(emptyCtx(), "Input was aborted. Read only " +
+                              std::to_string(In.gcount()) +
+                              " bytes of expected " +
+                              std::to_string(ContentLength) + ".\n");
           break;
         }
 
         JSONRef = StringRef(JSON.data(), ContentLength);
       }
 
       if (auto Doc = json::parse(JSONRef)) {
         // Log the formatted message.
-        Out.log(llvm::formatv(Out.Pretty ? "<-- {0:2}" : "<-- {0}", *Doc));
+        log(emptyCtx(),
+            llvm::formatv(Out.Pretty ? "<-- {0:2}\n" : "<-- {0}\n", *Doc));
         // Finally, execute the action for this JSON message.
         if (!Dispatcher.call(*Doc, Out))
-          Out.log("JSON dispatch failed!");
+          log(emptyCtx(), "JSON dispatch failed!\n");
       } else {
         // Parse error. Log the raw message.
-        Out.log("<-- " + JSONRef);
-        Out.log(llvm::Twine("JSON parse error: ") +
-                llvm::toString(Doc.takeError()));
+        log(emptyCtx(), "<-- " + JSONRef + "\n");
+        log(emptyCtx(), llvm::Twine("JSON parse error: ") +
+                            llvm::toString(Doc.takeError()) + "\n");
       }
 
       // If we're done, exit the loop.
       if (IsDone)
         break;
     } else {
-      Out.log("Warning: Missing Content-Length header, or message has zero "
-              "length.");
+      log(emptyCtx(),
+          "Warning: Missing Content-Length header, or message has zero "
+          "length.\n");
     }
   }
 }
Index: clangd/GlobalCompilationDatabase.h
===================================================================
--- clangd/GlobalCompilationDatabase.h
+++ clangd/GlobalCompilationDatabase.h
@@ -51,7 +51,7 @@
     : public GlobalCompilationDatabase {
 public:
   DirectoryBasedGlobalCompilationDatabase(
-      clangd::Logger &Logger, llvm::Optional<Path> CompileCommandsDir);
+      llvm::Optional<Path> CompileCommandsDir);
 
   /// Scans File's parents looking for compilation databases.
   /// Any extra flags will be added.
@@ -77,8 +77,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
@@ -26,8 +26,8 @@
 
 DirectoryBasedGlobalCompilationDatabase::
     DirectoryBasedGlobalCompilationDatabase(
-        clangd::Logger &Logger, llvm::Optional<Path> CompileCommandsDir)
-    : Logger(Logger), CompileCommandsDir(std::move(CompileCommandsDir)) {}
+        llvm::Optional<Path> CompileCommandsDir)
+    : CompileCommandsDir(std::move(CompileCommandsDir)) {}
 
 llvm::Optional<tooling::CompileCommand>
 DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File) const {
@@ -104,8 +104,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());
+      log(emptyCtx(), "Failed to find compilation database for " + Twine(File) +
+                          "in overriden directory " +
+                          CompileCommandsDir.getValue());
     return ReturnValue;
   }
 
@@ -118,7 +119,7 @@
     return CDB;
   }
 
-  Logger.log("Failed to find compilation database for " + Twine(File));
+  log(emptyCtx(), "Failed to find compilation database for " + Twine(File));
   return nullptr;
 }
 
Index: clangd/CodeComplete.h
===================================================================
--- clangd/CodeComplete.h
+++ clangd/CodeComplete.h
@@ -15,6 +15,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H
 
+#include "Context.h"
 #include "Logger.h"
 #include "Path.h"
 #include "Protocol.h"
@@ -67,14 +68,14 @@
                             StringRef Contents, Position Pos,
                             IntrusiveRefCntPtr<vfs::FileSystem> VFS,
                             std::shared_ptr<PCHContainerOperations> PCHs,
-                            CodeCompleteOptions Opts, Logger &Logger);
+                            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, Logger &Logger);
+              std::shared_ptr<PCHContainerOperations> PCHs, Context &Ctx);
 
 } // namespace clangd
 } // namespace clang
Index: clangd/CodeComplete.cpp
===================================================================
--- clangd/CodeComplete.cpp
+++ clangd/CodeComplete.cpp
@@ -591,7 +591,7 @@
                         PrecompiledPreamble const *Preamble, StringRef Contents,
                         Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
                         std::shared_ptr<PCHContainerOperations> PCHs,
-                        Logger &Logger) {
+                        Context &Ctx) {
   std::vector<const char *> ArgStrs;
   for (const auto &S : Command.CommandLine)
     ArgStrs.push_back(S.c_str());
@@ -634,12 +634,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;
   }
 
@@ -666,7 +666,7 @@
                             StringRef Contents, Position Pos,
                             IntrusiveRefCntPtr<vfs::FileSystem> VFS,
                             std::shared_ptr<PCHContainerOperations> PCHs,
-                            CodeCompleteOptions Opts, Logger &Logger) {
+                            CodeCompleteOptions Opts, Context &Ctx) {
   CompletionList Results;
   std::unique_ptr<CodeCompleteConsumer> Consumer;
   if (Opts.EnableSnippets) {
@@ -678,24 +678,24 @@
   }
   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
 signatureHelp(PathRef FileName, const tooling::CompileCommand &Command,
               PrecompiledPreamble const *Preamble, StringRef Contents,
               Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
-              std::shared_ptr<PCHContainerOperations> PCHs, Logger &Logger) {
+              std::shared_ptr<PCHContainerOperations> PCHs, 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;
 }
 
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,18 +252,22 @@
   std::shared_ptr<const PreambleData> LatestAvailablePreamble;
   /// Utility class, required by clang.
   std::shared_ptr<PCHContainerOperations> PCHs;
-  /// Used for logging various messages.
-  clangd::Logger &Logger;
 };
 
+/// 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
@@ -170,8 +170,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);
@@ -189,12 +188,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.
@@ -320,7 +319,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)
@@ -423,23 +422,20 @@
 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) {
-  Logger.log("Opened file " + FileName + " with command [" +
-             this->Command.Directory + "] " +
-             llvm::join(this->Command.CommandLine, " "));
+      RebuildInProgress(false), PCHs(std::move(PCHs)) {
+  log(emptyCtx(), "Opened file " + FileName + " with command [" +
+                      this->Command.Directory + "] " +
+                      llvm::join(this->Command.CommandLine, " "));
 
   std::lock_guard<std::mutex> Lock(Mutex);
   LatestAvailablePreamble = nullptr;
@@ -491,12 +487,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;
@@ -533,9 +529,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
@@ -631,9 +628,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
@@ -37,8 +37,6 @@
 
 namespace clangd {
 
-class Logger;
-
 /// Turn a [line, column] pair into an offset in Code.
 size_t positionToOffset(StringRef Code, Position P);
 
@@ -205,13 +203,10 @@
   ///
   /// \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,
-               clangd::Logger &Logger,
                llvm::Optional<StringRef> ResourceDir = llvm::None);
 
   /// Set the root path of the workspace.
@@ -223,17 +218,18 @@
   /// 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<Context> 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<Context> 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<Context> forceReparse(PathRef File, Context Ctx);
 
   /// DEPRECATED. Please use a callback-based version, this API is deprecated
   /// and will soon be removed.
@@ -252,19 +248,25 @@
   /// 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.
-  std::future<Tagged<CompletionList>>
+  ///
+  /// The callers are responsible for making sure \p Ctx stays alive until
+  /// std::future<> is ready (i.e. wait() or get() returns)
+  std::future<std::pair<Tagged<CompletionList>, Context>>
   codeComplete(PathRef File, Position Pos,
-               const clangd::CodeCompleteOptions &Opts,
+               const clangd::CodeCompleteOptions &Opts, 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.
-  void codeComplete(UniqueFunction<void(Tagged<CompletionList>)> Callback,
-                    PathRef File, Position Pos,
-                    const clangd::CodeCompleteOptions &Opts,
-                    llvm::Optional<StringRef> OverridenContents = llvm::None,
-                    IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
+  /// The callers are responsible for making sure \p Ctx stays alive until \p
+  /// Callback is executed.
+  void
+  codeComplete(UniqueFunction<void(Tagged<CompletionList>, Context)> Callback,
+               PathRef File, Position Pos,
+               const clangd::CodeCompleteOptions &Opts, Context Ctx,
+               llvm::Optional<StringRef> OverridenContents = llvm::None,
+               IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
 
   /// Provide signature help for \p File at \p Pos. If \p OverridenContents is
   /// not None, they will used only for signature help, i.e. no diagnostics
@@ -274,13 +276,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.
@@ -294,8 +296,8 @@
   std::vector<tooling::Replacement> formatOnType(PathRef File, Position Pos);
   /// Rename all occurrences of the symbol at the \p Pos in \p File to
   /// \p NewName.
-  Expected<std::vector<tooling::Replacement>> rename(PathRef File, Position Pos,
-                                                     llvm::StringRef NewName);
+  Expected<std::vector<tooling::Replacement>>
+  rename(PathRef File, Position Pos, llvm::StringRef NewName, Context &Ctx);
 
   /// Gets current document contents for \p File. \p File must point to a
   /// currently tracked file.
@@ -311,14 +313,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<Context> 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<Context> 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
@@ -28,14 +28,16 @@
 
 namespace {
 
-class FulfillPromiseGuard {
+class FulfillContextPromiseGuard {
 public:
-  FulfillPromiseGuard(std::promise<void> &Promise) : Promise(Promise) {}
+  FulfillContextPromiseGuard(std::promise<Context> &Promise, Context &Ctx)
+      : Promise(Promise), Ctx(Ctx) {}
 
-  ~FulfillPromiseGuard() { Promise.set_value(); }
+  ~FulfillContextPromiseGuard() { Promise.set_value(std::move(Ctx)); }
 
 private:
-  std::promise<void> &Promise;
+  std::promise<Context> &Promise;
+  Context &Ctx;
 };
 
 std::vector<tooling::Replacement> formatCode(StringRef Code, StringRef Filename,
@@ -173,10 +175,9 @@
                            DiagnosticsConsumer &DiagConsumer,
                            FileSystemProvider &FSProvider,
                            unsigned AsyncThreadsCount,
-                           bool StorePreamblesInMemory, clangd::Logger &Logger,
+                           bool StorePreamblesInMemory,
                            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),
@@ -189,65 +190,69 @@
     this->RootPath = NewRootPath;
 }
 
-std::future<void> ClangdServer::addDocument(PathRef File, StringRef Contents) {
+std::future<Context> 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<Context> 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<Context> 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>>
+std::future<std::pair<Tagged<CompletionList>, Context>>
 ClangdServer::codeComplete(PathRef File, Position Pos,
-                           const clangd::CodeCompleteOptions &Opts,
+                           const clangd::CodeCompleteOptions &Opts, Context Ctx,
                            llvm::Optional<StringRef> OverridenContents,
                            IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS) {
-  using ResultType = Tagged<CompletionList>;
+  using ResultType = std::pair<Tagged<CompletionList>, Context>;
 
   std::promise<ResultType> ResultPromise;
 
   auto Callback = [](std::promise<ResultType> ResultPromise,
-                     ResultType Result) -> void {
-    ResultPromise.set_value(std::move(Result));
+                     Tagged<CompletionList> Result, Context Ctx) -> void {
+    ResultPromise.set_value({std::move(Result), std::move(Ctx)});
   };
 
   std::future<ResultType> ResultFuture = ResultPromise.get_future();
   codeComplete(BindWithForward(Callback, std::move(ResultPromise)), File, Pos,
-               Opts, OverridenContents, UsedFS);
+               Opts, std::move(Ctx), OverridenContents, UsedFS);
   return ResultFuture;
 }
 
 void ClangdServer::codeComplete(
-    UniqueFunction<void(Tagged<CompletionList>)> Callback, PathRef File,
-    Position Pos, const clangd::CodeCompleteOptions &Opts,
-    llvm::Optional<StringRef> OverridenContents,
+    UniqueFunction<void(Tagged<CompletionList>, Context)> Callback,
+    PathRef File, Position Pos, const clangd::CodeCompleteOptions &Opts,
+    Context Ctx, llvm::Optional<StringRef> OverridenContents,
     IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS) {
-  using CallbackType = UniqueFunction<void(Tagged<CompletionList>)>;
+  using CallbackType = UniqueFunction<void(Tagged<CompletionList>, Context)>;
 
   std::string Contents;
   if (OverridenContents) {
@@ -278,7 +283,7 @@
   // A task that will be run asynchronously.
   auto Task =
       // 'mutable' to reassign Preamble variable.
-      [=](CallbackType Callback) mutable {
+      [=](CallbackType Callback, Context Ctx) mutable {
         if (!Preamble) {
           // Maybe we built some preamble before processing this request.
           Preamble = Resources->getPossiblyStalePreamble();
@@ -289,16 +294,18 @@
         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)));
+        Callback(make_tagged(std::move(Result), std::move(TaggedFS.Tag)),
+                 std::move(Ctx));
       };
 
-  WorkScheduler.addToFront(std::move(Task), std::move(Callback));
+  WorkScheduler.addToFront(std::move(Task), std::move(Callback),
+                           std::move(Ctx));
 }
 
 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;
@@ -324,10 +331,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);
 }
 
@@ -361,7 +368,8 @@
 }
 
 Expected<std::vector<tooling::Replacement>>
-ClangdServer::rename(PathRef File, Position Pos, llvm::StringRef NewName) {
+ClangdServer::rename(PathRef File, Position Pos, llvm::StringRef NewName,
+                     Context &Ctx) {
   std::string Code = getDocument(File);
   std::shared_ptr<CppFile> Resources = Units.getFile(File);
   RefactoringResultCollector ResultCollector;
@@ -432,7 +440,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);
@@ -442,10 +450,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,32 +517,32 @@
   return llvm::None;
 }
 
-std::future<void> ClangdServer::scheduleReparseAndDiags(
+std::future<Context> 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;
-  std::future<void> DoneFuture = DonePromise.get_future();
+  std::promise<Context> DonePromise;
+  std::future<Context> DoneFuture = DonePromise.get_future();
 
   DocVersion Version = Contents.Version;
   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 {
-    FulfillPromiseGuard Guard(DonePromise);
+      [this, FileStr, Version, Tag](
+          UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>(Context &)>
+              DeferredRebuild,
+          std::promise<Context> DonePromise, Context Ctx) -> void {
+    FulfillContextPromiseGuard Guard(DonePromise, Ctx);
 
     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.
 
@@ -555,28 +563,31 @@
   };
 
   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) {
-  std::promise<void> DonePromise;
-  std::future<void> DoneFuture = DonePromise.get_future();
+std::future<Context>
+ClangdServer::scheduleCancelRebuild(std::shared_ptr<CppFile> Resources,
+                                    Context Ctx) {
+  std::promise<Context> DonePromise;
+  std::future<Context> DoneFuture = DonePromise.get_future();
   if (!Resources) {
     // No need to schedule any cleanup.
-    DonePromise.set_value();
+    DonePromise.set_value(std::move(Ctx));
     return DoneFuture;
   }
 
   UniqueFunction<void()> DeferredCancel = Resources->deferCancelRebuild();
-  auto CancelReparses = [Resources](std::promise<void> DonePromise,
-                                    UniqueFunction<void()> DeferredCancel) {
-    FulfillPromiseGuard Guard(DonePromise);
+  auto CancelReparses = [Resources](std::promise<Context> DonePromise,
+                                    UniqueFunction<void()> DeferredCancel,
+                                    Context Ctx) {
+    FulfillContextPromiseGuard Guard(DonePromise, Ctx);
     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
@@ -35,7 +35,7 @@
 } // namespace
 
 void ClangdLSPServer::onInitialize(Ctx C, InitializeParams &Params) {
-  C.reply(json::obj{
+  reply(C, json::obj{
       {{"capabilities",
         json::obj{
             {"textDocumentSync", 1},
@@ -72,7 +72,7 @@
 void ClangdLSPServer::onShutdown(Ctx C, ShutdownParams &Params) {
   // Do essentially nothing, just say we're ready to exit.
   ShutdownRequestReceived = true;
-  C.reply(nullptr);
+  reply(C, nullptr);
 }
 
 void ClangdLSPServer::onExit(Ctx C, ExitParams &Params) { IsDone = true; }
@@ -82,17 +82,19 @@
   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,
+                     std::move(C));
 }
 
 void ClangdLSPServer::onDocumentDidChange(Ctx C,
                                           DidChangeTextDocumentParams &Params) {
   if (Params.contentChanges.size() != 1)
-    return C.replyError(ErrorCode::InvalidParams,
-                        "can only apply one change at a time");
+    return replyError(C, ErrorCode::InvalidParams,
+                      "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,
+                     std::move(C));
 }
 
 void ClangdLSPServer::onFileEvent(Ctx C, DidChangeWatchedFilesParams &Params) {
@@ -113,62 +115,63 @@
 
     ApplyWorkspaceEditParams ApplyEdit;
     ApplyEdit.edit = *Params.workspaceEdit;
-    C.reply("Fix applied.");
+    reply(C, "Fix applied.");
     // We don't need the response so id == 1 is OK.
     // Ideally, we would wait for the response and if there is no error, we
     // would reply success/failure to the original RPC.
-    C.call("workspace/applyEdit", ApplyEdit);
+    call(C, "workspace/applyEdit", ApplyEdit);
   } else {
     // We should not get here because ExecuteCommandParams would not have
     // parsed in the first place and this handler should not be called. But if
     // more commands are added, this will be here has a safe guard.
-    C.replyError(
+    replyError(C,
         ErrorCode::InvalidParams,
         llvm::formatv("Unsupported command \"{0}\".", Params.command).str());
   }
 }
 
 void ClangdLSPServer::onRename(Ctx C, RenameParams &Params) {
   auto File = Params.textDocument.uri.file;
-  auto Replacements = Server.rename(File, Params.position, Params.newName);
+  auto Replacements =
+      Server.rename(File, Params.position, Params.newName, C);
   if (!Replacements) {
-    C.replyError(ErrorCode::InternalError,
-                 llvm::toString(Replacements.takeError()));
+    replyError(C, ErrorCode::InternalError,
+               llvm::toString(Replacements.takeError()));
     return;
   }
   std::string Code = Server.getDocument(File);
   std::vector<TextEdit> Edits = replacementsToEdits(Code, *Replacements);
   WorkspaceEdit WE;
   WE.changes = {{Params.textDocument.uri.uri, Edits}};
-  C.reply(WE);
+  reply(C, WE);
 }
 
 void ClangdLSPServer::onDocumentDidClose(Ctx C,
                                          DidCloseTextDocumentParams &Params) {
-  Server.removeDocument(Params.textDocument.uri.file);
+  Server.removeDocument(Params.textDocument.uri.file, std::move(C));
 }
 
 void ClangdLSPServer::onDocumentOnTypeFormatting(
     Ctx C, DocumentOnTypeFormattingParams &Params) {
   auto File = Params.textDocument.uri.file;
   std::string Code = Server.getDocument(File);
-  C.reply(json::ary(
+  reply(C, json::ary(
       replacementsToEdits(Code, Server.formatOnType(File, Params.position))));
 }
 
 void ClangdLSPServer::onDocumentRangeFormatting(
     Ctx C, DocumentRangeFormattingParams &Params) {
   auto File = Params.textDocument.uri.file;
   std::string Code = Server.getDocument(File);
-  C.reply(json::ary(
+  reply(C, json::ary(
       replacementsToEdits(Code, Server.formatRange(File, Params.range))));
 }
 
 void ClangdLSPServer::onDocumentFormatting(Ctx C,
                                            DocumentFormattingParams &Params) {
   auto File = Params.textDocument.uri.file;
   std::string Code = Server.getDocument(File);
-  C.reply(json::ary(replacementsToEdits(Code, Server.formatFile(File))));
+  reply(C, json::ary(replacementsToEdits(Code, Server.formatFile(File))));
 }
 
 void ClangdLSPServer::onCodeAction(Ctx C, CodeActionParams &Params) {
@@ -190,68 +193,67 @@
       });
     }
   }
-  C.reply(std::move(Commands));
+  reply(C, std::move(Commands));
 }
 
 void ClangdLSPServer::onCompletion(Ctx C, TextDocumentPositionParams &Params) {
-  auto List =
-      Server
-          .codeComplete(
-              Params.textDocument.uri.file,
-              Position{Params.position.line, Params.position.character}, CCOpts)
-          .get() // FIXME(ibiryukov): This could be made async if we
-                 // had an API that would allow to attach callbacks to
-                 // futures returned by ClangdServer.
-          .Value;
-  C.reply(List);
+  auto List = Server
+                  .codeComplete(
+                      Params.textDocument.uri.file,
+                      Position{Params.position.line, Params.position.character},
+                      CCOpts, C.derive())
+                  .get() // FIXME(ibiryukov): This could be made async if we
+                         // had an API that would allow to attach callbacks to
+                         // futures returned by ClangdServer.
+                  .first.Value;
+  reply(C, 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);
   if (!SignatureHelp)
-    return C.replyError(ErrorCode::InvalidParams,
-                        llvm::toString(SignatureHelp.takeError()));
-  C.reply(SignatureHelp->Value);
+    return replyError(C, ErrorCode::InvalidParams,
+                      llvm::toString(SignatureHelp.takeError()));
+  reply(C, SignatureHelp->Value);
 }
 
 void ClangdLSPServer::onGoToDefinition(Ctx C,
                                        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);
   if (!Items)
-    return C.replyError(ErrorCode::InvalidParams,
-                        llvm::toString(Items.takeError()));
-  C.reply(json::ary(Items->Value));
+    return replyError(C, ErrorCode::InvalidParams,
+                      llvm::toString(Items.takeError()));
+  reply(C, json::ary(Items->Value));
 }
 
 void ClangdLSPServer::onSwitchSourceHeader(Ctx C,
                                            TextDocumentIdentifier &Params) {
   llvm::Optional<Path> Result = Server.switchSourceHeader(Params.uri.file);
   std::string ResultUri;
-  C.reply(Result ? URI::fromFile(*Result).uri : "");
+  reply(C, Result ? URI::fromFile(*Result).uri : "");
 }
 
 ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, unsigned AsyncThreadsCount,
                                  bool StorePreamblesInMemory,
                                  const clangd::CodeCompleteOptions &CCOpts,
                                  llvm::Optional<StringRef> ResourceDir,
                                  llvm::Optional<Path> CompileCommandsDir)
-    : Out(Out), CDB(/*Logger=*/Out, std::move(CompileCommandsDir)),
-      CCOpts(CCOpts), Server(CDB, /*DiagConsumer=*/*this, FSProvider,
-                             AsyncThreadsCount, StorePreamblesInMemory,
-                             /*Logger=*/Out, ResourceDir) {}
+    : Out(Out), CDB(std::move(CompileCommandsDir)), CCOpts(CCOpts),
+      Server(CDB, /*DiagConsumer=*/*this, FSProvider, AsyncThreadsCount,
+             StorePreamblesInMemory, ResourceDir) {}
 
 bool ClangdLSPServer::run(std::istream &In) {
   assert(!IsDone && "Run was called before");
 
   // Set up JSONRPCDispatcher.
   JSONRPCDispatcher Dispatcher(
-      [](RequestContext Ctx, const json::Expr &Params) {
-        Ctx.replyError(ErrorCode::MethodNotFound, "method not found");
+      [](Context Ctx, const json::Expr &Params) {
+        replyError(Ctx, ErrorCode::MethodNotFound, "method not found");
       });
   registerCallbackHandlers(Dispatcher, Out, /*Callbacks=*/*this);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to