<div dir="ltr">And sorry for breaking the build, it's a non-deterministic failure that didn't show up on my test run :-(</div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, May 15, 2017 at 9:02 PM, Ilya Biryukov <span dir="ltr"><<a href="mailto:ibiryukov@google.com" target="_blank">ibiryukov@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div>There's a '-run-synchronously' flag forgotten in the test.</div><div>Still, it shouldn't panic.</div><div><br></div>I'll take a look at it tomorrow, thanks for reverting the commit.</div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, May 15, 2017 at 8:29 PM, Adam Nemet <span dir="ltr"><<a href="mailto:anemet@apple.com" target="_blank">anemet@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">Even after Simon’s fix there is still a test failure (<a href="http://lab.llvm.org:8080/green/job/clang-stage1-configure-RA_check/31377/consoleFull#18373900728254eaf0-7326-4999-85b0-388101f2d404" target="_blank">http://lab.llvm.org:8080/gree<wbr>n/job/clang-stage1-configure-<wbr>RA_check/31377/consoleFull#183<wbr>73900728254eaf0-7326-4999-85b0<wbr>-388101f2d404</a>).  Reverted the original commit and the fix in r303093 and r303094.<div><br><div><blockquote type="cite"><div>On May 15, 2017, at 10:06 AM, Adam Nemet <<a href="mailto:anemet@apple.com" target="_blank">anemet@apple.com</a>> wrote:</div><br class="m_3771896676606961527m_-3724680780602895101Apple-interchange-newline"><div><div style="word-wrap:break-word">Hi Simon,<div><br></div><div>Is r303078 supposed to fix this?</div><div><br></div><div>Adam</div><div><br><div><blockquote type="cite"><div>On May 15, 2017, at 9:28 AM, Adam Nemet <<a href="mailto:anemet@apple.com" target="_blank">anemet@apple.com</a>> wrote:</div><br class="m_3771896676606961527m_-3724680780602895101Apple-interchange-newline"><div><div style="word-wrap:break-word">This broke the build <a href="http://green.lab.llvm.org/green/job/clang-stage1-configure-RA/34305/" target="_blank">http://green.lab.llvm.or<wbr>g/green/job/clang-stage1-confi<wbr>gure-RA/34305/</a>, please take a look.<div><br></div><div>Adam</div><div><br><div><blockquote type="cite"><div>On May 15, 2017, at 7:17 AM, Ilya Biryukov via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>> wrote:</div><br class="m_3771896676606961527m_-3724680780602895101Apple-interchange-newline"><div><div>Author: ibiryukov<br>Date: Mon May 15 09:17:35 2017<br>New Revision: 303067<br><br>URL: <a href="http://llvm.org/viewvc/llvm-project?rev=303067&view=rev" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject?rev=303067&view=rev</a><br>Log:<br>[ClangD] Refactor clangd into separate components<br><br>Summary: Major refactoring to split LSP implementation, Clang API calls and threading(mostly synchronization)<br><br>Reviewers: bkramer, krasimir<br><br>Reviewed By: bkramer<br><br>Subscribers: cfe-commits, mgorny, klimek<br><br>Tags: #clang-tools-extra<br><br>Differential Revision: <a href="https://reviews.llvm.org/D33047" target="_blank">https://reviews.llvm.org/D3304<wbr>7</a><br><br>Added:<br>    clang-tools-extra/trunk/cla<wbr>ngd/ClangdLSPServer.cpp<br>    clang-tools-extra/trunk/cla<wbr>ngd/ClangdLSPServer.h<br>    clang-tools-extra/trunk/cla<wbr>ngd/ClangdServer.cpp<br>      - copied, changed from r303060, clang-tools-extra/trunk/clangd<wbr>/ASTManager.cpp<br>    clang-tools-extra/trunk/cla<wbr>ngd/ClangdServer.h<br>      - copied, changed from r303063, clang-tools-extra/trunk/clangd<wbr>/ASTManager.h<br>    clang-tools-extra/trunk/cla<wbr>ngd/ClangdUnit.cpp<br>    clang-tools-extra/trunk/cla<wbr>ngd/ClangdUnit.h<br>    clang-tools-extra/trunk/cla<wbr>ngd/ClangdUnitStore.cpp<br>    clang-tools-extra/trunk/cla<wbr>ngd/ClangdUnitStore.h<br>    clang-tools-extra/trunk/cla<wbr>ngd/DraftStore.cpp<br>    clang-tools-extra/trunk/cla<wbr>ngd/DraftStore.h<br>      - copied, changed from r303060, clang-tools-extra/trunk/clangd<wbr>/DocumentStore.h<br>    clang-tools-extra/trunk/cla<wbr>ngd/GlobalCompilationDatabase.<wbr>cpp<br>    clang-tools-extra/trunk/cla<wbr>ngd/GlobalCompilationDatabase.<wbr>h<br>    clang-tools-extra/trunk/cla<wbr>ngd/Path.h<br>Removed:<br>    clang-tools-extra/trunk/cla<wbr>ngd/ASTManager.cpp<br>    clang-tools-extra/trunk/cla<wbr>ngd/ASTManager.h<br>    clang-tools-extra/trunk/cla<wbr>ngd/DocumentStore.h<br>Modified:<br>    clang-tools-extra/trunk/cla<wbr>ngd/CMakeLists.txt<br>    clang-tools-extra/trunk/cla<wbr>ngd/ClangdMain.cpp<br>    clang-tools-extra/trunk/cla<wbr>ngd/ProtocolHandlers.cpp<br>    clang-tools-extra/trunk/cla<wbr>ngd/ProtocolHandlers.h<br><br>Removed: clang-tools-extra/trunk/clangd<wbr>/ASTManager.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ASTManager.cpp?rev=303066&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ASTManager.cpp?rev=<wbr>303066&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ASTManager.cpp (original)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ASTManager.cpp (removed)<br>@@ -1,440 +0,0 @@<br>-//===--- ASTManager.cpp - Clang AST manager ------------------------------<wbr>-===//<br>-//<br>-//                     The LLVM Compiler Infrastructure<br>-//<br>-// This file is distributed under the University of Illinois Open Source<br>-// License. See LICENSE.TXT for details.<br>-//<br>-//===------------------------<wbr>------------------------------<wbr>----------------===//<br>-<br>-#include "ASTManager.h"<br>-#include "JSONRPCDispatcher.h"<br>-#include "Protocol.h"<br>-#include "clang/Frontend/ASTUnit.h"<br>-#include "clang/Frontend/CompilerInstan<wbr>ce.h"<br>-#include "clang/Tooling/CompilationData<wbr>base.h"<br>-#include "llvm/Support/Format.h"<br>-#include "llvm/Support/Path.h"<br>-#include <mutex><br>-#include <thread><br>-using namespace clang;<br>-using namespace clangd;<br>-<br>-void DocData::setAST(std::unique_pt<wbr>r<ASTUnit> AST) {<br>-  this->AST = std::move(AST);<br>-}<br>-<br>-ASTUnit *DocData::getAST() const { return AST.get(); }<br>-<br>-void DocData::cacheFixIts(Diagnosti<wbr>cToReplacementMap FixIts) {<br>-  this->FixIts = std::move(FixIts);<br>-}<br>-<br>-std::vector<clang::tooling::R<wbr>eplacement><br>-DocData::getFixIts(const clangd::Diagnostic &D) const {<br>-  auto it = FixIts.find(D);<br>-  if (it != FixIts.end())<br>-    return it->second;<br>-  return {};<br>-}<br>-<br>-ASTManagerRequest::ASTManager<wbr>Request(ASTManagerRequestType Type,<br>-                               <wbr>      std::string File,<br>-                               <wbr>      DocVersion Version)<br>-    : Type(Type), File(File), Version(Version) {}<br>-<br>-/// Retrieve a copy of the contents of every file in the store, for feeding into<br>-/// ASTUnit.<br>-static std::vector<ASTUnit::RemappedF<wbr>ile><br>-getRemappedFiles(const DocumentStore &Docs) {<br>-  // FIXME: Use VFS instead. This would allow us to get rid of the chdir below.<br>-  std::vector<ASTUnit::Remapped<wbr>File> RemappedFiles;<br>-  for (const auto &P : Docs.getAllDocuments()) {<br>-    StringRef FileName = P.first;<br>-    RemappedFiles.push_back(AST<wbr>Unit::RemappedFile(<br>-        FileName,<br>-        llvm::MemoryBuffer::get<wbr>MemBufferCopy(P.second, FileName).release()));<br>-  }<br>-  return RemappedFiles;<br>-}<br>-<br>-/// Convert from clang diagnostic level to LSP severity.<br>-static int getSeverity(DiagnosticsEngine:<wbr>:Level L) {<br>-  switch (L) {<br>-  case DiagnosticsEngine::Remark:<br>-    return 4;<br>-  case DiagnosticsEngine::Note:<br>-    return 3;<br>-  case DiagnosticsEngine::Warning:<br>-    return 2;<br>-  case DiagnosticsEngine::Fatal:<br>-  case DiagnosticsEngine::Error:<br>-    return 1;<br>-  case DiagnosticsEngine::Ignored:<br>-    return 0;<br>-  }<br>-  llvm_unreachable("Unknown diagnostic level!");<br>-}<br>-<br>-static CompletionItemKind getKind(CXCursorKind K) {<br>-  switch (K) {<br>-  case CXCursor_MacroInstantiation:<br>-  case CXCursor_MacroDefinition:<br>-    return CompletionItemKind::Text;<br>-  case CXCursor_CXXMethod:<br>-    return CompletionItemKind::Method;<br>-  case CXCursor_FunctionDecl:<br>-  case CXCursor_FunctionTemplate:<br>-    return CompletionItemKind::Function;<br>-  case CXCursor_Constructor:<br>-  case CXCursor_Destructor:<br>-    return CompletionItemKind::Constructo<wbr>r;<br>-  case CXCursor_FieldDecl:<br>-    return CompletionItemKind::Field;<br>-  case CXCursor_VarDecl:<br>-  case CXCursor_ParmDecl:<br>-    return CompletionItemKind::Variable;<br>-  case CXCursor_ClassDecl:<br>-  case CXCursor_StructDecl:<br>-  case CXCursor_UnionDecl:<br>-  case CXCursor_ClassTemplate:<br>-  case CXCursor_ClassTemplatePartialS<wbr>pecialization:<br>-    return CompletionItemKind::Class;<br>-  case CXCursor_Namespace:<br>-  case CXCursor_NamespaceAlias:<br>-  case CXCursor_NamespaceRef:<br>-    return CompletionItemKind::Module;<br>-  case CXCursor_EnumConstantDecl:<br>-    return CompletionItemKind::Value;<br>-  case CXCursor_EnumDecl:<br>-    return CompletionItemKind::Enum;<br>-  case CXCursor_TypeAliasDecl:<br>-  case CXCursor_TypeAliasTemplateDecl<wbr>:<br>-  case CXCursor_TypedefDecl:<br>-  case CXCursor_MemberRef:<br>-  case CXCursor_TypeRef:<br>-    return CompletionItemKind::Reference;<br>-  default:<br>-    return CompletionItemKind::Missing;<br>-  }<br>-}<br>-<br>-ASTManager::ASTManager(JSONOu<wbr>tput &Output, DocumentStore &Store,<br>-                       bool RunSynchronously)<br>-    : Output(Output), Store(Store), RunSynchronously(RunSynchronou<wbr>sly),<br>-      PCHs(std::make_shared<PCH<wbr>ContainerOperations>()),<br>-      ClangWorker([this]() { runWorker(); }) {}<br>-<br>-void ASTManager::runWorker() {<br>-  while (true) {<br>-    ASTManagerRequest Request;<br>-<br>-    // Pick request from the queue<br>-    {<br>-      std::unique_lock<std::mut<wbr>ex> Lock(RequestLock);<br>-      // Wait for more requests.<br>-      ClangRequestCV.wait(Lock,<br>-                          [this<wbr>] { return !RequestQueue.empty() || Done; });<br>-      if (Done)<br>-        return;<br>-      assert(!RequestQueue.empt<wbr>y() && "RequestQueue was empty");<br>-<br>-      Request = std::move(RequestQueue.back())<wbr>;<br>-      RequestQueue.pop_back();<br>-<br>-      // Skip outdated requests<br>-      if (Request.Version != DocVersions.find(Request.File)<wbr>->second) {<br>-        Output.log("Version for " + Twine(Request.File) +<br>-                   " in request is outdated, skipping request\n");<br>-        continue;<br>-      }<br>-    } // unlock RequestLock<br>-<br>-    handleRequest(Request.Type, Request.File);<br>-  }<br>-}<br>-<br>-void ASTManager::queueOrRun(ASTMana<wbr>gerRequestType RequestType, StringRef File) {<br>-  if (RunSynchronously) {<br>-    handleRequest(RequestType, File);<br>-    return;<br>-  }<br>-<br>-  std::lock_guard<std::mutex> Guard(RequestLock);<br>-  // We increment the version of the added document immediately and schedule<br>-  // the requested operation to be run on a worker thread<br>-  DocVersion version = ++DocVersions[File];<br>-  RequestQueue.push_back(ASTMan<wbr>agerRequest(RequestType, File, version));<br>-  ClangRequestCV.notify_one();<br>-}<br>-<br>-void ASTManager::handleRequest(ASTM<wbr>anagerRequestType RequestType,<br>-                               <wbr>StringRef File) {<br>-  switch (RequestType) {<br>-  case ASTManagerRequestType::ParseAn<wbr>dPublishDiagnostics:<br>-    parseFileAndPublishDiagnost<wbr>ics(File);<br>-    break;<br>-  case ASTManagerRequestType::RemoveD<wbr>ocData: {<br>-    std::lock_guard<std::mutex> Lock(ClangObjectLock);<br>-    auto DocDataIt = DocDatas.find(File);<br>-    // We could get the remove request before parsing for the document is<br>-    // started, just do nothing in that case, parsing request will be discarded<br>-    // because it has a lower version value<br>-    if (DocDataIt == DocDatas.end())<br>-      return;<br>-    DocDatas.erase(DocDataIt);<br>-    break;<br>-  } // unlock ClangObjectLock<br>-  }<br>-}<br>-<br>-void ASTManager::parseFileAndPublis<wbr>hDiagnostics(StringRef File) {<br>-  std::unique_lock<std::mutex> ClangObjectLockGuard(ClangObje<wbr>ctLock);<br>-<br>-  auto &DocData = DocDatas[File];<br>-  ASTUnit *Unit = DocData.getAST();<br>-  if (!Unit) {<br>-    auto newAST = createASTUnitForFile(File, this->Store);<br>-    Unit = newAST.get();<br>-<br>-    DocData.setAST(std::move(ne<wbr>wAST));<br>-  } else {<br>-    // Do a reparse if this wasn't the first parse.<br>-    // FIXME: This might have the wrong working directory if it changed in the<br>-    // meantime.<br>-    Unit->Reparse(PCHs, getRemappedFiles(this->Store))<wbr>;<br>-  }<br>-<br>-  if (!Unit)<br>-    return;<br>-<br>-  // Send the diagnotics to the editor.<br>-  // FIXME: If the diagnostic comes from a different file, do we want to<br>-  // show them all? Right now we drop everything not coming from the<br>-  // main file.<br>-  std::string Diagnostics;<br>-  DocData::DiagnosticToReplacem<wbr>entMap LocalFixIts; // Temporary storage<br>-  for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),<br>-                               <wbr>      DEnd = Unit->stored_diag_end();<br>-       D != DEnd; ++D) {<br>-    if (!D->getLocation().isValid() ||<br>-        !D->getLocation().getMa<wbr>nager().isInMainFile(D->getLoc<wbr>ation()))<br>-      continue;<br>-    Position P;<br>-    P.line = D->getLocation().getSpellingLi<wbr>neNumber() - 1;<br>-    P.character = D->getLocation().getSpellingCo<wbr>lumnNumber();<br>-    Range R = {P, P};<br>-    Diagnostics +=<br>-        R"({"range":)" + Range::unparse(R) +<br>-        R"(,"severity":)" + std::to_string(getSeverity(D-><wbr>getLevel())) +<br>-        R"(,"message":")" + llvm::yaml::escape(D->getMessa<wbr>ge()) +<br>-        R"("},)";<br>-<br>-    // We convert to Replacements to become independent of the SourceManager.<br>-    clangd::Diagnostic Diag = {R, getSeverity(D->getLevel()), D->getMessage()};<br>-    auto &FixItsForDiagnostic = LocalFixIts[Diag];<br>-    for (const FixItHint &Fix : D->getFixIts()) {<br>-      FixItsForDiagnostic.push_<wbr>back(clang::tooling::Replaceme<wbr>nt(<br>-          Unit->getSourceManage<wbr>r(), Fix.RemoveRange, Fix.CodeToInsert));<br>-    }<br>-  }<br>-<br>-  // Put FixIts into place.<br>-  DocData.cacheFixIts(std::move<wbr>(LocalFixIts));<br>-<br>-  ClangObjectLockGuard.unlock()<wbr>;<br>-  // No accesses to clang objects are allowed after this point.<br>-<br>-  // Publish diagnostics.<br>-  if (!Diagnostics.empty())<br>-    Diagnostics.pop_back(); // Drop trailing comma.<br>-  Output.writeMessage(<br>-      R"({"jsonrpc":"2.0","meth<wbr>od":"textDocument/publishDiagn<wbr>ostics","params":{"uri":")" +<br>-      URI::fromFile(File).uri + R"(","diagnostics":[)" + Diagnostics + R"(]}})");<br>-}<br>-<br>-ASTManager::~ASTManager() {<br>-  {<br>-    std::lock_guard<std::mutex> Guard(RequestLock);<br>-    // Wake up the clang worker thread, then exit.<br>-    Done = true;<br>-    ClangRequestCV.notify_one()<wbr>;<br>-  } // unlock DocDataLock<br>-  ClangWorker.join();<br>-}<br>-<br>-void ASTManager::onDocumentAdd(Stri<wbr>ngRef File) {<br>-  queueOrRun(ASTManagerRequestT<wbr>ype::ParseAndPublishDiagnostic<wbr>s, File);<br>-}<br>-<br>-void ASTManager::onDocumentRemove(S<wbr>tringRef File) {<br>-  queueOrRun(ASTManagerRequestT<wbr>ype::RemoveDocData, File);<br>-}<br>-<br>-tooling::CompilationDatabase *<br>-ASTManager::getOrCreateCompil<wbr>ationDatabaseForFile(StringRef File) {<br>-  namespace path = llvm::sys::path;<br>-<br>-  assert((path::is_absolute(Fil<wbr>e, path::Style::posix) ||<br>-          path::is_absolute(Fil<wbr>e, path::Style::windows)) &&<br>-         "path must be absolute");<br>-<br>-  for (auto Path = path::parent_path(File); !Path.empty();<br>-       Path = path::parent_path(Path)) {<br>-<br>-    auto CachedIt = CompilationDatabases.find(Path<wbr>);<br>-    if (CachedIt != CompilationDatabases.end())<br>-      return CachedIt->second.get();<br>-    std::string Error;<br>-    auto CDB = tooling::CompilationDatabase::<wbr>loadFromDirectory(Path, Error);<br>-    if (!CDB) {<br>-      if (!Error.empty()) {<br>-        Output.log("Error when trying to load compilation database from " +<br>-                   Twine(Path) + ": " + Twine(Error) + "\n");<br>-      }<br>-      continue;<br>-    }<br>-<br>-    // TODO(ibiryukov): Invalidate cached compilation databases on changes<br>-    auto result = CDB.get();<br>-    CompilationDatabases.insert<wbr>(std::make_pair(Path, std::move(CDB)));<br>-    return result;<br>-  }<br>-<br>-  Output.log("Failed to find compilation database for " + Twine(File) + "\n");<br>-  return nullptr;<br>-}<br>-<br>-std::unique_ptr<clang::ASTUni<wbr>t><br>-ASTManager::createASTUnitForF<wbr>ile(StringRef File, const DocumentStore &Docs) {<br>-  tooling::CompilationDatabase *CDB =<br>-      getOrCreateCompilationDat<wbr>abaseForFile(File);<br>-<br>-  std::vector<tooling::CompileC<wbr>ommand> Commands;<br>-<br>-  if (CDB) {<br>-    Commands = CDB->getCompileCommands(File);<br>-    // chdir. This is thread hostile.<br>-    if (!Commands.empty())<br>-      llvm::sys::fs::set_curren<wbr>t_path(Commands.front().Direct<wbr>ory);<br>-  }<br>-  if (Commands.empty()) {<br>-    // Add a fake command line if we know nothing.<br>-    Commands.push_back(tooling:<wbr>:CompileCommand(<br>-        llvm::sys::path::parent<wbr>_path(File), llvm::sys::path::filename(File<wbr>),<br>-        {"clang", "-fsyntax-only", File.str()}, ""));<br>-  }<br>-<br>-  // Inject the resource dir.<br>-  // FIXME: Don't overwrite it if it's already there.<br>-  static int Dummy; // Just an address in this process.<br>-  std::string ResourceDir =<br>-      CompilerInvocation::GetRe<wbr>sourcesPath("clangd", (void *)&Dummy);<br>-  Commands.front().CommandLine.<wbr>push_back("-resource-dir=" + ResourceDir);<br>-<br>-  IntrusiveRefCntPtr<Diagnostic<wbr>sEngine> Diags =<br>-      CompilerInstance::createD<wbr>iagnostics(new DiagnosticOptions);<br>-<br>-  std::vector<const char *> ArgStrs;<br>-  for (const auto &S : Commands.front().CommandLine)<br>-    ArgStrs.push_back(S.c_str()<wbr>);<br>-<br>-  auto ArgP = &*ArgStrs.begin();<br>-  return std::unique_ptr<clang::ASTUnit<wbr>>(ASTUnit::LoadFromCommandLine<wbr>(<br>-      ArgP, ArgP + ArgStrs.size(), PCHs, Diags, ResourceDir,<br>-      /*OnlyLocalDecls=*/false, /*CaptureDiagnostics=*/true,<br>-      getRemappedFiles(Docs),<br>-      /*RemappedFilesKeepOrigin<wbr>alName=*/true,<br>-      /*PrecompilePreambleAfter<wbr>NParses=*/1, /*TUKind=*/TU_Complete,<br>-      /*CacheCodeCompletionResu<wbr>lts=*/true,<br>-      /*IncludeBriefCommentsInC<wbr>odeCompletion=*/true,<br>-      /*AllowPCHWithCompilerErr<wbr>ors=*/true));<br>-}<br>-<br>-std::vector<clang::tooling::R<wbr>eplacement><br>-ASTManager::getFixIts(StringR<wbr>ef File, const clangd::Diagnostic &D) {<br>-  // TODO(ibiryukov): the FixIts should be available immediately<br>-  // even when parsing is being run on a worker thread<br>-  std::lock_guard<std::mutex> Guard(ClangObjectLock);<br>-  return DocDatas[File].getFixIts(D);<br>-}<br>-<br>-namespace {<br>-class CompletionItemsCollector : public CodeCompleteConsumer {<br>-  std::vector<CompletionItem> *Items;<br>-  std::shared_ptr<clang::Global<wbr>CodeCompletionAllocator> Allocator;<br>-  CodeCompletionTUInfo CCTUInfo;<br>-<br>-public:<br>-  CompletionItemsCollector(std:<wbr>:vector<CompletionItem> *Items,<br>-                           cons<wbr>t CodeCompleteOptions &CodeCompleteOpts)<br>-      : CodeCompleteConsumer(CodeCompl<wbr>eteOpts, /*OutputIsBinary=*/false),<br>-        Items(Items),<br>-        Allocator(std::make_sha<wbr>red<clang::GlobalCodeCompletio<wbr>nAllocator>()),<br>-        CCTUInfo(Allocator) {}<br>-<br>-  void ProcessCodeCompleteResults(Sem<wbr>a &S, CodeCompletionContext Context,<br>-                               <wbr>   CodeCompletionResult *Results,<br>-                               <wbr>   unsigned NumResults) override {<br>-    for (unsigned I = 0; I != NumResults; ++I) {<br>-      CodeCompletionResult &Result = Results[I];<br>-      CodeCompletionString *CCS = Result.CreateCodeCompletionStr<wbr>ing(<br>-          S, Context, *Allocator, CCTUInfo,<br>-          CodeCompleteOpts.Incl<wbr>udeBriefComments);<br>-      if (CCS) {<br>-        CompletionItem Item;<br>-        assert(CCS->getTypedTex<wbr>t());<br>-        Item.label = CCS->getTypedText();<br>-        Item.kind = getKind(Result.CursorKind);<br>-        if (CCS->getBriefComment())<br>-          Item.documentation = CCS->getBriefComment();<br>-        Items->push_back(std::m<wbr>ove(Item));<br>-      }<br>-    }<br>-  }<br>-<br>-  GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }<br>-<br>-  CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }<br>-};<br>-<br>-} // namespace<br>-<br>-std::vector<CompletionItem><br>-ASTManager::codeComplete(Stri<wbr>ngRef File, unsigned Line, unsigned Column) {<br>-  CodeCompleteOptions CCO;<br>-  CCO.IncludeBriefComments = 1;<br>-  // This is where code completion stores dirty buffers. Need to free after<br>-  // completion.<br>-  SmallVector<const llvm::MemoryBuffer *, 4> OwnedBuffers;<br>-  SmallVector<StoredDiagnostic, 4> StoredDiagnostics;<br>-  IntrusiveRefCntPtr<Diagnostic<wbr>sEngine> DiagEngine(<br>-      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions));<br>-  std::vector<CompletionItem> Items;<br>-  CompletionItemsCollector Collector(&Items, CCO);<br>-<br>-  std::lock_guard<std::mutex> Guard(ClangObjectLock);<br>-  auto &DocData = DocDatas[File];<br>-  auto Unit = DocData.getAST();<br>-  if (!Unit) {<br>-    auto newAST = createASTUnitForFile(File, this->Store);<br>-    Unit = newAST.get();<br>-    DocData.setAST(std::move(ne<wbr>wAST));<br>-  }<br>-  if (!Unit)<br>-    return {};<br>-  IntrusiveRefCntPtr<SourceMana<wbr>ger> SourceMgr(<br>-      new SourceManager(*DiagEngine, Unit->getFileManager()));<br>-  // CodeComplete seems to require fresh LangOptions.<br>-  LangOptions LangOpts = Unit->getLangOpts();<br>-  // The language server protocol uses zero-based line and column numbers.<br>-  // The clang code completion uses one-based numbers.<br>-  Unit->CodeComplete(File, Line + 1, Column + 1, getRemappedFiles(this->Store),<br>-                     CCO.Includ<wbr>eMacros, CCO.IncludeCodePatterns,<br>-                     CCO.Includ<wbr>eBriefComments, Collector, PCHs, *DiagEngine,<br>-                     LangOpts, *SourceMgr, Unit->getFileManager(),<br>-                     StoredDiag<wbr>nostics, OwnedBuffers);<br>-  for (const llvm::MemoryBuffer *Buffer : OwnedBuffers)<br>-    delete Buffer;<br>-  return Items;<br>-}<br><br>Removed: clang-tools-extra/trunk/clangd<wbr>/ASTManager.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ASTManager.h?rev=303066&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ASTManager.h?rev=303066<wbr>&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ASTManager.h (original)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ASTManager.h (removed)<br>@@ -1,162 +0,0 @@<br>-//===--- ASTManager.h - Clang AST manager -----------------------*- C++ -*-===//<br>-//<br>-//                     The LLVM Compiler Infrastructure<br>-//<br>-// This file is distributed under the University of Illinois Open Source<br>-// License. See LICENSE.TXT for details.<br>-//<br>-//===------------------------<wbr>------------------------------<wbr>----------------===//<br>-<br>-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>ASTMANAGER_H<br>-#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>ASTMANAGER_H<br>-<br>-#include "DocumentStore.h"<br>-#include "JSONRPCDispatcher.h"<br>-#include "Protocol.h"<br>-#include "clang/Tooling/Core/Replacemen<wbr>t.h"<br>-#include "llvm/ADT/IntrusiveRefCntPtr.h<wbr>"<br>-#include <condition_variable><br>-#include <deque><br>-#include <thread><br>-<br>-namespace clang {<br>-class ASTUnit;<br>-class DiagnosticsEngine;<br>-class PCHContainerOperations;<br>-namespace tooling {<br>-class CompilationDatabase;<br>-} // namespace tooling<br>-<br>-namespace clangd {<br>-<br>-/// Using 'unsigned' here to avoid undefined behaviour on overflow.<br>-typedef unsigned DocVersion;<br>-<br>-/// Stores ASTUnit and FixIts map for an opened document.<br>-class DocData {<br>-public:<br>-  typedef std::map<clangd::Diagnostic, std::vector<clang::tooling::Re<wbr>placement>><br>-      DiagnosticToReplacementMa<wbr>p;<br>-<br>-public:<br>-  void setAST(std::unique_ptr<ASTUnit<wbr>> AST);<br>-  ASTUnit *getAST() const;<br>-<br>-  void cacheFixIts(DiagnosticToReplac<wbr>ementMap FixIts);<br>-  std::vector<clang::tooling::R<wbr>eplacement><br>-  getFixIts(const clangd::Diagnostic &D) const;<br>-<br>-private:<br>-  std::unique_ptr<ASTUnit> AST;<br>-  DiagnosticToReplacementMap FixIts;<br>-};<br>-<br>-enum class ASTManagerRequestType { ParseAndPublishDiagnostics, RemoveDocData };<br>-<br>-/// A request to the worker thread<br>-class ASTManagerRequest {<br>-public:<br>-  ASTManagerRequest() = default;<br>-  ASTManagerRequest(ASTManagerR<wbr>equestType Type, std::string File,<br>-                    DocVersion Version);<br>-<br>-  ASTManagerRequestType Type;<br>-  std::string File;<br>-  DocVersion Version;<br>-};<br>-<br>-class ASTManager : public DocumentStoreListener {<br>-public:<br>-  ASTManager(JSONOutput &Output, DocumentStore &Store, bool RunSynchronously);<br>-  ~ASTManager() override;<br>-<br>-  void onDocumentAdd(StringRef File) override;<br>-  void onDocumentRemove(StringRef File) override;<br>-<br>-  /// Get code completions at a specified \p Line and \p Column in \p File.<br>-  ///<br>-  /// This function is thread-safe and returns completion items that own the<br>-  /// data they contain.<br>-  std::vector<CompletionItem> codeComplete(StringRef File, unsigned Line,<br>-                               <wbr>            unsigned Column);<br>-<br>-  /// Get the fixes associated with a certain diagnostic in a specified file as<br>-  /// replacements.<br>-  ///<br>-  /// This function is thread-safe. It returns a copy to avoid handing out<br>-  /// references to unguarded data.<br>-  std::vector<clang::tooling::R<wbr>eplacement><br>-  getFixIts(StringRef File, const clangd::Diagnostic &D);<br>-<br>-  DocumentStore &getStore() const { return Store; }<br>-<br>-private:<br>-  JSONOutput &Output;<br>-  DocumentStore &Store;<br>-<br>-  // Set to true if requests should block instead of being processed<br>-  // asynchronously.<br>-  bool RunSynchronously;<br>-<br>-  /// Loads a compilation database for File. May return nullptr if it fails. The<br>-  /// database is cached for subsequent accesses.<br>-  clang::tooling::CompilationDa<wbr>tabase *<br>-  getOrCreateCompilationDatabas<wbr>eForFile(StringRef File);<br>-  // Creates a new ASTUnit for the document at File.<br>-  // FIXME: This calls chdir internally, which is thread unsafe.<br>-  std::unique_ptr<clang::ASTUni<wbr>t><br>-  createASTUnitForFile(StringRe<wbr>f File, const DocumentStore &Docs);<br>-<br>-  /// If RunSynchronously is false, queues the request to be run on the worker<br>-  /// thread.<br>-  /// If RunSynchronously is true, runs the request handler immediately on the<br>-  /// main thread.<br>-  void queueOrRun(ASTManagerRequestTy<wbr>pe RequestType, StringRef File);<br>-<br>-  void runWorker();<br>-  void handleRequest(ASTManagerReques<wbr>tType RequestType, StringRef File);<br>-<br>-  /// Parses files and publishes diagnostics.<br>-  /// This function is called on the worker thread in asynchronous mode and<br>-  /// on the main thread in synchronous mode.<br>-  void parseFileAndPublishDiagnostics<wbr>(StringRef File);<br>-<br>-  /// Caches compilation databases loaded from directories(keys are directories).<br>-  llvm::StringMap<std::unique_p<wbr>tr<clang::tooling::Compilation<wbr>Database>><br>-      CompilationDatabases;<br>-<br>-  /// Clang objects.<br>-  /// A map from filenames to DocData structures that store ASTUnit and Fixits for<br>-  /// the files. The ASTUnits are used for generating diagnostics and fix-it-s<br>-  /// asynchronously by the worker thread and synchronously for code completion.<br>-  llvm::StringMap<DocData> DocDatas;<br>-  std::shared_ptr<clang::PCHCon<wbr>tainerOperations> PCHs;<br>-  /// A lock for access to the DocDatas, CompilationDatabases and PCHs.<br>-  std::mutex ClangObjectLock;<br>-<br>-  /// Stores latest versions of the tracked documents to discard outdated requests.<br>-  /// Guarded by RequestLock.<br>-  /// TODO(ibiryukov): the entries are neved deleted from this map.<br>-  llvm::StringMap<DocVersion> DocVersions;<br>-<br>-  /// A LIFO queue of requests. Note that requests are discarded if the `version`<br>-  /// field is not equal to the one stored inside DocVersions.<br>-  /// TODO(krasimir): code completion should always have priority over parsing<br>-  /// for diagnostics.<br>-  std::deque<ASTManagerRequest> RequestQueue;<br>-  /// Setting Done to true will make the worker thread terminate.<br>-  bool Done = false;<br>-  /// Condition variable to wake up the worker thread.<br>-  std::condition_variable ClangRequestCV;<br>-  /// Lock for accesses to RequestQueue, DocVersions and Done.<br>-  std::mutex RequestLock;<br>-<br>-  /// We run parsing on a separate thread. This thread looks into RequestQueue to<br>-  /// find requests to handle and terminates when Done is set to true.<br>-  std::thread ClangWorker;<br>-};<br>-<br>-} // namespace clangd<br>-} // namespace clang<br>-<br>-#endif<br><br>Modified: clang-tools-extra/trunk/clangd<wbr>/CMakeLists.txt<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CMakeLists.txt?rev=303067&r1=303066&r2=303067&view=diff" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/CMakeLists.txt?rev=<wbr>303067&r1=303066&r2=303067&<wbr>view=diff</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/CMakeLists.txt (original)<br>+++ clang-tools-extra/trunk/clangd<wbr>/CMakeLists.txt Mon May 15 09:17:35 2017<br>@@ -1,6 +1,11 @@<br> add_clang_executable(clangd<br>-  ASTManager.cpp<br>+  ClangdLSPServer.cpp<br>   ClangdMain.cpp<br>+  ClangdServer.cpp<br>+  ClangdUnit.cpp<br>+  ClangdUnitStore.cpp<br>+  DraftStore.cpp<br>+  GlobalCompilationDatabase.cpp<br>   JSONRPCDispatcher.cpp<br>   Protocol.cpp<br>   ProtocolHandlers.cpp<br><br>Added: clang-tools-extra/trunk/clangd<wbr>/ClangdLSPServer.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=303067&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ClangdLSPServer.cpp?<wbr>rev=303067&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ClangdLSPServer.cpp (added)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ClangdLSPServer.cpp Mon May 15 09:17:35 2017<br>@@ -0,0 +1,100 @@<br>+//===--- ClangdLSPServer.cpp - LSP server ------------------------*- C++-*-===//<br>+//<br>+//                     The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>+// License. See LICENSE.TXT for details.<br>+//<br>+//===------------------------<wbr>------------------------------<wbr>---------------===//<br>+<br>+#include "ClangdLSPServer.h"<br>+#include "JSONRPCDispatcher.h"<br>+<br>+using namespace clang::clangd;<br>+using namespace clang;<br>+<br>+class ClangdLSPServer::LSPDiagnostic<wbr>sConsumer : public DiagnosticsConsumer {<br>+public:<br>+  LSPDiagnosticsConsumer(Clangd<wbr>LSPServer &Server) : Server(Server) {}<br>+<br>+  virtual void onDiagnosticsReady(PathRef File,<br>+                               <wbr>   std::vector<DiagWithFixIts> Diagnostics) {<br>+    Server.consumeDiagnostics(F<wbr>ile, Diagnostics);<br>+  }<br>+<br>+private:<br>+  ClangdLSPServer &Server;<br>+};<br>+<br>+ClangdLSPServer::ClangdLSPSer<wbr>ver(JSONOutput &Out, bool RunSynchronously)<br>+    : Out(Out),<br>+      Server(llvm::make_unique<<wbr>DirectoryBasedGlobalCompilatio<wbr>nDatabase>(),<br>+             llvm::make_unique<<wbr>LSPDiagnosticsConsumer>(*this)<wbr>,<br>+             RunSynchronously) {}<br>+<br>+void ClangdLSPServer::openDocument(<wbr>StringRef File, StringRef Contents) {<br>+  Server.addDocument(File, Contents);<br>+}<br>+<br>+void ClangdLSPServer::closeDocument<wbr>(StringRef File) {<br>+  Server.removeDocument(File);<br>+}<br>+<br>+std::vector<CompletionItem> ClangdLSPServer::codeComplete(<wbr>PathRef File,<br>+                               <wbr>                           Pos<wbr>ition Pos) {<br>+  return Server.codeComplete(File, Pos);<br>+}<br>+<br>+std::vector<clang::tooling::R<wbr>eplacement><br>+ClangdLSPServer::getFixIts(St<wbr>ringRef File, const clangd::Diagnostic &D) {<br>+  std::lock_guard<std::mutex> Lock(FixItsMutex);<br>+  auto DiagToFixItsIter = FixItsMap.find(File);<br>+  if (DiagToFixItsIter == FixItsMap.end())<br>+    return {};<br>+<br>+  const auto &DiagToFixItsMap = DiagToFixItsIter->second;<br>+  auto FixItsIter = DiagToFixItsMap.find(D);<br>+  if (FixItsIter == DiagToFixItsMap.end())<br>+    return {};<br>+<br>+  return FixItsIter->second;<br>+}<br>+<br>+std::string ClangdLSPServer::getDocument(P<wbr>athRef File) {<br>+  return Server.getDocument(File);<br>+}<br>+<br>+void ClangdLSPServer::consumeDiagno<wbr>stics(<br>+    PathRef File, std::vector<DiagWithFixIts> Diagnostics) {<br>+  std::string DiagnosticsJSON;<br>+<br>+  DiagnosticToReplacementMap LocalFixIts; // Temporary storage<br>+  for (auto &DiagWithFixes : Diagnostics) {<br>+    auto Diag = DiagWithFixes.Diag;<br>+    DiagnosticsJSON +=<br>+        R"({"range":)" + Range::unparse(Diag.range) +<br>+        R"(,"severity":)" + std::to_string(Diag.severity) +<br>+        R"(,"message":")" + llvm::yaml::escape(Diag.messag<wbr>e) +<br>+        R"("},)";<br>+<br>+    // We convert to Replacements to become independent of the SourceManager.<br>+    auto &FixItsForDiagnostic = LocalFixIts[Diag];<br>+    std::copy(DiagWithFixes.Fix<wbr>Its.begin(), DiagWithFixes.FixIts.end(),<br>+              std::back_inserte<wbr>r(FixItsForDiagnostic));<br>+  }<br>+<br>+  // Cache FixIts<br>+  {<br>+    // FIXME(ibiryukov): should be deleted when documents are removed<br>+    std::lock_guard<std::mutex> Lock(FixItsMutex);<br>+    FixItsMap[File] = LocalFixIts;<br>+  }<br>+<br>+  // Publish diagnostics.<br>+  if (!DiagnosticsJSON.empty())<br>+    DiagnosticsJSON.pop_back(); // Drop trailing comma.<br>+  Out.writeMessage(<br>+      R"({"jsonrpc":"2.0","meth<wbr>od":"textDocument/publishDiagn<wbr>ostics","params":{"uri":")" +<br>+      URI::fromFile(File).uri + R"(","diagnostics":[)" + DiagnosticsJSON +<br>+      R"(]}})");<br>+}<br><br>Added: clang-tools-extra/trunk/clangd<wbr>/ClangdLSPServer.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.h?rev=303067&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ClangdLSPServer.h?rev=<wbr>303067&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ClangdLSPServer.h (added)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ClangdLSPServer.h Mon May 15 09:17:35 2017<br>@@ -0,0 +1,79 @@<br>+//===--- ClangdLSPServer.h - LSP server --------------------------*- C++-*-===//<br>+//<br>+//                     The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>+// License. See LICENSE.TXT for details.<br>+//<br>+//===------------------------<wbr>------------------------------<wbr>---------------===//<br>+<br>+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>CLANGDLSPSERVER_H<br>+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>CLANGDLSPSERVER_H<br>+<br>+#include "ClangdServer.h"<br>+#include "Path.h"<br>+#include "Protocol.h"<br>+#include "clang/Tooling/Core/Replacemen<wbr>t.h"<br>+<br>+namespace clang {<br>+namespace clangd {<br>+<br>+class JSONOutput;<br>+<br>+/// This class serves as an intermediate layer of LSP server implementation,<br>+/// glueing the JSON LSP protocol layer and ClangdServer together. It doesn't<br>+/// directly handle input from LSP client.<br>+/// Most methods are synchronous and return their result directly, but<br>+/// diagnostics are provided asynchronously when ready via<br>+/// JSONOutput::writeMessage.<br>+class ClangdLSPServer {<br>+public:<br>+  ClangdLSPServer(JSONOutput &Out, bool RunSynchronously);<br>+<br>+  /// Update the document text for \p File with \p Contents, schedule update of<br>+  /// diagnostics. Out.writeMessage will called to push diagnostics to LSP<br>+  /// client asynchronously when they are ready.<br>+  void openDocument(PathRef File, StringRef Contents);<br>+  /// Stop tracking the document for \p File.<br>+  void closeDocument(PathRef File);<br>+<br>+  /// Run code completion synchronously.<br>+  std::vector<CompletionItem> codeComplete(PathRef File, Position Pos);<br>+<br>+  /// Get the fixes associated with a certain diagnostic in a specified file as<br>+  /// replacements.<br>+  ///<br>+  /// This function is thread-safe. It returns a copy to avoid handing out<br>+  /// references to unguarded data.<br>+  std::vector<clang::tooling::R<wbr>eplacement><br>+  getFixIts(StringRef File, const clangd::Diagnostic &D);<br>+<br>+  /// Get the current document contents stored for \p File.<br>+  /// FIXME(ibiryukov): This function is here to allow implementation of<br>+  /// formatCode from ProtocolHandlers.cpp. We should move formatCode to<br>+  /// ClangdServer class and remove this function from public interface.<br>+  std::string getDocument(PathRef File);<br>+<br>+private:<br>+  class LSPDiagnosticsConsumer;<br>+<br>+  /// Function that will be called on a separate thread when diagnostics are<br>+  /// ready. Sends the Dianostics to LSP client via Out.writeMessage and caches<br>+  /// corresponding fixits in the FixItsMap.<br>+  void consumeDiagnostics(PathRef File,<br>+                          std::<wbr>vector<DiagWithFixIts> Diagnostics);<br>+<br>+  JSONOutput &Out;<br>+  ClangdServer Server;<br>+<br>+  std::mutex FixItsMutex;<br>+  typedef std::map<clangd::Diagnostic, std::vector<clang::tooling::Re<wbr>placement>><br>+      DiagnosticToReplacementMa<wbr>p;<br>+  /// Caches FixIts per file and diagnostics<br>+  llvm::StringMap<DiagnosticToR<wbr>eplacementMap> FixItsMap;<br>+};<br>+<br>+} // namespace clangd<br>+} // namespace clang<br>+<br>+#endif<br><br>Modified: clang-tools-extra/trunk/clangd<wbr>/ClangdMain.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdMain.cpp?rev=303067&r1=303066&r2=303067&view=diff" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ClangdMain.cpp?rev=<wbr>303067&r1=303066&r2=303067&<wbr>view=diff</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ClangdMain.cpp (original)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ClangdMain.cpp Mon May 15 09:17:35 2017<br>@@ -7,15 +7,19 @@<br> //<br> //===-------------------------<wbr>------------------------------<wbr>---------------===//<br><br>-#include "ASTManager.h"<br>-#include "DocumentStore.h"<br> #include "JSONRPCDispatcher.h"<br>+#include "ClangdLSPServer.h"<br>+#include "Protocol.h"<br> #include "ProtocolHandlers.h"<br> #include "llvm/Support/CommandLine.h"<br> #include "llvm/Support/FileSystem.h"<br> #include "llvm/Support/Program.h"<br>+<br> #include <iostream><br>+#include <memory><br> #include <string><br>+<br>+using namespace clang;<br> using namespace clang::clangd;<br><br> static llvm::cl::opt<bool><br>@@ -34,9 +38,7 @@ int main(int argc, char *argv[]) {<br><br>   // Set up a document store and intialize all the method handlers for JSONRPC<br>   // dispatching.<br>-  DocumentStore Store;<br>-  ASTManager AST(Out, Store, RunSynchronously);<br>-  Store.addListener(&AST);<br>+  ClangdLSPServer LSPServer(Out, RunSynchronously);<br>   JSONRPCDispatcher Dispatcher(llvm::make_unique<H<wbr>andler>(Out));<br>   Dispatcher.registerHandler("<wbr>initialize",<br>                              l<wbr>lvm::make_unique<InitializeHan<wbr>dler>(Out));<br>@@ -45,26 +47,26 @@ int main(int argc, char *argv[]) {<br>   Dispatcher.registerHandler("<wbr>shutdown", std::move(ShutdownPtr));<br>   Dispatcher.registerHandler(<br>       "textDocument/didOpen",<br>-      llvm::make_unique<TextDoc<wbr>umentDidOpenHandler>(Out, Store));<br>+      llvm::make_unique<TextDoc<wbr>umentDidOpenHandler>(Out, LSPServer));<br>   Dispatcher.registerHandler(<br>       "textDocument/didClose",<br>-      llvm::make_unique<TextDoc<wbr>umentDidCloseHandler>(Out, Store));<br>+      llvm::make_unique<TextDoc<wbr>umentDidCloseHandler>(Out, LSPServer));<br>   Dispatcher.registerHandler(<br>       "textDocument/didChange"<wbr>,<br>-      llvm::make_unique<TextDoc<wbr>umentDidChangeHandler>(Out, Store));<br>+      llvm::make_unique<TextDoc<wbr>umentDidChangeHandler>(Out, LSPServer));<br>   Dispatcher.registerHandler(<br>       "textDocument/rangeForma<wbr>tting",<br>-      llvm::make_unique<TextDoc<wbr>umentRangeFormattingHandler>(<wbr>Out, Store));<br>+      llvm::make_unique<TextDoc<wbr>umentRangeFormattingHandler>(<wbr>Out, LSPServer));<br>   Dispatcher.registerHandler(<br>       "textDocument/onTypeForm<wbr>atting",<br>-      llvm::make_unique<TextDoc<wbr>umentOnTypeFormattingHandler>(<wbr>Out, Store));<br>+      llvm::make_unique<TextDoc<wbr>umentOnTypeFormattingHandler>(<wbr>Out, LSPServer));<br>   Dispatcher.registerHandler(<br>       "textDocument/formatting<wbr>",<br>-      llvm::make_unique<TextDoc<wbr>umentFormattingHandler>(Out, Store));<br>+      llvm::make_unique<TextDoc<wbr>umentFormattingHandler>(Out, LSPServer));<br>   Dispatcher.registerHandler("<wbr>textDocument/codeAction",<br>-                             ll<wbr>vm::make_unique<CodeActionHand<wbr>ler>(Out, AST));<br>+                             ll<wbr>vm::make_unique<CodeActionHand<wbr>ler>(Out, LSPServer));<br>   Dispatcher.registerHandler("<wbr>textDocument/completion",<br>-                             ll<wbr>vm::make_unique<CompletionHand<wbr>ler>(Out, AST));<br>+                             ll<wbr>vm::make_unique<CompletionHand<wbr>ler>(Out, LSPServer));<br><br>   while (std::cin.good()) {<br>     // A Language Server Protocol message starts with a HTTP header, delimited<br><br>Copied: clang-tools-extra/trunk/clangd<wbr>/ClangdServer.cpp (from r303060, clang-tools-extra/trunk/clangd<wbr>/ASTManager.cpp)<br>URL: <a href="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" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ClangdServer.cpp?p2=<wbr>clang-tools-extra/trunk/clangd<wbr>/ClangdServer.cpp&p1=clang-<wbr>tools-extra/trunk/clangd/<wbr>ASTManager.cpp&r1=303060&r2=<wbr>303067&rev=303067&view=diff</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ASTManager.cpp (original)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ClangdServer.cpp Mon May 15 09:17:35 2017<br>@@ -1,440 +1,149 @@<br>-//===--- ASTManager.cpp - Clang AST manager ------------------------------<wbr>-===//<br>+//===--- ClangdServer.cpp - Main clangd server code --------------*- C++-*-===//<br> //<br> //                     The LLVM Compiler Infrastructure<br> //<br> // This file is distributed under the University of Illinois Open Source<br> // License. See LICENSE.TXT for details.<br> //<br>-//===------------------------<wbr>------------------------------<wbr>----------------===//<br>+//===------------------------<wbr>------------------------------<wbr>-------------===//<br><br>-#include "ASTManager.h"<br>-#include "JSONRPCDispatcher.h"<br>-#include "Protocol.h"<br>+#include "ClangdServer.h"<br> #include "clang/Frontend/ASTUnit.h"<br> #include "clang/Frontend/CompilerInstan<wbr>ce.h"<br>+#include "clang/Frontend/CompilerInvoca<wbr>tion.h"<br> #include "clang/Tooling/CompilationData<wbr>base.h"<br>-#include "llvm/Support/Format.h"<br>-#include "llvm/Support/Path.h"<br>-#include <mutex><br>-#include <thread><br>-using namespace clang;<br>-using namespace clangd;<br>+#include "llvm/Support/FileSystem.h"<br><br>-void DocData::setAST(std::unique_pt<wbr>r<ASTUnit> AST) {<br>-  this->AST = std::move(AST);<br>-}<br>-<br>-ASTUnit *DocData::getAST() const { return AST.get(); }<br>-<br>-void DocData::cacheFixIts(Diagnosti<wbr>cToReplacementMap FixIts) {<br>-  this->FixIts = std::move(FixIts);<br>-}<br>+using namespace clang::clangd;<br><br>-std::vector<clang::tooling::R<wbr>eplacement><br>-DocData::getFixIts(const clangd::Diagnostic &D) const {<br>-  auto it = FixIts.find(D);<br>-  if (it != FixIts.end())<br>-    return it->second;<br>-  return {};<br>-}<br>-<br>-ASTManagerRequest::ASTManager<wbr>Request(ASTManagerRequestType Type,<br>-                               <wbr>      std::string File,<br>-                               <wbr>      DocVersion Version)<br>-    : Type(Type), File(File), Version(Version) {}<br>-<br>-/// Retrieve a copy of the contents of every file in the store, for feeding into<br>-/// ASTUnit.<br>-static std::vector<ASTUnit::RemappedF<wbr>ile><br>-getRemappedFiles(const DocumentStore &Docs) {<br>-  // FIXME: Use VFS instead. This would allow us to get rid of the chdir below.<br>-  std::vector<ASTUnit::Remapped<wbr>File> RemappedFiles;<br>-  for (const auto &P : Docs.getAllDocuments()) {<br>-    StringRef FileName = P.first;<br>-    RemappedFiles.push_back(AST<wbr>Unit::RemappedFile(<br>-        FileName,<br>-        llvm::MemoryBuffer::get<wbr>MemBufferCopy(P.second, FileName).release()));<br>-  }<br>-  return RemappedFiles;<br>-}<br>+WorkerRequest::WorkerRequest(<wbr>WorkerRequestKind Kind, Path File,<br>+                             Do<wbr>cVersion Version)<br>+    : Kind(Kind), File(File), Version(Version) {}<br><br>-/// Convert from clang diagnostic level to LSP severity.<br>-static int getSeverity(DiagnosticsEngine:<wbr>:Level L) {<br>-  switch (L) {<br>-  case DiagnosticsEngine::Remark:<br>-    return 4;<br>-  case DiagnosticsEngine::Note:<br>-    return 3;<br>-  case DiagnosticsEngine::Warning:<br>-    return 2;<br>-  case DiagnosticsEngine::Fatal:<br>-  case DiagnosticsEngine::Error:<br>-    return 1;<br>-  case DiagnosticsEngine::Ignored:<br>-    return 0;<br>-  }<br>-  llvm_unreachable("Unknown diagnostic level!");<br>-}<br>-<br>-static CompletionItemKind getKind(CXCursorKind K) {<br>-  switch (K) {<br>-  case CXCursor_MacroInstantiation:<br>-  case CXCursor_MacroDefinition:<br>-    return CompletionItemKind::Text;<br>-  case CXCursor_CXXMethod:<br>-    return CompletionItemKind::Method;<br>-  case CXCursor_FunctionDecl:<br>-  case CXCursor_FunctionTemplate:<br>-    return CompletionItemKind::Function;<br>-  case CXCursor_Constructor:<br>-  case CXCursor_Destructor:<br>-    return CompletionItemKind::Constructo<wbr>r;<br>-  case CXCursor_FieldDecl:<br>-    return CompletionItemKind::Field;<br>-  case CXCursor_VarDecl:<br>-  case CXCursor_ParmDecl:<br>-    return CompletionItemKind::Variable;<br>-  case CXCursor_ClassDecl:<br>-  case CXCursor_StructDecl:<br>-  case CXCursor_UnionDecl:<br>-  case CXCursor_ClassTemplate:<br>-  case CXCursor_ClassTemplatePartialS<wbr>pecialization:<br>-    return CompletionItemKind::Class;<br>-  case CXCursor_Namespace:<br>-  case CXCursor_NamespaceAlias:<br>-  case CXCursor_NamespaceRef:<br>-    return CompletionItemKind::Module;<br>-  case CXCursor_EnumConstantDecl:<br>-    return CompletionItemKind::Value;<br>-  case CXCursor_EnumDecl:<br>-    return CompletionItemKind::Enum;<br>-  case CXCursor_TypeAliasDecl:<br>-  case CXCursor_TypeAliasTemplateDecl<wbr>:<br>-  case CXCursor_TypedefDecl:<br>-  case CXCursor_MemberRef:<br>-  case CXCursor_TypeRef:<br>-    return CompletionItemKind::Reference;<br>-  default:<br>-    return CompletionItemKind::Missing;<br>-  }<br>-}<br>-<br>-ASTManager::ASTManager(JSONOu<wbr>tput &Output, DocumentStore &Store,<br>-                       bool RunSynchronously)<br>-    : Output(Output), Store(Store), RunSynchronously(RunSynchronou<wbr>sly),<br>-      PCHs(std::make_shared<PCH<wbr>ContainerOperations>()),<br>-      ClangWorker([this]() { runWorker(); }) {}<br>-<br>-void ASTManager::runWorker() {<br>-  while (true) {<br>-    ASTManagerRequest Request;<br>-<br>-    // Pick request from the queue<br>-    {<br>-      std::unique_lock<std::mut<wbr>ex> Lock(RequestLock);<br>-      // Wait for more requests.<br>-      ClangRequestCV.wait(Lock,<br>-                          [this<wbr>] { return !RequestQueue.empty() || Done; });<br>-      if (Done)<br>-        return;<br>-      assert(!RequestQueue.empt<wbr>y() && "RequestQueue was empty");<br>-<br>-      Request = std::move(RequestQueue.back())<wbr>;<br>-      RequestQueue.pop_back();<br>-<br>-      // Skip outdated requests<br>-      if (Request.Version != DocVersions.find(Request.File)<wbr>->second) {<br>-        Output.log("Version for " + Twine(Request.File) +<br>-                   " in request is outdated, skipping request\n");<br>-        continue;<br>-      }<br>-    } // unlock RequestLock<br>-<br>-    handleRequest(Request.Type, Request.File);<br>-  }<br>-}<br>-<br>-void ASTManager::queueOrRun(ASTMana<wbr>gerRequestType RequestType, StringRef File) {<br>+ClangdScheduler::ClangdSchedu<wbr>ler(ClangdServer &Server, bool RunSynchronously)<br>+    : RunSynchronously(RunSynchronou<wbr>sly) {<br>   if (RunSynchronously) {<br>-    handleRequest(RequestType, File);<br>+    // Don't start the worker thread if we're running synchronously<br>     return;<br>   }<br><br>-  std::lock_guard<std::mutex> Guard(RequestLock);<br>-  // We increment the version of the added document immediately and schedule<br>-  // the requested operation to be run on a worker thread<br>-  DocVersion version = ++DocVersions[File];<br>-  RequestQueue.push_back(ASTMan<wbr>agerRequest(RequestType, File, version));<br>-  ClangRequestCV.notify_one();<br>-}<br>-<br>-void ASTManager::handleRequest(ASTM<wbr>anagerRequestType RequestType,<br>-                               <wbr>StringRef File) {<br>-  switch (RequestType) {<br>-  case ASTManagerRequestType::ParseAn<wbr>dPublishDiagnostics:<br>-    parseFileAndPublishDiagnost<wbr>ics(File);<br>-    break;<br>-  case ASTManagerRequestType::RemoveD<wbr>ocData: {<br>-    std::lock_guard<std::mutex> Lock(ClangObjectLock);<br>-    auto DocDataIt = DocDatas.find(File);<br>-    // We could get the remove request before parsing for the document is<br>-    // started, just do nothing in that case, parsing request will be discarded<br>-    // because it has a lower version value<br>-    if (DocDataIt == DocDatas.end())<br>-      return;<br>-    DocDatas.erase(DocDataIt);<br>-    break;<br>-  } // unlock ClangObjectLock<br>-  }<br>-}<br>-<br>-void ASTManager::parseFileAndPublis<wbr>hDiagnostics(StringRef File) {<br>-  std::unique_lock<std::mutex> ClangObjectLockGuard(ClangObje<wbr>ctLock);<br>-<br>-  auto &DocData = DocDatas[File];<br>-  ASTUnit *Unit = DocData.getAST();<br>-  if (!Unit) {<br>-    auto newAST = createASTUnitForFile(File, this->Store);<br>-    Unit = newAST.get();<br>-<br>-    DocData.setAST(std::move(ne<wbr>wAST));<br>-  } else {<br>-    // Do a reparse if this wasn't the first parse.<br>-    // FIXME: This might have the wrong working directory if it changed in the<br>-    // meantime.<br>-    Unit->Reparse(PCHs, getRemappedFiles(this->Store))<wbr>;<br>-  }<br>+  // Initialize Worker in ctor body, rather than init list to avoid potentially<br>+  // using not-yet-initialized members<br>+  Worker = std::thread([&Server, this]() {<br>+    while (true) {<br>+      WorkerRequest Request;<br>+<br>+      // Pick request from the queue<br>+      {<br>+        std::unique_lock<std::m<wbr>utex> Lock(Mutex);<br>+        // Wait for more requests.<br>+        RequestCV.wait(Lock, [this] { return !RequestQueue.empty() || Done; });<br>+        if (Done)<br>+          return;<br>+<br>+        assert(!RequestQueue.em<wbr>pty() && "RequestQueue was empty");<br>+<br>+        Request = std::move(RequestQueue.back())<wbr>;<br>+        RequestQueue.pop_back()<wbr>;<br>+<br>+        // Skip outdated requests<br>+        if (Request.Version != Server.DraftMgr.getVersion(Req<wbr>uest.File)) {<br>+          // FIXME(ibiryukov): Logging<br>+          // Output.log("Version for " + Twine(Request.File) +<br>+          //            " in request is outdated, skipping request\n");<br>+          continue;<br>+        }<br>+      } // unlock Mutex<br><br>-  if (!Unit)<br>-    return;<br>-<br>-  // Send the diagnotics to the editor.<br>-  // FIXME: If the diagnostic comes from a different file, do we want to<br>-  // show them all? Right now we drop everything not coming from the<br>-  // main file.<br>-  std::string Diagnostics;<br>-  DocData::DiagnosticToReplacem<wbr>entMap LocalFixIts; // Temporary storage<br>-  for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),<br>-                               <wbr>      DEnd = Unit->stored_diag_end();<br>-       D != DEnd; ++D) {<br>-    if (!D->getLocation().isValid() ||<br>-        !D->getLocation().getMa<wbr>nager().isInMainFile(D->getLoc<wbr>ation()))<br>-      continue;<br>-    Position P;<br>-    P.line = D->getLocation().getSpellingLi<wbr>neNumber() - 1;<br>-    P.character = D->getLocation().getSpellingCo<wbr>lumnNumber();<br>-    Range R = {P, P};<br>-    Diagnostics +=<br>-        R"({"range":)" + Range::unparse(R) +<br>-        R"(,"severity":)" + std::to_string(getSeverity(D-><wbr>getLevel())) +<br>-        R"(,"message":")" + llvm::yaml::escape(D->getMessa<wbr>ge()) +<br>-        R"("},)";<br>-<br>-    // We convert to Replacements to become independent of the SourceManager.<br>-    clangd::Diagnostic Diag = {R, getSeverity(D->getLevel()), D->getMessage()};<br>-    auto &FixItsForDiagnostic = LocalFixIts[Diag];<br>-    for (const FixItHint &Fix : D->getFixIts()) {<br>-      FixItsForDiagnostic.push_<wbr>back(clang::tooling::Replaceme<wbr>nt(<br>-          Unit->getSourceManage<wbr>r(), Fix.RemoveRange, Fix.CodeToInsert));<br>+      Server.handleRequest(std:<wbr>:move(Request));<br>     }<br>-  }<br>-<br>-  // Put FixIts into place.<br>-  DocData.cacheFixIts(std::move<wbr>(LocalFixIts));<br>-<br>-  ClangObjectLockGuard.unlock()<wbr>;<br>-  // No accesses to clang objects are allowed after this point.<br>-<br>-  // Publish diagnostics.<br>-  if (!Diagnostics.empty())<br>-    Diagnostics.pop_back(); // Drop trailing comma.<br>-  Output.writeMessage(<br>-      R"({"jsonrpc":"2.0","meth<wbr>od":"textDocument/publishDiagn<wbr>ostics","params":{"uri":")" +<br>-      URI::fromFile(File).uri + R"(","diagnostics":[)" + Diagnostics + R"(]}})");<br>+  });<br> }<br><br>-ASTManager::~ASTManager() {<br>+ClangdScheduler::~ClangdSched<wbr>uler() {<br>+  if (RunSynchronously)<br>+    return; // no worker thread is running in that case<br>+<br>   {<br>-    std::lock_guard<std::mutex> Guard(RequestLock);<br>-    // Wake up the clang worker thread, then exit.<br>+    std::lock_guard<std::mutex> Lock(Mutex);<br>+    // Wake up the worker thread<br>     Done = true;<br>-    ClangRequestCV.notify_one()<wbr>;<br>-  } // unlock DocDataLock<br>-  ClangWorker.join();<br>-}<br>-<br>-void ASTManager::onDocumentAdd(Stri<wbr>ngRef File) {<br>-  queueOrRun(ASTManagerRequestT<wbr>ype::ParseAndPublishDiagnostic<wbr>s, File);<br>-}<br>-<br>-void ASTManager::onDocumentRemove(S<wbr>tringRef File) {<br>-  queueOrRun(ASTManagerRequestT<wbr>ype::RemoveDocData, File);<br>-}<br>-<br>-tooling::CompilationDatabase *<br>-ASTManager::getOrCreateCompil<wbr>ationDatabaseForFile(StringRef File) {<br>-  namespace path = llvm::sys::path;<br>-<br>-  assert((path::is_absolute(Fil<wbr>e, path::Style::posix) ||<br>-          path::is_absolute(Fil<wbr>e, path::Style::windows)) &&<br>-         "path must be absolute");<br>-<br>-  for (auto Path = path::parent_path(File); !Path.empty();<br>-       Path = path::parent_path(Path)) {<br>-<br>-    auto CachedIt = CompilationDatabases.find(Path<wbr>);<br>-    if (CachedIt != CompilationDatabases.end())<br>-      return CachedIt->second.get();<br>-    std::string Error;<br>-    auto CDB = tooling::CompilationDatabase::<wbr>loadFromDirectory(Path, Error);<br>-    if (!CDB) {<br>-      if (!Error.empty()) {<br>-        Output.log("Error when trying to load compilation database from " +<br>-                   Twine(Path) + ": " + Twine(Error) + "\n");<br>-      }<br>-      continue;<br>-    }<br>-<br>-    // TODO(ibiryukov): Invalidate cached compilation databases on changes<br>-    auto result = CDB.get();<br>-    CompilationDatabases.insert<wbr>(std::make_pair(Path, std::move(CDB)));<br>-    return result;<br>-  }<br>-<br>-  Output.log("Failed to find compilation database for " + Twine(File) + "\n");<br>-  return nullptr;<br>+    RequestCV.notify_one();<br>+  } // unlock Mutex<br>+  Worker.join();<br> }<br><br>-std::unique_ptr<clang::ASTUni<wbr>t><br>-ASTManager::createASTUnitForF<wbr>ile(StringRef File, const DocumentStore &Docs) {<br>-  tooling::CompilationDatabase *CDB =<br>-      getOrCreateCompilationDat<wbr>abaseForFile(File);<br>-<br>-  std::vector<tooling::CompileC<wbr>ommand> Commands;<br>-<br>-  if (CDB) {<br>-    Commands = CDB->getCompileCommands(File);<br>-    // chdir. This is thread hostile.<br>-    if (!Commands.empty())<br>-      llvm::sys::fs::set_curren<wbr>t_path(Commands.front().Direct<wbr>ory);<br>-  }<br>-  if (Commands.empty()) {<br>-    // Add a fake command line if we know nothing.<br>-    Commands.push_back(tooling:<wbr>:CompileCommand(<br>-        llvm::sys::path::parent<wbr>_path(File), llvm::sys::path::filename(File<wbr>),<br>-        {"clang", "-fsyntax-only", File.str()}, ""));<br>+void ClangdScheduler::enqueue(Clang<wbr>dServer &Server, WorkerRequest Request) {<br>+  if (RunSynchronously) {<br>+    Server.handleRequest(Reques<wbr>t);<br>+    return;<br>   }<br><br>-  // Inject the resource dir.<br>-  // FIXME: Don't overwrite it if it's already there.<br>-  static int Dummy; // Just an address in this process.<br>-  std::string ResourceDir =<br>-      CompilerInvocation::GetRe<wbr>sourcesPath("clangd", (void *)&Dummy);<br>-  Commands.front().CommandLine.<wbr>push_back("-resource-dir=" + ResourceDir);<br>-<br>-  IntrusiveRefCntPtr<Diagnostic<wbr>sEngine> Diags =<br>-      CompilerInstance::createD<wbr>iagnostics(new DiagnosticOptions);<br>-<br>-  std::vector<const char *> ArgStrs;<br>-  for (const auto &S : Commands.front().CommandLine)<br>-    ArgStrs.push_back(S.c_str()<wbr>);<br>-<br>-  auto ArgP = &*ArgStrs.begin();<br>-  return std::unique_ptr<clang::ASTUnit<wbr>>(ASTUnit::LoadFromCommandLine<wbr>(<br>-      ArgP, ArgP + ArgStrs.size(), PCHs, Diags, ResourceDir,<br>-      /*OnlyLocalDecls=*/false, /*CaptureDiagnostics=*/true,<br>-      getRemappedFiles(Docs),<br>-      /*RemappedFilesKeepOrigin<wbr>alName=*/true,<br>-      /*PrecompilePreambleAfter<wbr>NParses=*/1, /*TUKind=*/TU_Complete,<br>-      /*CacheCodeCompletionResu<wbr>lts=*/true,<br>-      /*IncludeBriefCommentsInC<wbr>odeCompletion=*/true,<br>-      /*AllowPCHWithCompilerErr<wbr>ors=*/true));<br>+  std::lock_guard<std::mutex> Lock(Mutex);<br>+  RequestQueue.push_back(Reques<wbr>t);<br>+  RequestCV.notify_one();<br> }<br><br>-std::vector<clang::tooling::R<wbr>eplacement><br>-ASTManager::getFixIts(StringR<wbr>ef File, const clangd::Diagnostic &D) {<br>-  // TODO(ibiryukov): the FixIts should be available immediately<br>-  // even when parsing is being run on a worker thread<br>-  std::lock_guard<std::mutex> Guard(ClangObjectLock);<br>-  return DocDatas[File].getFixIts(D);<br>-}<br>+ClangdServer::ClangdServer(st<wbr>d::unique_ptr<GlobalCompilatio<wbr>nDatabase> CDB,<br>+                           std:<wbr>:unique_ptr<DiagnosticsConsume<wbr>r> DiagConsumer,<br>+                           bool RunSynchronously)<br>+    : CDB(std::move(CDB)), DiagConsumer(std::move(DiagCon<wbr>sumer)),<br>+      PCHs(std::make_shared<PCH<wbr>ContainerOperations>()),<br>+      WorkScheduler(*this, RunSynchronously) {}<br><br>-namespace {<br>-class CompletionItemsCollector : public CodeCompleteConsumer {<br>-  std::vector<CompletionItem> *Items;<br>-  std::shared_ptr<clang::Global<wbr>CodeCompletionAllocator> Allocator;<br>-  CodeCompletionTUInfo CCTUInfo;<br>-<br>-public:<br>-  CompletionItemsCollector(std:<wbr>:vector<CompletionItem> *Items,<br>-                           cons<wbr>t CodeCompleteOptions &CodeCompleteOpts)<br>-      : CodeCompleteConsumer(CodeCompl<wbr>eteOpts, /*OutputIsBinary=*/false),<br>-        Items(Items),<br>-        Allocator(std::make_sha<wbr>red<clang::GlobalCodeCompletio<wbr>nAllocator>()),<br>-        CCTUInfo(Allocator) {}<br>-<br>-  void ProcessCodeCompleteResults(Sem<wbr>a &S, CodeCompletionContext Context,<br>-                               <wbr>   CodeCompletionResult *Results,<br>-                               <wbr>   unsigned NumResults) override {<br>-    for (unsigned I = 0; I != NumResults; ++I) {<br>-      CodeCompletionResult &Result = Results[I];<br>-      CodeCompletionString *CCS = Result.CreateCodeCompletionStr<wbr>ing(<br>-          S, Context, *Allocator, CCTUInfo,<br>-          CodeCompleteOpts.Incl<wbr>udeBriefComments);<br>-      if (CCS) {<br>-        CompletionItem Item;<br>-        assert(CCS->getTypedTex<wbr>t());<br>-        Item.label = CCS->getTypedText();<br>-        Item.kind = getKind(Result.CursorKind);<br>-        if (CCS->getBriefComment())<br>-          Item.documentation = CCS->getBriefComment();<br>-        Items->push_back(std::m<wbr>ove(Item));<br>-      }<br>-    }<br>+void ClangdServer::addDocument(Path<wbr>Ref File, StringRef Contents) {<br>+  DocVersion NewVersion = DraftMgr.updateDraft(File, Contents);<br>+  WorkScheduler.enqueue(<br>+      *this, WorkerRequest(WorkerRequestKin<wbr>d::ParseAndPublishDiagnostics, File,<br>+                           NewV<wbr>ersion));<br>+}<br>+<br>+void ClangdServer::removeDocument(P<wbr>athRef File) {<br>+  auto NewVersion = DraftMgr.removeDraft(File);<br>+  WorkScheduler.enqueue(<br>+      *this, WorkerRequest(WorkerRequestKin<wbr>d::RemoveDocData, File, NewVersion));<br>+}<br>+<br>+std::vector<CompletionItem> ClangdServer::codeComplete(Pat<wbr>hRef File,<br>+                               <wbr>                        Positi<wbr>on Pos) {<br>+  auto FileContents = DraftMgr.getDraft(File);<br>+  assert(FileContents.Draft && "codeComplete is called for non-added document");<br>+<br>+  std::vector<CompletionItem> Result;<br>+  Units.runOnUnitWithoutReparse<wbr>(<br>+      File, *FileContents.Draft, *CDB, PCHs, [&](ClangdUnit &Unit) {<br>+        Result = Unit.codeComplete(*FileContent<wbr>s.Draft, Pos);<br>+      });<br>+  return Result;<br>+}<br>+<br>+std::string ClangdServer::getDocument(Path<wbr>Ref File) {<br>+  auto draft = DraftMgr.getDraft(File);<br>+  assert(draft.Draft && "File is not tracked, cannot get contents");<br>+  return *draft.Draft;<br>+}<br>+<br>+void ClangdServer::handleRequest(Wo<wbr>rkerRequest Request) {<br>+  switch (Request.Kind) {<br>+  case WorkerRequestKind::ParseAndPub<wbr>lishDiagnostics: {<br>+    auto FileContents = DraftMgr.getDraft(Request.File<wbr>);<br>+    if (FileContents.Version != Request.Version)<br>+      return; // This request is outdated, do nothing<br>+<br>+    assert(FileContents.Draft &&<br>+           "No contents inside a file that was scheduled for reparse");<br>+    Units.runOnUnit(Request.Fil<wbr>e, *FileContents.Draft, *CDB, PCHs,<br>+                    [&](ClangdU<wbr>nit const &Unit) {<br>+                      DiagConsu<wbr>mer->onDiagnosticsReady(<br>+                          Reque<wbr>st.File, Unit.getLocalDiagnostics());<br>+                    });<br>+    break;<br>   }<br>+  case WorkerRequestKind::RemoveDocDa<wbr>ta:<br>+    if (Request.Version != DraftMgr.getVersion(Request.Fi<wbr>le))<br>+      return; // This request is outdated, do nothing<br><br>-  GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }<br>-<br>-  CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }<br>-};<br>-<br>-} // namespace<br>-<br>-std::vector<CompletionItem><br>-ASTManager::codeComplete(Stri<wbr>ngRef File, unsigned Line, unsigned Column) {<br>-  CodeCompleteOptions CCO;<br>-  CCO.IncludeBriefComments = 1;<br>-  // This is where code completion stores dirty buffers. Need to free after<br>-  // completion.<br>-  SmallVector<const llvm::MemoryBuffer *, 4> OwnedBuffers;<br>-  SmallVector<StoredDiagnostic, 4> StoredDiagnostics;<br>-  IntrusiveRefCntPtr<Diagnostic<wbr>sEngine> DiagEngine(<br>-      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions));<br>-  std::vector<CompletionItem> Items;<br>-  CompletionItemsCollector Collector(&Items, CCO);<br>-<br>-  std::lock_guard<std::mutex> Guard(ClangObjectLock);<br>-  auto &DocData = DocDatas[File];<br>-  auto Unit = DocData.getAST();<br>-  if (!Unit) {<br>-    auto newAST = createASTUnitForFile(File, this->Store);<br>-    Unit = newAST.get();<br>-    DocData.setAST(std::move(ne<wbr>wAST));<br>+    Units.removeUnitIfPresent(R<wbr>equest.File);<br>+    break;<br>   }<br>-  if (!Unit)<br>-    return {};<br>-  IntrusiveRefCntPtr<SourceMana<wbr>ger> SourceMgr(<br>-      new SourceManager(*DiagEngine, Unit->getFileManager()));<br>-  // CodeComplete seems to require fresh LangOptions.<br>-  LangOptions LangOpts = Unit->getLangOpts();<br>-  // The language server protocol uses zero-based line and column numbers.<br>-  // The clang code completion uses one-based numbers.<br>-  Unit->CodeComplete(File, Line + 1, Column + 1, getRemappedFiles(this->Store),<br>-                     CCO.Includ<wbr>eMacros, CCO.IncludeCodePatterns,<br>-                     CCO.Includ<wbr>eBriefComments, Collector, PCHs, *DiagEngine,<br>-                     LangOpts, *SourceMgr, Unit->getFileManager(),<br>-                     StoredDiag<wbr>nostics, OwnedBuffers);<br>-  for (const llvm::MemoryBuffer *Buffer : OwnedBuffers)<br>-    delete Buffer;<br>-  return Items;<br> }<br><br>Copied: clang-tools-extra/trunk/clangd<wbr>/ClangdServer.h (from r303063, clang-tools-extra/trunk/clangd<wbr>/ASTManager.h)<br>URL: <a href="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" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ClangdServer.h?p2=<wbr>clang-tools-extra/trunk/clangd<wbr>/ClangdServer.h&p1=clang-<wbr>tools-extra/trunk/clangd/<wbr>ASTManager.h&r1=303063&r2=<wbr>303067&rev=303067&view=diff</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ASTManager.h (original)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ClangdServer.h Mon May 15 09:17:35 2017<br>@@ -1,4 +1,4 @@<br>-//===--- ASTManager.h - Clang AST manager -----------------------*- C++ -*-===//<br>+//===--- ClangdServer.h - Main clangd server code ----------------*- C++-*-===//<br> //<br> //                     The LLVM Compiler Infrastructure<br> //<br>@@ -7,153 +7,129 @@<br> //<br> //===-------------------------<wbr>------------------------------<wbr>---------------===//<br><br>-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>ASTMANAGER_H<br>-#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>ASTMANAGER_H<br>+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>CLANGDSERVER_H<br>+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>CLANGDSERVER_H<br><br>-#include "DocumentStore.h"<br>-#include "JSONRPCDispatcher.h"<br>-#include "Protocol.h"<br>+#include "ClangdUnitStore.h"<br>+#include "DraftStore.h"<br>+#include "GlobalCompilationDatabase.h"<br>+#include "clang/Frontend/ASTUnit.h"<br>+#include "clang/Tooling/CompilationData<wbr>base.h"<br> #include "clang/Tooling/Core/Replacemen<wbr>t.h"<br> #include "llvm/ADT/IntrusiveRefCntPtr.h<wbr>"<br>+#include "llvm/ADT/Optional.h"<br>+#include "llvm/ADT/StringRef.h"<br>+<br>+#include "ClangdUnit.h"<br>+#include "Protocol.h"<br>+<br> #include <condition_variable><br>-#include <deque><br>+#include <mutex><br>+#include <string><br> #include <thread><br>+#include <utility><br><br> namespace clang {<br>-class ASTUnit;<br>-class DiagnosticsEngine;<br> class PCHContainerOperations;<br>-namespace tooling {<br>-class CompilationDatabase;<br>-} // namespace tooling<br><br> namespace clangd {<br><br>-/// Using 'unsigned' here to avoid undefined behaviour on overflow.<br>-typedef unsigned DocVersion;<br>-<br>-/// Stores ASTUnit and FixIts map for an opened document.<br>-class DocData {<br>-public:<br>-  typedef std::map<clangd::Diagnostic, std::vector<clang::tooling::Re<wbr>placement>><br>-      DiagnosticToReplacementMa<wbr>p;<br>-<br>+class DiagnosticsConsumer {<br> public:<br>-  void setAST(std::unique_ptr<ASTUnit<wbr>> AST);<br>-  ASTUnit *getAST() const;<br>-<br>-  void cacheFixIts(DiagnosticToReplac<wbr>ementMap FixIts);<br>-  std::vector<clang::tooling::R<wbr>eplacement><br>-  getFixIts(const clangd::Diagnostic &D) const;<br>+  virtual ~DiagnosticsConsumer() = default;<br><br>-private:<br>-  std::unique_ptr<ASTUnit> AST;<br>-  DiagnosticToReplacementMap FixIts;<br>+  /// Called by ClangdServer when \p Diagnostics for \p File are ready.<br>+  virtual void onDiagnosticsReady(PathRef File,<br>+                               <wbr>   std::vector<DiagWithFixIts> Diagnostics) = 0;<br> };<br><br>-enum class ASTManagerRequestType { ParseAndPublishDiagnostics, RemoveDocData };<br>+enum class WorkerRequestKind { ParseAndPublishDiagnostics, RemoveDocData };<br><br> /// A request to the worker thread<br>-class ASTManagerRequest {<br>+class WorkerRequest {<br> public:<br>-  ASTManagerRequest() = default;<br>-  ASTManagerRequest(ASTManagerR<wbr>equestType Type, std::string File,<br>-                    DocVersion Version);<br>+  WorkerRequest() = default;<br>+  WorkerRequest(WorkerRequestKi<wbr>nd Kind, Path File, DocVersion Version);<br><br>-  ASTManagerRequestType Type;<br>-  std::string File;<br>+  WorkerRequestKind Kind;<br>+  Path File;<br>   DocVersion Version;<br> };<br><br>-class ASTManager : public DocumentStoreListener {<br>-public:<br>-  ASTManager(JSONOutput &Output, DocumentStore &Store, bool RunSynchronously);<br>-  ~ASTManager() override;<br>-<br>-  void onDocumentAdd(StringRef File) override;<br>-  void onDocumentRemove(StringRef File) override;<br>+class ClangdServer;<br><br>-  /// Get code completions at a specified \p Line and \p Column in \p File.<br>-  ///<br>-  /// This function is thread-safe and returns completion items that own the<br>-  /// data they contain.<br>-  std::vector<CompletionItem> codeComplete(StringRef File, unsigned Line,<br>-                               <wbr>            unsigned Column);<br>-<br>-  /// Get the fixes associated with a certain diagnostic in a specified file as<br>-  /// replacements.<br>-  ///<br>-  /// This function is thread-safe. It returns a copy to avoid handing out<br>-  /// references to unguarded data.<br>-  std::vector<clang::tooling::R<wbr>eplacement><br>-  getFixIts(StringRef File, const clangd::Diagnostic &D);<br>+/// Handles running WorkerRequests of ClangdServer on a separate threads.<br>+/// Currently runs only one worker thread.<br>+class ClangdScheduler {<br>+public:<br>+  ClangdScheduler(ClangdServer &Server, bool RunSynchronously);<br>+  ~ClangdScheduler();<br><br>-  DocumentStore &getStore() const { return Store; }<br>+  /// Enqueue WorkerRequest to be run on a worker thread<br>+  void enqueue(ClangdServer &Server, WorkerRequest Request);<br><br> private:<br>-  JSONOutput &Output;<br>-  DocumentStore &Store;<br>-<br>-  // Set to true if requests should block instead of being processed<br>-  // asynchronously.<br>   bool RunSynchronously;<br>-<br>-  /// Loads a compilation database for File. May return nullptr if it fails. The<br>-  /// database is cached for subsequent accesses.<br>-  clang::tooling::CompilationDa<wbr>tabase *<br>-  getOrCreateCompilationDatabas<wbr>eForFile(StringRef File);<br>-  // Creates a new ASTUnit for the document at File.<br>-  // FIXME: This calls chdir internally, which is thread unsafe.<br>-  std::unique_ptr<clang::ASTUni<wbr>t><br>-  createASTUnitForFile(StringRe<wbr>f File, const DocumentStore &Docs);<br>-<br>-  /// If RunSynchronously is false, queues the request to be run on the worker<br>-  /// thread.<br>-  /// If RunSynchronously is true, runs the request handler immediately on the<br>-  /// main thread.<br>-  void queueOrRun(ASTManagerRequestTy<wbr>pe RequestType, StringRef File);<br>-<br>-  void runWorker();<br>-  void handleRequest(ASTManagerReques<wbr>tType RequestType, StringRef File);<br>-<br>-  /// Parses files and publishes diagnostics.<br>-  /// This function is called on the worker thread in asynchronous mode and<br>-  /// on the main thread in synchronous mode.<br>-  void parseFileAndPublishDiagnostics<wbr>(StringRef File);<br>-<br>-  /// Caches compilation databases loaded from directories(keys are directories).<br>-  llvm::StringMap<std::unique_p<wbr>tr<clang::tooling::Compilation<wbr>Database>><br>-      CompilationDatabases;<br>-<br>-  /// Clang objects.<br>-  /// A map from filenames to DocData structures that store ASTUnit and Fixits for<br>-  /// the files. The ASTUnits are used for generating diagnostics and fix-it-s<br>-  /// asynchronously by the worker thread and synchronously for code completion.<br>-  llvm::StringMap<DocData> DocDatas;<br>-  std::shared_ptr<clang::PCHCon<wbr>tainerOperations> PCHs;<br>-  /// A lock for access to the DocDatas, CompilationDatabases and PCHs.<br>-  std::mutex ClangObjectLock;<br>-<br>-  /// Stores latest versions of the tracked documents to discard outdated requests.<br>-  /// Guarded by RequestLock.<br>-  /// TODO(ibiryukov): the entries are neved deleted from this map.<br>-  llvm::StringMap<DocVersion> DocVersions;<br>-<br>-  /// A LIFO queue of requests. Note that requests are discarded if the `version`<br>-  /// field is not equal to the one stored inside DocVersions.<br>-  /// TODO(krasimir): code completion should always have priority over parsing<br>-  /// for diagnostics.<br>-  std::deque<ASTManagerRequest> RequestQueue;<br>+  std::mutex Mutex;<br>+  /// We run some tasks on a separate thread(parsing, ClangdUnit cleanup).<br>+  /// This thread looks into RequestQueue to find requests to handle and<br>+  /// terminates when Done is set to true.<br>+  std::thread Worker;<br>   /// Setting Done to true will make the worker thread terminate.<br>   bool Done = false;<br>+  /// A LIFO queue of requests. Note that requests are discarded if the<br>+  /// `version` field is not equal to the one stored inside DraftStore.<br>+  /// FIXME(krasimir): code completion should always have priority over parsing<br>+  /// for diagnostics.<br>+  std::deque<WorkerRequest> RequestQueue;<br>   /// Condition variable to wake up the worker thread.<br>-  std::condition_variable ClangRequestCV;<br>-  /// Lock for accesses to RequestQueue, DocVersions and Done.<br>-  std::mutex RequestLock;<br>-<br>-  /// We run parsing on a separate thread. This thread looks into RequestQueue to<br>-  /// find requests to handle and terminates when Done is set to true.<br>-  std::thread ClangWorker;<br>+  std::condition_variable RequestCV;<br>+};<br>+<br>+/// Provides API to manage ASTs for a collection of C++ files and request<br>+/// various language features(currently, only codeCompletion and async<br>+/// diagnostics for tracked files).<br>+class ClangdServer {<br>+public:<br>+  ClangdServer(std::unique_ptr<<wbr>GlobalCompilationDatabase> CDB,<br>+               std::unique_ptr<<wbr>DiagnosticsConsumer> DiagConsumer,<br>+               bool RunSynchronously);<br>+<br>+  /// Add a \p File to the list of tracked C++ files or update the contents if<br>+  /// \p File is already tracked. Also schedules parsing of the AST for it on a<br>+  /// separate thread. When the parsing is complete, DiagConsumer passed in<br>+  /// constructor will receive onDiagnosticsReady callback.<br>+  void addDocument(PathRef File, StringRef Contents);<br>+<br>+  /// Remove \p File from list of tracked files, schedule a request to free<br>+  /// resources associated with it.<br>+  void removeDocument(PathRef File);<br>+<br>+  /// Run code completion for \p File at \p Pos.<br>+  std::vector<CompletionItem> codeComplete(PathRef File, Position Pos);<br>+<br>+  /// Gets current document contents for \p File. \p File must point to a<br>+  /// currently tracked file.<br>+  /// FIXME(ibiryukov): This function is here to allow implementation of<br>+  /// formatCode from ProtocolHandlers.cpp. We should move formatCode to this<br>+  /// class and remove this function from public interface.<br>+  std::string getDocument(PathRef File);<br>+<br>+private:<br>+  friend class ClangdScheduler;<br>+<br>+  /// This function is called on a worker thread.<br>+  void handleRequest(WorkerRequest Request);<br>+<br>+  std::unique_ptr<GlobalCompila<wbr>tionDatabase> CDB;<br>+  std::unique_ptr<DiagnosticsCo<wbr>nsumer> DiagConsumer;<br>+  DraftStore DraftMgr;<br>+  ClangdUnitStore Units;<br>+  std::shared_ptr<PCHContainerO<wbr>perations> PCHs;<br>+  // WorkScheduler has to be the last member, because its destructor has to be<br>+  // called before all other members to stop the worker thread that references<br>+  // ClangdServer<br>+  ClangdScheduler WorkScheduler;<br> };<br><br> } // namespace clangd<br><br>Added: clang-tools-extra/trunk/clangd<wbr>/ClangdUnit.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.cpp?rev=303067&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ClangdUnit.cpp?rev=<wbr>303067&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ClangdUnit.cpp (added)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ClangdUnit.cpp Mon May 15 09:17:35 2017<br>@@ -0,0 +1,224 @@<br>+//===--- ClangdUnit.cpp ------------------------------<wbr>-----------*- C++-*-===//<br>+//<br>+//                     The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>+// License. See LICENSE.TXT for details.<br>+//<br>+//===------------------------<wbr>------------------------------<wbr>---------------===//<br>+<br>+#include "ClangdUnit.h"<br>+#include "clang/Frontend/ASTUnit.h"<br>+#include "clang/Frontend/CompilerInstan<wbr>ce.h"<br>+#include "clang/Frontend/CompilerInvoca<wbr>tion.h"<br>+#include "clang/Tooling/CompilationData<wbr>base.h"<br>+<br>+using namespace clang::clangd;<br>+using namespace clang;<br>+<br>+ClangdUnit::ClangdUnit(PathRe<wbr>f FileName, StringRef Contents,<br>+                       std::sha<wbr>red_ptr<PCHContainerOperations<wbr>> PCHs,<br>+                       std::vec<wbr>tor<tooling::CompileCommand> Commands)<br>+    : FileName(FileName), PCHs(PCHs) {<br>+  assert(!Commands.empty() && "No compile commands provided");<br>+<br>+  // Inject the resource dir.<br>+  // FIXME: Don't overwrite it if it's already there.<br>+  static int Dummy; // Just an address in this process.<br>+  std::string ResourceDir =<br>+      CompilerInvocation::GetRe<wbr>sourcesPath("clangd", (void *)&Dummy);<br>+  Commands.front().CommandLine.<wbr>push_back("-resource-dir=" + ResourceDir);<br>+<br>+  IntrusiveRefCntPtr<Diagnostic<wbr>sEngine> Diags =<br>+      CompilerInstance::createD<wbr>iagnostics(new DiagnosticOptions);<br>+<br>+  std::vector<const char *> ArgStrs;<br>+  for (const auto &S : Commands.front().CommandLine)<br>+    ArgStrs.push_back(S.c_str()<wbr>);<br>+<br>+  ASTUnit::RemappedFile RemappedSource(<br>+      FileName,<br>+      llvm::MemoryBuffer::getMe<wbr>mBufferCopy(Contents, FileName).release());<br>+<br>+  auto ArgP = &*ArgStrs.begin();<br>+  Unit = std::unique_ptr<ASTUnit>(ASTUn<wbr>it::LoadFromCommandLine(<br>+      ArgP, ArgP + ArgStrs.size(), PCHs, Diags, ResourceDir,<br>+      /*OnlyLocalDecls=*/false, /*CaptureDiagnostics=*/true, RemappedSource,<br>+      /*RemappedFilesKeepOrigin<wbr>alName=*/true,<br>+      /*PrecompilePreambleAfter<wbr>NParses=*/1, /*TUKind=*/TU_Complete,<br>+      /*CacheCodeCompletionResu<wbr>lts=*/true,<br>+      /*IncludeBriefCommentsInC<wbr>odeCompletion=*/true,<br>+      /*AllowPCHWithCompilerErr<wbr>ors=*/true));<br>+}<br>+<br>+void ClangdUnit::reparse(StringRef Contents) {<br>+  // Do a reparse if this wasn't the first parse.<br>+  // FIXME: This might have the wrong working directory if it changed in the<br>+  // meantime.<br>+  ASTUnit::RemappedFile RemappedSource(<br>+      FileName,<br>+      llvm::MemoryBuffer::getMe<wbr>mBufferCopy(Contents, FileName).release());<br>+<br>+  Unit->Reparse(PCHs, RemappedSource);<br>+}<br>+<br>+namespace {<br>+<br>+CompletionItemKind getKind(CXCursorKind K) {<br>+  switch (K) {<br>+  case CXCursor_MacroInstantiation:<br>+  case CXCursor_MacroDefinition:<br>+    return CompletionItemKind::Text;<br>+  case CXCursor_CXXMethod:<br>+    return CompletionItemKind::Method;<br>+  case CXCursor_FunctionDecl:<br>+  case CXCursor_FunctionTemplate:<br>+    return CompletionItemKind::Function;<br>+  case CXCursor_Constructor:<br>+  case CXCursor_Destructor:<br>+    return CompletionItemKind::Constructo<wbr>r;<br>+  case CXCursor_FieldDecl:<br>+    return CompletionItemKind::Field;<br>+  case CXCursor_VarDecl:<br>+  case CXCursor_ParmDecl:<br>+    return CompletionItemKind::Variable;<br>+  case CXCursor_ClassDecl:<br>+  case CXCursor_StructDecl:<br>+  case CXCursor_UnionDecl:<br>+  case CXCursor_ClassTemplate:<br>+  case CXCursor_ClassTemplatePartialS<wbr>pecialization:<br>+    return CompletionItemKind::Class;<br>+  case CXCursor_Namespace:<br>+  case CXCursor_NamespaceAlias:<br>+  case CXCursor_NamespaceRef:<br>+    return CompletionItemKind::Module;<br>+  case CXCursor_EnumConstantDecl:<br>+    return CompletionItemKind::Value;<br>+  case CXCursor_EnumDecl:<br>+    return CompletionItemKind::Enum;<br>+  case CXCursor_TypeAliasDecl:<br>+  case CXCursor_TypeAliasTemplateDecl<wbr>:<br>+  case CXCursor_TypedefDecl:<br>+  case CXCursor_MemberRef:<br>+  case CXCursor_TypeRef:<br>+    return CompletionItemKind::Reference;<br>+  default:<br>+    return CompletionItemKind::Missing;<br>+  }<br>+}<br>+<br>+class CompletionItemsCollector : public CodeCompleteConsumer {<br>+  std::vector<CompletionItem> *Items;<br>+  std::shared_ptr<clang::Global<wbr>CodeCompletionAllocator> Allocator;<br>+  CodeCompletionTUInfo CCTUInfo;<br>+<br>+public:<br>+  CompletionItemsCollector(std:<wbr>:vector<CompletionItem> *Items,<br>+                           cons<wbr>t CodeCompleteOptions &CodeCompleteOpts)<br>+      : CodeCompleteConsumer(CodeCompl<wbr>eteOpts, /*OutputIsBinary=*/false),<br>+        Items(Items),<br>+        Allocator(std::make_sha<wbr>red<clang::GlobalCodeCompletio<wbr>nAllocator>()),<br>+        CCTUInfo(Allocator) {}<br>+<br>+  void ProcessCodeCompleteResults(Sem<wbr>a &S, CodeCompletionContext Context,<br>+                               <wbr>   CodeCompletionResult *Results,<br>+                               <wbr>   unsigned NumResults) override {<br>+    for (unsigned I = 0; I != NumResults; ++I) {<br>+      CodeCompletionResult &Result = Results[I];<br>+      CodeCompletionString *CCS = Result.CreateCodeCompletionStr<wbr>ing(<br>+          S, Context, *Allocator, CCTUInfo,<br>+          CodeCompleteOpts.Incl<wbr>udeBriefComments);<br>+      if (CCS) {<br>+        CompletionItem Item;<br>+        assert(CCS->getTypedTex<wbr>t());<br>+        Item.label = CCS->getTypedText();<br>+        Item.kind = getKind(Result.CursorKind);<br>+        if (CCS->getBriefComment())<br>+          Item.documentation = CCS->getBriefComment();<br>+        Items->push_back(std::m<wbr>ove(Item));<br>+      }<br>+    }<br>+  }<br>+<br>+  GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }<br>+<br>+  CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }<br>+};<br>+} // namespace<br>+<br>+std::vector<CompletionItem> ClangdUnit::codeComplete(Strin<wbr>gRef Contents,<br>+                               <wbr>                      Position Pos) {<br>+  CodeCompleteOptions CCO;<br>+  CCO.IncludeBriefComments = 1;<br>+  // This is where code completion stores dirty buffers. Need to free after<br>+  // completion.<br>+  SmallVector<const llvm::MemoryBuffer *, 4> OwnedBuffers;<br>+  SmallVector<StoredDiagnostic, 4> StoredDiagnostics;<br>+  IntrusiveRefCntPtr<Diagnostic<wbr>sEngine> DiagEngine(<br>+      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions));<br>+  std::vector<CompletionItem> Items;<br>+  CompletionItemsCollector Collector(&Items, CCO);<br>+<br>+  ASTUnit::RemappedFile RemappedSource(<br>+      FileName,<br>+      llvm::MemoryBuffer::getMe<wbr>mBufferCopy(Contents, FileName).release());<br>+<br>+  IntrusiveRefCntPtr<SourceMana<wbr>ger> SourceMgr(<br>+      new SourceManager(*DiagEngine, Unit->getFileManager()));<br>+  // CodeComplete seems to require fresh LangOptions.<br>+  LangOptions LangOpts = Unit->getLangOpts();<br>+  // The language server protocol uses zero-based line and column numbers.<br>+  // The clang code completion uses one-based numbers.<br>+  Unit->CodeComplete(FileName, Pos.line + 1, Pos.character + 1, RemappedSource,<br>+                     CCO.Includ<wbr>eMacros, CCO.IncludeCodePatterns,<br>+                     CCO.Includ<wbr>eBriefComments, Collector, PCHs, *DiagEngine,<br>+                     LangOpts, *SourceMgr, Unit->getFileManager(),<br>+                     StoredDiag<wbr>nostics, OwnedBuffers);<br>+  for (const llvm::MemoryBuffer *Buffer : OwnedBuffers)<br>+    delete Buffer;<br>+  return Items;<br>+}<br>+<br>+namespace {<br>+/// Convert from clang diagnostic level to LSP severity.<br>+static int getSeverity(DiagnosticsEngine:<wbr>:Level L) {<br>+  switch (L) {<br>+  case DiagnosticsEngine::Remark:<br>+    return 4;<br>+  case DiagnosticsEngine::Note:<br>+    return 3;<br>+  case DiagnosticsEngine::Warning:<br>+    return 2;<br>+  case DiagnosticsEngine::Fatal:<br>+  case DiagnosticsEngine::Error:<br>+    return 1;<br>+  case DiagnosticsEngine::Ignored:<br>+    return 0;<br>+  }<br>+  llvm_unreachable("Unknown diagnostic level!");<br>+}<br>+} // namespace<br>+<br>+std::vector<DiagWithFixIts> ClangdUnit::getLocalDiagnostic<wbr>s() const {<br>+  std::vector<DiagWithFixIts> Result;<br>+  for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),<br>+                               <wbr>      DEnd = Unit->stored_diag_end();<br>+       D != DEnd; ++D) {<br>+    if (!D->getLocation().isValid() ||<br>+        !D->getLocation().getMa<wbr>nager().isInMainFile(D->getLoc<wbr>ation()))<br>+      continue;<br>+    Position P;<br>+    P.line = D->getLocation().getSpellingLi<wbr>neNumber() - 1;<br>+    P.character = D->getLocation().getSpellingCo<wbr>lumnNumber();<br>+    Range R = {P, P};<br>+    clangd::Diagnostic Diag = {R, getSeverity(D->getLevel()), D->getMessage()};<br>+<br>+    llvm::SmallVector<tooling::<wbr>Replacement, 1> FixItsForDiagnostic;<br>+    for (const FixItHint &Fix : D->getFixIts()) {<br>+      FixItsForDiagnostic.push_<wbr>back(clang::tooling::Replaceme<wbr>nt(<br>+          Unit->getSourceManage<wbr>r(), Fix.RemoveRange, Fix.CodeToInsert));<br>+    }<br>+    Result.push_back({Diag, std::move(FixItsForDiagnostic)<wbr>});<br>+  }<br>+  return Result;<br>+}<br><br>Added: clang-tools-extra/trunk/clangd<wbr>/ClangdUnit.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.h?rev=303067&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ClangdUnit.h?rev=303067<wbr>&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ClangdUnit.h (added)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ClangdUnit.h Mon May 15 09:17:35 2017<br>@@ -0,0 +1,63 @@<br>+//===--- ClangdUnit.h ------------------------------<wbr>-------------*- C++-*-===//<br>+//<br>+//                     The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>+// License. See LICENSE.TXT for details.<br>+//<br>+//===------------------------<wbr>------------------------------<wbr>---------------===//<br>+<br>+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>CLANGDUNIT_H<br>+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>CLANGDUNIT_H<br>+<br>+#include "Protocol.h"<br>+#include "Path.h"<br>+#include "clang/Frontend/ASTUnit.h"<br>+#include "clang/Tooling/Core/Replacemen<wbr>t.h"<br>+#include <memory><br>+<br>+namespace clang {<br>+class ASTUnit;<br>+class PCHContainerOperations;<br>+<br>+namespace tooling {<br>+struct CompileCommand;<br>+}<br>+<br>+namespace clangd {<br>+<br>+/// A diagnostic with its FixIts.<br>+struct DiagWithFixIts {<br>+  clangd::Diagnostic Diag;<br>+  llvm::SmallVector<tooling::Re<wbr>placement, 1> FixIts;<br>+};<br>+<br>+/// Stores parsed C++ AST and provides implementations of all operations clangd<br>+/// would want to perform on parsed C++ files.<br>+class ClangdUnit {<br>+public:<br>+  ClangdUnit(PathRef FileName, StringRef Contents,<br>+             std::shared_ptr<PC<wbr>HContainerOperations> PCHs,<br>+             std::vector<toolin<wbr>g::CompileCommand> Commands);<br>+<br>+  /// Reparse with new contents.<br>+  void reparse(StringRef Contents);<br>+<br>+  /// Get code completions at a specified \p Line and \p Column in \p File.<br>+  ///<br>+  /// This function is thread-safe and returns completion items that own the<br>+  /// data they contain.<br>+  std::vector<CompletionItem> codeComplete(StringRef Contents, Position Pos);<br>+  /// Returns diagnostics and corresponding FixIts for each diagnostic that are<br>+  /// located in the current file.<br>+  std::vector<DiagWithFixIts> getLocalDiagnostics() const;<br>+<br>+private:<br>+  Path FileName;<br>+  std::unique_ptr<ASTUnit> Unit;<br>+  std::shared_ptr<PCHContainerO<wbr>perations> PCHs;<br>+};<br>+<br>+} // namespace clangd<br>+} // namespace clang<br>+#endif<br><br>Added: clang-tools-extra/trunk/clangd<wbr>/ClangdUnitStore.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnitStore.cpp?rev=303067&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ClangdUnitStore.cpp?<wbr>rev=303067&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ClangdUnitStore.cpp (added)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ClangdUnitStore.cpp Mon May 15 09:17:35 2017<br>@@ -0,0 +1,34 @@<br>+//===--- ClangdUnitStore.cpp - A ClangdUnits container -----------*-C++-*-===//<br>+//<br>+//                     The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>+// License. See LICENSE.TXT for details.<br>+//<br>+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>+<br>+#include "ClangdUnitStore.h"<br>+#include "llvm/Support/Path.h"<br>+<br>+using namespace clang::clangd;<br>+using namespace clang;<br>+<br>+void ClangdUnitStore::removeUnitIfP<wbr>resent(PathRef File) {<br>+  std::lock_guard<std::mutex> Lock(Mutex);<br>+<br>+  auto It = OpenedFiles.find(File);<br>+  if (It == OpenedFiles.end())<br>+    return;<br>+  OpenedFiles.erase(It);<br>+}<br>+<br>+std::vector<tooling::CompileC<wbr>ommand> ClangdUnitStore::getCompileCom<wbr>mands(GlobalCompilationDatabas<wbr>e &CDB, PathRef File) {<br>+  std::vector<tooling::CompileC<wbr>ommand> Commands = CDB.getCompileCommands(File);<br>+  if (Commands.empty()) {<br>+    // Add a fake command line if we know nothing.<br>+    Commands.push_back(tooling:<wbr>:CompileCommand(<br>+        llvm::sys::path::parent<wbr>_path(File), llvm::sys::path::filename(File<wbr>),<br>+        {"clang", "-fsyntax-only", File.str()}, ""));<br>+  }<br>+  return Commands;<br>+}<br><br>Added: clang-tools-extra/trunk/clangd<wbr>/ClangdUnitStore.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnitStore.h?rev=303067&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ClangdUnitStore.h?rev=<wbr>303067&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ClangdUnitStore.h (added)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ClangdUnitStore.h Mon May 15 09:17:35 2017<br>@@ -0,0 +1,93 @@<br>+//===--- ClangdUnitStore.h - A ClangdUnits container -------------*-C++-*-===//<br>+//<br>+//                     The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>+// License. See LICENSE.TXT for details.<br>+//<br>+//===------------------------<wbr>------------------------------<wbr>---------------===//<br>+<br>+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>CLANGDUNITSTORE_H<br>+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>CLANGDUNITSTORE_H<br>+<br>+#include <mutex><br>+<br>+#include "ClangdUnit.h"<br>+#include "GlobalCompilationDatabase.h"<br>+#include "Path.h"<br>+#include "clang/Tooling/CompilationData<wbr>base.h"<br>+<br>+namespace clang {<br>+namespace clangd {<br>+<br>+/// Thread-safe collection of ASTs built for specific files. Provides<br>+/// synchronized access to ASTs.<br>+class ClangdUnitStore {<br>+public:<br>+  /// Run specified \p Action on the ClangdUnit for \p File.<br>+  /// If the file is not present in ClangdUnitStore, a new ClangdUnit will be<br>+  /// created from the \p FileContents. If the file is already present in the<br>+  /// store, ClangdUnit::reparse will be called with the new contents before<br>+  /// running \p Action.<br>+  template <class Func><br>+  void runOnUnit(PathRef File, StringRef FileContents,<br>+                 GlobalCompilat<wbr>ionDatabase &CDB,<br>+                 std::shared_pt<wbr>r<PCHContainerOperations> PCHs, Func Action) {<br>+    runOnUnitImpl(File, FileContents, CDB, PCHs, /*ReparseBeforeAction=*/true,<br>+                  std::forward<<wbr>Func>(Action));<br>+  }<br>+<br>+  /// Run specified \p Action on the ClangdUnit for \p File.<br>+  /// If the file is not present in ClangdUnitStore, a new ClangdUnit will be<br>+  /// created from the \p FileContents. If the file is already present in the<br>+  /// store, the \p Action will be run directly on it.<br>+  template <class Func><br>+  void runOnUnitWithoutReparse(PathRe<wbr>f File, StringRef FileContents,<br>+                               <wbr>GlobalCompilationDatabase &CDB,<br>+                               <wbr>std::shared_ptr<PCHContainerOp<wbr>erations> PCHs,<br>+                               <wbr>Func Action) {<br>+    runOnUnitImpl(File, FileContents, CDB, PCHs, /*ReparseBeforeAction=*/false,<br>+                  std::forward<<wbr>Func>(Action));<br>+  }<br>+<br>+  /// Remove ClangdUnit for \p File, if any<br>+  void removeUnitIfPresent(PathRef File);<br>+<br>+private:<br>+  /// Run specified \p Action on the ClangdUnit for \p File.<br>+  template <class Func><br>+  void runOnUnitImpl(PathRef File, StringRef FileContents,<br>+                     GlobalComp<wbr>ilationDatabase &CDB,<br>+                     std::share<wbr>d_ptr<PCHContainerOperations> PCHs,<br>+                     bool ReparseBeforeAction, Func Action) {<br>+    std::lock_guard<std::mutex> Lock(Mutex);<br>+<br>+    auto Commands = getCompileCommands(CDB, File);<br>+    assert(!Commands.empty() &&<br>+           "getCompileCommands should add default command");<br>+    // chdir. This is thread hostile.<br>+    // FIXME(ibiryukov): get rid of this<br>+    llvm::sys::fs::set_current_<wbr>path(Commands.front().Director<wbr>y);<br>+<br>+    auto It = OpenedFiles.find(File);<br>+    if (It == OpenedFiles.end()) {<br>+      It = OpenedFiles<br>+               .insert(std::mak<wbr>e_pair(<br>+                   File, ClangdUnit(File, FileContents, PCHs, Commands)))<br>+               .first;<br>+    } else if (ReparseBeforeAction) {<br>+      It->second.reparse(FileCo<wbr>ntents);<br>+    }<br>+    return Action(It->second);<br>+  }<br>+<br>+  std::vector<tooling::CompileC<wbr>ommand><br>+  getCompileCommands(GlobalComp<wbr>ilationDatabase &CDB, PathRef File);<br>+<br>+  std::mutex Mutex;<br>+  llvm::StringMap<ClangdUnit> OpenedFiles;<br>+};<br>+} // namespace clangd<br>+} // namespace clang<br>+<br>+#endif<br><br>Removed: clang-tools-extra/trunk/clangd<wbr>/DocumentStore.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/DocumentStore.h?rev=303066&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/DocumentStore.h?rev=<wbr>303066&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/DocumentStore.h (original)<br>+++ clang-tools-extra/trunk/clangd<wbr>/DocumentStore.h (removed)<br>@@ -1,86 +0,0 @@<br>-//===--- DocumentStore.h - File contents container --------------*- C++ -*-===//<br>-//<br>-//                     The LLVM Compiler Infrastructure<br>-//<br>-// This file is distributed under the University of Illinois Open Source<br>-// License. See LICENSE.TXT for details.<br>-//<br>-//===------------------------<wbr>------------------------------<wbr>----------------===//<br>-<br>-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>DOCUMENTSTORE_H<br>-#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>DOCUMENTSTORE_H<br>-<br>-#include "clang/Basic/LLVM.h"<br>-#include "llvm/ADT/StringMap.h"<br>-#include <mutex><br>-#include <string><br>-#include <vector><br>-<br>-namespace clang {<br>-namespace clangd {<br>-class DocumentStore;<br>-<br>-struct DocumentStoreListener {<br>-  virtual ~DocumentStoreListener() = default;<br>-  virtual void onDocumentAdd(StringRef File) {}<br>-  virtual void onDocumentRemove(StringRef File) {}<br>-};<br>-<br>-/// A container for files opened in a workspace, addressed by File. The contents<br>-/// are owned by the DocumentStore.<br>-class DocumentStore {<br>-public:<br>-  /// Add a document to the store. Overwrites existing contents.<br>-  void addDocument(StringRef File, StringRef Text) {<br>-    {<br>-      std::lock_guard<std::mute<wbr>x> Guard(DocsMutex);<br>-      Docs[File] = Text;<br>-    }<br>-    for (const auto &Listener : Listeners)<br>-      Listener->onDocumentAdd(F<wbr>ile);<br>-  }<br>-  /// Delete a document from the store.<br>-  void removeDocument(StringRef File) {<br>-    {<br>-      std::lock_guard<std::mute<wbr>x> Guard(DocsMutex);<br>-      Docs.erase(File);<br>-    }<br>-    for (const auto &Listener : Listeners)<br>-      Listener->onDocumentRemov<wbr>e(File);<br>-  }<br>-  /// Retrieve a document from the store. Empty string if it's unknown.<br>-  ///<br>-  /// This function is thread-safe. It returns a copy to avoid handing out<br>-  /// references to unguarded data.<br>-  std::string getDocument(StringRef File) const {<br>-    // FIXME: This could be a reader lock.<br>-    std::lock_guard<std::mutex> Guard(DocsMutex);<br>-    return Docs.lookup(File);<br>-  }<br>-<br>-  /// Add a listener. Does not take ownership.<br>-  void addListener(DocumentStoreListe<wbr>ner *DSL) { Listeners.push_back(DSL); }<br>-<br>-  /// Get name and constents of all documents in this store.<br>-  ///<br>-  /// This function is thread-safe. It returns a copies to avoid handing out<br>-  /// references to unguarded data.<br>-  std::vector<std::pair<std::st<wbr>ring, std::string>> getAllDocuments() const {<br>-    std::vector<std::pair<std::<wbr>string, std::string>> AllDocs;<br>-    std::lock_guard<std::mutex> Guard(DocsMutex);<br>-    for (const auto &P : Docs)<br>-      AllDocs.emplace_back(P.fi<wbr>rst(), P.second);<br>-    return AllDocs;<br>-  }<br>-<br>-private:<br>-  llvm::StringMap<std::string> Docs;<br>-  std::vector<DocumentStoreList<wbr>ener *> Listeners;<br>-<br>-  mutable std::mutex DocsMutex;<br>-};<br>-<br>-} // namespace clangd<br>-} // namespace clang<br>-<br>-#endif<br><br>Added: clang-tools-extra/trunk/clangd<wbr>/DraftStore.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/DraftStore.cpp?rev=303067&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/DraftStore.cpp?rev=<wbr>303067&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/DraftStore.cpp (added)<br>+++ clang-tools-extra/trunk/clangd<wbr>/DraftStore.cpp Mon May 15 09:17:35 2017<br>@@ -0,0 +1,48 @@<br>+//===--- DraftStore.cpp - File contents container ---------------*- C++ -*-===//<br>+//<br>+//                     The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>+// License. See LICENSE.TXT for details.<br>+//<br>+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>+<br>+#include "DraftStore.h"<br>+<br>+using namespace clang::clangd;<br>+<br>+VersionedDraft DraftStore::getDraft(PathRef File) const {<br>+  std::lock_guard<std::mutex> Lock(Mutex);<br>+<br>+  auto It = Drafts.find(File);<br>+  if (It == Drafts.end())<br>+    return {0, llvm::None};<br>+  return It->second;<br>+}<br>+<br>+DocVersion DraftStore::getVersion(PathRef File) const {<br>+  std::lock_guard<std::mutex> Lock(Mutex);<br>+<br>+  auto It = Drafts.find(File);<br>+  if (It == Drafts.end())<br>+    return 0;<br>+  return It->second.Version;<br>+}<br>+<br>+DocVersion DraftStore::updateDraft(PathRe<wbr>f File, StringRef Contents) {<br>+  std::lock_guard<std::mutex> Lock(Mutex);<br>+<br>+  auto &Entry = Drafts[File];<br>+  DocVersion NewVersion = ++Entry.Version;<br>+  Entry.Draft = Contents;<br>+  return NewVersion;<br>+}<br>+<br>+DocVersion DraftStore::removeDraft(PathRe<wbr>f File) {<br>+  std::lock_guard<std::mutex> Lock(Mutex);<br>+<br>+  auto &Entry = Drafts[File];<br>+  DocVersion NewVersion = ++Entry.Version;<br>+  Entry.Draft = llvm::None;<br>+  return NewVersion;<br>+}<br><br>Copied: clang-tools-extra/trunk/clangd<wbr>/DraftStore.h (from r303060, clang-tools-extra/trunk/clangd<wbr>/DocumentStore.h)<br>URL: <a href="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" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/DraftStore.h?p2=clang-<wbr>tools-extra/trunk/clangd/<wbr>DraftStore.h&p1=clang-tools-<wbr>extra/trunk/clangd/DocumentSto<wbr>re.h&r1=303060&r2=303067&rev=<wbr>303067&view=diff</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/DocumentStore.h (original)<br>+++ clang-tools-extra/trunk/clangd<wbr>/DraftStore.h Mon May 15 09:17:35 2017<br>@@ -1,4 +1,4 @@<br>-//===--- DocumentStore.h - File contents container --------------*- C++ -*-===//<br>+//===--- DraftStore.h - File contents container -----------------*- C++ -*-===//<br> //<br> //                     The LLVM Compiler Infrastructure<br> //<br>@@ -7,9 +7,10 @@<br> //<br> //===-------------------------<wbr>------------------------------<wbr>---------------===//<br><br>-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>DOCUMENTSTORE_H<br>-#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>DOCUMENTSTORE_H<br>+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>DRAFTSTORE_H<br>+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>DRAFTSTORE_H<br><br>+#include "Path.h"<br> #include "clang/Basic/LLVM.h"<br> #include "llvm/ADT/StringMap.h"<br> #include <mutex><br>@@ -18,66 +19,40 @@<br><br> namespace clang {<br> namespace clangd {<br>-class DocumentStore;<br><br>-struct DocumentStoreListener {<br>-  virtual ~DocumentStoreListener() = default;<br>-  virtual void onDocumentAdd(StringRef File) {}<br>-  virtual void onDocumentRemove(StringRef File) {}<br>+/// Using 'unsigned' here to avoid undefined behaviour on overflow.<br>+typedef unsigned DocVersion;<br>+<br>+/// Document draft with a version of this draft.<br>+struct VersionedDraft {<br>+  DocVersion Version;<br>+  /// If the value of the field is None, draft is now deleted<br>+  llvm::Optional<std::string> Draft;<br> };<br><br>-/// A container for files opened in a workspace, addressed by File. The contents<br>-/// are owned by the DocumentStore.<br>-class DocumentStore {<br>+/// A thread-safe container for files opened in a workspace, addressed by<br>+/// filenames. The contents are owned by the DraftStore. Versions are mantained<br>+/// for the all added documents, including removed ones. The document version is<br>+/// incremented on each update and removal of the document.<br>+class DraftStore {<br> public:<br>-  /// Add a document to the store. Overwrites existing contents.<br>-  void addDocument(StringRef File, StringRef Text) {<br>-    {<br>-      std::lock_guard<std::mute<wbr>x> Guard(DocsMutex);<br>-      Docs[File] = Text;<br>-    }<br>-    for (const auto &Listener : Listeners)<br>-      Listener->onDocumentAdd(F<wbr>ile);<br>-  }<br>-  /// Delete a document from the store.<br>-  void removeDocument(StringRef File) {<br>-    {<br>-      std::lock_guard<std::mute<wbr>x> Guard(DocsMutex);<br>-      Docs.erase(File);<br>-    }<br>-    for (const auto &Listener : Listeners)<br>-      Listener->onDocumentRemov<wbr>e(File);<br>-  }<br>-  /// Retrieve a document from the store. Empty string if it's unknown.<br>-  ///<br>-  /// This function is thread-safe. It returns a copy to avoid handing out<br>-  /// references to unguarded data.<br>-  std::string getDocument(StringRef File) const {<br>-    // FIXME: This could be a reader lock.<br>-    std::lock_guard<std::mutex> Guard(DocsMutex);<br>-    return Docs.lookup(File);<br>-  }<br>-<br>-  /// Add a listener. Does not take ownership.<br>-  void addListener(DocumentStoreListe<wbr>ner *DSL) { Listeners.push_back(DSL); }<br>-<br>-  /// Get name and constents of all documents in this store.<br>-  ///<br>-  /// This function is thread-safe. It returns a copies to avoid handing out<br>-  /// references to unguarded data.<br>-  std::vector<std::pair<std::st<wbr>ring, std::string>> getAllDocuments() const {<br>-    std::vector<std::pair<std::<wbr>string, std::string>> AllDocs;<br>-    std::lock_guard<std::mutex> Guard(DocsMutex);<br>-    for (const auto &P : Docs)<br>-      AllDocs.emplace_back(P.fi<wbr>rst(), P.second);<br>-    return AllDocs;<br>-  }<br>+  /// \return version and contents of the stored document.<br>+  /// For untracked files, a (0, None) pair is returned.<br>+  VersionedDraft getDraft(PathRef File) const;<br>+  /// \return version of the tracked document.<br>+  /// For untracked files, 0 is returned.<br>+  DocVersion getVersion(PathRef File) const;<br>+<br>+  /// Replace contents of the draft for \p File with \p Contents.<br>+  /// \return The new version of the draft for \p File.<br>+  DocVersion updateDraft(PathRef File, StringRef Contents);<br>+  /// Remove the contents of the draft<br>+  /// \return The new version of the draft for \p File.<br>+  DocVersion removeDraft(PathRef File);<br><br> private:<br>-  llvm::StringMap<std::string> Docs;<br>-  std::vector<DocumentStoreList<wbr>ener *> Listeners;<br>-<br>-  mutable std::mutex DocsMutex;<br>+  mutable std::mutex Mutex;<br>+  llvm::StringMap<VersionedDraf<wbr>t> Drafts;<br> };<br><br> } // namespace clangd<br><br>Added: clang-tools-extra/trunk/clangd<wbr>/GlobalCompilationDatabase.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.cpp?rev=303067&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/GlobalCompilationDataba<wbr>se.cpp?rev=303067&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/GlobalCompilationDatabase.cpp (added)<br>+++ clang-tools-extra/trunk/clangd<wbr>/GlobalCompilationDatabase.cpp Mon May 15 09:17:35 2017<br>@@ -0,0 +1,65 @@<br>+//===--- GlobalCompilationDatabase.cpp --------------------------*- C++-*-===//<br>+//<br>+//                     The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>+// License. See LICENSE.TXT for details.<br>+//<br>+//===------------------------<wbr>------------------------------<wbr>---------------===//<br>+<br>+#include "GlobalCompilationDatabase.h"<br>+#include "clang/Tooling/CompilationData<wbr>base.h"<br>+#include "llvm/Support/FileSystem.h"<br>+#include "llvm/Support/Path.h"<br>+<br>+using namespace clang::clangd;<br>+using namespace clang;<br>+<br>+std::vector<tooling::CompileC<wbr>ommand><br>+DirectoryBasedGlobalCompilati<wbr>onDatabase::<wbr>getCompileCommands(PathRef File) {<br>+  std::vector<tooling::CompileC<wbr>ommand> Commands;<br>+<br>+  auto CDB = getCompilationDatabase(File);<br>+  if (!CDB)<br>+    return {};<br>+  return CDB->getCompileCommands(File);<br>+}<br>+<br>+tooling::CompilationDatabase *<br>+DirectoryBasedGlobalCompilati<wbr>onDatabase::getCompilationData<wbr>base(PathRef File) {<br>+  std::lock_guard<std::mutex> Lock(Mutex);<br>+<br>+  namespace path = llvm::sys::path;<br>+<br>+  assert((path::is_absolute(Fil<wbr>e, path::Style::posix) ||<br>+          path::is_absolute(Fil<wbr>e, path::Style::windows)) &&<br>+         "path must be absolute");<br>+<br>+  for (auto Path = path::parent_path(File); !Path.empty();<br>+       Path = path::parent_path(Path)) {<br>+<br>+    auto CachedIt = CompilationDatabases.find(Path<wbr>);<br>+    if (CachedIt != CompilationDatabases.end())<br>+      return CachedIt->second.get();<br>+    std::string Error;<br>+    auto CDB = tooling::CompilationDatabase::<wbr>loadFromDirectory(Path, Error);<br>+    if (!CDB) {<br>+      if (!Error.empty()) {<br>+        // FIXME(ibiryukov): logging<br>+        // Output.log("Error when trying to load compilation database from " +<br>+        //            Twine(Path) + ": " + Twine(Error) + "\n");<br>+      }<br>+      continue;<br>+    }<br>+<br>+    // FIXME(ibiryukov): Invalidate cached compilation databases on changes<br>+    auto result = CDB.get();<br>+    CompilationDatabases.insert<wbr>(std::make_pair(Path, std::move(CDB)));<br>+    return result;<br>+  }<br>+<br>+  // FIXME(ibiryukov): logging<br>+  // Output.log("Failed to find compilation database for " + Twine(File) +<br>+  // "\n");<br>+  return nullptr;<br>+}<br><br>Added: clang-tools-extra/trunk/clangd<wbr>/GlobalCompilationDatabase.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.h?rev=303067&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/GlobalCompilationDataba<wbr>se.h?rev=303067&view=auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/GlobalCompilationDatabase.h (added)<br>+++ clang-tools-extra/trunk/clangd<wbr>/GlobalCompilationDatabase.h Mon May 15 09:17:35 2017<br>@@ -0,0 +1,59 @@<br>+//===--- GlobalCompilationDatabase.h ----------------------------*- C++-*-===//<br>+//<br>+//                     The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>+// License. See LICENSE.TXT for details.<br>+//<br>+//===------------------------<wbr>------------------------------<wbr>---------------===//<br>+<br>+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>GLOBALCOMPILATIONDATABASE_H<br>+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>GLOBALCOMPILATIONDATABASE_H<br>+<br>+#include "Path.h"<br>+#include "llvm/ADT/StringMap.h"<br>+#include <memory><br>+#include <mutex><br>+<br>+namespace clang {<br>+<br>+namespace tooling {<br>+class CompilationDatabase;<br>+struct CompileCommand;<br>+} // namespace tooling<br>+<br>+namespace clangd {<br>+<br>+/// Provides compilation arguments used for building ClangdUnit.<br>+class GlobalCompilationDatabase {<br>+public:<br>+  virtual ~GlobalCompilationDatabase() = default;<br>+<br>+  virtual std::vector<tooling::CompileCo<wbr>mmand><br>+  getCompileCommands(PathRef File) = 0;<br>+<br>+  /// FIXME(ibiryukov): add facilities to track changes to compilation flags of<br>+  /// existing targets.<br>+};<br>+<br>+/// Gets compile args from tooling::CompilationDatabases built for parent<br>+/// directories.<br>+class DirectoryBasedGlobalCompilatio<wbr>nDatabase<br>+    : public GlobalCompilationDatabase {<br>+public:<br>+  std::vector<tooling::CompileC<wbr>ommand><br>+  getCompileCommands(PathRef File) override;<br>+<br>+private:<br>+  tooling::CompilationDatabase *getCompilationDatabase(PathRe<wbr>f File);<br>+<br>+  std::mutex Mutex;<br>+  /// Caches compilation databases loaded from directories(keys are<br>+  /// directories).<br>+  llvm::StringMap<std::unique_p<wbr>tr<clang::tooling::Compilation<wbr>Database>><br>+      CompilationDatabases;<br>+};<br>+} // namespace clangd<br>+} // namespace clang<br>+<br>+#endif<br><br>Added: clang-tools-extra/trunk/clangd<wbr>/Path.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Path.h?rev=303067&view=auto" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/Path.h?rev=303067&view=<wbr>auto</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/Path.h (added)<br>+++ clang-tools-extra/trunk/clangd<wbr>/Path.h Mon May 15 09:17:35 2017<br>@@ -0,0 +1,29 @@<br>+//===--- Path.h - Helper typedefs ------------------------------<wbr>--*- C++-*-===//<br>+//<br>+//                     The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>+// License. See LICENSE.TXT for details.<br>+//<br>+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>+<br>+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>PATH_H<br>+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>PATH_H<br>+<br>+#include "llvm/ADT/StringRef.h"<br>+#include <string><br>+<br>+namespace clang {<br>+namespace clangd {<br>+<br>+/// A typedef to represent a file path. Used solely for more descriptive<br>+/// signatures.<br>+using Path = std::string;<br>+/// A typedef to represent a ref to file path. Used solely for more descriptive<br>+/// signatures.<br>+using PathRef = llvm::StringRef;<br>+<br>+} // namespace clangd<br>+} // namespace clang<br>+<br>+#endif<br><br>Modified: clang-tools-extra/trunk/clangd<wbr>/ProtocolHandlers.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp?rev=303067&r1=303066&r2=303067&view=diff" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ProtocolHandlers.cpp?<wbr>rev=303067&r1=303066&r2=303067<wbr>&view=diff</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ProtocolHandlers.cpp (original)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ProtocolHandlers.cpp Mon May 15 09:17:35 2017<br>@@ -8,9 +8,10 @@<br> //===-------------------------<wbr>------------------------------<wbr>---------------===//<br><br> #include "ProtocolHandlers.h"<br>-#include "ASTManager.h"<br>-#include "DocumentStore.h"<br>+#include "ClangdServer.h"<br>+#include "DraftStore.h"<br> #include "clang/Format/Format.h"<br>+#include "ClangdLSPServer.h"<br> using namespace clang;<br> using namespace clangd;<br><br>@@ -21,7 +22,7 @@ void TextDocumentDidOpenHandler::ha<wbr>ndleN<br>     Output.log("Failed to decode DidOpenTextDocumentParams!\n")<wbr>;<br>     return;<br>   }<br>-  Store.addDocument(DOTDP->text<wbr>Document.uri.file, DOTDP->textDocument.text);<br>+  AST.openDocument(DOTDP->textD<wbr>ocument.uri.file, DOTDP->textDocument.text);<br> }<br><br> void TextDocumentDidCloseHandler::h<wbr>andleNotification(<br>@@ -32,7 +33,7 @@ void TextDocumentDidCloseHandler::h<wbr>andle<br>     return;<br>   }<br><br>-  Store.removeDocument(DCTDP->t<wbr>extDocument.uri.file);<br>+  AST.closeDocument(DCTDP->text<wbr>Document.uri.file);<br> }<br><br> void TextDocumentDidChangeHandler::<wbr>handleNotification(<br>@@ -43,7 +44,7 @@ void TextDocumentDidChangeHandler::<wbr>handl<br>     return;<br>   }<br>   // We only support full syncing right now.<br>-  Store.addDocument(DCTDP->text<wbr>Document.uri.file, DCTDP->contentChanges[0].text)<wbr>;<br>+  AST.openDocument(DCTDP->textD<wbr>ocument.uri.file, DCTDP->contentChanges[0].text)<wbr>;<br> }<br><br> /// Turn a [line, column] pair into an offset in Code.<br>@@ -110,7 +111,7 @@ void TextDocumentRangeFormattingHan<wbr>dler:<br>     return;<br>   }<br><br>-  std::string Code = Store.getDocument(DRFP->textDo<wbr>cument.uri.file);<br>+  std::string Code = AST.getDocument(DRFP->textDocu<wbr>ment.uri.file);<br><br>   size_t Begin = positionToOffset(Code, DRFP->range.start);<br>   size_t Len = positionToOffset(Code, DRFP->range.end) - Begin;<br>@@ -129,7 +130,7 @@ void TextDocumentOnTypeFormattingHa<wbr>ndler<br><br>   // Look for the previous opening brace from the character position and format<br>   // starting from there.<br>-  std::string Code = Store.getDocument(DOTFP->textD<wbr>ocument.uri.file);<br>+  std::string Code = AST.getDocument(DOTFP->textDoc<wbr>ument.uri.file);<br>   size_t CursorPos = positionToOffset(Code, DOTFP->position);<br>   size_t PreviousLBracePos = StringRef(Code).find_last_of('<wbr>{', CursorPos);<br>   if (PreviousLBracePos == StringRef::npos)<br>@@ -149,7 +150,7 @@ void TextDocumentFormattingHandler:<wbr>:hand<br>   }<br><br>   // Format everything.<br>-  std::string Code = Store.getDocument(DFP->textDoc<wbr>ument.uri.file);<br>+  std::string Code = AST.getDocument(DFP->textDocum<wbr>ent.uri.file);<br>   writeMessage(formatCode(Code<wbr>, DFP->textDocument.uri.file,<br>                           {cla<wbr>ng::tooling::Range(0, Code.size())}, ID));<br> }<br>@@ -164,7 +165,7 @@ void CodeActionHandler::handleMetho<wbr>d(llv<br><br>   // We provide a code action for each diagnostic at the requested location<br>   // which has FixIts available.<br>-  std::string Code = AST.getStore().getDocument(CAP<wbr>->textDocument.uri.file);<br>+  std::string Code = AST.getDocument(CAP->textDocum<wbr>ent.uri.file);<br>   std::string Commands;<br>   for (Diagnostic &D : CAP->context.diagnostics) {<br>     std::vector<clang::tooling<wbr>::Replacement> Fixes = AST.getFixIts(CAP->textDocumen<wbr>t.uri.file, D);<br>@@ -195,8 +196,8 @@ void CompletionHandler::handleMetho<wbr>d(llv<br>     return;<br>   }<br><br>-  auto Items = AST.codeComplete(TDPP->textDoc<wbr>ument.uri.file, TDPP->position.line,<br>-                               <wbr> TDPP->position.character);<br>+  auto Items = AST.codeComplete(TDPP->textDoc<wbr>ument.uri.file, Position{TDPP->position.line,<br>+          TDPP->position.charac<wbr>ter});<br>   std::string Completions;<br>   for (const auto &Item : Items) {<br>     Completions += CompletionItem::unparse(Item);<br><br>Modified: clang-tools-extra/trunk/clangd<wbr>/ProtocolHandlers.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.h?rev=303067&r1=303066&r2=303067&view=diff" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ProtocolHandlers.h?rev=<wbr>303067&r1=303066&r2=303067&<wbr>view=diff</a><br>==============================<wbr>==============================<wbr>==================<br>--- clang-tools-extra/trunk/clangd<wbr>/ProtocolHandlers.h (original)<br>+++ clang-tools-extra/trunk/clangd<wbr>/ProtocolHandlers.h Mon May 15 09:17:35 2017<br>@@ -22,8 +22,8 @@<br><br> namespace clang {<br> namespace clangd {<br>-class ASTManager;<br>-class DocumentStore;<br>+class ClangdLSPServer;<br>+class ClangdLSPServer;<br><br> struct InitializeHandler : Handler {<br>   InitializeHandler(JSONOutput &Output) : Handler(Output) {}<br>@@ -56,83 +56,83 @@ private:<br> };<br><br> struct TextDocumentDidOpenHandler : Handler {<br>-  TextDocumentDidOpenHandler(JS<wbr>ONOutput &Output, DocumentStore &Store)<br>-      : Handler(Output), Store(Store) {}<br>+  TextDocumentDidOpenHandler(JS<wbr>ONOutput &Output, ClangdLSPServer &AST)<br>+      : Handler(Output), AST(AST) {}<br><br>   void handleNotification(llvm::yaml:<wbr>:MappingNode *Params) override;<br><br> private:<br>-  DocumentStore &Store;<br>+  ClangdLSPServer &AST;<br> };<br><br> struct TextDocumentDidChangeHandler : Handler {<br>-  TextDocumentDidChangeHandler(<wbr>JSONOutput &Output, DocumentStore &Store)<br>-      : Handler(Output), Store(Store) {}<br>+  TextDocumentDidChangeHandler(<wbr>JSONOutput &Output, ClangdLSPServer &AST)<br>+      : Handler(Output), AST(AST) {}<br><br>   void handleNotification(llvm::yaml:<wbr>:MappingNode *Params) override;<br><br> private:<br>-  DocumentStore &Store;<br>+  ClangdLSPServer &AST;<br> };<br><br> struct TextDocumentDidCloseHandler : Handler {<br>-  TextDocumentDidCloseHandler(J<wbr>SONOutput &Output, DocumentStore &Store)<br>-      : Handler(Output), Store(Store) {}<br>+  TextDocumentDidCloseHandler(J<wbr>SONOutput &Output, ClangdLSPServer &AST)<br>+      : Handler(Output), AST(AST) {}<br><br>   void handleNotification(llvm::yaml:<wbr>:MappingNode *Params) override;<br><br> private:<br>-  DocumentStore &Store;<br>+  ClangdLSPServer &AST;<br> };<br><br> struct TextDocumentOnTypeFormattingHa<wbr>ndler : Handler {<br>-  TextDocumentOnTypeFormattingH<wbr>andler(JSONOutput &Output, DocumentStore &Store)<br>-      : Handler(Output), Store(Store) {}<br>+  TextDocumentOnTypeFormattingH<wbr>andler(JSONOutput &Output, ClangdLSPServer &AST)<br>+      : Handler(Output), AST(AST) {}<br><br>   void handleMethod(llvm::yaml::Mappi<wbr>ngNode *Params, StringRef ID) override;<br><br> private:<br>-  DocumentStore &Store;<br>+  ClangdLSPServer &AST;<br> };<br><br> struct TextDocumentRangeFormattingHan<wbr>dler : Handler {<br>-  TextDocumentRangeFormattingHa<wbr>ndler(JSONOutput &Output, DocumentStore &Store)<br>-      : Handler(Output), Store(Store) {}<br>+  TextDocumentRangeFormattingHa<wbr>ndler(JSONOutput &Output, ClangdLSPServer &AST)<br>+      : Handler(Output), AST(AST) {}<br><br>   void handleMethod(llvm::yaml::Mappi<wbr>ngNode *Params, StringRef ID) override;<br><br> private:<br>-  DocumentStore &Store;<br>+  ClangdLSPServer &AST;<br> };<br><br> struct TextDocumentFormattingHandler : Handler {<br>-  TextDocumentFormattingHandler<wbr>(JSONOutput &Output, DocumentStore &Store)<br>-      : Handler(Output), Store(Store) {}<br>+  TextDocumentFormattingHandler<wbr>(JSONOutput &Output, ClangdLSPServer &AST)<br>+      : Handler(Output), AST(AST) {}<br><br>   void handleMethod(llvm::yaml::Mappi<wbr>ngNode *Params, StringRef ID) override;<br><br> private:<br>-  DocumentStore &Store;<br>+  ClangdLSPServer &AST;<br> };<br><br> struct CodeActionHandler : Handler {<br>-  CodeActionHandler(JSONOutput &Output, ASTManager &AST)<br>+  CodeActionHandler(JSONOutput &Output, ClangdLSPServer &AST)<br>       : Handler(Output), AST(AST) {}<br><br>   void handleMethod(llvm::yaml::Mappi<wbr>ngNode *Params, StringRef ID) override;<br><br> private:<br>-  ASTManager &AST;<br>+  ClangdLSPServer &AST;<br> };<br><br> struct CompletionHandler : Handler {<br>-  CompletionHandler(JSONOutput &Output, ASTManager &AST)<br>+  CompletionHandler(JSONOutput &Output, ClangdLSPServer &AST)<br>       : Handler(Output), AST(AST) {}<br><br>   void handleMethod(llvm::yaml::Mappi<wbr>ngNode *Params, StringRef ID) override;<br><br>  private:<br>-  ASTManager &AST;<br>+  ClangdLSPServer &AST;<br> };<br><br> } // namespace clangd<br><br><br>______________________________<wbr>_________________<br>cfe-commits mailing list<br><a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br><a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br></div></div></blockquote></div><br></div></div></div></blockquote></div><br></div></div></div></blockquote></div><br></div></div></blockquote></div><span class="HOEnZb"><font color="#888888"><br><br clear="all"><div><br></div>-- <br><div class="m_3771896676606961527gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div>Regards,</div><div>Ilya Biryukov</div></div></div></div></div>
</font></span></div>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div>Regards,</div><div>Ilya Biryukov</div></div></div></div></div>
</div>