brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.0 KiB · 0177a17 Raw
691 lines · cpp
1//===----------------- ModulesBuilder.cpp ------------------------*- C++-*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "ModulesBuilder.h"10#include "Compiler.h"11#include "support/Logger.h"12#include "clang/Frontend/FrontendAction.h"13#include "clang/Frontend/FrontendActions.h"14#include "clang/Serialization/ASTReader.h"15#include "clang/Serialization/ModuleCache.h"16#include "llvm/ADT/ScopeExit.h"17#include "llvm/Support/CommandLine.h"18 19#include <queue>20 21namespace clang {22namespace clangd {23 24namespace {25 26llvm::cl::opt<bool> DebugModulesBuilder(27    "debug-modules-builder",28    llvm::cl::desc("Don't remove clangd's built module files for debugging. "29                   "Remember to remove them later after debugging."),30    llvm::cl::init(false));31 32// Create a path to store module files. Generally it should be:33//34//   {TEMP_DIRS}/clangd/module_files/{hashed-file-name}-%%-%%-%%-%%-%%-%%/.35//36// {TEMP_DIRS} is the temporary directory for the system, e.g., "/var/tmp"37// or "C:/TEMP".38//39// '%%' means random value to make the generated path unique.40//41// \param MainFile is used to get the root of the project from global42// compilation database.43//44// TODO: Move these module fils out of the temporary directory if the module45// files are persistent.46llvm::SmallString<256> getUniqueModuleFilesPath(PathRef MainFile) {47  llvm::SmallString<128> HashedPrefix = llvm::sys::path::filename(MainFile);48  // There might be multiple files with the same name in a project. So appending49  // the hash value of the full path to make sure they won't conflict.50  HashedPrefix += std::to_string(llvm::hash_value(MainFile));51 52  llvm::SmallString<256> ResultPattern;53 54  llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/true,55                                         ResultPattern);56 57  llvm::sys::path::append(ResultPattern, "clangd");58  llvm::sys::path::append(ResultPattern, "module_files");59 60  llvm::sys::path::append(ResultPattern, HashedPrefix);61 62  ResultPattern.append("-%%-%%-%%-%%-%%-%%");63 64  llvm::SmallString<256> Result;65  llvm::sys::fs::createUniquePath(ResultPattern, Result,66                                  /*MakeAbsolute=*/false);67 68  llvm::sys::fs::create_directories(Result);69  return Result;70}71 72// Get a unique module file path under \param ModuleFilesPrefix.73std::string getModuleFilePath(llvm::StringRef ModuleName,74                              PathRef ModuleFilesPrefix) {75  llvm::SmallString<256> ModuleFilePath(ModuleFilesPrefix);76  auto [PrimaryModuleName, PartitionName] = ModuleName.split(':');77  llvm::sys::path::append(ModuleFilePath, PrimaryModuleName);78  if (!PartitionName.empty()) {79    ModuleFilePath.append("-");80    ModuleFilePath.append(PartitionName);81  }82 83  ModuleFilePath.append(".pcm");84  return std::string(ModuleFilePath);85}86 87// FailedPrerequisiteModules - stands for the PrerequisiteModules which has88// errors happened during the building process.89class FailedPrerequisiteModules : public PrerequisiteModules {90public:91  ~FailedPrerequisiteModules() override = default;92 93  // We shouldn't adjust the compilation commands based on94  // FailedPrerequisiteModules.95  void adjustHeaderSearchOptions(HeaderSearchOptions &Options) const override {96  }97 98  // FailedPrerequisiteModules can never be reused.99  bool100  canReuse(const CompilerInvocation &CI,101           llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) const override {102    return false;103  }104};105 106/// Represents a reference to a module file (*.pcm).107class ModuleFile {108protected:109  ModuleFile(StringRef ModuleName, PathRef ModuleFilePath)110      : ModuleName(ModuleName.str()), ModuleFilePath(ModuleFilePath.str()) {}111 112public:113  ModuleFile() = delete;114 115  ModuleFile(const ModuleFile &) = delete;116  ModuleFile operator=(const ModuleFile &) = delete;117 118  // The move constructor is needed for llvm::SmallVector.119  ModuleFile(ModuleFile &&Other)120      : ModuleName(std::move(Other.ModuleName)),121        ModuleFilePath(std::move(Other.ModuleFilePath)) {122    Other.ModuleName.clear();123    Other.ModuleFilePath.clear();124  }125 126  ModuleFile &operator=(ModuleFile &&Other) {127    if (this == &Other)128      return *this;129 130    this->~ModuleFile();131    new (this) ModuleFile(std::move(Other));132    return *this;133  }134  virtual ~ModuleFile() = default;135 136  StringRef getModuleName() const { return ModuleName; }137 138  StringRef getModuleFilePath() const { return ModuleFilePath; }139 140protected:141  std::string ModuleName;142  std::string ModuleFilePath;143};144 145/// Represents a prebuilt module file which is not owned by us.146class PrebuiltModuleFile : public ModuleFile {147private:148  // private class to make sure the class can only be constructed by member149  // functions.150  struct CtorTag {};151 152public:153  PrebuiltModuleFile(StringRef ModuleName, PathRef ModuleFilePath, CtorTag)154      : ModuleFile(ModuleName, ModuleFilePath) {}155 156  static std::shared_ptr<PrebuiltModuleFile> make(StringRef ModuleName,157                                                  PathRef ModuleFilePath) {158    return std::make_shared<PrebuiltModuleFile>(ModuleName, ModuleFilePath,159                                                CtorTag{});160  }161};162 163/// Represents a module file built by us. We're responsible to remove it.164class BuiltModuleFile : public ModuleFile {165private:166  // private class to make sure the class can only be constructed by member167  // functions.168  struct CtorTag {};169 170public:171  BuiltModuleFile(StringRef ModuleName, PathRef ModuleFilePath, CtorTag)172      : ModuleFile(ModuleName, ModuleFilePath) {}173 174  static std::shared_ptr<BuiltModuleFile> make(StringRef ModuleName,175                                               PathRef ModuleFilePath) {176    return std::make_shared<BuiltModuleFile>(ModuleName, ModuleFilePath,177                                             CtorTag{});178  }179 180  virtual ~BuiltModuleFile() {181    if (!ModuleFilePath.empty() && !DebugModulesBuilder)182      llvm::sys::fs::remove(ModuleFilePath);183  }184};185 186// ReusablePrerequisiteModules - stands for PrerequisiteModules for which all187// the required modules are built successfully. All the module files188// are owned by the modules builder.189class ReusablePrerequisiteModules : public PrerequisiteModules {190public:191  ReusablePrerequisiteModules() = default;192 193  ReusablePrerequisiteModules(const ReusablePrerequisiteModules &Other) =194      default;195  ReusablePrerequisiteModules &196  operator=(const ReusablePrerequisiteModules &) = default;197  ReusablePrerequisiteModules(ReusablePrerequisiteModules &&) = delete;198  ReusablePrerequisiteModules199  operator=(ReusablePrerequisiteModules &&) = delete;200 201  ~ReusablePrerequisiteModules() override = default;202 203  void adjustHeaderSearchOptions(HeaderSearchOptions &Options) const override {204    // Appending all built module files.205    for (const auto &RequiredModule : RequiredModules)206      Options.PrebuiltModuleFiles.insert_or_assign(207          RequiredModule->getModuleName().str(),208          RequiredModule->getModuleFilePath().str());209  }210 211  std::string getAsString() const {212    std::string Result;213    llvm::raw_string_ostream OS(Result);214    for (const auto &MF : RequiredModules) {215      OS << "-fmodule-file=" << MF->getModuleName() << "="216         << MF->getModuleFilePath() << " ";217    }218    return Result;219  }220 221  bool canReuse(const CompilerInvocation &CI,222                llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) const override;223 224  bool isModuleUnitBuilt(llvm::StringRef ModuleName) const {225    return BuiltModuleNames.contains(ModuleName);226  }227 228  void addModuleFile(std::shared_ptr<const ModuleFile> MF) {229    BuiltModuleNames.insert(MF->getModuleName());230    RequiredModules.emplace_back(std::move(MF));231  }232 233private:234  llvm::SmallVector<std::shared_ptr<const ModuleFile>, 8> RequiredModules;235  // A helper class to speedup the query if a module is built.236  llvm::StringSet<> BuiltModuleNames;237};238 239bool IsModuleFileUpToDate(PathRef ModuleFilePath,240                          const PrerequisiteModules &RequisiteModules,241                          llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {242  HeaderSearchOptions HSOpts;243  RequisiteModules.adjustHeaderSearchOptions(HSOpts);244  HSOpts.ForceCheckCXX20ModulesInputFiles = true;245  HSOpts.ValidateASTInputFilesContent = true;246 247  clang::clangd::IgnoreDiagnostics IgnoreDiags;248  DiagnosticOptions DiagOpts;249  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =250      CompilerInstance::createDiagnostics(*VFS, DiagOpts, &IgnoreDiags,251                                          /*ShouldOwnClient=*/false);252 253  LangOptions LangOpts;254  LangOpts.SkipODRCheckInGMF = true;255 256  FileManager FileMgr(FileSystemOptions(), VFS);257 258  SourceManager SourceMgr(*Diags, FileMgr);259 260  HeaderSearch HeaderInfo(HSOpts, SourceMgr, *Diags, LangOpts,261                          /*Target=*/nullptr);262 263  PreprocessorOptions PPOpts;264  TrivialModuleLoader ModuleLoader;265  Preprocessor PP(PPOpts, *Diags, LangOpts, SourceMgr, HeaderInfo,266                  ModuleLoader);267 268  IntrusiveRefCntPtr<ModuleCache> ModCache = createCrossProcessModuleCache();269  PCHContainerOperations PCHOperations;270  CodeGenOptions CodeGenOpts;271  ASTReader Reader(PP, *ModCache, /*ASTContext=*/nullptr,272                   PCHOperations.getRawReader(), CodeGenOpts, {});273 274  // We don't need any listener here. By default it will use a validator275  // listener.276  Reader.setListener(nullptr);277 278  if (Reader.ReadAST(ModuleFilePath, serialization::MK_MainFile,279                     SourceLocation(),280                     ASTReader::ARR_None) != ASTReader::Success)281    return false;282 283  bool UpToDate = true;284  Reader.getModuleManager().visit([&](serialization::ModuleFile &MF) -> bool {285    Reader.visitInputFiles(286        MF, /*IncludeSystem=*/false, /*Complain=*/false,287        [&](const serialization::InputFile &IF, bool isSystem) {288          if (!IF.getFile() || IF.isOutOfDate())289            UpToDate = false;290        });291    return !UpToDate;292  });293  return UpToDate;294}295 296bool IsModuleFilesUpToDate(297    llvm::SmallVector<PathRef> ModuleFilePaths,298    const PrerequisiteModules &RequisiteModules,299    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {300  return llvm::all_of(301      ModuleFilePaths, [&RequisiteModules, VFS](auto ModuleFilePath) {302        return IsModuleFileUpToDate(ModuleFilePath, RequisiteModules, VFS);303      });304}305 306/// Build a module file for module with `ModuleName`. The information of built307/// module file are stored in \param BuiltModuleFiles.308llvm::Expected<std::shared_ptr<BuiltModuleFile>>309buildModuleFile(llvm::StringRef ModuleName, PathRef ModuleUnitFileName,310                const GlobalCompilationDatabase &CDB, const ThreadsafeFS &TFS,311                const ReusablePrerequisiteModules &BuiltModuleFiles) {312  // Try cheap operation earlier to boil-out cheaply if there are problems.313  auto Cmd = CDB.getCompileCommand(ModuleUnitFileName);314  if (!Cmd)315    return llvm::createStringError(316        llvm::formatv("No compile command for {0}", ModuleUnitFileName));317 318  llvm::SmallString<256> ModuleFilesPrefix =319      getUniqueModuleFilesPath(ModuleUnitFileName);320 321  Cmd->Output = getModuleFilePath(ModuleName, ModuleFilesPrefix);322 323  ParseInputs Inputs;324  Inputs.TFS = &TFS;325  Inputs.CompileCommand = std::move(*Cmd);326 327  IgnoreDiagnostics IgnoreDiags;328  auto CI = buildCompilerInvocation(Inputs, IgnoreDiags);329  if (!CI)330    return llvm::createStringError("Failed to build compiler invocation");331 332  auto FS = Inputs.TFS->view(Inputs.CompileCommand.Directory);333  auto Buf = FS->getBufferForFile(Inputs.CompileCommand.Filename);334  if (!Buf)335    return llvm::createStringError("Failed to create buffer");336 337  // In clang's driver, we will suppress the check for ODR violation in GMF.338  // See the implementation of RenderModulesOptions in Clang.cpp.339  CI->getLangOpts().SkipODRCheckInGMF = true;340 341  // Hash the contents of input files and store the hash value to the BMI files.342  // So that we can check if the files are still valid when we want to reuse the343  // BMI files.344  CI->getHeaderSearchOpts().ValidateASTInputFilesContent = true;345 346  BuiltModuleFiles.adjustHeaderSearchOptions(CI->getHeaderSearchOpts());347 348  CI->getFrontendOpts().OutputFile = Inputs.CompileCommand.Output;349  auto Clang =350      prepareCompilerInstance(std::move(CI), /*Preamble=*/nullptr,351                              std::move(*Buf), std::move(FS), IgnoreDiags);352  if (!Clang)353    return llvm::createStringError("Failed to prepare compiler instance");354 355  GenerateReducedModuleInterfaceAction Action;356  Clang->ExecuteAction(Action);357 358  if (Clang->getDiagnostics().hasErrorOccurred()) {359    std::string Cmds;360    for (const auto &Arg : Inputs.CompileCommand.CommandLine) {361      if (!Cmds.empty())362        Cmds += " ";363      Cmds += Arg;364    }365 366    clangd::vlog("Failed to compile {0} with command: {1}", ModuleUnitFileName,367                 Cmds);368 369    std::string BuiltModuleFilesStr = BuiltModuleFiles.getAsString();370    if (!BuiltModuleFilesStr.empty())371      clangd::vlog("The actual used module files built by clangd is {0}",372                   BuiltModuleFilesStr);373 374    return llvm::createStringError(375        llvm::formatv("Failed to compile {0}. Use '--log=verbose' to view "376                      "detailed failure reasons. It is helpful to use "377                      "'--debug-modules-builder' flag to keep the clangd's "378                      "built module files to reproduce the failure for "379                      "debugging. Remember to remove them after debugging.",380                      ModuleUnitFileName));381  }382 383  return BuiltModuleFile::make(ModuleName, Inputs.CompileCommand.Output);384}385 386bool ReusablePrerequisiteModules::canReuse(387    const CompilerInvocation &CI,388    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) const {389  if (RequiredModules.empty())390    return true;391 392  llvm::SmallVector<llvm::StringRef> BMIPaths;393  for (auto &MF : RequiredModules)394    BMIPaths.push_back(MF->getModuleFilePath());395  return IsModuleFilesUpToDate(BMIPaths, *this, VFS);396}397 398class ModuleFileCache {399public:400  ModuleFileCache(const GlobalCompilationDatabase &CDB) : CDB(CDB) {}401  const GlobalCompilationDatabase &getCDB() const { return CDB; }402 403  std::shared_ptr<const ModuleFile> getModule(StringRef ModuleName);404 405  void add(StringRef ModuleName, std::shared_ptr<const ModuleFile> ModuleFile) {406    std::lock_guard<std::mutex> Lock(ModuleFilesMutex);407 408    ModuleFiles[ModuleName] = ModuleFile;409  }410 411  void remove(StringRef ModuleName);412 413private:414  const GlobalCompilationDatabase &CDB;415 416  llvm::StringMap<std::weak_ptr<const ModuleFile>> ModuleFiles;417  // Mutex to guard accesses to ModuleFiles.418  std::mutex ModuleFilesMutex;419};420 421std::shared_ptr<const ModuleFile>422ModuleFileCache::getModule(StringRef ModuleName) {423  std::lock_guard<std::mutex> Lock(ModuleFilesMutex);424 425  auto Iter = ModuleFiles.find(ModuleName);426  if (Iter == ModuleFiles.end())427    return nullptr;428 429  if (auto Res = Iter->second.lock())430    return Res;431 432  ModuleFiles.erase(Iter);433  return nullptr;434}435 436void ModuleFileCache::remove(StringRef ModuleName) {437  std::lock_guard<std::mutex> Lock(ModuleFilesMutex);438 439  ModuleFiles.erase(ModuleName);440}441 442class ModuleNameToSourceCache {443public:444  std::string getSourceForModuleName(llvm::StringRef ModuleName) {445    std::lock_guard<std::mutex> Lock(CacheMutex);446    auto Iter = ModuleNameToSourceCache.find(ModuleName);447    if (Iter != ModuleNameToSourceCache.end())448      return Iter->second;449    return "";450  }451 452  void addEntry(llvm::StringRef ModuleName, PathRef Source) {453    std::lock_guard<std::mutex> Lock(CacheMutex);454    ModuleNameToSourceCache[ModuleName] = Source.str();455  }456 457  void eraseEntry(llvm::StringRef ModuleName) {458    std::lock_guard<std::mutex> Lock(CacheMutex);459    ModuleNameToSourceCache.erase(ModuleName);460  }461 462private:463  std::mutex CacheMutex;464  llvm::StringMap<std::string> ModuleNameToSourceCache;465};466 467class CachingProjectModules : public ProjectModules {468public:469  CachingProjectModules(std::unique_ptr<ProjectModules> MDB,470                        ModuleNameToSourceCache &Cache)471      : MDB(std::move(MDB)), Cache(Cache) {472    assert(this->MDB && "CachingProjectModules should only be created with a "473                        "valid underlying ProjectModules");474  }475 476  std::vector<std::string> getRequiredModules(PathRef File) override {477    return MDB->getRequiredModules(File);478  }479 480  std::string getModuleNameForSource(PathRef File) override {481    return MDB->getModuleNameForSource(File);482  }483 484  std::string getSourceForModuleName(llvm::StringRef ModuleName,485                                     PathRef RequiredSrcFile) override {486    std::string CachedResult = Cache.getSourceForModuleName(ModuleName);487 488    // Verify Cached Result by seeing if the source declaring the same module489    // as we query.490    if (!CachedResult.empty()) {491      std::string ModuleNameOfCachedSource =492          MDB->getModuleNameForSource(CachedResult);493      if (ModuleNameOfCachedSource == ModuleName)494        return CachedResult;495 496      // Cached Result is invalid. Clear it.497      Cache.eraseEntry(ModuleName);498    }499 500    auto Result = MDB->getSourceForModuleName(ModuleName, RequiredSrcFile);501    Cache.addEntry(ModuleName, Result);502 503    return Result;504  }505 506private:507  std::unique_ptr<ProjectModules> MDB;508  ModuleNameToSourceCache &Cache;509};510 511/// Collect the directly and indirectly required module names for \param512/// ModuleName in topological order. The \param ModuleName is guaranteed to513/// be the last element in \param ModuleNames.514llvm::SmallVector<std::string> getAllRequiredModules(PathRef RequiredSource,515                                                     CachingProjectModules &MDB,516                                                     StringRef ModuleName) {517  llvm::SmallVector<std::string> ModuleNames;518  llvm::StringSet<> ModuleNamesSet;519 520  auto VisitDeps = [&](StringRef ModuleName, auto Visitor) -> void {521    ModuleNamesSet.insert(ModuleName);522 523    for (StringRef RequiredModuleName : MDB.getRequiredModules(524             MDB.getSourceForModuleName(ModuleName, RequiredSource)))525      if (ModuleNamesSet.insert(RequiredModuleName).second)526        Visitor(RequiredModuleName, Visitor);527 528    ModuleNames.push_back(ModuleName.str());529  };530  VisitDeps(ModuleName, VisitDeps);531 532  return ModuleNames;533}534 535} // namespace536 537class ModulesBuilder::ModulesBuilderImpl {538public:539  ModulesBuilderImpl(const GlobalCompilationDatabase &CDB) : Cache(CDB) {}540 541  ModuleNameToSourceCache &getProjectModulesCache() {542    return ProjectModulesCache;543  }544  const GlobalCompilationDatabase &getCDB() const { return Cache.getCDB(); }545 546  llvm::Error547  getOrBuildModuleFile(PathRef RequiredSource, StringRef ModuleName,548                       const ThreadsafeFS &TFS, CachingProjectModules &MDB,549                       ReusablePrerequisiteModules &BuiltModuleFiles);550 551private:552  /// Try to get prebuilt module files from the compilation database.553  void getPrebuiltModuleFile(StringRef ModuleName, PathRef ModuleUnitFileName,554                             const ThreadsafeFS &TFS,555                             ReusablePrerequisiteModules &BuiltModuleFiles);556 557  ModuleFileCache Cache;558  ModuleNameToSourceCache ProjectModulesCache;559};560 561void ModulesBuilder::ModulesBuilderImpl::getPrebuiltModuleFile(562    StringRef ModuleName, PathRef ModuleUnitFileName, const ThreadsafeFS &TFS,563    ReusablePrerequisiteModules &BuiltModuleFiles) {564  auto Cmd = getCDB().getCompileCommand(ModuleUnitFileName);565  if (!Cmd)566    return;567 568  ParseInputs Inputs;569  Inputs.TFS = &TFS;570  Inputs.CompileCommand = std::move(*Cmd);571 572  IgnoreDiagnostics IgnoreDiags;573  auto CI = buildCompilerInvocation(Inputs, IgnoreDiags);574  if (!CI)575    return;576 577  // We don't need to check if the module files are in ModuleCache or adding578  // them to the module cache. As even if the module files are in the module579  // cache, we still need to validate them. And it looks not helpful to add them580  // to the module cache, since we may always try to get the prebuilt module581  // files before building the module files by ourselves.582  for (auto &[ModuleName, ModuleFilePath] :583       CI->getHeaderSearchOpts().PrebuiltModuleFiles) {584    if (BuiltModuleFiles.isModuleUnitBuilt(ModuleName))585      continue;586 587    if (IsModuleFileUpToDate(ModuleFilePath, BuiltModuleFiles,588                             TFS.view(std::nullopt))) {589      log("Reusing prebuilt module file {0} of module {1} for {2}",590          ModuleFilePath, ModuleName, ModuleUnitFileName);591      BuiltModuleFiles.addModuleFile(592          PrebuiltModuleFile::make(ModuleName, ModuleFilePath));593    }594  }595}596 597llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile(598    PathRef RequiredSource, StringRef ModuleName, const ThreadsafeFS &TFS,599    CachingProjectModules &MDB, ReusablePrerequisiteModules &BuiltModuleFiles) {600  if (BuiltModuleFiles.isModuleUnitBuilt(ModuleName))601    return llvm::Error::success();602 603  std::string ModuleUnitFileName =604      MDB.getSourceForModuleName(ModuleName, RequiredSource);605  /// It is possible that we're meeting third party modules (modules whose606  /// source are not in the project. e.g, the std module may be a third-party607  /// module for most project) or something wrong with the implementation of608  /// ProjectModules.609  /// FIXME: How should we treat third party modules here? If we want to ignore610  /// third party modules, we should return true instead of false here.611  /// Currently we simply bail out.612  if (ModuleUnitFileName.empty())613    return llvm::createStringError(614        llvm::formatv("Don't get the module unit for module {0}", ModuleName));615 616  /// Try to get prebuilt module files from the compilation database first. This617  /// helps to avoid building the module files that are already built by the618  /// compiler.619  getPrebuiltModuleFile(ModuleName, ModuleUnitFileName, TFS, BuiltModuleFiles);620 621  // Get Required modules in topological order.622  auto ReqModuleNames = getAllRequiredModules(RequiredSource, MDB, ModuleName);623  for (llvm::StringRef ReqModuleName : ReqModuleNames) {624    if (BuiltModuleFiles.isModuleUnitBuilt(ReqModuleName))625      continue;626 627    if (auto Cached = Cache.getModule(ReqModuleName)) {628      if (IsModuleFileUpToDate(Cached->getModuleFilePath(), BuiltModuleFiles,629                               TFS.view(std::nullopt))) {630        log("Reusing module {0} from {1}", ReqModuleName,631            Cached->getModuleFilePath());632        BuiltModuleFiles.addModuleFile(std::move(Cached));633        continue;634      }635      Cache.remove(ReqModuleName);636    }637 638    std::string ReqFileName =639        MDB.getSourceForModuleName(ReqModuleName, RequiredSource);640    llvm::Expected<std::shared_ptr<BuiltModuleFile>> MF = buildModuleFile(641        ReqModuleName, ReqFileName, getCDB(), TFS, BuiltModuleFiles);642    if (llvm::Error Err = MF.takeError())643      return Err;644 645    log("Built module {0} to {1}", ReqModuleName, (*MF)->getModuleFilePath());646    Cache.add(ReqModuleName, *MF);647    BuiltModuleFiles.addModuleFile(std::move(*MF));648  }649 650  return llvm::Error::success();651}652 653std::unique_ptr<PrerequisiteModules>654ModulesBuilder::buildPrerequisiteModulesFor(PathRef File,655                                            const ThreadsafeFS &TFS) {656  std::unique_ptr<ProjectModules> MDB = Impl->getCDB().getProjectModules(File);657  if (!MDB) {658    elog("Failed to get Project Modules information for {0}", File);659    return std::make_unique<FailedPrerequisiteModules>();660  }661  CachingProjectModules CachedMDB(std::move(MDB),662                                  Impl->getProjectModulesCache());663 664  std::vector<std::string> RequiredModuleNames =665      CachedMDB.getRequiredModules(File);666  if (RequiredModuleNames.empty())667    return std::make_unique<ReusablePrerequisiteModules>();668 669  auto RequiredModules = std::make_unique<ReusablePrerequisiteModules>();670  for (llvm::StringRef RequiredModuleName : RequiredModuleNames) {671    // Return early if there is any error.672    if (llvm::Error Err = Impl->getOrBuildModuleFile(673            File, RequiredModuleName, TFS, CachedMDB, *RequiredModules.get())) {674      elog("Failed to build module {0}; due to {1}", RequiredModuleName,675           toString(std::move(Err)));676      return std::make_unique<FailedPrerequisiteModules>();677    }678  }679 680  return std::move(RequiredModules);681}682 683ModulesBuilder::ModulesBuilder(const GlobalCompilationDatabase &CDB) {684  Impl = std::make_unique<ModulesBuilderImpl>(CDB);685}686 687ModulesBuilder::~ModulesBuilder() {}688 689} // namespace clangd690} // namespace clang691