[clang-tools-extra] [clangd] [Modules] Support Reusable Modules Builder (PR #106683)

kadir çetinkaya via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 8 05:46:22 PST 2024


================
@@ -316,36 +294,205 @@ llvm::Error buildModuleFile(llvm::StringRef ModuleName,
   if (Clang->getDiagnostics().hasErrorOccurred())
     return llvm::createStringError("Compilation failed");
 
-  BuiltModuleFiles.addModuleFile(ModuleName, Inputs.CompileCommand.Output);
-  return llvm::Error::success();
+  return ModuleFile{ModuleName, Inputs.CompileCommand.Output};
+}
+
+bool ReusablePrerequisiteModules::canReuse(
+    const CompilerInvocation &CI,
+    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) const {
+  if (RequiredModules.empty())
+    return true;
+
+  SmallVector<StringRef> BMIPaths;
+  for (auto &MF : RequiredModules)
+    BMIPaths.push_back(MF->getModuleFilePath());
+  return IsModuleFilesUpToDate(BMIPaths, *this, VFS);
+}
+
+class ModuleFileCache {
+public:
+  ModuleFileCache(const GlobalCompilationDatabase &CDB) : CDB(CDB) {}
+
+  llvm::Error
+  getOrBuildModuleFile(StringRef ModuleName, const ThreadsafeFS &TFS,
+                       ProjectModules &MDB,
+                       ReusablePrerequisiteModules &RequiredModules);
+  const GlobalCompilationDatabase &getCDB() const { return CDB; }
+
+  std::shared_ptr<ModuleFile>
+  getValidModuleFile(StringRef ModuleName, ProjectModules &MDB,
+                     const ThreadsafeFS &TFS,
+                     PrerequisiteModules &BuiltModuleFiles);
+
+  void add(StringRef ModuleName, std::shared_ptr<ModuleFile> ModuleFile) {
+    std::lock_guard<std::mutex> _(ModuleFilesMutex);
+
+    ModuleFiles.insert_or_assign(ModuleName, ModuleFile);
+  }
+
+private:
+  const GlobalCompilationDatabase &CDB;
+
+  llvm::StringMap<std::shared_ptr<ModuleFile>> ModuleFiles;
+  // Mutex to guard accesses to ModuleFiles.
+  std::mutex ModuleFilesMutex;
+};
+
+/// Collect the directly and indirectly required module names for \param
+/// ModuleName. The \param ModuleName is guaranteed to be the first element in
+/// \param ModuleNames.
+void getAllRequiredModules(ProjectModules &MDB, StringRef ModuleName,
+                           llvm::SmallVector<StringRef> &ModuleNames) {
+  std::queue<StringRef> Worklist;
+  llvm::StringSet<> ModuleNamesSet;
+  Worklist.push(ModuleName);
+
+  while (!Worklist.empty()) {
+    StringRef CurrentModule = Worklist.front();
+    Worklist.pop();
+
+    if (!ModuleNamesSet.insert(CurrentModule).second)
+      continue;
+
+    ModuleNames.push_back(CurrentModule);
+
+    for (StringRef RequiredModuleName :
+         MDB.getRequiredModules(MDB.getSourceForModuleName(CurrentModule)))
+      if (!ModuleNamesSet.contains(RequiredModuleName))
+        Worklist.push(RequiredModuleName);
+  }
+}
+
+std::shared_ptr<ModuleFile>
+ModuleFileCache::getValidModuleFile(StringRef ModuleName, ProjectModules &MDB,
+                                    const ThreadsafeFS &TFS,
+                                    PrerequisiteModules &BuiltModuleFiles) {
+  {
+    std::lock_guard<std::mutex> _(ModuleFilesMutex);
+
+    if (ModuleFiles.find(ModuleName) == ModuleFiles.end())
+      return nullptr;
+  }
+
+  llvm::SmallVector<StringRef> ModuleNames;
+  getAllRequiredModules(MDB, ModuleName, ModuleNames);
+
+  llvm::SmallVector<std::shared_ptr<ModuleFile>> RequiredModuleFiles;
+
+  {
+    std::lock_guard<std::mutex> _(ModuleFilesMutex);
+
+    for (StringRef ModuleName : ModuleNames) {
+      auto Iter = ModuleFiles.find(ModuleName);
+      if (Iter == ModuleFiles.end())
+        return nullptr;
+
+      RequiredModuleFiles.push_back(Iter->second);
+    }
+  }
+
+  if (RequiredModuleFiles.empty())
+    return nullptr;
----------------
kadircet wrote:

if that's what you're worried about, i think we should be asserting on `ModuleNames` not being empty instead.

https://github.com/llvm/llvm-project/pull/106683


More information about the cfe-commits mailing list