[clang-tools-extra] 448d8fa - [NFC] [clangd] [Modules] Extract ModuleFile class and IsModuleFileUpToDate function

Chuanqi Xu via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 29 23:48:19 PDT 2024


Author: Chuanqi Xu
Date: 2024-08-30T14:43:41+08:00
New Revision: 448d8fa880be5cae0f63c3b248f07f647013a5a4

URL: https://github.com/llvm/llvm-project/commit/448d8fa880be5cae0f63c3b248f07f647013a5a4
DIFF: https://github.com/llvm/llvm-project/commit/448d8fa880be5cae0f63c3b248f07f647013a5a4.diff

LOG: [NFC] [clangd] [Modules] Extract ModuleFile class and IsModuleFileUpToDate function

This patch extracts ModuleFile class from StandalonePrerequisiteModules
so that we can reuse it further. And also we implement
IsModuleFileUpToDate function to implement
StandalonePrerequisiteModules::CanReuse. Both of them aims to ease the
future improvements to the support of modules in clangd. And both of
them should be NFC.

Added: 
    

Modified: 
    clang-tools-extra/clangd/ModulesBuilder.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index 94c7eec2d09e4e..dd00adc6f6c8d2 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -92,6 +92,88 @@ class FailedPrerequisiteModules : public PrerequisiteModules {
   }
 };
 
+struct ModuleFile {
+  ModuleFile(StringRef ModuleName, PathRef ModuleFilePath)
+      : ModuleName(ModuleName.str()), ModuleFilePath(ModuleFilePath.str()) {}
+
+  ModuleFile() = delete;
+
+  ModuleFile(const ModuleFile &) = delete;
+  ModuleFile operator=(const ModuleFile &) = delete;
+
+  // The move constructor is needed for llvm::SmallVector.
+  ModuleFile(ModuleFile &&Other)
+      : ModuleName(std::move(Other.ModuleName)),
+        ModuleFilePath(std::move(Other.ModuleFilePath)) {
+    Other.ModuleName.clear();
+    Other.ModuleFilePath.clear();
+  }
+
+  ModuleFile &operator=(ModuleFile &&Other) {
+    if (this == &Other)
+      return *this;
+
+    this->~ModuleFile();
+    new (this) ModuleFile(std::move(Other));
+    return *this;
+  }
+
+  ~ModuleFile() {
+    if (!ModuleFilePath.empty())
+      llvm::sys::fs::remove(ModuleFilePath);
+  }
+
+  std::string ModuleName;
+  std::string ModuleFilePath;
+};
+
+bool IsModuleFileUpToDate(
+    PathRef ModuleFilePath,
+    const PrerequisiteModules *RequisiteModules) {
+IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+      CompilerInstance::createDiagnostics(new DiagnosticOptions());
+
+  auto HSOpts = std::make_shared<HeaderSearchOptions>();
+  if (RequisiteModules)
+    RequisiteModules->adjustHeaderSearchOptions(*HSOpts);
+  HSOpts->ForceCheckCXX20ModulesInputFiles = true;
+  HSOpts->ValidateASTInputFilesContent = true;
+
+  PCHContainerOperations PCHOperations;
+  std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
+      ModuleFilePath.str(), PCHOperations.getRawReader(), ASTUnit::LoadASTOnly,
+      Diags, FileSystemOptions(), std::move(HSOpts));
+
+  if (!Unit)
+    return false;
+
+  auto Reader = Unit->getASTReader();
+  if (!Reader)
+    return false;
+
+  bool UpToDate = true;
+  Reader->getModuleManager().visit([&](serialization::ModuleFile &MF) -> bool {
+    Reader->visitInputFiles(
+        MF, /*IncludeSystem=*/false, /*Complain=*/false,
+        [&](const serialization::InputFile &IF, bool isSystem) {
+          if (!IF.getFile() || IF.isOutOfDate())
+            UpToDate = false;
+        });
+
+    return !UpToDate;
+  });
+
+  return UpToDate;
+}
+
+bool IsModuleFilesUpToDate(
+    llvm::SmallVector<PathRef> ModuleFilePaths,
+    const PrerequisiteModules *RequisiteModules = nullptr) {
+  return llvm::all_of(ModuleFilePaths, [RequisiteModules](auto ModuleFilePath) {
+    return IsModuleFileUpToDate(ModuleFilePath, RequisiteModules);
+  });
+}
+
 // StandalonePrerequisiteModules - stands for PrerequisiteModules for which all
 // the required modules are built successfully. All the module files
 // are owned by the StandalonePrerequisiteModules class.
@@ -135,29 +217,6 @@ class StandalonePrerequisiteModules : public PrerequisiteModules {
   }
 
 private:
-  struct ModuleFile {
-    ModuleFile(llvm::StringRef ModuleName, PathRef ModuleFilePath)
-        : ModuleName(ModuleName.str()), ModuleFilePath(ModuleFilePath.str()) {}
-
-    ModuleFile(const ModuleFile &) = delete;
-    ModuleFile operator=(const ModuleFile &) = delete;
-
-    // The move constructor is needed for llvm::SmallVector.
-    ModuleFile(ModuleFile &&Other)
-        : ModuleName(std::move(Other.ModuleName)),
-          ModuleFilePath(std::move(Other.ModuleFilePath)) {}
-
-    ModuleFile &operator=(ModuleFile &&Other) = delete;
-
-    ~ModuleFile() {
-      if (!ModuleFilePath.empty())
-        llvm::sys::fs::remove(ModuleFilePath);
-    }
-
-    std::string ModuleName;
-    std::string ModuleFilePath;
-  };
-
   llvm::SmallVector<ModuleFile, 8> RequiredModules;
   // A helper class to speedup the query if a module is built.
   llvm::StringSet<> BuiltModuleNames;
@@ -286,50 +345,10 @@ bool StandalonePrerequisiteModules::canReuse(
   if (RequiredModules.empty())
     return true;
 
-  CompilerInstance Clang;
-
-  Clang.setInvocation(std::make_shared<CompilerInvocation>(CI));
-  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(new DiagnosticOptions());
-  Clang.setDiagnostics(Diags.get());
-
-  FileManager *FM = Clang.createFileManager(VFS);
-  Clang.createSourceManager(*FM);
-
-  if (!Clang.createTarget())
-    return false;
-
-  assert(Clang.getHeaderSearchOptsPtr());
-  adjustHeaderSearchOptions(Clang.getHeaderSearchOpts());
-  // Since we don't need to compile the source code actually, the TU kind here
-  // doesn't matter.
-  Clang.createPreprocessor(TU_Complete);
-  Clang.getHeaderSearchOpts().ForceCheckCXX20ModulesInputFiles = true;
-  Clang.getHeaderSearchOpts().ValidateASTInputFilesContent = true;
-
-  // Following the practice of clang's driver to suppres the checking for ODR
-  // violation in GMF.
-  // See
-  // https://clang.llvm.org/docs/StandardCPlusPlusModules.html#object-definition-consistency
-  // for example.
-  Clang.getLangOpts().SkipODRCheckInGMF = true;
-
-  Clang.createASTReader();
-  for (auto &RequiredModule : RequiredModules) {
-    llvm::StringRef BMIPath = RequiredModule.ModuleFilePath;
-    // FIXME: Loading BMI fully is too heavy considering something cheaply to
-    // check if we can reuse the BMI.
-    auto ReadResult =
-        Clang.getASTReader()->ReadAST(BMIPath, serialization::MK_MainFile,
-                                      SourceLocation(), ASTReader::ARR_None);
-
-    if (ReadResult != ASTReader::Success) {
-      elog("Can't reuse {0}: {1}", BMIPath, ReadResult);
-      return false;
-    }
-  }
-
-  return true;
+  SmallVector<StringRef> BMIPaths;
+  for (auto &MF : RequiredModules)
+    BMIPaths.push_back(MF.ModuleFilePath);
+  return IsModuleFilesUpToDate(BMIPaths, this);
 }
 
 } // namespace clangd


        


More information about the cfe-commits mailing list