Revert "[ClangD] Refactor clangd into separate components"
authorAdam Nemet <anemet@apple.com>
Mon, 15 May 2017 18:14:35 +0000 (18:14 +0000)
committerAdam Nemet <anemet@apple.com>
Mon, 15 May 2017 18:14:35 +0000 (18:14 +0000)
This reverts commit r303067.

Caused http://green.lab.llvm.org/green/job/clang-stage1-configure-RA/34305/

And even after Simon's fix there is still a test failure.

llvm-svn: 303094

20 files changed:
clang-tools-extra/clangd/ASTManager.cpp [new file with mode: 0644]
clang-tools-extra/clangd/ASTManager.h [new file with mode: 0644]
clang-tools-extra/clangd/CMakeLists.txt
clang-tools-extra/clangd/ClangdLSPServer.cpp [deleted file]
clang-tools-extra/clangd/ClangdLSPServer.h [deleted file]
clang-tools-extra/clangd/ClangdMain.cpp
clang-tools-extra/clangd/ClangdServer.cpp [deleted file]
clang-tools-extra/clangd/ClangdServer.h [deleted file]
clang-tools-extra/clangd/ClangdUnit.cpp [deleted file]
clang-tools-extra/clangd/ClangdUnit.h [deleted file]
clang-tools-extra/clangd/ClangdUnitStore.cpp [deleted file]
clang-tools-extra/clangd/ClangdUnitStore.h [deleted file]
clang-tools-extra/clangd/DocumentStore.h [new file with mode: 0644]
clang-tools-extra/clangd/DraftStore.cpp [deleted file]
clang-tools-extra/clangd/DraftStore.h [deleted file]
clang-tools-extra/clangd/GlobalCompilationDatabase.cpp [deleted file]
clang-tools-extra/clangd/GlobalCompilationDatabase.h [deleted file]
clang-tools-extra/clangd/Path.h [deleted file]
clang-tools-extra/clangd/ProtocolHandlers.cpp
clang-tools-extra/clangd/ProtocolHandlers.h

diff --git a/clang-tools-extra/clangd/ASTManager.cpp b/clang-tools-extra/clangd/ASTManager.cpp
new file mode 100644 (file)
index 0000000..04cbf58
--- /dev/null
@@ -0,0 +1,440 @@
+//===--- 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;
+}
diff --git a/clang-tools-extra/clangd/ASTManager.h b/clang-tools-extra/clangd/ASTManager.h
new file mode 100644 (file)
index 0000000..e213822
--- /dev/null
@@ -0,0 +1,162 @@
+//===--- 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
index 42ce778..170fe20 100644 (file)
@@ -1,11 +1,6 @@
 add_clang_executable(clangd
-  ClangdLSPServer.cpp
+  ASTManager.cpp
   ClangdMain.cpp
-  ClangdServer.cpp
-  ClangdUnit.cpp
-  ClangdUnitStore.cpp
-  DraftStore.cpp
-  GlobalCompilationDatabase.cpp
   JSONRPCDispatcher.cpp
   Protocol.cpp
   ProtocolHandlers.cpp
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
deleted file mode 100644 (file)
index 2a2e0bf..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-//===--- 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"(]}})");
-}
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h
deleted file mode 100644 (file)
index 371bc74..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-//===--- 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
index 44f8665..c6e16a7 100644 (file)
@@ -7,19 +7,15 @@
 //
 //===----------------------------------------------------------------------===//
 
+#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>
@@ -38,7 +34,9 @@ int main(int argc, char *argv[]) {
 
   // Set up a document store and intialize all the method handlers for JSONRPC
   // dispatching.
-  ClangdLSPServer LSPServer(Out, RunSynchronously);
+  DocumentStore Store;
+  ASTManager AST(Out, Store, RunSynchronously);
+  Store.addListener(&AST);
   JSONRPCDispatcher Dispatcher(llvm::make_unique<Handler>(Out));
   Dispatcher.registerHandler("initialize",
                              llvm::make_unique<InitializeHandler>(Out));
@@ -47,26 +45,26 @@ int main(int argc, char *argv[]) {
   Dispatcher.registerHandler("shutdown", std::move(ShutdownPtr));
   Dispatcher.registerHandler(
       "textDocument/didOpen",
-      llvm::make_unique<TextDocumentDidOpenHandler>(Out, LSPServer));
+      llvm::make_unique<TextDocumentDidOpenHandler>(Out, Store));
   Dispatcher.registerHandler(
       "textDocument/didClose",
-      llvm::make_unique<TextDocumentDidCloseHandler>(Out, LSPServer));
+      llvm::make_unique<TextDocumentDidCloseHandler>(Out, Store));
   Dispatcher.registerHandler(
       "textDocument/didChange",
-      llvm::make_unique<TextDocumentDidChangeHandler>(Out, LSPServer));
+      llvm::make_unique<TextDocumentDidChangeHandler>(Out, Store));
   Dispatcher.registerHandler(
       "textDocument/rangeFormatting",
-      llvm::make_unique<TextDocumentRangeFormattingHandler>(Out, LSPServer));
+      llvm::make_unique<TextDocumentRangeFormattingHandler>(Out, Store));
   Dispatcher.registerHandler(
       "textDocument/onTypeFormatting",
-      llvm::make_unique<TextDocumentOnTypeFormattingHandler>(Out, LSPServer));
+      llvm::make_unique<TextDocumentOnTypeFormattingHandler>(Out, Store));
   Dispatcher.registerHandler(
       "textDocument/formatting",
-      llvm::make_unique<TextDocumentFormattingHandler>(Out, LSPServer));
+      llvm::make_unique<TextDocumentFormattingHandler>(Out, Store));
   Dispatcher.registerHandler("textDocument/codeAction",
-                             llvm::make_unique<CodeActionHandler>(Out, LSPServer));
+                             llvm::make_unique<CodeActionHandler>(Out, AST));
   Dispatcher.registerHandler("textDocument/completion",
-                             llvm::make_unique<CompletionHandler>(Out, LSPServer));
+                             llvm::make_unique<CompletionHandler>(Out, AST));
 
   while (std::cin.good()) {
     // A Language Server Protocol message starts with a HTTP header, delimited
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
deleted file mode 100644 (file)
index 89e935a..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-//===--- 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 "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/FileSystem.h"
-
-using namespace clang::clangd;
-
-WorkerRequest::WorkerRequest(WorkerRequestKind Kind, Path File,
-                             DocVersion Version)
-    : Kind(Kind), File(File), Version(Version) {}
-
-ClangdScheduler::ClangdScheduler(ClangdServer &Server, bool RunSynchronously)
-    : RunSynchronously(RunSynchronously) {
-  if (RunSynchronously) {
-    // Don't start the worker thread if we're running synchronously
-    return;
-  }
-
-  // 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
-
-      Server.handleRequest(std::move(Request));
-    }
-  });
-}
-
-ClangdScheduler::~ClangdScheduler() {
-  if (RunSynchronously)
-    return; // no worker thread is running in that case
-
-  {
-    std::lock_guard<std::mutex> Lock(Mutex);
-    // Wake up the worker thread
-    Done = true;
-    RequestCV.notify_one();
-  } // unlock Mutex
-  Worker.join();
-}
-
-void ClangdScheduler::enqueue(ClangdServer &Server, WorkerRequest Request) {
-  if (RunSynchronously) {
-    Server.handleRequest(Request);
-    return;
-  }
-
-  std::lock_guard<std::mutex> Lock(Mutex);
-  RequestQueue.push_back(Request);
-  RequestCV.notify_one();
-}
-
-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) {}
-
-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
-
-    Units.removeUnitIfPresent(Request.File);
-    break;
-  }
-}
diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
deleted file mode 100644 (file)
index 72b6bd5..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-//===--- ClangdServer.h - 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.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_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 <mutex>
-#include <string>
-#include <thread>
-#include <utility>
-
-namespace clang {
-class PCHContainerOperations;
-
-namespace clangd {
-
-class DiagnosticsConsumer {
-public:
-  virtual ~DiagnosticsConsumer() = default;
-
-  /// Called by ClangdServer when \p Diagnostics for \p File are ready.
-  virtual void onDiagnosticsReady(PathRef File,
-                                  std::vector<DiagWithFixIts> Diagnostics) = 0;
-};
-
-enum class WorkerRequestKind { ParseAndPublishDiagnostics, RemoveDocData };
-
-/// A request to the worker thread
-class WorkerRequest {
-public:
-  WorkerRequest() = default;
-  WorkerRequest(WorkerRequestKind Kind, Path File, DocVersion Version);
-
-  WorkerRequestKind Kind;
-  Path File;
-  DocVersion Version;
-};
-
-class ClangdServer;
-
-/// Handles running WorkerRequests of ClangdServer on a separate threads.
-/// Currently runs only one worker thread.
-class ClangdScheduler {
-public:
-  ClangdScheduler(ClangdServer &Server, bool RunSynchronously);
-  ~ClangdScheduler();
-
-  /// Enqueue WorkerRequest to be run on a worker thread
-  void enqueue(ClangdServer &Server, WorkerRequest Request);
-
-private:
-  bool RunSynchronously;
-  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 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
-} // namespace clang
-
-#endif
diff --git a/clang-tools-extra/clangd/ClangdUnit.cpp b/clang-tools-extra/clangd/ClangdUnit.cpp
deleted file mode 100644 (file)
index ff1ce9b..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-//===--- 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;
-}
diff --git a/clang-tools-extra/clangd/ClangdUnit.h b/clang-tools-extra/clangd/ClangdUnit.h
deleted file mode 100644 (file)
index ca8f003..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-//===--- 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
diff --git a/clang-tools-extra/clangd/ClangdUnitStore.cpp b/clang-tools-extra/clangd/ClangdUnitStore.cpp
deleted file mode 100644 (file)
index 56e6f54..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-//===--- 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;
-}
diff --git a/clang-tools-extra/clangd/ClangdUnitStore.h b/clang-tools-extra/clangd/ClangdUnitStore.h
deleted file mode 100644 (file)
index fdd7124..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-//===--- 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
diff --git a/clang-tools-extra/clangd/DocumentStore.h b/clang-tools-extra/clangd/DocumentStore.h
new file mode 100644 (file)
index 0000000..4d42893
--- /dev/null
@@ -0,0 +1,86 @@
+//===--- 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
diff --git a/clang-tools-extra/clangd/DraftStore.cpp b/clang-tools-extra/clangd/DraftStore.cpp
deleted file mode 100644 (file)
index 3455699..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-//===--- 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;
-}
diff --git a/clang-tools-extra/clangd/DraftStore.h b/clang-tools-extra/clangd/DraftStore.h
deleted file mode 100644 (file)
index c4e31e7..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-//===--- DraftStore.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_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>
-#include <string>
-#include <vector>
-
-namespace clang {
-namespace clangd {
-
-/// 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 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:
-  /// \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:
-  mutable std::mutex Mutex;
-  llvm::StringMap<VersionedDraft> Drafts;
-};
-
-} // namespace clangd
-} // namespace clang
-
-#endif
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
deleted file mode 100644 (file)
index 91d7702..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-//===--- 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;
-}
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.h b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
deleted file mode 100644 (file)
index c708c5c..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-//===--- 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
diff --git a/clang-tools-extra/clangd/Path.h b/clang-tools-extra/clangd/Path.h
deleted file mode 100644 (file)
index b4c9335..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-//===--- 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
index 66edee3..4c81692 100644 (file)
@@ -8,10 +8,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "ProtocolHandlers.h"
-#include "ClangdServer.h"
-#include "DraftStore.h"
+#include "ASTManager.h"
+#include "DocumentStore.h"
 #include "clang/Format/Format.h"
-#include "ClangdLSPServer.h"
 using namespace clang;
 using namespace clangd;
 
@@ -22,7 +21,7 @@ void TextDocumentDidOpenHandler::handleNotification(
     Output.log("Failed to decode DidOpenTextDocumentParams!\n");
     return;
   }
-  AST.openDocument(DOTDP->textDocument.uri.file, DOTDP->textDocument.text);
+  Store.addDocument(DOTDP->textDocument.uri.file, DOTDP->textDocument.text);
 }
 
 void TextDocumentDidCloseHandler::handleNotification(
@@ -33,7 +32,7 @@ void TextDocumentDidCloseHandler::handleNotification(
     return;
   }
 
-  AST.closeDocument(DCTDP->textDocument.uri.file);
+  Store.removeDocument(DCTDP->textDocument.uri.file);
 }
 
 void TextDocumentDidChangeHandler::handleNotification(
@@ -44,7 +43,7 @@ void TextDocumentDidChangeHandler::handleNotification(
     return;
   }
   // We only support full syncing right now.
-  AST.openDocument(DCTDP->textDocument.uri.file, DCTDP->contentChanges[0].text);
+  Store.addDocument(DCTDP->textDocument.uri.file, DCTDP->contentChanges[0].text);
 }
 
 /// Turn a [line, column] pair into an offset in Code.
@@ -111,7 +110,7 @@ void TextDocumentRangeFormattingHandler::handleMethod(
     return;
   }
 
-  std::string Code = AST.getDocument(DRFP->textDocument.uri.file);
+  std::string Code = Store.getDocument(DRFP->textDocument.uri.file);
 
   size_t Begin = positionToOffset(Code, DRFP->range.start);
   size_t Len = positionToOffset(Code, DRFP->range.end) - Begin;
@@ -130,7 +129,7 @@ void TextDocumentOnTypeFormattingHandler::handleMethod(
 
   // Look for the previous opening brace from the character position and format
   // starting from there.
-  std::string Code = AST.getDocument(DOTFP->textDocument.uri.file);
+  std::string Code = Store.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)
@@ -150,7 +149,7 @@ void TextDocumentFormattingHandler::handleMethod(
   }
 
   // Format everything.
-  std::string Code = AST.getDocument(DFP->textDocument.uri.file);
+  std::string Code = Store.getDocument(DFP->textDocument.uri.file);
   writeMessage(formatCode(Code, DFP->textDocument.uri.file,
                           {clang::tooling::Range(0, Code.size())}, ID));
 }
@@ -165,7 +164,7 @@ void CodeActionHandler::handleMethod(llvm::yaml::MappingNode *Params,
 
   // We provide a code action for each diagnostic at the requested location
   // which has FixIts available.
-  std::string Code = AST.getDocument(CAP->textDocument.uri.file);
+  std::string Code = AST.getStore().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);
@@ -196,8 +195,8 @@ void CompletionHandler::handleMethod(llvm::yaml::MappingNode *Params,
     return;
   }
 
-  auto Items = AST.codeComplete(TDPP->textDocument.uri.file, Position{TDPP->position.line,
-          TDPP->position.character});
+  auto Items = AST.codeComplete(TDPP->textDocument.uri.file, TDPP->position.line,
+                                TDPP->position.character);
   std::string Completions;
   for (const auto &Item : Items) {
     Completions += CompletionItem::unparse(Item);
index e957d35..521e6b6 100644 (file)
@@ -22,8 +22,8 @@
 
 namespace clang {
 namespace clangd {
-class ClangdLSPServer;
-class ClangdLSPServer;
+class ASTManager;
+class DocumentStore;
 
 struct InitializeHandler : Handler {
   InitializeHandler(JSONOutput &Output) : Handler(Output) {}
@@ -56,83 +56,83 @@ private:
 };
 
 struct TextDocumentDidOpenHandler : Handler {
-  TextDocumentDidOpenHandler(JSONOutput &Output, ClangdLSPServer &AST)
-      : Handler(Output), AST(AST) {}
+  TextDocumentDidOpenHandler(JSONOutput &Output, DocumentStore &Store)
+      : Handler(Output), Store(Store) {}
 
   void handleNotification(llvm::yaml::MappingNode *Params) override;
 
 private:
-  ClangdLSPServer &AST;
+  DocumentStore &Store;
 };
 
 struct TextDocumentDidChangeHandler : Handler {
-  TextDocumentDidChangeHandler(JSONOutput &Output, ClangdLSPServer &AST)
-      : Handler(Output), AST(AST) {}
+  TextDocumentDidChangeHandler(JSONOutput &Output, DocumentStore &Store)
+      : Handler(Output), Store(Store) {}
 
   void handleNotification(llvm::yaml::MappingNode *Params) override;
 
 private:
-  ClangdLSPServer &AST;
+  DocumentStore &Store;
 };
 
 struct TextDocumentDidCloseHandler : Handler {
-  TextDocumentDidCloseHandler(JSONOutput &Output, ClangdLSPServer &AST)
-      : Handler(Output), AST(AST) {}
+  TextDocumentDidCloseHandler(JSONOutput &Output, DocumentStore &Store)
+      : Handler(Output), Store(Store) {}
 
   void handleNotification(llvm::yaml::MappingNode *Params) override;
 
 private:
-  ClangdLSPServer &AST;
+  DocumentStore &Store;
 };
 
 struct TextDocumentOnTypeFormattingHandler : Handler {
-  TextDocumentOnTypeFormattingHandler(JSONOutput &Output, ClangdLSPServer &AST)
-      : Handler(Output), AST(AST) {}
+  TextDocumentOnTypeFormattingHandler(JSONOutput &Output, DocumentStore &Store)
+      : Handler(Output), Store(Store) {}
 
   void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
 
 private:
-  ClangdLSPServer &AST;
+  DocumentStore &Store;
 };
 
 struct TextDocumentRangeFormattingHandler : Handler {
-  TextDocumentRangeFormattingHandler(JSONOutput &Output, ClangdLSPServer &AST)
-      : Handler(Output), AST(AST) {}
+  TextDocumentRangeFormattingHandler(JSONOutput &Output, DocumentStore &Store)
+      : Handler(Output), Store(Store) {}
 
   void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
 
 private:
-  ClangdLSPServer &AST;
+  DocumentStore &Store;
 };
 
 struct TextDocumentFormattingHandler : Handler {
-  TextDocumentFormattingHandler(JSONOutput &Output, ClangdLSPServer &AST)
-      : Handler(Output), AST(AST) {}
+  TextDocumentFormattingHandler(JSONOutput &Output, DocumentStore &Store)
+      : Handler(Output), Store(Store) {}
 
   void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
 
 private:
-  ClangdLSPServer &AST;
+  DocumentStore &Store;
 };
 
 struct CodeActionHandler : Handler {
-  CodeActionHandler(JSONOutput &Output, ClangdLSPServer &AST)
+  CodeActionHandler(JSONOutput &Output, ASTManager &AST)
       : Handler(Output), AST(AST) {}
 
   void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
 
 private:
-  ClangdLSPServer &AST;
+  ASTManager &AST;
 };
 
 struct CompletionHandler : Handler {
-  CompletionHandler(JSONOutput &Output, ClangdLSPServer &AST)
+  CompletionHandler(JSONOutput &Output, ASTManager &AST)
       : Handler(Output), AST(AST) {}
 
   void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
 
  private:
-  ClangdLSPServer &AST;
+  ASTManager &AST;
 };
 
 } // namespace clangd