ilya-biryukov created this revision.

https://reviews.llvm.org/D36398

Files:
  clangd/ClangdServer.cpp
  clangd/ClangdServer.h
  clangd/ClangdUnitStore.cpp
  clangd/ClangdUnitStore.h

Index: clangd/ClangdUnitStore.h
===================================================================
--- clangd/ClangdUnitStore.h
+++ clangd/ClangdUnitStore.h
@@ -42,6 +42,16 @@
     return It->second;
   }
 
+  struct RecreateResult {
+    std::shared_ptr<CppFile> FileInCollection;
+    std::shared_ptr<CppFile> RemovedFile;
+  };
+
+  RecreateResult recreateFileIfCompileCommandChanged(
+      PathRef File, PathRef ResourceDir, GlobalCompilationDatabase &CDB,
+      std::shared_ptr<PCHContainerOperations> PCHs,
+      IntrusiveRefCntPtr<vfs::FileSystem> VFS);
+
   std::shared_ptr<CppFile> getFile(PathRef File) {
     std::lock_guard<std::mutex> Lock(Mutex);
 
@@ -59,6 +69,9 @@
   tooling::CompileCommand getCompileCommand(GlobalCompilationDatabase &CDB,
                                             PathRef File, PathRef ResourceDir);
 
+  bool compileCommandsAreEqual(tooling::CompileCommand const &LHS,
+                               tooling::CompileCommand const &RHS);
+
   std::mutex Mutex;
   llvm::StringMap<std::shared_ptr<CppFile>> OpenedFiles;
 };
Index: clangd/ClangdUnitStore.cpp
===================================================================
--- clangd/ClangdUnitStore.cpp
+++ clangd/ClangdUnitStore.cpp
@@ -9,6 +9,7 @@
 
 #include "ClangdUnitStore.h"
 #include "llvm/Support/Path.h"
+#include <algorithm>
 
 using namespace clang::clangd;
 using namespace clang;
@@ -25,6 +26,34 @@
   return Result;
 }
 
+CppFileCollection::RecreateResult
+CppFileCollection::recreateFileIfCompileCommandChanged(
+    PathRef File, PathRef ResourceDir, GlobalCompilationDatabase &CDB,
+    std::shared_ptr<PCHContainerOperations> PCHs,
+    IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
+  auto NewCommand = getCompileCommand(CDB, File, ResourceDir);
+
+  std::lock_guard<std::mutex> Lock(Mutex);
+
+  RecreateResult Result;
+  auto It = OpenedFiles.find(File);
+  if (It == OpenedFiles.end()) {
+    It = OpenedFiles
+             .try_emplace(File, CppFile::Create(File, std::move(NewCommand),
+                                                std::move(PCHs)))
+             .first;
+    Result.RemovedFile = nullptr;
+  } else if (!compileCommandsAreEqual(It->second->getCompileCommand(),
+                                      NewCommand)) {
+    Result.RemovedFile = std::move(It->second);
+    It->second = CppFile::Create(File, std::move(NewCommand), std::move(PCHs));
+  } else {
+    Result.RemovedFile = nullptr;
+  }
+  Result.FileInCollection = It->second;
+  return Result;
+}
+
 tooling::CompileCommand
 CppFileCollection::getCompileCommand(GlobalCompilationDatabase &CDB,
                                      PathRef File, PathRef ResourceDir) {
@@ -39,3 +68,12 @@
                                          std::string(ResourceDir));
   return std::move(Commands.front());
 }
+
+bool CppFileCollection::compileCommandsAreEqual(
+    tooling::CompileCommand const &LHS, tooling::CompileCommand const &RHS) {
+  // tooling::CompileCommand.Output is ignored, it's not relevant for clangd.
+  return LHS.Directory == RHS.Directory &&
+         LHS.CommandLine.size() == RHS.CommandLine.size() &&
+         std::equal(LHS.CommandLine.begin(), LHS.CommandLine.end(),
+                    RHS.CommandLine.begin());
+}
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -192,10 +192,13 @@
   std::future<void> addDocument(PathRef File, StringRef Contents);
   /// Remove \p File from list of tracked files, schedule a request to free
   /// resources associated with it.
-  /// \return A future that will become ready the file is removed and all
-  /// associated reosources are freed.
+  /// \return A future that will become ready when the file is removed and all
+  /// associated resources are freed.
   std::future<void> removeDocument(PathRef File);
   /// Force \p File to be reparsed using the latest contents.
+  /// Will also check if CompileCommand, provided by GlobalCompilationDatabase
+  /// for \p File has changed. If it has, will remove currently stored Preamble
+  /// and AST and rebuild them from scratch.
   std::future<void> forceReparse(PathRef File);
 
   /// Run code completion for \p File at \p Pos. If \p OverridenContents is not
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -154,9 +154,20 @@
 }
 
 std::future<void> ClangdServer::forceReparse(PathRef File) {
-  // The addDocument schedules the reparse even if the contents of the file
-  // never changed, so we just call it here.
-  return addDocument(File, getDocument(File));
+  auto FileContents = DraftMgr.getDraft(File);
+  assert(FileContents.Draft &&
+         "forceReparse() was called for non-added document");
+
+  auto TaggedFS = FSProvider.getTaggedFileSystem(File);
+  auto Recreated = Units.recreateFileIfCompileCommandChanged(
+      File, ResourceDir, CDB, PCHs, TaggedFS.Value);
+
+  // Note that std::future from this cleanup action is ignored.
+  scheduleCancelRebuild(std::move(Recreated.RemovedFile));
+  // Schedule a reparse.
+  return scheduleReparseAndDiags(File, std::move(FileContents),
+                                 std::move(Recreated.FileInCollection),
+                                 std::move(TaggedFS));
 }
 
 Tagged<std::vector<CompletionItem>>
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to