DaanDeMeyer updated this revision to Diff 305489.
DaanDeMeyer added a comment.

Fix all the bugs after doing some proper testing.

One thing we don't handle yet is header files since those don't appear in the 
compilation database. Maybe we need to add prebuilding for those as well?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D91509/new/

https://reviews.llvm.org/D91509

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/ClangdServer.h
  clang-tools-extra/clangd/Config.h
  clang-tools-extra/clangd/ConfigCompile.cpp
  clang-tools-extra/clangd/ConfigFragment.h
  clang-tools-extra/clangd/ConfigYAML.cpp
  clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
  clang-tools-extra/clangd/GlobalCompilationDatabase.h
  clang-tools-extra/clangd/QueryDriverDatabase.cpp
  clang-tools-extra/clangd/TUScheduler.cpp
  clang-tools-extra/clangd/TUScheduler.h
  clang-tools-extra/clangd/unittests/ClangdTests.cpp
  clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
  clang-tools-extra/clangd/unittests/TestFS.cpp
  clang-tools-extra/clangd/unittests/TestFS.h

Index: clang-tools-extra/clangd/unittests/TestFS.h
===================================================================
--- clang-tools-extra/clangd/unittests/TestFS.h
+++ clang-tools-extra/clangd/unittests/TestFS.h
@@ -65,6 +65,8 @@
   llvm::Optional<tooling::CompileCommand>
   getCompileCommand(PathRef File) const override;
 
+  tooling::CompilationDatabase *lookupCDB(PathRef File) const override;
+
   llvm::Optional<ProjectInfo> getProjectInfo(PathRef File) const override;
 
   std::vector<std::string> ExtraClangFlags;
Index: clang-tools-extra/clangd/unittests/TestFS.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/TestFS.cpp
+++ clang-tools-extra/clangd/unittests/TestFS.cpp
@@ -71,6 +71,11 @@
                                   FileName, std::move(CommandLine), "")};
 }
 
+tooling::CompilationDatabase *
+MockCompilationDatabase::lookupCDB(PathRef File) const {
+  return nullptr;
+}
+
 const char *testRoot() {
 #ifdef _WIN32
   return "C:\\clangd-test";
Index: clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
+++ clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
@@ -70,6 +70,10 @@
       return None;
     }
 
+    tooling::CompilationDatabase *lookupCDB(PathRef File) const override {
+      return nullptr;
+    }
+
     tooling::CompileCommand
     getFallbackCommand(llvm::StringRef File) const override {
       return cmd(File, "-DA=2");
Index: clang-tools-extra/clangd/unittests/ClangdTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/ClangdTests.cpp
+++ clang-tools-extra/clangd/unittests/ClangdTests.cpp
@@ -1123,6 +1123,10 @@
                                       FileName, std::move(CommandLine), "")};
     }
 
+    tooling::CompilationDatabase *lookupCDB(PathRef File) const override {
+      return nullptr;
+    }
+
     std::vector<std::string> ExtraClangFlags;
 
   private:
Index: clang-tools-extra/clangd/TUScheduler.h
===================================================================
--- clang-tools-extra/clangd/TUScheduler.h
+++ clang-tools-extra/clangd/TUScheduler.h
@@ -231,6 +231,8 @@
   /// Returns true if the file was not previously tracked.
   bool update(PathRef File, ParseInputs Inputs, WantDiagnostics WD);
 
+  bool hasFile(PathRef File);
+
   /// Remove \p File from the list of tracked files and schedule removal of its
   /// resources. Pending diagnostics for closed files may not be delivered, even
   /// if requested with WantDiags::Auto or WantDiags::Yes.
Index: clang-tools-extra/clangd/TUScheduler.cpp
===================================================================
--- clang-tools-extra/clangd/TUScheduler.cpp
+++ clang-tools-extra/clangd/TUScheduler.cpp
@@ -627,11 +627,15 @@
       FileInputs = Inputs;
     }
 
-    log("ASTWorker building file {0} version {1} with command {2}\n[{3}]\n{4}",
+    log("ASTWorker building file {0} version {1}", FileName, Inputs.Version);
+    vlog("ASTWorker building file {0} version {1} with command {2}\n[{3}]\n{4}",
         FileName, Inputs.Version, Inputs.CompileCommand.Heuristic,
         Inputs.CompileCommand.Directory,
         llvm::join(Inputs.CompileCommand.CommandLine, " "));
 
+    if (!InputsAreTheSame)
+      log("ASTWorker inputs are not the same, cached AST is invalidated");
+
     StoreDiags CompilerInvocationDiagConsumer;
     std::vector<std::string> CC1Args;
     std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation(
@@ -1289,6 +1293,8 @@
   return NewFile;
 }
 
+bool TUScheduler::hasFile(PathRef File) { return Files[File] != nullptr; }
+
 void TUScheduler::remove(PathRef File) {
   bool Removed = Files.erase(File);
   if (!Removed)
Index: clang-tools-extra/clangd/QueryDriverDatabase.cpp
===================================================================
--- clang-tools-extra/clangd/QueryDriverDatabase.cpp
+++ clang-tools-extra/clangd/QueryDriverDatabase.cpp
@@ -277,6 +277,10 @@
     return addSystemIncludes(*Cmd, SystemIncludes);
   }
 
+  tooling::CompilationDatabase *lookupCDB(PathRef File) const override {
+    return Base->lookupCDB(File);
+  }
+
   llvm::Optional<ProjectInfo> getProjectInfo(PathRef File) const override {
     return Base->getProjectInfo(File);
   }
Index: clang-tools-extra/clangd/GlobalCompilationDatabase.h
===================================================================
--- clang-tools-extra/clangd/GlobalCompilationDatabase.h
+++ clang-tools-extra/clangd/GlobalCompilationDatabase.h
@@ -40,6 +40,8 @@
   virtual llvm::Optional<tooling::CompileCommand>
   getCompileCommand(PathRef File) const = 0;
 
+  virtual tooling::CompilationDatabase *lookupCDB(PathRef File) const = 0;
+
   /// Finds the closest project to \p File.
   virtual llvm::Optional<ProjectInfo> getProjectInfo(PathRef File) const {
     return llvm::None;
@@ -76,6 +78,8 @@
   llvm::Optional<tooling::CompileCommand>
   getCompileCommand(PathRef File) const override;
 
+  virtual tooling::CompilationDatabase *lookupCDB(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;
@@ -132,6 +136,9 @@
 
   llvm::Optional<tooling::CompileCommand>
   getCompileCommand(PathRef File) const override;
+
+  tooling::CompilationDatabase *lookupCDB(PathRef File) const override;
+
   tooling::CompileCommand getFallbackCommand(PathRef File) const override;
   /// Project info is gathered purely from the inner compilation database to
   /// ensure consistency.
Index: clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
===================================================================
--- clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -68,6 +68,20 @@
 
 llvm::Optional<tooling::CompileCommand>
 DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File) const {
+  auto *CDB = lookupCDB(File);
+  if (!CDB) {
+    return llvm::None;
+  }
+
+  auto Candidates = CDB->getCompileCommands(File);
+  if (!Candidates.empty())
+    return std::move(Candidates.front());
+
+  return None;
+}
+
+tooling::CompilationDatabase *
+DirectoryBasedGlobalCompilationDatabase::lookupCDB(PathRef File) const {
   CDBLookupRequest Req;
   Req.FileName = File;
   Req.ShouldBroadcast = true;
@@ -75,14 +89,10 @@
   auto Res = lookupCDB(Req);
   if (!Res) {
     log("Failed to find compilation database for {0}", File);
-    return llvm::None;
+    return nullptr;
   }
 
-  auto Candidates = Res->CDB->getCompileCommands(File);
-  if (!Candidates.empty())
-    return std::move(Candidates.front());
-
-  return None;
+  return Res->CDB;
 }
 
 // For platforms where paths are case-insensitive (but case-preserving),
@@ -270,6 +280,10 @@
   return Cmd;
 }
 
+tooling::CompilationDatabase *OverlayCDB::lookupCDB(PathRef File) const {
+  return Base ? Base->lookupCDB(File) : nullptr;
+}
+
 tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File) const {
   auto Cmd = Base ? Base->getFallbackCommand(File)
                   : GlobalCompilationDatabase::getFallbackCommand(File);
Index: clang-tools-extra/clangd/ConfigYAML.cpp
===================================================================
--- clang-tools-extra/clangd/ConfigYAML.cpp
+++ clang-tools-extra/clangd/ConfigYAML.cpp
@@ -40,6 +40,7 @@
     Dict.handle("CompileFlags", [&](Node &N) { parse(F.CompileFlags, N); });
     Dict.handle("Index", [&](Node &N) { parse(F.Index, N); });
     Dict.handle("Style", [&](Node &N) { parse(F.Style, N); });
+    Dict.handle("AST", [&](Node &N) { parse(F.AST, N); });
     Dict.parse(N);
     return !(N.failed() || HadError);
   }
@@ -89,6 +90,12 @@
     Dict.parse(N);
   }
 
+  void parse(Fragment::ASTBlock &F, Node &N) {
+    DictParser Dict("AST", this);
+    Dict.handle("Build", [&](Node &N) { F.Build = scalarValue(N, "Build"); });
+    Dict.parse(N);
+  }
+
   // Helper for parsing mapping nodes (dictionaries).
   // We don't use YamlIO as we want to control over unknown keys.
   class DictParser {
Index: clang-tools-extra/clangd/ConfigFragment.h
===================================================================
--- clang-tools-extra/clangd/ConfigFragment.h
+++ clang-tools-extra/clangd/ConfigFragment.h
@@ -174,6 +174,16 @@
     std::vector<Located<std::string>> FullyQualifiedNamespaces;
   };
   StyleBlock Style;
+
+  struct ASTBlock {
+    /// Controls whether clangd prebuilds the AST for the current file. When
+    /// opening a file for the first time. clangd iterates over all the files in
+    /// its compilation database and prebuilds the AST for those that have this
+    /// option set to "PreBuild". Legal values are "PreBuild" or "OnDemand".
+    /// Default is "OnDemand".
+    llvm::Optional<Located<std::string>> Build;
+  };
+  ASTBlock AST;
 };
 
 } // namespace config
Index: clang-tools-extra/clangd/ConfigCompile.cpp
===================================================================
--- clang-tools-extra/clangd/ConfigCompile.cpp
+++ clang-tools-extra/clangd/ConfigCompile.cpp
@@ -157,6 +157,7 @@
     compile(std::move(F.If));
     compile(std::move(F.CompileFlags));
     compile(std::move(F.Index));
+    compile(std::move(F.AST));
   }
 
   void compile(Fragment::IfBlock &&F) {
@@ -264,6 +265,18 @@
     }
   }
 
+  void compile(Fragment::ASTBlock &&F) {
+    if (F.Build) {
+      if (auto Val = compileEnum<Config::ASTPolicy>("Build", **F.Build)
+                         .map("OnDemand", Config::ASTPolicy::OnDemand)
+                         .map("PreBuild", Config::ASTPolicy::PreBuild)
+                         .value()) {
+        Out.Apply.push_back(
+            [Val](const Params &, Config &C) { C.AST.Build = *Val; });
+      }
+    }
+  }
+
   constexpr static llvm::SourceMgr::DiagKind Error = llvm::SourceMgr::DK_Error;
   constexpr static llvm::SourceMgr::DiagKind Warning =
       llvm::SourceMgr::DK_Warning;
Index: clang-tools-extra/clangd/Config.h
===================================================================
--- clang-tools-extra/clangd/Config.h
+++ clang-tools-extra/clangd/Config.h
@@ -70,6 +70,13 @@
     // ::). All nested namespaces are affected as well.
     std::vector<std::string> FullyQualifiedNamespaces;
   } Style;
+
+  enum class ASTPolicy { PreBuild, OnDemand };
+  /// Controls AST prebuild behavior.
+  struct {
+    /// Whether this AST should be prebuild.
+    ASTPolicy Build = ASTPolicy::OnDemand;
+  } AST;
 };
 
 } // namespace clangd
Index: clang-tools-extra/clangd/ClangdServer.h
===================================================================
--- clang-tools-extra/clangd/ClangdServer.h
+++ clang-tools-extra/clangd/ClangdServer.h
@@ -357,6 +357,7 @@
   Context createProcessingContext(PathRef) const;
   config::Provider *ConfigProvider = nullptr;
 
+  const GlobalCompilationDatabase &CDB;
   const ThreadsafeFS &TFS;
 
   Path ResourceDir;
Index: clang-tools-extra/clangd/ClangdServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdServer.cpp
+++ clang-tools-extra/clangd/ClangdServer.cpp
@@ -172,7 +172,7 @@
 ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
                            const ThreadsafeFS &TFS, const Options &Opts,
                            Callbacks *Callbacks)
-    : ConfigProvider(Opts.ConfigProvider), TFS(TFS),
+    : ConfigProvider(Opts.ConfigProvider), CDB(CDB), TFS(TFS),
       DynamicIdx(Opts.BuildDynamicSymbolIndex
                      ? new FileIndex(Opts.HeavyweightDynamicSymbolIndex,
                                      Opts.CollectMainFileRefs)
@@ -257,7 +257,7 @@
   Inputs.Contents = std::string(Contents);
   Inputs.Version = Version.str();
   Inputs.ForceRebuild = ForceRebuild;
-  Inputs.Opts = std::move(Opts);
+  Inputs.Opts = Opts;
   Inputs.Index = Index;
   Inputs.Opts.BuildRecoveryAST = BuildRecoveryAST;
   Inputs.Opts.PreserveRecoveryASTType = PreserveRecoveryASTType;
@@ -265,6 +265,23 @@
   // If we loaded Foo.h, we want to make sure Foo.cpp is indexed.
   if (NewFile && BackgroundIdx)
     BackgroundIdx->boostRelated(File);
+
+  if (NewFile) {
+    if (auto *InternalCDB = CDB.lookupCDB(File)) {
+      for (const auto &CDBFile : InternalCDB->getAllFiles()) {
+        if (CDBFile != File && !WorkScheduler.hasFile(CDBFile)) {
+          WithContext WithContext(createProcessingContext(CDBFile));
+          if (Config::current().AST.Build == Config::ASTPolicy::PreBuild) {
+            auto Buffer = llvm::MemoryBuffer::getFile(CDBFile);
+            Inputs.Contents = std::string(Buffer->get()->getBuffer());
+            WorkScheduler.update(CDBFile, Inputs, WantDiagnostics::No);
+            if (BackgroundIdx)
+              BackgroundIdx->boostRelated(CDBFile);
+          }
+        }
+      }
+    }
+  }
 }
 
 void ClangdServer::removeDocument(PathRef File) { WorkScheduler.remove(File); }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to