[clang-tools-extra] r303067 - [ClangD] Refactor clangd into separate components

Adam Nemet via cfe-commits cfe-commits at lists.llvm.org
Mon May 15 09:28:28 PDT 2017


This broke the build http://green.lab.llvm.org/green/job/clang-stage1-configure-RA/34305/ <http://green.lab.llvm.org/green/job/clang-stage1-configure-RA/34305/>, please take a look.

Adam

> On May 15, 2017, at 7:17 AM, Ilya Biryukov via cfe-commits <cfe-commits at lists.llvm.org> wrote:
> 
> Author: ibiryukov
> Date: Mon May 15 09:17:35 2017
> New Revision: 303067
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=303067&view=rev
> Log:
> [ClangD] Refactor clangd into separate components
> 
> Summary: Major refactoring to split LSP implementation, Clang API calls and threading(mostly synchronization)
> 
> Reviewers: bkramer, krasimir
> 
> Reviewed By: bkramer
> 
> Subscribers: cfe-commits, mgorny, klimek
> 
> Tags: #clang-tools-extra
> 
> Differential Revision: https://reviews.llvm.org/D33047
> 
> Added:
>    clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
>    clang-tools-extra/trunk/clangd/ClangdLSPServer.h
>    clang-tools-extra/trunk/clangd/ClangdServer.cpp
>      - copied, changed from r303060, clang-tools-extra/trunk/clangd/ASTManager.cpp
>    clang-tools-extra/trunk/clangd/ClangdServer.h
>      - copied, changed from r303063, clang-tools-extra/trunk/clangd/ASTManager.h
>    clang-tools-extra/trunk/clangd/ClangdUnit.cpp
>    clang-tools-extra/trunk/clangd/ClangdUnit.h
>    clang-tools-extra/trunk/clangd/ClangdUnitStore.cpp
>    clang-tools-extra/trunk/clangd/ClangdUnitStore.h
>    clang-tools-extra/trunk/clangd/DraftStore.cpp
>    clang-tools-extra/trunk/clangd/DraftStore.h
>      - copied, changed from r303060, clang-tools-extra/trunk/clangd/DocumentStore.h
>    clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.cpp
>    clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.h
>    clang-tools-extra/trunk/clangd/Path.h
> Removed:
>    clang-tools-extra/trunk/clangd/ASTManager.cpp
>    clang-tools-extra/trunk/clangd/ASTManager.h
>    clang-tools-extra/trunk/clangd/DocumentStore.h
> Modified:
>    clang-tools-extra/trunk/clangd/CMakeLists.txt
>    clang-tools-extra/trunk/clangd/ClangdMain.cpp
>    clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
>    clang-tools-extra/trunk/clangd/ProtocolHandlers.h
> 
> Removed: clang-tools-extra/trunk/clangd/ASTManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ASTManager.cpp?rev=303066&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ASTManager.cpp (original)
> +++ clang-tools-extra/trunk/clangd/ASTManager.cpp (removed)
> @@ -1,440 +0,0 @@
> -//===--- ASTManager.cpp - Clang AST manager -------------------------------===//
> -//
> -//                     The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
> -//===----------------------------------------------------------------------===//
> -
> -#include "ASTManager.h"
> -#include "JSONRPCDispatcher.h"
> -#include "Protocol.h"
> -#include "clang/Frontend/ASTUnit.h"
> -#include "clang/Frontend/CompilerInstance.h"
> -#include "clang/Tooling/CompilationDatabase.h"
> -#include "llvm/Support/Format.h"
> -#include "llvm/Support/Path.h"
> -#include <mutex>
> -#include <thread>
> -using namespace clang;
> -using namespace clangd;
> -
> -void DocData::setAST(std::unique_ptr<ASTUnit> AST) {
> -  this->AST = std::move(AST);
> -}
> -
> -ASTUnit *DocData::getAST() const { return AST.get(); }
> -
> -void DocData::cacheFixIts(DiagnosticToReplacementMap FixIts) {
> -  this->FixIts = std::move(FixIts);
> -}
> -
> -std::vector<clang::tooling::Replacement>
> -DocData::getFixIts(const clangd::Diagnostic &D) const {
> -  auto it = FixIts.find(D);
> -  if (it != FixIts.end())
> -    return it->second;
> -  return {};
> -}
> -
> -ASTManagerRequest::ASTManagerRequest(ASTManagerRequestType Type,
> -                                     std::string File,
> -                                     DocVersion Version)
> -    : Type(Type), File(File), Version(Version) {}
> -
> -/// Retrieve a copy of the contents of every file in the store, for feeding into
> -/// ASTUnit.
> -static std::vector<ASTUnit::RemappedFile>
> -getRemappedFiles(const DocumentStore &Docs) {
> -  // FIXME: Use VFS instead. This would allow us to get rid of the chdir below.
> -  std::vector<ASTUnit::RemappedFile> RemappedFiles;
> -  for (const auto &P : Docs.getAllDocuments()) {
> -    StringRef FileName = P.first;
> -    RemappedFiles.push_back(ASTUnit::RemappedFile(
> -        FileName,
> -        llvm::MemoryBuffer::getMemBufferCopy(P.second, FileName).release()));
> -  }
> -  return RemappedFiles;
> -}
> -
> -/// Convert from clang diagnostic level to LSP severity.
> -static int getSeverity(DiagnosticsEngine::Level L) {
> -  switch (L) {
> -  case DiagnosticsEngine::Remark:
> -    return 4;
> -  case DiagnosticsEngine::Note:
> -    return 3;
> -  case DiagnosticsEngine::Warning:
> -    return 2;
> -  case DiagnosticsEngine::Fatal:
> -  case DiagnosticsEngine::Error:
> -    return 1;
> -  case DiagnosticsEngine::Ignored:
> -    return 0;
> -  }
> -  llvm_unreachable("Unknown diagnostic level!");
> -}
> -
> -static CompletionItemKind getKind(CXCursorKind K) {
> -  switch (K) {
> -  case CXCursor_MacroInstantiation:
> -  case CXCursor_MacroDefinition:
> -    return CompletionItemKind::Text;
> -  case CXCursor_CXXMethod:
> -    return CompletionItemKind::Method;
> -  case CXCursor_FunctionDecl:
> -  case CXCursor_FunctionTemplate:
> -    return CompletionItemKind::Function;
> -  case CXCursor_Constructor:
> -  case CXCursor_Destructor:
> -    return CompletionItemKind::Constructor;
> -  case CXCursor_FieldDecl:
> -    return CompletionItemKind::Field;
> -  case CXCursor_VarDecl:
> -  case CXCursor_ParmDecl:
> -    return CompletionItemKind::Variable;
> -  case CXCursor_ClassDecl:
> -  case CXCursor_StructDecl:
> -  case CXCursor_UnionDecl:
> -  case CXCursor_ClassTemplate:
> -  case CXCursor_ClassTemplatePartialSpecialization:
> -    return CompletionItemKind::Class;
> -  case CXCursor_Namespace:
> -  case CXCursor_NamespaceAlias:
> -  case CXCursor_NamespaceRef:
> -    return CompletionItemKind::Module;
> -  case CXCursor_EnumConstantDecl:
> -    return CompletionItemKind::Value;
> -  case CXCursor_EnumDecl:
> -    return CompletionItemKind::Enum;
> -  case CXCursor_TypeAliasDecl:
> -  case CXCursor_TypeAliasTemplateDecl:
> -  case CXCursor_TypedefDecl:
> -  case CXCursor_MemberRef:
> -  case CXCursor_TypeRef:
> -    return CompletionItemKind::Reference;
> -  default:
> -    return CompletionItemKind::Missing;
> -  }
> -}
> -
> -ASTManager::ASTManager(JSONOutput &Output, DocumentStore &Store,
> -                       bool RunSynchronously)
> -    : Output(Output), Store(Store), RunSynchronously(RunSynchronously),
> -      PCHs(std::make_shared<PCHContainerOperations>()),
> -      ClangWorker([this]() { runWorker(); }) {}
> -
> -void ASTManager::runWorker() {
> -  while (true) {
> -    ASTManagerRequest Request;
> -
> -    // Pick request from the queue
> -    {
> -      std::unique_lock<std::mutex> Lock(RequestLock);
> -      // Wait for more requests.
> -      ClangRequestCV.wait(Lock,
> -                          [this] { return !RequestQueue.empty() || Done; });
> -      if (Done)
> -        return;
> -      assert(!RequestQueue.empty() && "RequestQueue was empty");
> -
> -      Request = std::move(RequestQueue.back());
> -      RequestQueue.pop_back();
> -
> -      // Skip outdated requests
> -      if (Request.Version != DocVersions.find(Request.File)->second) {
> -        Output.log("Version for " + Twine(Request.File) +
> -                   " in request is outdated, skipping request\n");
> -        continue;
> -      }
> -    } // unlock RequestLock
> -
> -    handleRequest(Request.Type, Request.File);
> -  }
> -}
> -
> -void ASTManager::queueOrRun(ASTManagerRequestType RequestType, StringRef File) {
> -  if (RunSynchronously) {
> -    handleRequest(RequestType, File);
> -    return;
> -  }
> -
> -  std::lock_guard<std::mutex> Guard(RequestLock);
> -  // We increment the version of the added document immediately and schedule
> -  // the requested operation to be run on a worker thread
> -  DocVersion version = ++DocVersions[File];
> -  RequestQueue.push_back(ASTManagerRequest(RequestType, File, version));
> -  ClangRequestCV.notify_one();
> -}
> -
> -void ASTManager::handleRequest(ASTManagerRequestType RequestType,
> -                               StringRef File) {
> -  switch (RequestType) {
> -  case ASTManagerRequestType::ParseAndPublishDiagnostics:
> -    parseFileAndPublishDiagnostics(File);
> -    break;
> -  case ASTManagerRequestType::RemoveDocData: {
> -    std::lock_guard<std::mutex> Lock(ClangObjectLock);
> -    auto DocDataIt = DocDatas.find(File);
> -    // We could get the remove request before parsing for the document is
> -    // started, just do nothing in that case, parsing request will be discarded
> -    // because it has a lower version value
> -    if (DocDataIt == DocDatas.end())
> -      return;
> -    DocDatas.erase(DocDataIt);
> -    break;
> -  } // unlock ClangObjectLock
> -  }
> -}
> -
> -void ASTManager::parseFileAndPublishDiagnostics(StringRef File) {
> -  std::unique_lock<std::mutex> ClangObjectLockGuard(ClangObjectLock);
> -
> -  auto &DocData = DocDatas[File];
> -  ASTUnit *Unit = DocData.getAST();
> -  if (!Unit) {
> -    auto newAST = createASTUnitForFile(File, this->Store);
> -    Unit = newAST.get();
> -
> -    DocData.setAST(std::move(newAST));
> -  } else {
> -    // Do a reparse if this wasn't the first parse.
> -    // FIXME: This might have the wrong working directory if it changed in the
> -    // meantime.
> -    Unit->Reparse(PCHs, getRemappedFiles(this->Store));
> -  }
> -
> -  if (!Unit)
> -    return;
> -
> -  // Send the diagnotics to the editor.
> -  // FIXME: If the diagnostic comes from a different file, do we want to
> -  // show them all? Right now we drop everything not coming from the
> -  // main file.
> -  std::string Diagnostics;
> -  DocData::DiagnosticToReplacementMap LocalFixIts; // Temporary storage
> -  for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
> -                                     DEnd = Unit->stored_diag_end();
> -       D != DEnd; ++D) {
> -    if (!D->getLocation().isValid() ||
> -        !D->getLocation().getManager().isInMainFile(D->getLocation()))
> -      continue;
> -    Position P;
> -    P.line = D->getLocation().getSpellingLineNumber() - 1;
> -    P.character = D->getLocation().getSpellingColumnNumber();
> -    Range R = {P, P};
> -    Diagnostics +=
> -        R"({"range":)" + Range::unparse(R) +
> -        R"(,"severity":)" + std::to_string(getSeverity(D->getLevel())) +
> -        R"(,"message":")" + llvm::yaml::escape(D->getMessage()) +
> -        R"("},)";
> -
> -    // We convert to Replacements to become independent of the SourceManager.
> -    clangd::Diagnostic Diag = {R, getSeverity(D->getLevel()), D->getMessage()};
> -    auto &FixItsForDiagnostic = LocalFixIts[Diag];
> -    for (const FixItHint &Fix : D->getFixIts()) {
> -      FixItsForDiagnostic.push_back(clang::tooling::Replacement(
> -          Unit->getSourceManager(), Fix.RemoveRange, Fix.CodeToInsert));
> -    }
> -  }
> -
> -  // Put FixIts into place.
> -  DocData.cacheFixIts(std::move(LocalFixIts));
> -
> -  ClangObjectLockGuard.unlock();
> -  // No accesses to clang objects are allowed after this point.
> -
> -  // Publish diagnostics.
> -  if (!Diagnostics.empty())
> -    Diagnostics.pop_back(); // Drop trailing comma.
> -  Output.writeMessage(
> -      R"({"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":")" +
> -      URI::fromFile(File).uri + R"(","diagnostics":[)" + Diagnostics + R"(]}})");
> -}
> -
> -ASTManager::~ASTManager() {
> -  {
> -    std::lock_guard<std::mutex> Guard(RequestLock);
> -    // Wake up the clang worker thread, then exit.
> -    Done = true;
> -    ClangRequestCV.notify_one();
> -  } // unlock DocDataLock
> -  ClangWorker.join();
> -}
> -
> -void ASTManager::onDocumentAdd(StringRef File) {
> -  queueOrRun(ASTManagerRequestType::ParseAndPublishDiagnostics, File);
> -}
> -
> -void ASTManager::onDocumentRemove(StringRef File) {
> -  queueOrRun(ASTManagerRequestType::RemoveDocData, File);
> -}
> -
> -tooling::CompilationDatabase *
> -ASTManager::getOrCreateCompilationDatabaseForFile(StringRef File) {
> -  namespace path = llvm::sys::path;
> -
> -  assert((path::is_absolute(File, path::Style::posix) ||
> -          path::is_absolute(File, path::Style::windows)) &&
> -         "path must be absolute");
> -
> -  for (auto Path = path::parent_path(File); !Path.empty();
> -       Path = path::parent_path(Path)) {
> -
> -    auto CachedIt = CompilationDatabases.find(Path);
> -    if (CachedIt != CompilationDatabases.end())
> -      return CachedIt->second.get();
> -    std::string Error;
> -    auto CDB = tooling::CompilationDatabase::loadFromDirectory(Path, Error);
> -    if (!CDB) {
> -      if (!Error.empty()) {
> -        Output.log("Error when trying to load compilation database from " +
> -                   Twine(Path) + ": " + Twine(Error) + "\n");
> -      }
> -      continue;
> -    }
> -
> -    // TODO(ibiryukov): Invalidate cached compilation databases on changes
> -    auto result = CDB.get();
> -    CompilationDatabases.insert(std::make_pair(Path, std::move(CDB)));
> -    return result;
> -  }
> -
> -  Output.log("Failed to find compilation database for " + Twine(File) + "\n");
> -  return nullptr;
> -}
> -
> -std::unique_ptr<clang::ASTUnit>
> -ASTManager::createASTUnitForFile(StringRef File, const DocumentStore &Docs) {
> -  tooling::CompilationDatabase *CDB =
> -      getOrCreateCompilationDatabaseForFile(File);
> -
> -  std::vector<tooling::CompileCommand> Commands;
> -
> -  if (CDB) {
> -    Commands = CDB->getCompileCommands(File);
> -    // chdir. This is thread hostile.
> -    if (!Commands.empty())
> -      llvm::sys::fs::set_current_path(Commands.front().Directory);
> -  }
> -  if (Commands.empty()) {
> -    // Add a fake command line if we know nothing.
> -    Commands.push_back(tooling::CompileCommand(
> -        llvm::sys::path::parent_path(File), llvm::sys::path::filename(File),
> -        {"clang", "-fsyntax-only", File.str()}, ""));
> -  }
> -
> -  // Inject the resource dir.
> -  // FIXME: Don't overwrite it if it's already there.
> -  static int Dummy; // Just an address in this process.
> -  std::string ResourceDir =
> -      CompilerInvocation::GetResourcesPath("clangd", (void *)&Dummy);
> -  Commands.front().CommandLine.push_back("-resource-dir=" + ResourceDir);
> -
> -  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
> -      CompilerInstance::createDiagnostics(new DiagnosticOptions);
> -
> -  std::vector<const char *> ArgStrs;
> -  for (const auto &S : Commands.front().CommandLine)
> -    ArgStrs.push_back(S.c_str());
> -
> -  auto ArgP = &*ArgStrs.begin();
> -  return std::unique_ptr<clang::ASTUnit>(ASTUnit::LoadFromCommandLine(
> -      ArgP, ArgP + ArgStrs.size(), PCHs, Diags, ResourceDir,
> -      /*OnlyLocalDecls=*/false, /*CaptureDiagnostics=*/true,
> -      getRemappedFiles(Docs),
> -      /*RemappedFilesKeepOriginalName=*/true,
> -      /*PrecompilePreambleAfterNParses=*/1, /*TUKind=*/TU_Complete,
> -      /*CacheCodeCompletionResults=*/true,
> -      /*IncludeBriefCommentsInCodeCompletion=*/true,
> -      /*AllowPCHWithCompilerErrors=*/true));
> -}
> -
> -std::vector<clang::tooling::Replacement>
> -ASTManager::getFixIts(StringRef File, const clangd::Diagnostic &D) {
> -  // TODO(ibiryukov): the FixIts should be available immediately
> -  // even when parsing is being run on a worker thread
> -  std::lock_guard<std::mutex> Guard(ClangObjectLock);
> -  return DocDatas[File].getFixIts(D);
> -}
> -
> -namespace {
> -class CompletionItemsCollector : public CodeCompleteConsumer {
> -  std::vector<CompletionItem> *Items;
> -  std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
> -  CodeCompletionTUInfo CCTUInfo;
> -
> -public:
> -  CompletionItemsCollector(std::vector<CompletionItem> *Items,
> -                           const CodeCompleteOptions &CodeCompleteOpts)
> -      : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
> -        Items(Items),
> -        Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
> -        CCTUInfo(Allocator) {}
> -
> -  void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
> -                                  CodeCompletionResult *Results,
> -                                  unsigned NumResults) override {
> -    for (unsigned I = 0; I != NumResults; ++I) {
> -      CodeCompletionResult &Result = Results[I];
> -      CodeCompletionString *CCS = Result.CreateCodeCompletionString(
> -          S, Context, *Allocator, CCTUInfo,
> -          CodeCompleteOpts.IncludeBriefComments);
> -      if (CCS) {
> -        CompletionItem Item;
> -        assert(CCS->getTypedText());
> -        Item.label = CCS->getTypedText();
> -        Item.kind = getKind(Result.CursorKind);
> -        if (CCS->getBriefComment())
> -          Item.documentation = CCS->getBriefComment();
> -        Items->push_back(std::move(Item));
> -      }
> -    }
> -  }
> -
> -  GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
> -
> -  CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
> -};
> -
> -} // namespace
> -
> -std::vector<CompletionItem>
> -ASTManager::codeComplete(StringRef File, unsigned Line, unsigned Column) {
> -  CodeCompleteOptions CCO;
> -  CCO.IncludeBriefComments = 1;
> -  // This is where code completion stores dirty buffers. Need to free after
> -  // completion.
> -  SmallVector<const llvm::MemoryBuffer *, 4> OwnedBuffers;
> -  SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
> -  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
> -      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions));
> -  std::vector<CompletionItem> Items;
> -  CompletionItemsCollector Collector(&Items, CCO);
> -
> -  std::lock_guard<std::mutex> Guard(ClangObjectLock);
> -  auto &DocData = DocDatas[File];
> -  auto Unit = DocData.getAST();
> -  if (!Unit) {
> -    auto newAST = createASTUnitForFile(File, this->Store);
> -    Unit = newAST.get();
> -    DocData.setAST(std::move(newAST));
> -  }
> -  if (!Unit)
> -    return {};
> -  IntrusiveRefCntPtr<SourceManager> SourceMgr(
> -      new SourceManager(*DiagEngine, Unit->getFileManager()));
> -  // CodeComplete seems to require fresh LangOptions.
> -  LangOptions LangOpts = Unit->getLangOpts();
> -  // The language server protocol uses zero-based line and column numbers.
> -  // The clang code completion uses one-based numbers.
> -  Unit->CodeComplete(File, Line + 1, Column + 1, getRemappedFiles(this->Store),
> -                     CCO.IncludeMacros, CCO.IncludeCodePatterns,
> -                     CCO.IncludeBriefComments, Collector, PCHs, *DiagEngine,
> -                     LangOpts, *SourceMgr, Unit->getFileManager(),
> -                     StoredDiagnostics, OwnedBuffers);
> -  for (const llvm::MemoryBuffer *Buffer : OwnedBuffers)
> -    delete Buffer;
> -  return Items;
> -}
> 
> Removed: clang-tools-extra/trunk/clangd/ASTManager.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ASTManager.h?rev=303066&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ASTManager.h (original)
> +++ clang-tools-extra/trunk/clangd/ASTManager.h (removed)
> @@ -1,162 +0,0 @@
> -//===--- ASTManager.h - Clang AST manager -----------------------*- C++ -*-===//
> -//
> -//                     The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
> -//===----------------------------------------------------------------------===//
> -
> -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTMANAGER_H
> -#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTMANAGER_H
> -
> -#include "DocumentStore.h"
> -#include "JSONRPCDispatcher.h"
> -#include "Protocol.h"
> -#include "clang/Tooling/Core/Replacement.h"
> -#include "llvm/ADT/IntrusiveRefCntPtr.h"
> -#include <condition_variable>
> -#include <deque>
> -#include <thread>
> -
> -namespace clang {
> -class ASTUnit;
> -class DiagnosticsEngine;
> -class PCHContainerOperations;
> -namespace tooling {
> -class CompilationDatabase;
> -} // namespace tooling
> -
> -namespace clangd {
> -
> -/// Using 'unsigned' here to avoid undefined behaviour on overflow.
> -typedef unsigned DocVersion;
> -
> -/// Stores ASTUnit and FixIts map for an opened document.
> -class DocData {
> -public:
> -  typedef std::map<clangd::Diagnostic, std::vector<clang::tooling::Replacement>>
> -      DiagnosticToReplacementMap;
> -
> -public:
> -  void setAST(std::unique_ptr<ASTUnit> AST);
> -  ASTUnit *getAST() const;
> -
> -  void cacheFixIts(DiagnosticToReplacementMap FixIts);
> -  std::vector<clang::tooling::Replacement>
> -  getFixIts(const clangd::Diagnostic &D) const;
> -
> -private:
> -  std::unique_ptr<ASTUnit> AST;
> -  DiagnosticToReplacementMap FixIts;
> -};
> -
> -enum class ASTManagerRequestType { ParseAndPublishDiagnostics, RemoveDocData };
> -
> -/// A request to the worker thread
> -class ASTManagerRequest {
> -public:
> -  ASTManagerRequest() = default;
> -  ASTManagerRequest(ASTManagerRequestType Type, std::string File,
> -                    DocVersion Version);
> -
> -  ASTManagerRequestType Type;
> -  std::string File;
> -  DocVersion Version;
> -};
> -
> -class ASTManager : public DocumentStoreListener {
> -public:
> -  ASTManager(JSONOutput &Output, DocumentStore &Store, bool RunSynchronously);
> -  ~ASTManager() override;
> -
> -  void onDocumentAdd(StringRef File) override;
> -  void onDocumentRemove(StringRef File) override;
> -
> -  /// Get code completions at a specified \p Line and \p Column in \p File.
> -  ///
> -  /// This function is thread-safe and returns completion items that own the
> -  /// data they contain.
> -  std::vector<CompletionItem> codeComplete(StringRef File, unsigned Line,
> -                                           unsigned Column);
> -
> -  /// Get the fixes associated with a certain diagnostic in a specified file as
> -  /// replacements.
> -  ///
> -  /// This function is thread-safe. It returns a copy to avoid handing out
> -  /// references to unguarded data.
> -  std::vector<clang::tooling::Replacement>
> -  getFixIts(StringRef File, const clangd::Diagnostic &D);
> -
> -  DocumentStore &getStore() const { return Store; }
> -
> -private:
> -  JSONOutput &Output;
> -  DocumentStore &Store;
> -
> -  // Set to true if requests should block instead of being processed
> -  // asynchronously.
> -  bool RunSynchronously;
> -
> -  /// Loads a compilation database for File. May return nullptr if it fails. The
> -  /// database is cached for subsequent accesses.
> -  clang::tooling::CompilationDatabase *
> -  getOrCreateCompilationDatabaseForFile(StringRef File);
> -  // Creates a new ASTUnit for the document at File.
> -  // FIXME: This calls chdir internally, which is thread unsafe.
> -  std::unique_ptr<clang::ASTUnit>
> -  createASTUnitForFile(StringRef File, const DocumentStore &Docs);
> -
> -  /// If RunSynchronously is false, queues the request to be run on the worker
> -  /// thread.
> -  /// If RunSynchronously is true, runs the request handler immediately on the
> -  /// main thread.
> -  void queueOrRun(ASTManagerRequestType RequestType, StringRef File);
> -
> -  void runWorker();
> -  void handleRequest(ASTManagerRequestType RequestType, StringRef File);
> -
> -  /// Parses files and publishes diagnostics.
> -  /// This function is called on the worker thread in asynchronous mode and
> -  /// on the main thread in synchronous mode.
> -  void parseFileAndPublishDiagnostics(StringRef File);
> -
> -  /// Caches compilation databases loaded from directories(keys are directories).
> -  llvm::StringMap<std::unique_ptr<clang::tooling::CompilationDatabase>>
> -      CompilationDatabases;
> -
> -  /// Clang objects.
> -  /// A map from filenames to DocData structures that store ASTUnit and Fixits for
> -  /// the files. The ASTUnits are used for generating diagnostics and fix-it-s
> -  /// asynchronously by the worker thread and synchronously for code completion.
> -  llvm::StringMap<DocData> DocDatas;
> -  std::shared_ptr<clang::PCHContainerOperations> PCHs;
> -  /// A lock for access to the DocDatas, CompilationDatabases and PCHs.
> -  std::mutex ClangObjectLock;
> -
> -  /// Stores latest versions of the tracked documents to discard outdated requests.
> -  /// Guarded by RequestLock.
> -  /// TODO(ibiryukov): the entries are neved deleted from this map.
> -  llvm::StringMap<DocVersion> DocVersions;
> -
> -  /// A LIFO queue of requests. Note that requests are discarded if the `version`
> -  /// field is not equal to the one stored inside DocVersions.
> -  /// TODO(krasimir): code completion should always have priority over parsing
> -  /// for diagnostics.
> -  std::deque<ASTManagerRequest> RequestQueue;
> -  /// Setting Done to true will make the worker thread terminate.
> -  bool Done = false;
> -  /// Condition variable to wake up the worker thread.
> -  std::condition_variable ClangRequestCV;
> -  /// Lock for accesses to RequestQueue, DocVersions and Done.
> -  std::mutex RequestLock;
> -
> -  /// We run parsing on a separate thread. This thread looks into RequestQueue to
> -  /// find requests to handle and terminates when Done is set to true.
> -  std::thread ClangWorker;
> -};
> -
> -} // namespace clangd
> -} // namespace clang
> -
> -#endif
> 
> Modified: clang-tools-extra/trunk/clangd/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CMakeLists.txt?rev=303067&r1=303066&r2=303067&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/CMakeLists.txt (original)
> +++ clang-tools-extra/trunk/clangd/CMakeLists.txt Mon May 15 09:17:35 2017
> @@ -1,6 +1,11 @@
> add_clang_executable(clangd
> -  ASTManager.cpp
> +  ClangdLSPServer.cpp
>   ClangdMain.cpp
> +  ClangdServer.cpp
> +  ClangdUnit.cpp
> +  ClangdUnitStore.cpp
> +  DraftStore.cpp
> +  GlobalCompilationDatabase.cpp
>   JSONRPCDispatcher.cpp
>   Protocol.cpp
>   ProtocolHandlers.cpp
> 
> Added: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=303067&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp (added)
> +++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp Mon May 15 09:17:35 2017
> @@ -0,0 +1,100 @@
> +//===--- ClangdLSPServer.cpp - LSP server ------------------------*- C++-*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#include "ClangdLSPServer.h"
> +#include "JSONRPCDispatcher.h"
> +
> +using namespace clang::clangd;
> +using namespace clang;
> +
> +class ClangdLSPServer::LSPDiagnosticsConsumer : public DiagnosticsConsumer {
> +public:
> +  LSPDiagnosticsConsumer(ClangdLSPServer &Server) : Server(Server) {}
> +
> +  virtual void onDiagnosticsReady(PathRef File,
> +                                  std::vector<DiagWithFixIts> Diagnostics) {
> +    Server.consumeDiagnostics(File, Diagnostics);
> +  }
> +
> +private:
> +  ClangdLSPServer &Server;
> +};
> +
> +ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, bool RunSynchronously)
> +    : Out(Out),
> +      Server(llvm::make_unique<DirectoryBasedGlobalCompilationDatabase>(),
> +             llvm::make_unique<LSPDiagnosticsConsumer>(*this),
> +             RunSynchronously) {}
> +
> +void ClangdLSPServer::openDocument(StringRef File, StringRef Contents) {
> +  Server.addDocument(File, Contents);
> +}
> +
> +void ClangdLSPServer::closeDocument(StringRef File) {
> +  Server.removeDocument(File);
> +}
> +
> +std::vector<CompletionItem> ClangdLSPServer::codeComplete(PathRef File,
> +                                                          Position Pos) {
> +  return Server.codeComplete(File, Pos);
> +}
> +
> +std::vector<clang::tooling::Replacement>
> +ClangdLSPServer::getFixIts(StringRef File, const clangd::Diagnostic &D) {
> +  std::lock_guard<std::mutex> Lock(FixItsMutex);
> +  auto DiagToFixItsIter = FixItsMap.find(File);
> +  if (DiagToFixItsIter == FixItsMap.end())
> +    return {};
> +
> +  const auto &DiagToFixItsMap = DiagToFixItsIter->second;
> +  auto FixItsIter = DiagToFixItsMap.find(D);
> +  if (FixItsIter == DiagToFixItsMap.end())
> +    return {};
> +
> +  return FixItsIter->second;
> +}
> +
> +std::string ClangdLSPServer::getDocument(PathRef File) {
> +  return Server.getDocument(File);
> +}
> +
> +void ClangdLSPServer::consumeDiagnostics(
> +    PathRef File, std::vector<DiagWithFixIts> Diagnostics) {
> +  std::string DiagnosticsJSON;
> +
> +  DiagnosticToReplacementMap LocalFixIts; // Temporary storage
> +  for (auto &DiagWithFixes : Diagnostics) {
> +    auto Diag = DiagWithFixes.Diag;
> +    DiagnosticsJSON +=
> +        R"({"range":)" + Range::unparse(Diag.range) +
> +        R"(,"severity":)" + std::to_string(Diag.severity) +
> +        R"(,"message":")" + llvm::yaml::escape(Diag.message) +
> +        R"("},)";
> +
> +    // We convert to Replacements to become independent of the SourceManager.
> +    auto &FixItsForDiagnostic = LocalFixIts[Diag];
> +    std::copy(DiagWithFixes.FixIts.begin(), DiagWithFixes.FixIts.end(),
> +              std::back_inserter(FixItsForDiagnostic));
> +  }
> +
> +  // Cache FixIts
> +  {
> +    // FIXME(ibiryukov): should be deleted when documents are removed
> +    std::lock_guard<std::mutex> Lock(FixItsMutex);
> +    FixItsMap[File] = LocalFixIts;
> +  }
> +
> +  // Publish diagnostics.
> +  if (!DiagnosticsJSON.empty())
> +    DiagnosticsJSON.pop_back(); // Drop trailing comma.
> +  Out.writeMessage(
> +      R"({"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":")" +
> +      URI::fromFile(File).uri + R"(","diagnostics":[)" + DiagnosticsJSON +
> +      R"(]}})");
> +}
> 
> Added: clang-tools-extra/trunk/clangd/ClangdLSPServer.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.h?rev=303067&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdLSPServer.h (added)
> +++ clang-tools-extra/trunk/clangd/ClangdLSPServer.h Mon May 15 09:17:35 2017
> @@ -0,0 +1,79 @@
> +//===--- ClangdLSPServer.h - LSP server --------------------------*- C++-*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
> +
> +#include "ClangdServer.h"
> +#include "Path.h"
> +#include "Protocol.h"
> +#include "clang/Tooling/Core/Replacement.h"
> +
> +namespace clang {
> +namespace clangd {
> +
> +class JSONOutput;
> +
> +/// This class serves as an intermediate layer of LSP server implementation,
> +/// glueing the JSON LSP protocol layer and ClangdServer together. It doesn't
> +/// directly handle input from LSP client.
> +/// Most methods are synchronous and return their result directly, but
> +/// diagnostics are provided asynchronously when ready via
> +/// JSONOutput::writeMessage.
> +class ClangdLSPServer {
> +public:
> +  ClangdLSPServer(JSONOutput &Out, bool RunSynchronously);
> +
> +  /// Update the document text for \p File with \p Contents, schedule update of
> +  /// diagnostics. Out.writeMessage will called to push diagnostics to LSP
> +  /// client asynchronously when they are ready.
> +  void openDocument(PathRef File, StringRef Contents);
> +  /// Stop tracking the document for \p File.
> +  void closeDocument(PathRef File);
> +
> +  /// Run code completion synchronously.
> +  std::vector<CompletionItem> codeComplete(PathRef File, Position Pos);
> +
> +  /// Get the fixes associated with a certain diagnostic in a specified file as
> +  /// replacements.
> +  ///
> +  /// This function is thread-safe. It returns a copy to avoid handing out
> +  /// references to unguarded data.
> +  std::vector<clang::tooling::Replacement>
> +  getFixIts(StringRef File, const clangd::Diagnostic &D);
> +
> +  /// Get the current document contents stored for \p File.
> +  /// FIXME(ibiryukov): This function is here to allow implementation of
> +  /// formatCode from ProtocolHandlers.cpp. We should move formatCode to
> +  /// ClangdServer class and remove this function from public interface.
> +  std::string getDocument(PathRef File);
> +
> +private:
> +  class LSPDiagnosticsConsumer;
> +
> +  /// Function that will be called on a separate thread when diagnostics are
> +  /// ready. Sends the Dianostics to LSP client via Out.writeMessage and caches
> +  /// corresponding fixits in the FixItsMap.
> +  void consumeDiagnostics(PathRef File,
> +                          std::vector<DiagWithFixIts> Diagnostics);
> +
> +  JSONOutput &Out;
> +  ClangdServer Server;
> +
> +  std::mutex FixItsMutex;
> +  typedef std::map<clangd::Diagnostic, std::vector<clang::tooling::Replacement>>
> +      DiagnosticToReplacementMap;
> +  /// Caches FixIts per file and diagnostics
> +  llvm::StringMap<DiagnosticToReplacementMap> FixItsMap;
> +};
> +
> +} // namespace clangd
> +} // namespace clang
> +
> +#endif
> 
> Modified: clang-tools-extra/trunk/clangd/ClangdMain.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdMain.cpp?rev=303067&r1=303066&r2=303067&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdMain.cpp (original)
> +++ clang-tools-extra/trunk/clangd/ClangdMain.cpp Mon May 15 09:17:35 2017
> @@ -7,15 +7,19 @@
> //
> //===----------------------------------------------------------------------===//
> 
> -#include "ASTManager.h"
> -#include "DocumentStore.h"
> #include "JSONRPCDispatcher.h"
> +#include "ClangdLSPServer.h"
> +#include "Protocol.h"
> #include "ProtocolHandlers.h"
> #include "llvm/Support/CommandLine.h"
> #include "llvm/Support/FileSystem.h"
> #include "llvm/Support/Program.h"
> +
> #include <iostream>
> +#include <memory>
> #include <string>
> +
> +using namespace clang;
> using namespace clang::clangd;
> 
> static llvm::cl::opt<bool>
> @@ -34,9 +38,7 @@ int main(int argc, char *argv[]) {
> 
>   // Set up a document store and intialize all the method handlers for JSONRPC
>   // dispatching.
> -  DocumentStore Store;
> -  ASTManager AST(Out, Store, RunSynchronously);
> -  Store.addListener(&AST);
> +  ClangdLSPServer LSPServer(Out, RunSynchronously);
>   JSONRPCDispatcher Dispatcher(llvm::make_unique<Handler>(Out));
>   Dispatcher.registerHandler("initialize",
>                              llvm::make_unique<InitializeHandler>(Out));
> @@ -45,26 +47,26 @@ int main(int argc, char *argv[]) {
>   Dispatcher.registerHandler("shutdown", std::move(ShutdownPtr));
>   Dispatcher.registerHandler(
>       "textDocument/didOpen",
> -      llvm::make_unique<TextDocumentDidOpenHandler>(Out, Store));
> +      llvm::make_unique<TextDocumentDidOpenHandler>(Out, LSPServer));
>   Dispatcher.registerHandler(
>       "textDocument/didClose",
> -      llvm::make_unique<TextDocumentDidCloseHandler>(Out, Store));
> +      llvm::make_unique<TextDocumentDidCloseHandler>(Out, LSPServer));
>   Dispatcher.registerHandler(
>       "textDocument/didChange",
> -      llvm::make_unique<TextDocumentDidChangeHandler>(Out, Store));
> +      llvm::make_unique<TextDocumentDidChangeHandler>(Out, LSPServer));
>   Dispatcher.registerHandler(
>       "textDocument/rangeFormatting",
> -      llvm::make_unique<TextDocumentRangeFormattingHandler>(Out, Store));
> +      llvm::make_unique<TextDocumentRangeFormattingHandler>(Out, LSPServer));
>   Dispatcher.registerHandler(
>       "textDocument/onTypeFormatting",
> -      llvm::make_unique<TextDocumentOnTypeFormattingHandler>(Out, Store));
> +      llvm::make_unique<TextDocumentOnTypeFormattingHandler>(Out, LSPServer));
>   Dispatcher.registerHandler(
>       "textDocument/formatting",
> -      llvm::make_unique<TextDocumentFormattingHandler>(Out, Store));
> +      llvm::make_unique<TextDocumentFormattingHandler>(Out, LSPServer));
>   Dispatcher.registerHandler("textDocument/codeAction",
> -                             llvm::make_unique<CodeActionHandler>(Out, AST));
> +                             llvm::make_unique<CodeActionHandler>(Out, LSPServer));
>   Dispatcher.registerHandler("textDocument/completion",
> -                             llvm::make_unique<CompletionHandler>(Out, AST));
> +                             llvm::make_unique<CompletionHandler>(Out, LSPServer));
> 
>   while (std::cin.good()) {
>     // A Language Server Protocol message starts with a HTTP header, delimited
> 
> Copied: clang-tools-extra/trunk/clangd/ClangdServer.cpp (from r303060, clang-tools-extra/trunk/clangd/ASTManager.cpp)
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.cpp?p2=clang-tools-extra/trunk/clangd/ClangdServer.cpp&p1=clang-tools-extra/trunk/clangd/ASTManager.cpp&r1=303060&r2=303067&rev=303067&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ASTManager.cpp (original)
> +++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Mon May 15 09:17:35 2017
> @@ -1,440 +1,149 @@
> -//===--- ASTManager.cpp - Clang AST manager -------------------------------===//
> +//===--- ClangdServer.cpp - Main clangd server code --------------*- C++-*-===//
> //
> //                     The LLVM Compiler Infrastructure
> //
> // This file is distributed under the University of Illinois Open Source
> // License. See LICENSE.TXT for details.
> //
> -//===----------------------------------------------------------------------===//
> +//===-------------------------------------------------------------------===//
> 
> -#include "ASTManager.h"
> -#include "JSONRPCDispatcher.h"
> -#include "Protocol.h"
> +#include "ClangdServer.h"
> #include "clang/Frontend/ASTUnit.h"
> #include "clang/Frontend/CompilerInstance.h"
> +#include "clang/Frontend/CompilerInvocation.h"
> #include "clang/Tooling/CompilationDatabase.h"
> -#include "llvm/Support/Format.h"
> -#include "llvm/Support/Path.h"
> -#include <mutex>
> -#include <thread>
> -using namespace clang;
> -using namespace clangd;
> +#include "llvm/Support/FileSystem.h"
> 
> -void DocData::setAST(std::unique_ptr<ASTUnit> AST) {
> -  this->AST = std::move(AST);
> -}
> -
> -ASTUnit *DocData::getAST() const { return AST.get(); }
> -
> -void DocData::cacheFixIts(DiagnosticToReplacementMap FixIts) {
> -  this->FixIts = std::move(FixIts);
> -}
> +using namespace clang::clangd;
> 
> -std::vector<clang::tooling::Replacement>
> -DocData::getFixIts(const clangd::Diagnostic &D) const {
> -  auto it = FixIts.find(D);
> -  if (it != FixIts.end())
> -    return it->second;
> -  return {};
> -}
> -
> -ASTManagerRequest::ASTManagerRequest(ASTManagerRequestType Type,
> -                                     std::string File,
> -                                     DocVersion Version)
> -    : Type(Type), File(File), Version(Version) {}
> -
> -/// Retrieve a copy of the contents of every file in the store, for feeding into
> -/// ASTUnit.
> -static std::vector<ASTUnit::RemappedFile>
> -getRemappedFiles(const DocumentStore &Docs) {
> -  // FIXME: Use VFS instead. This would allow us to get rid of the chdir below.
> -  std::vector<ASTUnit::RemappedFile> RemappedFiles;
> -  for (const auto &P : Docs.getAllDocuments()) {
> -    StringRef FileName = P.first;
> -    RemappedFiles.push_back(ASTUnit::RemappedFile(
> -        FileName,
> -        llvm::MemoryBuffer::getMemBufferCopy(P.second, FileName).release()));
> -  }
> -  return RemappedFiles;
> -}
> +WorkerRequest::WorkerRequest(WorkerRequestKind Kind, Path File,
> +                             DocVersion Version)
> +    : Kind(Kind), File(File), Version(Version) {}
> 
> -/// Convert from clang diagnostic level to LSP severity.
> -static int getSeverity(DiagnosticsEngine::Level L) {
> -  switch (L) {
> -  case DiagnosticsEngine::Remark:
> -    return 4;
> -  case DiagnosticsEngine::Note:
> -    return 3;
> -  case DiagnosticsEngine::Warning:
> -    return 2;
> -  case DiagnosticsEngine::Fatal:
> -  case DiagnosticsEngine::Error:
> -    return 1;
> -  case DiagnosticsEngine::Ignored:
> -    return 0;
> -  }
> -  llvm_unreachable("Unknown diagnostic level!");
> -}
> -
> -static CompletionItemKind getKind(CXCursorKind K) {
> -  switch (K) {
> -  case CXCursor_MacroInstantiation:
> -  case CXCursor_MacroDefinition:
> -    return CompletionItemKind::Text;
> -  case CXCursor_CXXMethod:
> -    return CompletionItemKind::Method;
> -  case CXCursor_FunctionDecl:
> -  case CXCursor_FunctionTemplate:
> -    return CompletionItemKind::Function;
> -  case CXCursor_Constructor:
> -  case CXCursor_Destructor:
> -    return CompletionItemKind::Constructor;
> -  case CXCursor_FieldDecl:
> -    return CompletionItemKind::Field;
> -  case CXCursor_VarDecl:
> -  case CXCursor_ParmDecl:
> -    return CompletionItemKind::Variable;
> -  case CXCursor_ClassDecl:
> -  case CXCursor_StructDecl:
> -  case CXCursor_UnionDecl:
> -  case CXCursor_ClassTemplate:
> -  case CXCursor_ClassTemplatePartialSpecialization:
> -    return CompletionItemKind::Class;
> -  case CXCursor_Namespace:
> -  case CXCursor_NamespaceAlias:
> -  case CXCursor_NamespaceRef:
> -    return CompletionItemKind::Module;
> -  case CXCursor_EnumConstantDecl:
> -    return CompletionItemKind::Value;
> -  case CXCursor_EnumDecl:
> -    return CompletionItemKind::Enum;
> -  case CXCursor_TypeAliasDecl:
> -  case CXCursor_TypeAliasTemplateDecl:
> -  case CXCursor_TypedefDecl:
> -  case CXCursor_MemberRef:
> -  case CXCursor_TypeRef:
> -    return CompletionItemKind::Reference;
> -  default:
> -    return CompletionItemKind::Missing;
> -  }
> -}
> -
> -ASTManager::ASTManager(JSONOutput &Output, DocumentStore &Store,
> -                       bool RunSynchronously)
> -    : Output(Output), Store(Store), RunSynchronously(RunSynchronously),
> -      PCHs(std::make_shared<PCHContainerOperations>()),
> -      ClangWorker([this]() { runWorker(); }) {}
> -
> -void ASTManager::runWorker() {
> -  while (true) {
> -    ASTManagerRequest Request;
> -
> -    // Pick request from the queue
> -    {
> -      std::unique_lock<std::mutex> Lock(RequestLock);
> -      // Wait for more requests.
> -      ClangRequestCV.wait(Lock,
> -                          [this] { return !RequestQueue.empty() || Done; });
> -      if (Done)
> -        return;
> -      assert(!RequestQueue.empty() && "RequestQueue was empty");
> -
> -      Request = std::move(RequestQueue.back());
> -      RequestQueue.pop_back();
> -
> -      // Skip outdated requests
> -      if (Request.Version != DocVersions.find(Request.File)->second) {
> -        Output.log("Version for " + Twine(Request.File) +
> -                   " in request is outdated, skipping request\n");
> -        continue;
> -      }
> -    } // unlock RequestLock
> -
> -    handleRequest(Request.Type, Request.File);
> -  }
> -}
> -
> -void ASTManager::queueOrRun(ASTManagerRequestType RequestType, StringRef File) {
> +ClangdScheduler::ClangdScheduler(ClangdServer &Server, bool RunSynchronously)
> +    : RunSynchronously(RunSynchronously) {
>   if (RunSynchronously) {
> -    handleRequest(RequestType, File);
> +    // Don't start the worker thread if we're running synchronously
>     return;
>   }
> 
> -  std::lock_guard<std::mutex> Guard(RequestLock);
> -  // We increment the version of the added document immediately and schedule
> -  // the requested operation to be run on a worker thread
> -  DocVersion version = ++DocVersions[File];
> -  RequestQueue.push_back(ASTManagerRequest(RequestType, File, version));
> -  ClangRequestCV.notify_one();
> -}
> -
> -void ASTManager::handleRequest(ASTManagerRequestType RequestType,
> -                               StringRef File) {
> -  switch (RequestType) {
> -  case ASTManagerRequestType::ParseAndPublishDiagnostics:
> -    parseFileAndPublishDiagnostics(File);
> -    break;
> -  case ASTManagerRequestType::RemoveDocData: {
> -    std::lock_guard<std::mutex> Lock(ClangObjectLock);
> -    auto DocDataIt = DocDatas.find(File);
> -    // We could get the remove request before parsing for the document is
> -    // started, just do nothing in that case, parsing request will be discarded
> -    // because it has a lower version value
> -    if (DocDataIt == DocDatas.end())
> -      return;
> -    DocDatas.erase(DocDataIt);
> -    break;
> -  } // unlock ClangObjectLock
> -  }
> -}
> -
> -void ASTManager::parseFileAndPublishDiagnostics(StringRef File) {
> -  std::unique_lock<std::mutex> ClangObjectLockGuard(ClangObjectLock);
> -
> -  auto &DocData = DocDatas[File];
> -  ASTUnit *Unit = DocData.getAST();
> -  if (!Unit) {
> -    auto newAST = createASTUnitForFile(File, this->Store);
> -    Unit = newAST.get();
> -
> -    DocData.setAST(std::move(newAST));
> -  } else {
> -    // Do a reparse if this wasn't the first parse.
> -    // FIXME: This might have the wrong working directory if it changed in the
> -    // meantime.
> -    Unit->Reparse(PCHs, getRemappedFiles(this->Store));
> -  }
> +  // Initialize Worker in ctor body, rather than init list to avoid potentially
> +  // using not-yet-initialized members
> +  Worker = std::thread([&Server, this]() {
> +    while (true) {
> +      WorkerRequest Request;
> +
> +      // Pick request from the queue
> +      {
> +        std::unique_lock<std::mutex> Lock(Mutex);
> +        // Wait for more requests.
> +        RequestCV.wait(Lock, [this] { return !RequestQueue.empty() || Done; });
> +        if (Done)
> +          return;
> +
> +        assert(!RequestQueue.empty() && "RequestQueue was empty");
> +
> +        Request = std::move(RequestQueue.back());
> +        RequestQueue.pop_back();
> +
> +        // Skip outdated requests
> +        if (Request.Version != Server.DraftMgr.getVersion(Request.File)) {
> +          // FIXME(ibiryukov): Logging
> +          // Output.log("Version for " + Twine(Request.File) +
> +          //            " in request is outdated, skipping request\n");
> +          continue;
> +        }
> +      } // unlock Mutex
> 
> -  if (!Unit)
> -    return;
> -
> -  // Send the diagnotics to the editor.
> -  // FIXME: If the diagnostic comes from a different file, do we want to
> -  // show them all? Right now we drop everything not coming from the
> -  // main file.
> -  std::string Diagnostics;
> -  DocData::DiagnosticToReplacementMap LocalFixIts; // Temporary storage
> -  for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
> -                                     DEnd = Unit->stored_diag_end();
> -       D != DEnd; ++D) {
> -    if (!D->getLocation().isValid() ||
> -        !D->getLocation().getManager().isInMainFile(D->getLocation()))
> -      continue;
> -    Position P;
> -    P.line = D->getLocation().getSpellingLineNumber() - 1;
> -    P.character = D->getLocation().getSpellingColumnNumber();
> -    Range R = {P, P};
> -    Diagnostics +=
> -        R"({"range":)" + Range::unparse(R) +
> -        R"(,"severity":)" + std::to_string(getSeverity(D->getLevel())) +
> -        R"(,"message":")" + llvm::yaml::escape(D->getMessage()) +
> -        R"("},)";
> -
> -    // We convert to Replacements to become independent of the SourceManager.
> -    clangd::Diagnostic Diag = {R, getSeverity(D->getLevel()), D->getMessage()};
> -    auto &FixItsForDiagnostic = LocalFixIts[Diag];
> -    for (const FixItHint &Fix : D->getFixIts()) {
> -      FixItsForDiagnostic.push_back(clang::tooling::Replacement(
> -          Unit->getSourceManager(), Fix.RemoveRange, Fix.CodeToInsert));
> +      Server.handleRequest(std::move(Request));
>     }
> -  }
> -
> -  // Put FixIts into place.
> -  DocData.cacheFixIts(std::move(LocalFixIts));
> -
> -  ClangObjectLockGuard.unlock();
> -  // No accesses to clang objects are allowed after this point.
> -
> -  // Publish diagnostics.
> -  if (!Diagnostics.empty())
> -    Diagnostics.pop_back(); // Drop trailing comma.
> -  Output.writeMessage(
> -      R"({"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":")" +
> -      URI::fromFile(File).uri + R"(","diagnostics":[)" + Diagnostics + R"(]}})");
> +  });
> }
> 
> -ASTManager::~ASTManager() {
> +ClangdScheduler::~ClangdScheduler() {
> +  if (RunSynchronously)
> +    return; // no worker thread is running in that case
> +
>   {
> -    std::lock_guard<std::mutex> Guard(RequestLock);
> -    // Wake up the clang worker thread, then exit.
> +    std::lock_guard<std::mutex> Lock(Mutex);
> +    // Wake up the worker thread
>     Done = true;
> -    ClangRequestCV.notify_one();
> -  } // unlock DocDataLock
> -  ClangWorker.join();
> -}
> -
> -void ASTManager::onDocumentAdd(StringRef File) {
> -  queueOrRun(ASTManagerRequestType::ParseAndPublishDiagnostics, File);
> -}
> -
> -void ASTManager::onDocumentRemove(StringRef File) {
> -  queueOrRun(ASTManagerRequestType::RemoveDocData, File);
> -}
> -
> -tooling::CompilationDatabase *
> -ASTManager::getOrCreateCompilationDatabaseForFile(StringRef File) {
> -  namespace path = llvm::sys::path;
> -
> -  assert((path::is_absolute(File, path::Style::posix) ||
> -          path::is_absolute(File, path::Style::windows)) &&
> -         "path must be absolute");
> -
> -  for (auto Path = path::parent_path(File); !Path.empty();
> -       Path = path::parent_path(Path)) {
> -
> -    auto CachedIt = CompilationDatabases.find(Path);
> -    if (CachedIt != CompilationDatabases.end())
> -      return CachedIt->second.get();
> -    std::string Error;
> -    auto CDB = tooling::CompilationDatabase::loadFromDirectory(Path, Error);
> -    if (!CDB) {
> -      if (!Error.empty()) {
> -        Output.log("Error when trying to load compilation database from " +
> -                   Twine(Path) + ": " + Twine(Error) + "\n");
> -      }
> -      continue;
> -    }
> -
> -    // TODO(ibiryukov): Invalidate cached compilation databases on changes
> -    auto result = CDB.get();
> -    CompilationDatabases.insert(std::make_pair(Path, std::move(CDB)));
> -    return result;
> -  }
> -
> -  Output.log("Failed to find compilation database for " + Twine(File) + "\n");
> -  return nullptr;
> +    RequestCV.notify_one();
> +  } // unlock Mutex
> +  Worker.join();
> }
> 
> -std::unique_ptr<clang::ASTUnit>
> -ASTManager::createASTUnitForFile(StringRef File, const DocumentStore &Docs) {
> -  tooling::CompilationDatabase *CDB =
> -      getOrCreateCompilationDatabaseForFile(File);
> -
> -  std::vector<tooling::CompileCommand> Commands;
> -
> -  if (CDB) {
> -    Commands = CDB->getCompileCommands(File);
> -    // chdir. This is thread hostile.
> -    if (!Commands.empty())
> -      llvm::sys::fs::set_current_path(Commands.front().Directory);
> -  }
> -  if (Commands.empty()) {
> -    // Add a fake command line if we know nothing.
> -    Commands.push_back(tooling::CompileCommand(
> -        llvm::sys::path::parent_path(File), llvm::sys::path::filename(File),
> -        {"clang", "-fsyntax-only", File.str()}, ""));
> +void ClangdScheduler::enqueue(ClangdServer &Server, WorkerRequest Request) {
> +  if (RunSynchronously) {
> +    Server.handleRequest(Request);
> +    return;
>   }
> 
> -  // Inject the resource dir.
> -  // FIXME: Don't overwrite it if it's already there.
> -  static int Dummy; // Just an address in this process.
> -  std::string ResourceDir =
> -      CompilerInvocation::GetResourcesPath("clangd", (void *)&Dummy);
> -  Commands.front().CommandLine.push_back("-resource-dir=" + ResourceDir);
> -
> -  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
> -      CompilerInstance::createDiagnostics(new DiagnosticOptions);
> -
> -  std::vector<const char *> ArgStrs;
> -  for (const auto &S : Commands.front().CommandLine)
> -    ArgStrs.push_back(S.c_str());
> -
> -  auto ArgP = &*ArgStrs.begin();
> -  return std::unique_ptr<clang::ASTUnit>(ASTUnit::LoadFromCommandLine(
> -      ArgP, ArgP + ArgStrs.size(), PCHs, Diags, ResourceDir,
> -      /*OnlyLocalDecls=*/false, /*CaptureDiagnostics=*/true,
> -      getRemappedFiles(Docs),
> -      /*RemappedFilesKeepOriginalName=*/true,
> -      /*PrecompilePreambleAfterNParses=*/1, /*TUKind=*/TU_Complete,
> -      /*CacheCodeCompletionResults=*/true,
> -      /*IncludeBriefCommentsInCodeCompletion=*/true,
> -      /*AllowPCHWithCompilerErrors=*/true));
> +  std::lock_guard<std::mutex> Lock(Mutex);
> +  RequestQueue.push_back(Request);
> +  RequestCV.notify_one();
> }
> 
> -std::vector<clang::tooling::Replacement>
> -ASTManager::getFixIts(StringRef File, const clangd::Diagnostic &D) {
> -  // TODO(ibiryukov): the FixIts should be available immediately
> -  // even when parsing is being run on a worker thread
> -  std::lock_guard<std::mutex> Guard(ClangObjectLock);
> -  return DocDatas[File].getFixIts(D);
> -}
> +ClangdServer::ClangdServer(std::unique_ptr<GlobalCompilationDatabase> CDB,
> +                           std::unique_ptr<DiagnosticsConsumer> DiagConsumer,
> +                           bool RunSynchronously)
> +    : CDB(std::move(CDB)), DiagConsumer(std::move(DiagConsumer)),
> +      PCHs(std::make_shared<PCHContainerOperations>()),
> +      WorkScheduler(*this, RunSynchronously) {}
> 
> -namespace {
> -class CompletionItemsCollector : public CodeCompleteConsumer {
> -  std::vector<CompletionItem> *Items;
> -  std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
> -  CodeCompletionTUInfo CCTUInfo;
> -
> -public:
> -  CompletionItemsCollector(std::vector<CompletionItem> *Items,
> -                           const CodeCompleteOptions &CodeCompleteOpts)
> -      : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
> -        Items(Items),
> -        Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
> -        CCTUInfo(Allocator) {}
> -
> -  void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
> -                                  CodeCompletionResult *Results,
> -                                  unsigned NumResults) override {
> -    for (unsigned I = 0; I != NumResults; ++I) {
> -      CodeCompletionResult &Result = Results[I];
> -      CodeCompletionString *CCS = Result.CreateCodeCompletionString(
> -          S, Context, *Allocator, CCTUInfo,
> -          CodeCompleteOpts.IncludeBriefComments);
> -      if (CCS) {
> -        CompletionItem Item;
> -        assert(CCS->getTypedText());
> -        Item.label = CCS->getTypedText();
> -        Item.kind = getKind(Result.CursorKind);
> -        if (CCS->getBriefComment())
> -          Item.documentation = CCS->getBriefComment();
> -        Items->push_back(std::move(Item));
> -      }
> -    }
> +void ClangdServer::addDocument(PathRef File, StringRef Contents) {
> +  DocVersion NewVersion = DraftMgr.updateDraft(File, Contents);
> +  WorkScheduler.enqueue(
> +      *this, WorkerRequest(WorkerRequestKind::ParseAndPublishDiagnostics, File,
> +                           NewVersion));
> +}
> +
> +void ClangdServer::removeDocument(PathRef File) {
> +  auto NewVersion = DraftMgr.removeDraft(File);
> +  WorkScheduler.enqueue(
> +      *this, WorkerRequest(WorkerRequestKind::RemoveDocData, File, NewVersion));
> +}
> +
> +std::vector<CompletionItem> ClangdServer::codeComplete(PathRef File,
> +                                                       Position Pos) {
> +  auto FileContents = DraftMgr.getDraft(File);
> +  assert(FileContents.Draft && "codeComplete is called for non-added document");
> +
> +  std::vector<CompletionItem> Result;
> +  Units.runOnUnitWithoutReparse(
> +      File, *FileContents.Draft, *CDB, PCHs, [&](ClangdUnit &Unit) {
> +        Result = Unit.codeComplete(*FileContents.Draft, Pos);
> +      });
> +  return Result;
> +}
> +
> +std::string ClangdServer::getDocument(PathRef File) {
> +  auto draft = DraftMgr.getDraft(File);
> +  assert(draft.Draft && "File is not tracked, cannot get contents");
> +  return *draft.Draft;
> +}
> +
> +void ClangdServer::handleRequest(WorkerRequest Request) {
> +  switch (Request.Kind) {
> +  case WorkerRequestKind::ParseAndPublishDiagnostics: {
> +    auto FileContents = DraftMgr.getDraft(Request.File);
> +    if (FileContents.Version != Request.Version)
> +      return; // This request is outdated, do nothing
> +
> +    assert(FileContents.Draft &&
> +           "No contents inside a file that was scheduled for reparse");
> +    Units.runOnUnit(Request.File, *FileContents.Draft, *CDB, PCHs,
> +                    [&](ClangdUnit const &Unit) {
> +                      DiagConsumer->onDiagnosticsReady(
> +                          Request.File, Unit.getLocalDiagnostics());
> +                    });
> +    break;
>   }
> +  case WorkerRequestKind::RemoveDocData:
> +    if (Request.Version != DraftMgr.getVersion(Request.File))
> +      return; // This request is outdated, do nothing
> 
> -  GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
> -
> -  CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
> -};
> -
> -} // namespace
> -
> -std::vector<CompletionItem>
> -ASTManager::codeComplete(StringRef File, unsigned Line, unsigned Column) {
> -  CodeCompleteOptions CCO;
> -  CCO.IncludeBriefComments = 1;
> -  // This is where code completion stores dirty buffers. Need to free after
> -  // completion.
> -  SmallVector<const llvm::MemoryBuffer *, 4> OwnedBuffers;
> -  SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
> -  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
> -      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions));
> -  std::vector<CompletionItem> Items;
> -  CompletionItemsCollector Collector(&Items, CCO);
> -
> -  std::lock_guard<std::mutex> Guard(ClangObjectLock);
> -  auto &DocData = DocDatas[File];
> -  auto Unit = DocData.getAST();
> -  if (!Unit) {
> -    auto newAST = createASTUnitForFile(File, this->Store);
> -    Unit = newAST.get();
> -    DocData.setAST(std::move(newAST));
> +    Units.removeUnitIfPresent(Request.File);
> +    break;
>   }
> -  if (!Unit)
> -    return {};
> -  IntrusiveRefCntPtr<SourceManager> SourceMgr(
> -      new SourceManager(*DiagEngine, Unit->getFileManager()));
> -  // CodeComplete seems to require fresh LangOptions.
> -  LangOptions LangOpts = Unit->getLangOpts();
> -  // The language server protocol uses zero-based line and column numbers.
> -  // The clang code completion uses one-based numbers.
> -  Unit->CodeComplete(File, Line + 1, Column + 1, getRemappedFiles(this->Store),
> -                     CCO.IncludeMacros, CCO.IncludeCodePatterns,
> -                     CCO.IncludeBriefComments, Collector, PCHs, *DiagEngine,
> -                     LangOpts, *SourceMgr, Unit->getFileManager(),
> -                     StoredDiagnostics, OwnedBuffers);
> -  for (const llvm::MemoryBuffer *Buffer : OwnedBuffers)
> -    delete Buffer;
> -  return Items;
> }
> 
> Copied: clang-tools-extra/trunk/clangd/ClangdServer.h (from r303063, clang-tools-extra/trunk/clangd/ASTManager.h)
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.h?p2=clang-tools-extra/trunk/clangd/ClangdServer.h&p1=clang-tools-extra/trunk/clangd/ASTManager.h&r1=303063&r2=303067&rev=303067&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ASTManager.h (original)
> +++ clang-tools-extra/trunk/clangd/ClangdServer.h Mon May 15 09:17:35 2017
> @@ -1,4 +1,4 @@
> -//===--- ASTManager.h - Clang AST manager -----------------------*- C++ -*-===//
> +//===--- ClangdServer.h - Main clangd server code ----------------*- C++-*-===//
> //
> //                     The LLVM Compiler Infrastructure
> //
> @@ -7,153 +7,129 @@
> //
> //===----------------------------------------------------------------------===//
> 
> -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTMANAGER_H
> -#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTMANAGER_H
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H
> 
> -#include "DocumentStore.h"
> -#include "JSONRPCDispatcher.h"
> -#include "Protocol.h"
> +#include "ClangdUnitStore.h"
> +#include "DraftStore.h"
> +#include "GlobalCompilationDatabase.h"
> +#include "clang/Frontend/ASTUnit.h"
> +#include "clang/Tooling/CompilationDatabase.h"
> #include "clang/Tooling/Core/Replacement.h"
> #include "llvm/ADT/IntrusiveRefCntPtr.h"
> +#include "llvm/ADT/Optional.h"
> +#include "llvm/ADT/StringRef.h"
> +
> +#include "ClangdUnit.h"
> +#include "Protocol.h"
> +
> #include <condition_variable>
> -#include <deque>
> +#include <mutex>
> +#include <string>
> #include <thread>
> +#include <utility>
> 
> namespace clang {
> -class ASTUnit;
> -class DiagnosticsEngine;
> class PCHContainerOperations;
> -namespace tooling {
> -class CompilationDatabase;
> -} // namespace tooling
> 
> namespace clangd {
> 
> -/// Using 'unsigned' here to avoid undefined behaviour on overflow.
> -typedef unsigned DocVersion;
> -
> -/// Stores ASTUnit and FixIts map for an opened document.
> -class DocData {
> -public:
> -  typedef std::map<clangd::Diagnostic, std::vector<clang::tooling::Replacement>>
> -      DiagnosticToReplacementMap;
> -
> +class DiagnosticsConsumer {
> public:
> -  void setAST(std::unique_ptr<ASTUnit> AST);
> -  ASTUnit *getAST() const;
> -
> -  void cacheFixIts(DiagnosticToReplacementMap FixIts);
> -  std::vector<clang::tooling::Replacement>
> -  getFixIts(const clangd::Diagnostic &D) const;
> +  virtual ~DiagnosticsConsumer() = default;
> 
> -private:
> -  std::unique_ptr<ASTUnit> AST;
> -  DiagnosticToReplacementMap FixIts;
> +  /// Called by ClangdServer when \p Diagnostics for \p File are ready.
> +  virtual void onDiagnosticsReady(PathRef File,
> +                                  std::vector<DiagWithFixIts> Diagnostics) = 0;
> };
> 
> -enum class ASTManagerRequestType { ParseAndPublishDiagnostics, RemoveDocData };
> +enum class WorkerRequestKind { ParseAndPublishDiagnostics, RemoveDocData };
> 
> /// A request to the worker thread
> -class ASTManagerRequest {
> +class WorkerRequest {
> public:
> -  ASTManagerRequest() = default;
> -  ASTManagerRequest(ASTManagerRequestType Type, std::string File,
> -                    DocVersion Version);
> +  WorkerRequest() = default;
> +  WorkerRequest(WorkerRequestKind Kind, Path File, DocVersion Version);
> 
> -  ASTManagerRequestType Type;
> -  std::string File;
> +  WorkerRequestKind Kind;
> +  Path File;
>   DocVersion Version;
> };
> 
> -class ASTManager : public DocumentStoreListener {
> -public:
> -  ASTManager(JSONOutput &Output, DocumentStore &Store, bool RunSynchronously);
> -  ~ASTManager() override;
> -
> -  void onDocumentAdd(StringRef File) override;
> -  void onDocumentRemove(StringRef File) override;
> +class ClangdServer;
> 
> -  /// Get code completions at a specified \p Line and \p Column in \p File.
> -  ///
> -  /// This function is thread-safe and returns completion items that own the
> -  /// data they contain.
> -  std::vector<CompletionItem> codeComplete(StringRef File, unsigned Line,
> -                                           unsigned Column);
> -
> -  /// Get the fixes associated with a certain diagnostic in a specified file as
> -  /// replacements.
> -  ///
> -  /// This function is thread-safe. It returns a copy to avoid handing out
> -  /// references to unguarded data.
> -  std::vector<clang::tooling::Replacement>
> -  getFixIts(StringRef File, const clangd::Diagnostic &D);
> +/// Handles running WorkerRequests of ClangdServer on a separate threads.
> +/// Currently runs only one worker thread.
> +class ClangdScheduler {
> +public:
> +  ClangdScheduler(ClangdServer &Server, bool RunSynchronously);
> +  ~ClangdScheduler();
> 
> -  DocumentStore &getStore() const { return Store; }
> +  /// Enqueue WorkerRequest to be run on a worker thread
> +  void enqueue(ClangdServer &Server, WorkerRequest Request);
> 
> private:
> -  JSONOutput &Output;
> -  DocumentStore &Store;
> -
> -  // Set to true if requests should block instead of being processed
> -  // asynchronously.
>   bool RunSynchronously;
> -
> -  /// Loads a compilation database for File. May return nullptr if it fails. The
> -  /// database is cached for subsequent accesses.
> -  clang::tooling::CompilationDatabase *
> -  getOrCreateCompilationDatabaseForFile(StringRef File);
> -  // Creates a new ASTUnit for the document at File.
> -  // FIXME: This calls chdir internally, which is thread unsafe.
> -  std::unique_ptr<clang::ASTUnit>
> -  createASTUnitForFile(StringRef File, const DocumentStore &Docs);
> -
> -  /// If RunSynchronously is false, queues the request to be run on the worker
> -  /// thread.
> -  /// If RunSynchronously is true, runs the request handler immediately on the
> -  /// main thread.
> -  void queueOrRun(ASTManagerRequestType RequestType, StringRef File);
> -
> -  void runWorker();
> -  void handleRequest(ASTManagerRequestType RequestType, StringRef File);
> -
> -  /// Parses files and publishes diagnostics.
> -  /// This function is called on the worker thread in asynchronous mode and
> -  /// on the main thread in synchronous mode.
> -  void parseFileAndPublishDiagnostics(StringRef File);
> -
> -  /// Caches compilation databases loaded from directories(keys are directories).
> -  llvm::StringMap<std::unique_ptr<clang::tooling::CompilationDatabase>>
> -      CompilationDatabases;
> -
> -  /// Clang objects.
> -  /// A map from filenames to DocData structures that store ASTUnit and Fixits for
> -  /// the files. The ASTUnits are used for generating diagnostics and fix-it-s
> -  /// asynchronously by the worker thread and synchronously for code completion.
> -  llvm::StringMap<DocData> DocDatas;
> -  std::shared_ptr<clang::PCHContainerOperations> PCHs;
> -  /// A lock for access to the DocDatas, CompilationDatabases and PCHs.
> -  std::mutex ClangObjectLock;
> -
> -  /// Stores latest versions of the tracked documents to discard outdated requests.
> -  /// Guarded by RequestLock.
> -  /// TODO(ibiryukov): the entries are neved deleted from this map.
> -  llvm::StringMap<DocVersion> DocVersions;
> -
> -  /// A LIFO queue of requests. Note that requests are discarded if the `version`
> -  /// field is not equal to the one stored inside DocVersions.
> -  /// TODO(krasimir): code completion should always have priority over parsing
> -  /// for diagnostics.
> -  std::deque<ASTManagerRequest> RequestQueue;
> +  std::mutex Mutex;
> +  /// We run some tasks on a separate thread(parsing, ClangdUnit cleanup).
> +  /// This thread looks into RequestQueue to find requests to handle and
> +  /// terminates when Done is set to true.
> +  std::thread Worker;
>   /// Setting Done to true will make the worker thread terminate.
>   bool Done = false;
> +  /// A LIFO queue of requests. Note that requests are discarded if the
> +  /// `version` field is not equal to the one stored inside DraftStore.
> +  /// FIXME(krasimir): code completion should always have priority over parsing
> +  /// for diagnostics.
> +  std::deque<WorkerRequest> RequestQueue;
>   /// Condition variable to wake up the worker thread.
> -  std::condition_variable ClangRequestCV;
> -  /// Lock for accesses to RequestQueue, DocVersions and Done.
> -  std::mutex RequestLock;
> -
> -  /// We run parsing on a separate thread. This thread looks into RequestQueue to
> -  /// find requests to handle and terminates when Done is set to true.
> -  std::thread ClangWorker;
> +  std::condition_variable RequestCV;
> +};
> +
> +/// Provides API to manage ASTs for a collection of C++ files and request
> +/// various language features(currently, only codeCompletion and async
> +/// diagnostics for tracked files).
> +class ClangdServer {
> +public:
> +  ClangdServer(std::unique_ptr<GlobalCompilationDatabase> CDB,
> +               std::unique_ptr<DiagnosticsConsumer> DiagConsumer,
> +               bool RunSynchronously);
> +
> +  /// Add a \p File to the list of tracked C++ files or update the contents if
> +  /// \p File is already tracked. Also schedules parsing of the AST for it on a
> +  /// separate thread. When the parsing is complete, DiagConsumer passed in
> +  /// constructor will receive onDiagnosticsReady callback.
> +  void addDocument(PathRef File, StringRef Contents);
> +
> +  /// Remove \p File from list of tracked files, schedule a request to free
> +  /// resources associated with it.
> +  void removeDocument(PathRef File);
> +
> +  /// Run code completion for \p File at \p Pos.
> +  std::vector<CompletionItem> codeComplete(PathRef File, Position Pos);
> +
> +  /// Gets current document contents for \p File. \p File must point to a
> +  /// currently tracked file.
> +  /// FIXME(ibiryukov): This function is here to allow implementation of
> +  /// formatCode from ProtocolHandlers.cpp. We should move formatCode to this
> +  /// class and remove this function from public interface.
> +  std::string getDocument(PathRef File);
> +
> +private:
> +  friend class ClangdScheduler;
> +
> +  /// This function is called on a worker thread.
> +  void handleRequest(WorkerRequest Request);
> +
> +  std::unique_ptr<GlobalCompilationDatabase> CDB;
> +  std::unique_ptr<DiagnosticsConsumer> DiagConsumer;
> +  DraftStore DraftMgr;
> +  ClangdUnitStore Units;
> +  std::shared_ptr<PCHContainerOperations> PCHs;
> +  // WorkScheduler has to be the last member, because its destructor has to be
> +  // called before all other members to stop the worker thread that references
> +  // ClangdServer
> +  ClangdScheduler WorkScheduler;
> };
> 
> } // namespace clangd
> 
> Added: clang-tools-extra/trunk/clangd/ClangdUnit.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.cpp?rev=303067&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdUnit.cpp (added)
> +++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp Mon May 15 09:17:35 2017
> @@ -0,0 +1,224 @@
> +//===--- ClangdUnit.cpp -----------------------------------------*- C++-*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#include "ClangdUnit.h"
> +#include "clang/Frontend/ASTUnit.h"
> +#include "clang/Frontend/CompilerInstance.h"
> +#include "clang/Frontend/CompilerInvocation.h"
> +#include "clang/Tooling/CompilationDatabase.h"
> +
> +using namespace clang::clangd;
> +using namespace clang;
> +
> +ClangdUnit::ClangdUnit(PathRef FileName, StringRef Contents,
> +                       std::shared_ptr<PCHContainerOperations> PCHs,
> +                       std::vector<tooling::CompileCommand> Commands)
> +    : FileName(FileName), PCHs(PCHs) {
> +  assert(!Commands.empty() && "No compile commands provided");
> +
> +  // Inject the resource dir.
> +  // FIXME: Don't overwrite it if it's already there.
> +  static int Dummy; // Just an address in this process.
> +  std::string ResourceDir =
> +      CompilerInvocation::GetResourcesPath("clangd", (void *)&Dummy);
> +  Commands.front().CommandLine.push_back("-resource-dir=" + ResourceDir);
> +
> +  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
> +      CompilerInstance::createDiagnostics(new DiagnosticOptions);
> +
> +  std::vector<const char *> ArgStrs;
> +  for (const auto &S : Commands.front().CommandLine)
> +    ArgStrs.push_back(S.c_str());
> +
> +  ASTUnit::RemappedFile RemappedSource(
> +      FileName,
> +      llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());
> +
> +  auto ArgP = &*ArgStrs.begin();
> +  Unit = std::unique_ptr<ASTUnit>(ASTUnit::LoadFromCommandLine(
> +      ArgP, ArgP + ArgStrs.size(), PCHs, Diags, ResourceDir,
> +      /*OnlyLocalDecls=*/false, /*CaptureDiagnostics=*/true, RemappedSource,
> +      /*RemappedFilesKeepOriginalName=*/true,
> +      /*PrecompilePreambleAfterNParses=*/1, /*TUKind=*/TU_Complete,
> +      /*CacheCodeCompletionResults=*/true,
> +      /*IncludeBriefCommentsInCodeCompletion=*/true,
> +      /*AllowPCHWithCompilerErrors=*/true));
> +}
> +
> +void ClangdUnit::reparse(StringRef Contents) {
> +  // Do a reparse if this wasn't the first parse.
> +  // FIXME: This might have the wrong working directory if it changed in the
> +  // meantime.
> +  ASTUnit::RemappedFile RemappedSource(
> +      FileName,
> +      llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());
> +
> +  Unit->Reparse(PCHs, RemappedSource);
> +}
> +
> +namespace {
> +
> +CompletionItemKind getKind(CXCursorKind K) {
> +  switch (K) {
> +  case CXCursor_MacroInstantiation:
> +  case CXCursor_MacroDefinition:
> +    return CompletionItemKind::Text;
> +  case CXCursor_CXXMethod:
> +    return CompletionItemKind::Method;
> +  case CXCursor_FunctionDecl:
> +  case CXCursor_FunctionTemplate:
> +    return CompletionItemKind::Function;
> +  case CXCursor_Constructor:
> +  case CXCursor_Destructor:
> +    return CompletionItemKind::Constructor;
> +  case CXCursor_FieldDecl:
> +    return CompletionItemKind::Field;
> +  case CXCursor_VarDecl:
> +  case CXCursor_ParmDecl:
> +    return CompletionItemKind::Variable;
> +  case CXCursor_ClassDecl:
> +  case CXCursor_StructDecl:
> +  case CXCursor_UnionDecl:
> +  case CXCursor_ClassTemplate:
> +  case CXCursor_ClassTemplatePartialSpecialization:
> +    return CompletionItemKind::Class;
> +  case CXCursor_Namespace:
> +  case CXCursor_NamespaceAlias:
> +  case CXCursor_NamespaceRef:
> +    return CompletionItemKind::Module;
> +  case CXCursor_EnumConstantDecl:
> +    return CompletionItemKind::Value;
> +  case CXCursor_EnumDecl:
> +    return CompletionItemKind::Enum;
> +  case CXCursor_TypeAliasDecl:
> +  case CXCursor_TypeAliasTemplateDecl:
> +  case CXCursor_TypedefDecl:
> +  case CXCursor_MemberRef:
> +  case CXCursor_TypeRef:
> +    return CompletionItemKind::Reference;
> +  default:
> +    return CompletionItemKind::Missing;
> +  }
> +}
> +
> +class CompletionItemsCollector : public CodeCompleteConsumer {
> +  std::vector<CompletionItem> *Items;
> +  std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
> +  CodeCompletionTUInfo CCTUInfo;
> +
> +public:
> +  CompletionItemsCollector(std::vector<CompletionItem> *Items,
> +                           const CodeCompleteOptions &CodeCompleteOpts)
> +      : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
> +        Items(Items),
> +        Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
> +        CCTUInfo(Allocator) {}
> +
> +  void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
> +                                  CodeCompletionResult *Results,
> +                                  unsigned NumResults) override {
> +    for (unsigned I = 0; I != NumResults; ++I) {
> +      CodeCompletionResult &Result = Results[I];
> +      CodeCompletionString *CCS = Result.CreateCodeCompletionString(
> +          S, Context, *Allocator, CCTUInfo,
> +          CodeCompleteOpts.IncludeBriefComments);
> +      if (CCS) {
> +        CompletionItem Item;
> +        assert(CCS->getTypedText());
> +        Item.label = CCS->getTypedText();
> +        Item.kind = getKind(Result.CursorKind);
> +        if (CCS->getBriefComment())
> +          Item.documentation = CCS->getBriefComment();
> +        Items->push_back(std::move(Item));
> +      }
> +    }
> +  }
> +
> +  GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
> +
> +  CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
> +};
> +} // namespace
> +
> +std::vector<CompletionItem> ClangdUnit::codeComplete(StringRef Contents,
> +                                                     Position Pos) {
> +  CodeCompleteOptions CCO;
> +  CCO.IncludeBriefComments = 1;
> +  // This is where code completion stores dirty buffers. Need to free after
> +  // completion.
> +  SmallVector<const llvm::MemoryBuffer *, 4> OwnedBuffers;
> +  SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
> +  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
> +      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions));
> +  std::vector<CompletionItem> Items;
> +  CompletionItemsCollector Collector(&Items, CCO);
> +
> +  ASTUnit::RemappedFile RemappedSource(
> +      FileName,
> +      llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());
> +
> +  IntrusiveRefCntPtr<SourceManager> SourceMgr(
> +      new SourceManager(*DiagEngine, Unit->getFileManager()));
> +  // CodeComplete seems to require fresh LangOptions.
> +  LangOptions LangOpts = Unit->getLangOpts();
> +  // The language server protocol uses zero-based line and column numbers.
> +  // The clang code completion uses one-based numbers.
> +  Unit->CodeComplete(FileName, Pos.line + 1, Pos.character + 1, RemappedSource,
> +                     CCO.IncludeMacros, CCO.IncludeCodePatterns,
> +                     CCO.IncludeBriefComments, Collector, PCHs, *DiagEngine,
> +                     LangOpts, *SourceMgr, Unit->getFileManager(),
> +                     StoredDiagnostics, OwnedBuffers);
> +  for (const llvm::MemoryBuffer *Buffer : OwnedBuffers)
> +    delete Buffer;
> +  return Items;
> +}
> +
> +namespace {
> +/// Convert from clang diagnostic level to LSP severity.
> +static int getSeverity(DiagnosticsEngine::Level L) {
> +  switch (L) {
> +  case DiagnosticsEngine::Remark:
> +    return 4;
> +  case DiagnosticsEngine::Note:
> +    return 3;
> +  case DiagnosticsEngine::Warning:
> +    return 2;
> +  case DiagnosticsEngine::Fatal:
> +  case DiagnosticsEngine::Error:
> +    return 1;
> +  case DiagnosticsEngine::Ignored:
> +    return 0;
> +  }
> +  llvm_unreachable("Unknown diagnostic level!");
> +}
> +} // namespace
> +
> +std::vector<DiagWithFixIts> ClangdUnit::getLocalDiagnostics() const {
> +  std::vector<DiagWithFixIts> Result;
> +  for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
> +                                     DEnd = Unit->stored_diag_end();
> +       D != DEnd; ++D) {
> +    if (!D->getLocation().isValid() ||
> +        !D->getLocation().getManager().isInMainFile(D->getLocation()))
> +      continue;
> +    Position P;
> +    P.line = D->getLocation().getSpellingLineNumber() - 1;
> +    P.character = D->getLocation().getSpellingColumnNumber();
> +    Range R = {P, P};
> +    clangd::Diagnostic Diag = {R, getSeverity(D->getLevel()), D->getMessage()};
> +
> +    llvm::SmallVector<tooling::Replacement, 1> FixItsForDiagnostic;
> +    for (const FixItHint &Fix : D->getFixIts()) {
> +      FixItsForDiagnostic.push_back(clang::tooling::Replacement(
> +          Unit->getSourceManager(), Fix.RemoveRange, Fix.CodeToInsert));
> +    }
> +    Result.push_back({Diag, std::move(FixItsForDiagnostic)});
> +  }
> +  return Result;
> +}
> 
> Added: clang-tools-extra/trunk/clangd/ClangdUnit.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.h?rev=303067&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdUnit.h (added)
> +++ clang-tools-extra/trunk/clangd/ClangdUnit.h Mon May 15 09:17:35 2017
> @@ -0,0 +1,63 @@
> +//===--- ClangdUnit.h -------------------------------------------*- C++-*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
> +
> +#include "Protocol.h"
> +#include "Path.h"
> +#include "clang/Frontend/ASTUnit.h"
> +#include "clang/Tooling/Core/Replacement.h"
> +#include <memory>
> +
> +namespace clang {
> +class ASTUnit;
> +class PCHContainerOperations;
> +
> +namespace tooling {
> +struct CompileCommand;
> +}
> +
> +namespace clangd {
> +
> +/// A diagnostic with its FixIts.
> +struct DiagWithFixIts {
> +  clangd::Diagnostic Diag;
> +  llvm::SmallVector<tooling::Replacement, 1> FixIts;
> +};
> +
> +/// Stores parsed C++ AST and provides implementations of all operations clangd
> +/// would want to perform on parsed C++ files.
> +class ClangdUnit {
> +public:
> +  ClangdUnit(PathRef FileName, StringRef Contents,
> +             std::shared_ptr<PCHContainerOperations> PCHs,
> +             std::vector<tooling::CompileCommand> Commands);
> +
> +  /// Reparse with new contents.
> +  void reparse(StringRef Contents);
> +
> +  /// Get code completions at a specified \p Line and \p Column in \p File.
> +  ///
> +  /// This function is thread-safe and returns completion items that own the
> +  /// data they contain.
> +  std::vector<CompletionItem> codeComplete(StringRef Contents, Position Pos);
> +  /// Returns diagnostics and corresponding FixIts for each diagnostic that are
> +  /// located in the current file.
> +  std::vector<DiagWithFixIts> getLocalDiagnostics() const;
> +
> +private:
> +  Path FileName;
> +  std::unique_ptr<ASTUnit> Unit;
> +  std::shared_ptr<PCHContainerOperations> PCHs;
> +};
> +
> +} // namespace clangd
> +} // namespace clang
> +#endif
> 
> Added: clang-tools-extra/trunk/clangd/ClangdUnitStore.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnitStore.cpp?rev=303067&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdUnitStore.cpp (added)
> +++ clang-tools-extra/trunk/clangd/ClangdUnitStore.cpp Mon May 15 09:17:35 2017
> @@ -0,0 +1,34 @@
> +//===--- ClangdUnitStore.cpp - A ClangdUnits container -----------*-C++-*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "ClangdUnitStore.h"
> +#include "llvm/Support/Path.h"
> +
> +using namespace clang::clangd;
> +using namespace clang;
> +
> +void ClangdUnitStore::removeUnitIfPresent(PathRef File) {
> +  std::lock_guard<std::mutex> Lock(Mutex);
> +
> +  auto It = OpenedFiles.find(File);
> +  if (It == OpenedFiles.end())
> +    return;
> +  OpenedFiles.erase(It);
> +}
> +
> +std::vector<tooling::CompileCommand> ClangdUnitStore::getCompileCommands(GlobalCompilationDatabase &CDB, PathRef File) {
> +  std::vector<tooling::CompileCommand> Commands = CDB.getCompileCommands(File);
> +  if (Commands.empty()) {
> +    // Add a fake command line if we know nothing.
> +    Commands.push_back(tooling::CompileCommand(
> +        llvm::sys::path::parent_path(File), llvm::sys::path::filename(File),
> +        {"clang", "-fsyntax-only", File.str()}, ""));
> +  }
> +  return Commands;
> +}
> 
> Added: clang-tools-extra/trunk/clangd/ClangdUnitStore.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnitStore.h?rev=303067&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdUnitStore.h (added)
> +++ clang-tools-extra/trunk/clangd/ClangdUnitStore.h Mon May 15 09:17:35 2017
> @@ -0,0 +1,93 @@
> +//===--- ClangdUnitStore.h - A ClangdUnits container -------------*-C++-*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNITSTORE_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNITSTORE_H
> +
> +#include <mutex>
> +
> +#include "ClangdUnit.h"
> +#include "GlobalCompilationDatabase.h"
> +#include "Path.h"
> +#include "clang/Tooling/CompilationDatabase.h"
> +
> +namespace clang {
> +namespace clangd {
> +
> +/// Thread-safe collection of ASTs built for specific files. Provides
> +/// synchronized access to ASTs.
> +class ClangdUnitStore {
> +public:
> +  /// Run specified \p Action on the ClangdUnit for \p File.
> +  /// If the file is not present in ClangdUnitStore, a new ClangdUnit will be
> +  /// created from the \p FileContents. If the file is already present in the
> +  /// store, ClangdUnit::reparse will be called with the new contents before
> +  /// running \p Action.
> +  template <class Func>
> +  void runOnUnit(PathRef File, StringRef FileContents,
> +                 GlobalCompilationDatabase &CDB,
> +                 std::shared_ptr<PCHContainerOperations> PCHs, Func Action) {
> +    runOnUnitImpl(File, FileContents, CDB, PCHs, /*ReparseBeforeAction=*/true,
> +                  std::forward<Func>(Action));
> +  }
> +
> +  /// Run specified \p Action on the ClangdUnit for \p File.
> +  /// If the file is not present in ClangdUnitStore, a new ClangdUnit will be
> +  /// created from the \p FileContents. If the file is already present in the
> +  /// store, the \p Action will be run directly on it.
> +  template <class Func>
> +  void runOnUnitWithoutReparse(PathRef File, StringRef FileContents,
> +                               GlobalCompilationDatabase &CDB,
> +                               std::shared_ptr<PCHContainerOperations> PCHs,
> +                               Func Action) {
> +    runOnUnitImpl(File, FileContents, CDB, PCHs, /*ReparseBeforeAction=*/false,
> +                  std::forward<Func>(Action));
> +  }
> +
> +  /// Remove ClangdUnit for \p File, if any
> +  void removeUnitIfPresent(PathRef File);
> +
> +private:
> +  /// Run specified \p Action on the ClangdUnit for \p File.
> +  template <class Func>
> +  void runOnUnitImpl(PathRef File, StringRef FileContents,
> +                     GlobalCompilationDatabase &CDB,
> +                     std::shared_ptr<PCHContainerOperations> PCHs,
> +                     bool ReparseBeforeAction, Func Action) {
> +    std::lock_guard<std::mutex> Lock(Mutex);
> +
> +    auto Commands = getCompileCommands(CDB, File);
> +    assert(!Commands.empty() &&
> +           "getCompileCommands should add default command");
> +    // chdir. This is thread hostile.
> +    // FIXME(ibiryukov): get rid of this
> +    llvm::sys::fs::set_current_path(Commands.front().Directory);
> +
> +    auto It = OpenedFiles.find(File);
> +    if (It == OpenedFiles.end()) {
> +      It = OpenedFiles
> +               .insert(std::make_pair(
> +                   File, ClangdUnit(File, FileContents, PCHs, Commands)))
> +               .first;
> +    } else if (ReparseBeforeAction) {
> +      It->second.reparse(FileContents);
> +    }
> +    return Action(It->second);
> +  }
> +
> +  std::vector<tooling::CompileCommand>
> +  getCompileCommands(GlobalCompilationDatabase &CDB, PathRef File);
> +
> +  std::mutex Mutex;
> +  llvm::StringMap<ClangdUnit> OpenedFiles;
> +};
> +} // namespace clangd
> +} // namespace clang
> +
> +#endif
> 
> Removed: clang-tools-extra/trunk/clangd/DocumentStore.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/DocumentStore.h?rev=303066&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/DocumentStore.h (original)
> +++ clang-tools-extra/trunk/clangd/DocumentStore.h (removed)
> @@ -1,86 +0,0 @@
> -//===--- DocumentStore.h - File contents container --------------*- C++ -*-===//
> -//
> -//                     The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
> -//===----------------------------------------------------------------------===//
> -
> -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_DOCUMENTSTORE_H
> -#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_DOCUMENTSTORE_H
> -
> -#include "clang/Basic/LLVM.h"
> -#include "llvm/ADT/StringMap.h"
> -#include <mutex>
> -#include <string>
> -#include <vector>
> -
> -namespace clang {
> -namespace clangd {
> -class DocumentStore;
> -
> -struct DocumentStoreListener {
> -  virtual ~DocumentStoreListener() = default;
> -  virtual void onDocumentAdd(StringRef File) {}
> -  virtual void onDocumentRemove(StringRef File) {}
> -};
> -
> -/// A container for files opened in a workspace, addressed by File. The contents
> -/// are owned by the DocumentStore.
> -class DocumentStore {
> -public:
> -  /// Add a document to the store. Overwrites existing contents.
> -  void addDocument(StringRef File, StringRef Text) {
> -    {
> -      std::lock_guard<std::mutex> Guard(DocsMutex);
> -      Docs[File] = Text;
> -    }
> -    for (const auto &Listener : Listeners)
> -      Listener->onDocumentAdd(File);
> -  }
> -  /// Delete a document from the store.
> -  void removeDocument(StringRef File) {
> -    {
> -      std::lock_guard<std::mutex> Guard(DocsMutex);
> -      Docs.erase(File);
> -    }
> -    for (const auto &Listener : Listeners)
> -      Listener->onDocumentRemove(File);
> -  }
> -  /// Retrieve a document from the store. Empty string if it's unknown.
> -  ///
> -  /// This function is thread-safe. It returns a copy to avoid handing out
> -  /// references to unguarded data.
> -  std::string getDocument(StringRef File) const {
> -    // FIXME: This could be a reader lock.
> -    std::lock_guard<std::mutex> Guard(DocsMutex);
> -    return Docs.lookup(File);
> -  }
> -
> -  /// Add a listener. Does not take ownership.
> -  void addListener(DocumentStoreListener *DSL) { Listeners.push_back(DSL); }
> -
> -  /// Get name and constents of all documents in this store.
> -  ///
> -  /// This function is thread-safe. It returns a copies to avoid handing out
> -  /// references to unguarded data.
> -  std::vector<std::pair<std::string, std::string>> getAllDocuments() const {
> -    std::vector<std::pair<std::string, std::string>> AllDocs;
> -    std::lock_guard<std::mutex> Guard(DocsMutex);
> -    for (const auto &P : Docs)
> -      AllDocs.emplace_back(P.first(), P.second);
> -    return AllDocs;
> -  }
> -
> -private:
> -  llvm::StringMap<std::string> Docs;
> -  std::vector<DocumentStoreListener *> Listeners;
> -
> -  mutable std::mutex DocsMutex;
> -};
> -
> -} // namespace clangd
> -} // namespace clang
> -
> -#endif
> 
> Added: clang-tools-extra/trunk/clangd/DraftStore.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/DraftStore.cpp?rev=303067&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/DraftStore.cpp (added)
> +++ clang-tools-extra/trunk/clangd/DraftStore.cpp Mon May 15 09:17:35 2017
> @@ -0,0 +1,48 @@
> +//===--- DraftStore.cpp - File contents container ---------------*- C++ -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "DraftStore.h"
> +
> +using namespace clang::clangd;
> +
> +VersionedDraft DraftStore::getDraft(PathRef File) const {
> +  std::lock_guard<std::mutex> Lock(Mutex);
> +
> +  auto It = Drafts.find(File);
> +  if (It == Drafts.end())
> +    return {0, llvm::None};
> +  return It->second;
> +}
> +
> +DocVersion DraftStore::getVersion(PathRef File) const {
> +  std::lock_guard<std::mutex> Lock(Mutex);
> +
> +  auto It = Drafts.find(File);
> +  if (It == Drafts.end())
> +    return 0;
> +  return It->second.Version;
> +}
> +
> +DocVersion DraftStore::updateDraft(PathRef File, StringRef Contents) {
> +  std::lock_guard<std::mutex> Lock(Mutex);
> +
> +  auto &Entry = Drafts[File];
> +  DocVersion NewVersion = ++Entry.Version;
> +  Entry.Draft = Contents;
> +  return NewVersion;
> +}
> +
> +DocVersion DraftStore::removeDraft(PathRef File) {
> +  std::lock_guard<std::mutex> Lock(Mutex);
> +
> +  auto &Entry = Drafts[File];
> +  DocVersion NewVersion = ++Entry.Version;
> +  Entry.Draft = llvm::None;
> +  return NewVersion;
> +}
> 
> Copied: clang-tools-extra/trunk/clangd/DraftStore.h (from r303060, clang-tools-extra/trunk/clangd/DocumentStore.h)
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/DraftStore.h?p2=clang-tools-extra/trunk/clangd/DraftStore.h&p1=clang-tools-extra/trunk/clangd/DocumentStore.h&r1=303060&r2=303067&rev=303067&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/DocumentStore.h (original)
> +++ clang-tools-extra/trunk/clangd/DraftStore.h Mon May 15 09:17:35 2017
> @@ -1,4 +1,4 @@
> -//===--- DocumentStore.h - File contents container --------------*- C++ -*-===//
> +//===--- DraftStore.h - File contents container -----------------*- C++ -*-===//
> //
> //                     The LLVM Compiler Infrastructure
> //
> @@ -7,9 +7,10 @@
> //
> //===----------------------------------------------------------------------===//
> 
> -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_DOCUMENTSTORE_H
> -#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_DOCUMENTSTORE_H
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_DRAFTSTORE_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_DRAFTSTORE_H
> 
> +#include "Path.h"
> #include "clang/Basic/LLVM.h"
> #include "llvm/ADT/StringMap.h"
> #include <mutex>
> @@ -18,66 +19,40 @@
> 
> namespace clang {
> namespace clangd {
> -class DocumentStore;
> 
> -struct DocumentStoreListener {
> -  virtual ~DocumentStoreListener() = default;
> -  virtual void onDocumentAdd(StringRef File) {}
> -  virtual void onDocumentRemove(StringRef File) {}
> +/// Using 'unsigned' here to avoid undefined behaviour on overflow.
> +typedef unsigned DocVersion;
> +
> +/// Document draft with a version of this draft.
> +struct VersionedDraft {
> +  DocVersion Version;
> +  /// If the value of the field is None, draft is now deleted
> +  llvm::Optional<std::string> Draft;
> };
> 
> -/// A container for files opened in a workspace, addressed by File. The contents
> -/// are owned by the DocumentStore.
> -class DocumentStore {
> +/// A thread-safe container for files opened in a workspace, addressed by
> +/// filenames. The contents are owned by the DraftStore. Versions are mantained
> +/// for the all added documents, including removed ones. The document version is
> +/// incremented on each update and removal of the document.
> +class DraftStore {
> public:
> -  /// Add a document to the store. Overwrites existing contents.
> -  void addDocument(StringRef File, StringRef Text) {
> -    {
> -      std::lock_guard<std::mutex> Guard(DocsMutex);
> -      Docs[File] = Text;
> -    }
> -    for (const auto &Listener : Listeners)
> -      Listener->onDocumentAdd(File);
> -  }
> -  /// Delete a document from the store.
> -  void removeDocument(StringRef File) {
> -    {
> -      std::lock_guard<std::mutex> Guard(DocsMutex);
> -      Docs.erase(File);
> -    }
> -    for (const auto &Listener : Listeners)
> -      Listener->onDocumentRemove(File);
> -  }
> -  /// Retrieve a document from the store. Empty string if it's unknown.
> -  ///
> -  /// This function is thread-safe. It returns a copy to avoid handing out
> -  /// references to unguarded data.
> -  std::string getDocument(StringRef File) const {
> -    // FIXME: This could be a reader lock.
> -    std::lock_guard<std::mutex> Guard(DocsMutex);
> -    return Docs.lookup(File);
> -  }
> -
> -  /// Add a listener. Does not take ownership.
> -  void addListener(DocumentStoreListener *DSL) { Listeners.push_back(DSL); }
> -
> -  /// Get name and constents of all documents in this store.
> -  ///
> -  /// This function is thread-safe. It returns a copies to avoid handing out
> -  /// references to unguarded data.
> -  std::vector<std::pair<std::string, std::string>> getAllDocuments() const {
> -    std::vector<std::pair<std::string, std::string>> AllDocs;
> -    std::lock_guard<std::mutex> Guard(DocsMutex);
> -    for (const auto &P : Docs)
> -      AllDocs.emplace_back(P.first(), P.second);
> -    return AllDocs;
> -  }
> +  /// \return version and contents of the stored document.
> +  /// For untracked files, a (0, None) pair is returned.
> +  VersionedDraft getDraft(PathRef File) const;
> +  /// \return version of the tracked document.
> +  /// For untracked files, 0 is returned.
> +  DocVersion getVersion(PathRef File) const;
> +
> +  /// Replace contents of the draft for \p File with \p Contents.
> +  /// \return The new version of the draft for \p File.
> +  DocVersion updateDraft(PathRef File, StringRef Contents);
> +  /// Remove the contents of the draft
> +  /// \return The new version of the draft for \p File.
> +  DocVersion removeDraft(PathRef File);
> 
> private:
> -  llvm::StringMap<std::string> Docs;
> -  std::vector<DocumentStoreListener *> Listeners;
> -
> -  mutable std::mutex DocsMutex;
> +  mutable std::mutex Mutex;
> +  llvm::StringMap<VersionedDraft> Drafts;
> };
> 
> } // namespace clangd
> 
> Added: clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.cpp?rev=303067&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.cpp (added)
> +++ clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.cpp Mon May 15 09:17:35 2017
> @@ -0,0 +1,65 @@
> +//===--- GlobalCompilationDatabase.cpp --------------------------*- C++-*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#include "GlobalCompilationDatabase.h"
> +#include "clang/Tooling/CompilationDatabase.h"
> +#include "llvm/Support/FileSystem.h"
> +#include "llvm/Support/Path.h"
> +
> +using namespace clang::clangd;
> +using namespace clang;
> +
> +std::vector<tooling::CompileCommand>
> +DirectoryBasedGlobalCompilationDatabase::getCompileCommands(PathRef File) {
> +  std::vector<tooling::CompileCommand> Commands;
> +
> +  auto CDB = getCompilationDatabase(File);
> +  if (!CDB)
> +    return {};
> +  return CDB->getCompileCommands(File);
> +}
> +
> +tooling::CompilationDatabase *
> +DirectoryBasedGlobalCompilationDatabase::getCompilationDatabase(PathRef File) {
> +  std::lock_guard<std::mutex> Lock(Mutex);
> +
> +  namespace path = llvm::sys::path;
> +
> +  assert((path::is_absolute(File, path::Style::posix) ||
> +          path::is_absolute(File, path::Style::windows)) &&
> +         "path must be absolute");
> +
> +  for (auto Path = path::parent_path(File); !Path.empty();
> +       Path = path::parent_path(Path)) {
> +
> +    auto CachedIt = CompilationDatabases.find(Path);
> +    if (CachedIt != CompilationDatabases.end())
> +      return CachedIt->second.get();
> +    std::string Error;
> +    auto CDB = tooling::CompilationDatabase::loadFromDirectory(Path, Error);
> +    if (!CDB) {
> +      if (!Error.empty()) {
> +        // FIXME(ibiryukov): logging
> +        // Output.log("Error when trying to load compilation database from " +
> +        //            Twine(Path) + ": " + Twine(Error) + "\n");
> +      }
> +      continue;
> +    }
> +
> +    // FIXME(ibiryukov): Invalidate cached compilation databases on changes
> +    auto result = CDB.get();
> +    CompilationDatabases.insert(std::make_pair(Path, std::move(CDB)));
> +    return result;
> +  }
> +
> +  // FIXME(ibiryukov): logging
> +  // Output.log("Failed to find compilation database for " + Twine(File) +
> +  // "\n");
> +  return nullptr;
> +}
> 
> Added: clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.h?rev=303067&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.h (added)
> +++ clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.h Mon May 15 09:17:35 2017
> @@ -0,0 +1,59 @@
> +//===--- GlobalCompilationDatabase.h ----------------------------*- C++-*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_GLOBALCOMPILATIONDATABASE_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_GLOBALCOMPILATIONDATABASE_H
> +
> +#include "Path.h"
> +#include "llvm/ADT/StringMap.h"
> +#include <memory>
> +#include <mutex>
> +
> +namespace clang {
> +
> +namespace tooling {
> +class CompilationDatabase;
> +struct CompileCommand;
> +} // namespace tooling
> +
> +namespace clangd {
> +
> +/// Provides compilation arguments used for building ClangdUnit.
> +class GlobalCompilationDatabase {
> +public:
> +  virtual ~GlobalCompilationDatabase() = default;
> +
> +  virtual std::vector<tooling::CompileCommand>
> +  getCompileCommands(PathRef File) = 0;
> +
> +  /// FIXME(ibiryukov): add facilities to track changes to compilation flags of
> +  /// existing targets.
> +};
> +
> +/// Gets compile args from tooling::CompilationDatabases built for parent
> +/// directories.
> +class DirectoryBasedGlobalCompilationDatabase
> +    : public GlobalCompilationDatabase {
> +public:
> +  std::vector<tooling::CompileCommand>
> +  getCompileCommands(PathRef File) override;
> +
> +private:
> +  tooling::CompilationDatabase *getCompilationDatabase(PathRef File);
> +
> +  std::mutex Mutex;
> +  /// Caches compilation databases loaded from directories(keys are
> +  /// directories).
> +  llvm::StringMap<std::unique_ptr<clang::tooling::CompilationDatabase>>
> +      CompilationDatabases;
> +};
> +} // namespace clangd
> +} // namespace clang
> +
> +#endif
> 
> Added: clang-tools-extra/trunk/clangd/Path.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Path.h?rev=303067&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/Path.h (added)
> +++ clang-tools-extra/trunk/clangd/Path.h Mon May 15 09:17:35 2017
> @@ -0,0 +1,29 @@
> +//===--- Path.h - Helper typedefs --------------------------------*- C++-*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_PATH_H
> +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PATH_H
> +
> +#include "llvm/ADT/StringRef.h"
> +#include <string>
> +
> +namespace clang {
> +namespace clangd {
> +
> +/// A typedef to represent a file path. Used solely for more descriptive
> +/// signatures.
> +using Path = std::string;
> +/// A typedef to represent a ref to file path. Used solely for more descriptive
> +/// signatures.
> +using PathRef = llvm::StringRef;
> +
> +} // namespace clangd
> +} // namespace clang
> +
> +#endif
> 
> Modified: clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp?rev=303067&r1=303066&r2=303067&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp (original)
> +++ clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp Mon May 15 09:17:35 2017
> @@ -8,9 +8,10 @@
> //===----------------------------------------------------------------------===//
> 
> #include "ProtocolHandlers.h"
> -#include "ASTManager.h"
> -#include "DocumentStore.h"
> +#include "ClangdServer.h"
> +#include "DraftStore.h"
> #include "clang/Format/Format.h"
> +#include "ClangdLSPServer.h"
> using namespace clang;
> using namespace clangd;
> 
> @@ -21,7 +22,7 @@ void TextDocumentDidOpenHandler::handleN
>     Output.log("Failed to decode DidOpenTextDocumentParams!\n");
>     return;
>   }
> -  Store.addDocument(DOTDP->textDocument.uri.file, DOTDP->textDocument.text);
> +  AST.openDocument(DOTDP->textDocument.uri.file, DOTDP->textDocument.text);
> }
> 
> void TextDocumentDidCloseHandler::handleNotification(
> @@ -32,7 +33,7 @@ void TextDocumentDidCloseHandler::handle
>     return;
>   }
> 
> -  Store.removeDocument(DCTDP->textDocument.uri.file);
> +  AST.closeDocument(DCTDP->textDocument.uri.file);
> }
> 
> void TextDocumentDidChangeHandler::handleNotification(
> @@ -43,7 +44,7 @@ void TextDocumentDidChangeHandler::handl
>     return;
>   }
>   // We only support full syncing right now.
> -  Store.addDocument(DCTDP->textDocument.uri.file, DCTDP->contentChanges[0].text);
> +  AST.openDocument(DCTDP->textDocument.uri.file, DCTDP->contentChanges[0].text);
> }
> 
> /// Turn a [line, column] pair into an offset in Code.
> @@ -110,7 +111,7 @@ void TextDocumentRangeFormattingHandler:
>     return;
>   }
> 
> -  std::string Code = Store.getDocument(DRFP->textDocument.uri.file);
> +  std::string Code = AST.getDocument(DRFP->textDocument.uri.file);
> 
>   size_t Begin = positionToOffset(Code, DRFP->range.start);
>   size_t Len = positionToOffset(Code, DRFP->range.end) - Begin;
> @@ -129,7 +130,7 @@ void TextDocumentOnTypeFormattingHandler
> 
>   // Look for the previous opening brace from the character position and format
>   // starting from there.
> -  std::string Code = Store.getDocument(DOTFP->textDocument.uri.file);
> +  std::string Code = AST.getDocument(DOTFP->textDocument.uri.file);
>   size_t CursorPos = positionToOffset(Code, DOTFP->position);
>   size_t PreviousLBracePos = StringRef(Code).find_last_of('{', CursorPos);
>   if (PreviousLBracePos == StringRef::npos)
> @@ -149,7 +150,7 @@ void TextDocumentFormattingHandler::hand
>   }
> 
>   // Format everything.
> -  std::string Code = Store.getDocument(DFP->textDocument.uri.file);
> +  std::string Code = AST.getDocument(DFP->textDocument.uri.file);
>   writeMessage(formatCode(Code, DFP->textDocument.uri.file,
>                           {clang::tooling::Range(0, Code.size())}, ID));
> }
> @@ -164,7 +165,7 @@ void CodeActionHandler::handleMethod(llv
> 
>   // We provide a code action for each diagnostic at the requested location
>   // which has FixIts available.
> -  std::string Code = AST.getStore().getDocument(CAP->textDocument.uri.file);
> +  std::string Code = AST.getDocument(CAP->textDocument.uri.file);
>   std::string Commands;
>   for (Diagnostic &D : CAP->context.diagnostics) {
>     std::vector<clang::tooling::Replacement> Fixes = AST.getFixIts(CAP->textDocument.uri.file, D);
> @@ -195,8 +196,8 @@ void CompletionHandler::handleMethod(llv
>     return;
>   }
> 
> -  auto Items = AST.codeComplete(TDPP->textDocument.uri.file, TDPP->position.line,
> -                                TDPP->position.character);
> +  auto Items = AST.codeComplete(TDPP->textDocument.uri.file, Position{TDPP->position.line,
> +          TDPP->position.character});
>   std::string Completions;
>   for (const auto &Item : Items) {
>     Completions += CompletionItem::unparse(Item);
> 
> Modified: clang-tools-extra/trunk/clangd/ProtocolHandlers.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.h?rev=303067&r1=303066&r2=303067&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ProtocolHandlers.h (original)
> +++ clang-tools-extra/trunk/clangd/ProtocolHandlers.h Mon May 15 09:17:35 2017
> @@ -22,8 +22,8 @@
> 
> namespace clang {
> namespace clangd {
> -class ASTManager;
> -class DocumentStore;
> +class ClangdLSPServer;
> +class ClangdLSPServer;
> 
> struct InitializeHandler : Handler {
>   InitializeHandler(JSONOutput &Output) : Handler(Output) {}
> @@ -56,83 +56,83 @@ private:
> };
> 
> struct TextDocumentDidOpenHandler : Handler {
> -  TextDocumentDidOpenHandler(JSONOutput &Output, DocumentStore &Store)
> -      : Handler(Output), Store(Store) {}
> +  TextDocumentDidOpenHandler(JSONOutput &Output, ClangdLSPServer &AST)
> +      : Handler(Output), AST(AST) {}
> 
>   void handleNotification(llvm::yaml::MappingNode *Params) override;
> 
> private:
> -  DocumentStore &Store;
> +  ClangdLSPServer &AST;
> };
> 
> struct TextDocumentDidChangeHandler : Handler {
> -  TextDocumentDidChangeHandler(JSONOutput &Output, DocumentStore &Store)
> -      : Handler(Output), Store(Store) {}
> +  TextDocumentDidChangeHandler(JSONOutput &Output, ClangdLSPServer &AST)
> +      : Handler(Output), AST(AST) {}
> 
>   void handleNotification(llvm::yaml::MappingNode *Params) override;
> 
> private:
> -  DocumentStore &Store;
> +  ClangdLSPServer &AST;
> };
> 
> struct TextDocumentDidCloseHandler : Handler {
> -  TextDocumentDidCloseHandler(JSONOutput &Output, DocumentStore &Store)
> -      : Handler(Output), Store(Store) {}
> +  TextDocumentDidCloseHandler(JSONOutput &Output, ClangdLSPServer &AST)
> +      : Handler(Output), AST(AST) {}
> 
>   void handleNotification(llvm::yaml::MappingNode *Params) override;
> 
> private:
> -  DocumentStore &Store;
> +  ClangdLSPServer &AST;
> };
> 
> struct TextDocumentOnTypeFormattingHandler : Handler {
> -  TextDocumentOnTypeFormattingHandler(JSONOutput &Output, DocumentStore &Store)
> -      : Handler(Output), Store(Store) {}
> +  TextDocumentOnTypeFormattingHandler(JSONOutput &Output, ClangdLSPServer &AST)
> +      : Handler(Output), AST(AST) {}
> 
>   void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
> 
> private:
> -  DocumentStore &Store;
> +  ClangdLSPServer &AST;
> };
> 
> struct TextDocumentRangeFormattingHandler : Handler {
> -  TextDocumentRangeFormattingHandler(JSONOutput &Output, DocumentStore &Store)
> -      : Handler(Output), Store(Store) {}
> +  TextDocumentRangeFormattingHandler(JSONOutput &Output, ClangdLSPServer &AST)
> +      : Handler(Output), AST(AST) {}
> 
>   void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
> 
> private:
> -  DocumentStore &Store;
> +  ClangdLSPServer &AST;
> };
> 
> struct TextDocumentFormattingHandler : Handler {
> -  TextDocumentFormattingHandler(JSONOutput &Output, DocumentStore &Store)
> -      : Handler(Output), Store(Store) {}
> +  TextDocumentFormattingHandler(JSONOutput &Output, ClangdLSPServer &AST)
> +      : Handler(Output), AST(AST) {}
> 
>   void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
> 
> private:
> -  DocumentStore &Store;
> +  ClangdLSPServer &AST;
> };
> 
> struct CodeActionHandler : Handler {
> -  CodeActionHandler(JSONOutput &Output, ASTManager &AST)
> +  CodeActionHandler(JSONOutput &Output, ClangdLSPServer &AST)
>       : Handler(Output), AST(AST) {}
> 
>   void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
> 
> private:
> -  ASTManager &AST;
> +  ClangdLSPServer &AST;
> };
> 
> struct CompletionHandler : Handler {
> -  CompletionHandler(JSONOutput &Output, ASTManager &AST)
> +  CompletionHandler(JSONOutput &Output, ClangdLSPServer &AST)
>       : Handler(Output), AST(AST) {}
> 
>   void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
> 
>  private:
> -  ASTManager &AST;
> +  ClangdLSPServer &AST;
> };
> 
> } // namespace clangd
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170515/ca53da19/attachment-0001.html>


More information about the cfe-commits mailing list