[clang-tools-extra] r365634 - [clangd] Filter out non-governed files from broadcast

Kadir Cetinkaya via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 10 07:11:46 PDT 2019


Author: kadircet
Date: Wed Jul 10 07:11:46 2019
New Revision: 365634

URL: http://llvm.org/viewvc/llvm-project?rev=365634&view=rev
Log:
[clangd] Filter out non-governed files from broadcast

Summary:
This also turns off implicit discovery of additional compilation
databases.

Reviewers: sammccall

Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D64247

Modified:
    clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.cpp
    clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.h
    clang-tools-extra/trunk/clangd/QueryDriverDatabase.cpp
    clang-tools-extra/trunk/clangd/index/Background.cpp
    clang-tools-extra/trunk/clangd/unittests/ClangdTests.cpp
    clang-tools-extra/trunk/clangd/unittests/GlobalCompilationDatabaseTests.cpp
    clang-tools-extra/trunk/clangd/unittests/TestFS.cpp
    clang-tools-extra/trunk/clangd/unittests/TestFS.h

Modified: clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.cpp?rev=365634&r1=365633&r2=365634&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.cpp (original)
+++ clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.cpp Wed Jul 10 07:11:46 2019
@@ -8,12 +8,18 @@
 
 #include "GlobalCompilationDatabase.h"
 #include "Logger.h"
+#include "Path.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Tooling/ArgumentsAdjusters.h"
 #include "clang/Tooling/CompilationDatabase.h"
+#include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
+#include <string>
+#include <tuple>
+#include <vector>
 
 namespace clang {
 namespace clangd {
@@ -43,6 +49,16 @@ std::string getStandardResourceDir() {
   return CompilerInvocation::GetResourcesPath("clangd", (void *)&Dummy);
 }
 
+// Runs the given action on all parent directories of filename, starting from
+// deepest directory and going up to root. Stops whenever action succeeds.
+void actOnAllParentDirectories(PathRef FileName,
+                               llvm::function_ref<bool(PathRef)> Action) {
+  for (auto Path = llvm::sys::path::parent_path(FileName);
+       !Path.empty() && !Action(Path);
+       Path = llvm::sys::path::parent_path(Path))
+    ;
+}
+
 } // namespace
 
 static std::string getFallbackClangPath() {
@@ -81,60 +97,138 @@ DirectoryBasedGlobalCompilationDatabase:
     ~DirectoryBasedGlobalCompilationDatabase() = default;
 
 llvm::Optional<tooling::CompileCommand>
-DirectoryBasedGlobalCompilationDatabase::getCompileCommand(
-    PathRef File, ProjectInfo *Project) const {
-  if (auto CDB = getCDBForFile(File, Project)) {
-    auto Candidates = CDB->getCompileCommands(File);
-    if (!Candidates.empty()) {
-      return std::move(Candidates.front());
-    }
-  } else {
+DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File) const {
+  CDBLookupRequest Req;
+  Req.FileName = File;
+  Req.ShouldBroadcast = true;
+
+  auto Res = lookupCDB(Req);
+  if (!Res) {
     log("Failed to find compilation database for {0}", File);
+    return llvm::None;
   }
+
+  auto Candidates = Res->CDB->getCompileCommands(File);
+  if (!Candidates.empty())
+    return std::move(Candidates.front());
+
   return None;
 }
 
-std::pair<tooling::CompilationDatabase *, /*Cached*/ bool>
+std::pair<tooling::CompilationDatabase *, /*SentBroadcast*/ bool>
 DirectoryBasedGlobalCompilationDatabase::getCDBInDirLocked(PathRef Dir) const {
   // FIXME(ibiryukov): Invalidate cached compilation databases on changes
   auto CachedIt = CompilationDatabases.find(Dir);
   if (CachedIt != CompilationDatabases.end())
-    return {CachedIt->second.get(), true};
+    return {CachedIt->second.CDB.get(), CachedIt->second.SentBroadcast};
   std::string Error = "";
-  auto CDB = tooling::CompilationDatabase::loadFromDirectory(Dir, Error);
-  auto Result = CDB.get();
-  CompilationDatabases.insert(std::make_pair(Dir, std::move(CDB)));
+
+  CachedCDB Entry;
+  Entry.CDB = tooling::CompilationDatabase::loadFromDirectory(Dir, Error);
+  auto Result = Entry.CDB.get();
+  CompilationDatabases[Dir] = std::move(Entry);
+
   return {Result, false};
 }
 
-tooling::CompilationDatabase *
-DirectoryBasedGlobalCompilationDatabase::getCDBForFile(
-    PathRef File, ProjectInfo *Project) const {
-  namespace path = llvm::sys::path;
-  assert((path::is_absolute(File, path::Style::posix) ||
-          path::is_absolute(File, path::Style::windows)) &&
+llvm::Optional<DirectoryBasedGlobalCompilationDatabase::CDBLookupResult>
+DirectoryBasedGlobalCompilationDatabase::lookupCDB(
+    CDBLookupRequest Request) const {
+  assert(llvm::sys::path::is_absolute(Request.FileName) &&
          "path must be absolute");
 
-  tooling::CompilationDatabase *CDB = nullptr;
-  bool Cached = false;
-  std::lock_guard<std::mutex> Lock(Mutex);
+  CDBLookupResult Result;
+  bool SentBroadcast = false;
+
+  {
+    std::lock_guard<std::mutex> Lock(Mutex);
+    if (CompileCommandsDir) {
+      std::tie(Result.CDB, SentBroadcast) =
+          getCDBInDirLocked(*CompileCommandsDir);
+      Result.PI.SourceRoot = *CompileCommandsDir;
+    } else {
+      actOnAllParentDirectories(
+          Request.FileName, [this, &SentBroadcast, &Result](PathRef Path) {
+            std::tie(Result.CDB, SentBroadcast) = getCDBInDirLocked(Path);
+            Result.PI.SourceRoot = Path;
+            return Result.CDB != nullptr;
+          });
+    }
+
+    if (!Result.CDB)
+      return llvm::None;
+
+    // Mark CDB as broadcasted to make sure discovery is performed once.
+    if (Request.ShouldBroadcast && !SentBroadcast)
+      CompilationDatabases[Result.PI.SourceRoot].SentBroadcast = true;
+  }
+
+  // FIXME: Maybe make the following part async, since this can block retrieval
+  // of compile commands.
+  if (Request.ShouldBroadcast && !SentBroadcast)
+    broadcastCDB(Result);
+  return Result;
+}
+
+void DirectoryBasedGlobalCompilationDatabase::broadcastCDB(
+    CDBLookupResult Result) const {
+  assert(Result.CDB && "Trying to broadcast an invalid CDB!");
+
+  std::vector<std::string> AllFiles = Result.CDB->getAllFiles();
+  // We assume CDB in CompileCommandsDir owns all of its entries, since we don't
+  // perform any search in parent paths whenever it is set.
   if (CompileCommandsDir) {
-    std::tie(CDB, Cached) = getCDBInDirLocked(*CompileCommandsDir);
-    if (Project && CDB)
-      Project->SourceRoot = *CompileCommandsDir;
-  } else {
-    for (auto Path = path::parent_path(File); !CDB && !Path.empty();
-         Path = path::parent_path(Path)) {
-      std::tie(CDB, Cached) = getCDBInDirLocked(Path);
-      if (Project && CDB)
-        Project->SourceRoot = Path;
+    assert(*CompileCommandsDir == Result.PI.SourceRoot &&
+           "Trying to broadcast a CDB outside of CompileCommandsDir!");
+    OnCommandChanged.broadcast(std::move(AllFiles));
+    return;
+  }
+
+  llvm::StringMap<bool> DirectoryHasCDB;
+  {
+    std::lock_guard<std::mutex> Lock(Mutex);
+    // Uniquify all parent directories of all files.
+    for (llvm::StringRef File : AllFiles) {
+      actOnAllParentDirectories(File, [&](PathRef Path) {
+        auto It = DirectoryHasCDB.try_emplace(Path);
+        // Already seen this path, and all of its parents.
+        if (!It.second)
+          return true;
+
+        auto Res = getCDBInDirLocked(Path);
+        It.first->second = Res.first != nullptr;
+        return Path == Result.PI.SourceRoot;
+      });
     }
   }
-  // FIXME: getAllFiles() may return relative paths, we need absolute paths.
-  // Hopefully the fix is to change JSONCompilationDatabase and the interface.
-  if (CDB && !Cached)
-    OnCommandChanged.broadcast(CDB->getAllFiles());
-  return CDB;
+
+  std::vector<std::string> GovernedFiles;
+  for (llvm::StringRef File : AllFiles) {
+    // A file is governed by this CDB if lookup for the file would find it.
+    // Independent of whether it has an entry for that file or not.
+    actOnAllParentDirectories(File, [&](PathRef Path) {
+      if (DirectoryHasCDB.lookup(Path)) {
+        if (Path == Result.PI.SourceRoot)
+          GovernedFiles.push_back(File);
+        // Stop as soon as we hit a CDB.
+        return true;
+      }
+      return false;
+    });
+  }
+
+  OnCommandChanged.broadcast(std::move(GovernedFiles));
+}
+
+llvm::Optional<ProjectInfo>
+DirectoryBasedGlobalCompilationDatabase::getProjectInfo(PathRef File) const {
+  CDBLookupRequest Req;
+  Req.FileName = File;
+  Req.ShouldBroadcast = false;
+  auto Res = lookupCDB(Req);
+  if (!Res)
+    return llvm::None;
+  return Res->PI;
 }
 
 OverlayCDB::OverlayCDB(const GlobalCompilationDatabase *Base,
@@ -150,19 +244,16 @@ OverlayCDB::OverlayCDB(const GlobalCompi
 }
 
 llvm::Optional<tooling::CompileCommand>
-OverlayCDB::getCompileCommand(PathRef File, ProjectInfo *Project) const {
+OverlayCDB::getCompileCommand(PathRef File) const {
   llvm::Optional<tooling::CompileCommand> Cmd;
   {
     std::lock_guard<std::mutex> Lock(Mutex);
     auto It = Commands.find(File);
-    if (It != Commands.end()) {
-      if (Project)
-        Project->SourceRoot = "";
+    if (It != Commands.end())
       Cmd = It->second;
-    }
   }
   if (!Cmd && Base)
-    Cmd = Base->getCompileCommand(File, Project);
+    Cmd = Base->getCompileCommand(File);
   if (!Cmd)
     return llvm::None;
   adjustArguments(*Cmd, ResourceDir);
@@ -191,5 +282,17 @@ void OverlayCDB::setCompileCommand(
   OnCommandChanged.broadcast({File});
 }
 
+llvm::Optional<ProjectInfo> OverlayCDB::getProjectInfo(PathRef File) const {
+  {
+    std::lock_guard<std::mutex> Lock(Mutex);
+    auto It = Commands.find(File);
+    if (It != Commands.end())
+      return ProjectInfo{};
+  }
+  if (Base)
+    return Base->getProjectInfo(File);
+
+  return llvm::None;
+}
 } // namespace clangd
 } // namespace clang

Modified: clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.h?rev=365634&r1=365633&r2=365634&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.h (original)
+++ clang-tools-extra/trunk/clangd/GlobalCompilationDatabase.h Wed Jul 10 07:11:46 2019
@@ -40,9 +40,13 @@ public:
   virtual ~GlobalCompilationDatabase() = default;
 
   /// If there are any known-good commands for building this file, returns one.
-  /// If the ProjectInfo pointer is set, it will also be populated.
   virtual llvm::Optional<tooling::CompileCommand>
-  getCompileCommand(PathRef File, ProjectInfo * = nullptr) const = 0;
+  getCompileCommand(PathRef File) const = 0;
+
+  /// Finds the closest project to \p File.
+  virtual llvm::Optional<ProjectInfo> getProjectInfo(PathRef File) const {
+    return llvm::None;
+  }
 
   /// Makes a guess at how to build a file.
   /// The default implementation just runs clang on the file.
@@ -71,20 +75,40 @@ public:
 
   /// Scans File's parents looking for compilation databases.
   /// Any extra flags will be added.
+  /// Might trigger OnCommandChanged, if CDB wasn't broadcasted yet.
   llvm::Optional<tooling::CompileCommand>
-  getCompileCommand(PathRef File, ProjectInfo * = nullptr) const override;
+  getCompileCommand(PathRef File) const override;
+
+  /// Returns the path to first directory containing a compilation database in
+  /// \p File's parents.
+  llvm::Optional<ProjectInfo> getProjectInfo(PathRef File) const override;
 
 private:
-  tooling::CompilationDatabase *getCDBForFile(PathRef File,
-                                              ProjectInfo *) const;
-  std::pair<tooling::CompilationDatabase *, /*Cached*/ bool>
+  std::pair<tooling::CompilationDatabase *, /*SentBroadcast*/ bool>
   getCDBInDirLocked(PathRef File) const;
 
+  struct CDBLookupRequest {
+    PathRef FileName;
+    // Whether this lookup should trigger discovery of the CDB found.
+    bool ShouldBroadcast = false;
+  };
+  struct CDBLookupResult {
+    tooling::CompilationDatabase *CDB = nullptr;
+    ProjectInfo PI;
+  };
+  llvm::Optional<CDBLookupResult> lookupCDB(CDBLookupRequest Request) const;
+
+  // Performs broadcast on governed files.
+  void broadcastCDB(CDBLookupResult Res) const;
+
   mutable std::mutex Mutex;
   /// Caches compilation databases loaded from directories(keys are
   /// directories).
-  mutable llvm::StringMap<std::unique_ptr<clang::tooling::CompilationDatabase>>
-      CompilationDatabases;
+  struct CachedCDB {
+    std::unique_ptr<clang::tooling::CompilationDatabase> CDB = nullptr;
+    bool SentBroadcast = false;
+  };
+  mutable llvm::StringMap<CachedCDB> CompilationDatabases;
 
   /// Used for command argument pointing to folder where compile_commands.json
   /// is located.
@@ -109,8 +133,9 @@ public:
              llvm::Optional<std::string> ResourceDir = llvm::None);
 
   llvm::Optional<tooling::CompileCommand>
-  getCompileCommand(PathRef File, ProjectInfo * = nullptr) const override;
+  getCompileCommand(PathRef File) const override;
   tooling::CompileCommand getFallbackCommand(PathRef File) const override;
+  llvm::Optional<ProjectInfo> getProjectInfo(PathRef File) const override;
 
   /// Sets or clears the compilation command for a particular file.
   void

Modified: clang-tools-extra/trunk/clangd/QueryDriverDatabase.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/QueryDriverDatabase.cpp?rev=365634&r1=365633&r2=365634&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/QueryDriverDatabase.cpp (original)
+++ clang-tools-extra/trunk/clangd/QueryDriverDatabase.cpp Wed Jul 10 07:11:46 2019
@@ -215,8 +215,8 @@ public:
   }
 
   llvm::Optional<tooling::CompileCommand>
-  getCompileCommand(PathRef File, ProjectInfo *PI = nullptr) const override {
-    auto Cmd = Base->getCompileCommand(File, PI);
+  getCompileCommand(PathRef File) const override {
+    auto Cmd = Base->getCompileCommand(File);
     if (!Cmd || Cmd->CommandLine.empty())
       return Cmd;
 
@@ -240,6 +240,10 @@ public:
     return addSystemIncludes(*Cmd, SystemIncludes);
   }
 
+  llvm::Optional<ProjectInfo> getProjectInfo(PathRef File) const override {
+    return Base->getProjectInfo(File);
+  }
+
 private:
   mutable std::mutex Mu;
   // Caches includes extracted from a driver.

Modified: clang-tools-extra/trunk/clangd/index/Background.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/index/Background.cpp?rev=365634&r1=365633&r2=365634&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/index/Background.cpp (original)
+++ clang-tools-extra/trunk/clangd/index/Background.cpp Wed Jul 10 07:11:46 2019
@@ -619,11 +619,15 @@ BackgroundIndex::loadShards(std::vector<
   llvm::StringSet<> LoadedShards;
   Rebuilder.startLoading();
   for (const auto &File : ChangedFiles) {
-    ProjectInfo PI;
-    auto Cmd = CDB.getCompileCommand(File, &PI);
+    auto Cmd = CDB.getCompileCommand(File);
     if (!Cmd)
       continue;
-    BackgroundIndexStorage *IndexStorage = IndexStorageFactory(PI.SourceRoot);
+
+    std::string ProjectRoot;
+    if (auto PI = CDB.getProjectInfo(File))
+      ProjectRoot = std::move(PI->SourceRoot);
+
+    BackgroundIndexStorage *IndexStorage = IndexStorageFactory(ProjectRoot);
     auto Dependencies = loadShard(*Cmd, IndexStorage, LoadedShards);
     for (const auto &Dependency : Dependencies) {
       if (!Dependency.NeedsReIndexing || FilesToIndex.count(Dependency.Path))

Modified: clang-tools-extra/trunk/clangd/unittests/ClangdTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/ClangdTests.cpp?rev=365634&r1=365633&r2=365634&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/ClangdTests.cpp (original)
+++ clang-tools-extra/trunk/clangd/unittests/ClangdTests.cpp Wed Jul 10 07:11:46 2019
@@ -1064,7 +1064,7 @@ TEST_F(ClangdVFSTest, FallbackWhenPreamb
   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
 
   auto FooCpp = testPath("foo.cpp");
-   Annotations Code(R"cpp(
+  Annotations Code(R"cpp(
     namespace ns { int xyz; }
     using namespace ns;
     int main() {
@@ -1113,7 +1113,7 @@ TEST_F(ClangdVFSTest, FallbackWhenWaitin
         : CanReturnCommand(CanReturnCommand) {}
 
     llvm::Optional<tooling::CompileCommand>
-    getCompileCommand(PathRef File, ProjectInfo * = nullptr) const override {
+    getCompileCommand(PathRef File) const override {
       // FIXME: make this timeout and fail instead of waiting forever in case
       // something goes wrong.
       CanReturnCommand.wait();

Modified: clang-tools-extra/trunk/clangd/unittests/GlobalCompilationDatabaseTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/GlobalCompilationDatabaseTests.cpp?rev=365634&r1=365633&r2=365634&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/GlobalCompilationDatabaseTests.cpp (original)
+++ clang-tools-extra/trunk/clangd/unittests/GlobalCompilationDatabaseTests.cpp Wed Jul 10 07:11:46 2019
@@ -8,10 +8,21 @@
 
 #include "GlobalCompilationDatabase.h"
 
+#include "Path.h"
 #include "TestFS.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include <fstream>
+#include <string>
 
 namespace clang {
 namespace clangd {
@@ -20,8 +31,10 @@ using ::testing::AllOf;
 using ::testing::Contains;
 using ::testing::ElementsAre;
 using ::testing::EndsWith;
+using ::testing::IsEmpty;
 using ::testing::Not;
 using ::testing::StartsWith;
+using ::testing::UnorderedElementsAre;
 
 TEST(GlobalCompilationDatabaseTest, FallbackCommand) {
   DirectoryBasedGlobalCompilationDatabase DB(None);
@@ -50,13 +63,9 @@ class OverlayCDBTest : public ::testing:
   class BaseCDB : public GlobalCompilationDatabase {
   public:
     llvm::Optional<tooling::CompileCommand>
-    getCompileCommand(llvm::StringRef File,
-                      ProjectInfo *Project) const override {
-      if (File == testPath("foo.cc")) {
-        if (Project)
-          Project->SourceRoot = testRoot();
+    getCompileCommand(llvm::StringRef File) const override {
+      if (File == testPath("foo.cc"))
         return cmd(File, "-DA=1");
-      }
       return None;
     }
 
@@ -64,6 +73,10 @@ class OverlayCDBTest : public ::testing:
     getFallbackCommand(llvm::StringRef File) const override {
       return cmd(File, "-DA=2");
     }
+
+    llvm::Optional<ProjectInfo> getProjectInfo(PathRef File) const override {
+      return ProjectInfo{testRoot()};
+    }
   };
 
 protected:
@@ -153,6 +166,109 @@ TEST_F(OverlayCDBTest, Adjustments) {
                     Not(Contains("random-plugin"))));
 }
 
+TEST(GlobalCompilationDatabaseTest, DiscoveryWithNestedCDBs) {
+  const char *const CDBOuter =
+      R"cdb(
+      [
+        {
+          "file": "a.cc",
+          "command": "",
+          "directory": "{0}",
+        },
+        {
+          "file": "build/gen.cc",
+          "command": "",
+          "directory": "{0}",
+        },
+        {
+          "file": "build/gen2.cc",
+          "command": "",
+          "directory": "{0}",
+        }
+      ]
+      )cdb";
+  const char *const CDBInner =
+      R"cdb(
+      [
+        {
+          "file": "gen.cc",
+          "command": "",
+          "directory": "{0}/build",
+        }
+      ]
+      )cdb";
+  class CleaningFS {
+  public:
+    llvm::SmallString<128> Root;
+
+    CleaningFS() {
+      EXPECT_FALSE(
+          llvm::sys::fs::createUniqueDirectory("clangd-cdb-test", Root))
+          << "Failed to create unique directory";
+    }
+
+    ~CleaningFS() {
+      EXPECT_FALSE(llvm::sys::fs::remove_directories(Root))
+          << "Failed to cleanup " << Root;
+    }
+
+    void registerFile(PathRef RelativePath, llvm::StringRef Contents) {
+      llvm::SmallString<128> AbsPath(Root);
+      llvm::sys::path::append(AbsPath, RelativePath);
+
+      EXPECT_FALSE(llvm::sys::fs::create_directories(
+          llvm::sys::path::parent_path(AbsPath)))
+          << "Failed to create directories for: " << AbsPath;
+
+      std::error_code EC;
+      llvm::raw_fd_ostream OS(AbsPath, EC);
+      EXPECT_FALSE(EC) << "Failed to open " << AbsPath << " for writing";
+      OS << llvm::formatv(Contents.data(), Root);
+      OS.close();
+
+      EXPECT_FALSE(OS.has_error());
+    }
+  };
+
+  CleaningFS FS;
+  FS.registerFile("compile_commands.json", CDBOuter);
+  FS.registerFile("build/compile_commands.json", CDBInner);
+
+  // Note that gen2.cc goes missing with our following model, not sure this
+  // happens in practice though.
+  {
+    DirectoryBasedGlobalCompilationDatabase DB(llvm::None);
+    std::vector<std::string> DiscoveredFiles;
+    auto Sub =
+        DB.watch([&DiscoveredFiles](const std::vector<std::string> Changes) {
+          DiscoveredFiles = Changes;
+        });
+    DB.getCompileCommand((FS.Root + "/a.cc").str());
+    EXPECT_THAT(DiscoveredFiles, UnorderedElementsAre(EndsWith("a.cc")));
+
+    DB.getCompileCommand((FS.Root + "/build/gen.cc").str());
+    EXPECT_THAT(DiscoveredFiles, UnorderedElementsAre(EndsWith("gen.cc")));
+  }
+
+  // With a custom compile commands dir.
+  {
+    DirectoryBasedGlobalCompilationDatabase DB(FS.Root.str().str());
+    std::vector<std::string> DiscoveredFiles;
+    auto Sub =
+        DB.watch([&DiscoveredFiles](const std::vector<std::string> Changes) {
+          DiscoveredFiles = Changes;
+        });
+    DB.getCompileCommand((FS.Root + "/a.cc").str());
+    EXPECT_THAT(DiscoveredFiles,
+                UnorderedElementsAre(EndsWith("a.cc"), EndsWith("gen.cc"),
+                                     EndsWith("gen2.cc")));
+
+    DiscoveredFiles.clear();
+    DB.getCompileCommand((FS.Root + "/build/gen.cc").str());
+    EXPECT_THAT(DiscoveredFiles, IsEmpty());
+  }
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang

Modified: clang-tools-extra/trunk/clangd/unittests/TestFS.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/TestFS.cpp?rev=365634&r1=365633&r2=365634&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/TestFS.cpp (original)
+++ clang-tools-extra/trunk/clangd/unittests/TestFS.cpp Wed Jul 10 07:11:46 2019
@@ -6,7 +6,11 @@
 //
 //===----------------------------------------------------------------------===//
 #include "TestFS.h"
+#include "GlobalCompilationDatabase.h"
+#include "Path.h"
 #include "URI.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/Path.h"
@@ -36,9 +40,13 @@ MockCompilationDatabase::MockCompilation
   // -ffreestanding avoids implicit stdc-predef.h.
 }
 
+llvm::Optional<ProjectInfo>
+MockCompilationDatabase::getProjectInfo(PathRef File) const {
+  return ProjectInfo{Directory};
+};
+
 llvm::Optional<tooling::CompileCommand>
-MockCompilationDatabase::getCompileCommand(PathRef File,
-                                           ProjectInfo *Project) const {
+MockCompilationDatabase::getCompileCommand(PathRef File) const {
   if (ExtraClangFlags.empty())
     return None;
 
@@ -57,8 +65,6 @@ MockCompilationDatabase::getCompileComma
     CommandLine.push_back(RelativeFilePath.str());
   }
 
-  if (Project)
-    Project->SourceRoot = Directory;
   return {tooling::CompileCommand(Directory != llvm::StringRef()
                                       ? Directory
                                       : llvm::sys::path::parent_path(File),

Modified: clang-tools-extra/trunk/clangd/unittests/TestFS.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/TestFS.h?rev=365634&r1=365633&r2=365634&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/TestFS.h (original)
+++ clang-tools-extra/trunk/clangd/unittests/TestFS.h Wed Jul 10 07:11:46 2019
@@ -12,6 +12,8 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTFS_H
 #define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTFS_H
 #include "ClangdServer.h"
+#include "GlobalCompilationDatabase.h"
+#include "Path.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/VirtualFileSystem.h"
@@ -48,7 +50,9 @@ public:
                           StringRef RelPathPrefix = StringRef());
 
   llvm::Optional<tooling::CompileCommand>
-  getCompileCommand(PathRef File, ProjectInfo * = nullptr) const override;
+  getCompileCommand(PathRef File) const override;
+
+  llvm::Optional<ProjectInfo> getProjectInfo(PathRef File) const override;
 
   std::vector<std::string> ExtraClangFlags;
 




More information about the cfe-commits mailing list