[clang-tools-extra] [clangd] [C++20] [Modules] Add scanning cache (PR #125988)
Chuanqi Xu via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 13 23:29:22 PST 2025
https://github.com/ChuanqiXu9 updated https://github.com/llvm/llvm-project/pull/125988
>From 42eb3826ed79de5aabb7f0197cfda2ad62d9735d Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Tue, 11 Feb 2025 11:21:34 +0800
Subject: [PATCH 1/3] [clangd] [C++20] [Modules] Introduce cache for scanning
modules
---
clang-tools-extra/clangd/ModulesBuilder.cpp | 115 +++++++++++++++---
clang-tools-extra/clangd/ProjectModules.h | 6 +-
.../clangd/ScanningProjectModules.cpp | 15 ++-
3 files changed, 112 insertions(+), 24 deletions(-)
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index bee31fe51555e..121a4cec4c8c2 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -360,7 +360,8 @@ void ModuleFileCache::remove(StringRef ModuleName) {
/// Collect the directly and indirectly required module names for \param
/// ModuleName in topological order. The \param ModuleName is guaranteed to
/// be the last element in \param ModuleNames.
-llvm::SmallVector<StringRef> getAllRequiredModules(ProjectModules &MDB,
+llvm::SmallVector<StringRef> getAllRequiredModules(PathRef RequiredSource,
+ ProjectModules &MDB,
StringRef ModuleName) {
llvm::SmallVector<llvm::StringRef> ModuleNames;
llvm::StringSet<> ModuleNamesSet;
@@ -368,8 +369,8 @@ llvm::SmallVector<StringRef> getAllRequiredModules(ProjectModules &MDB,
auto VisitDeps = [&](StringRef ModuleName, auto Visitor) -> void {
ModuleNamesSet.insert(ModuleName);
- for (StringRef RequiredModuleName :
- MDB.getRequiredModules(MDB.getSourceForModuleName(ModuleName)))
+ for (StringRef RequiredModuleName : MDB.getRequiredModules(
+ MDB.getSourceForModuleName(ModuleName, RequiredSource)))
if (ModuleNamesSet.insert(RequiredModuleName).second)
Visitor(RequiredModuleName, Visitor);
@@ -380,30 +381,114 @@ llvm::SmallVector<StringRef> getAllRequiredModules(ProjectModules &MDB,
return ModuleNames;
}
+class CachingProjectModules : public ProjectModules {
+public:
+ CachingProjectModules(const GlobalCompilationDatabase &CDB) : CDB(CDB) {}
+
+ std::vector<std::string> getRequiredModules(PathRef File) override {
+ std::unique_ptr<ProjectModules> MDB = CDB.getProjectModules(File);
+ if (!MDB) {
+ elog("Failed to get Project Modules information for {0}", File);
+ return {};
+ }
+ return MDB->getRequiredModules(File);
+ }
+
+ std::string getModuleNameForSource(PathRef File) override {
+ std::unique_ptr<ProjectModules> MDB = CDB.getProjectModules(File);
+ if (!MDB) {
+ elog("Failed to get Project Modules information for {0}", File);
+ return {};
+ }
+ return MDB->getModuleNameForSource(File);
+ }
+
+ void setCommandMangler(CommandMangler M) override {
+ // GlobalCompilationDatabase::getProjectModules() will set mangler
+ // for the underlying ProjectModules.
+ }
+
+ std::string getSourceForModuleName(llvm::StringRef ModuleName,
+ PathRef RequiredSrcFile) override {
+ std::string CachedResult;
+ {
+ std::lock_guard<std::mutex> Lock(CacheMutex);
+ auto Iter = ModuleNameToSourceCache.find(ModuleName);
+ if (Iter != ModuleNameToSourceCache.end())
+ CachedResult = Iter->second;
+ }
+
+ std::unique_ptr<ProjectModules> MDB =
+ CDB.getProjectModules(RequiredSrcFile);
+ if (!MDB) {
+ elog("Failed to get Project Modules information for {0}",
+ RequiredSrcFile);
+ return {};
+ }
+
+ // Verify Cached Result by seeing if the source declaring the same module
+ // as we query.
+ if (!CachedResult.empty()) {
+ std::string ModuleNameOfCachedSource =
+ MDB->getModuleNameForSource(CachedResult);
+ if (ModuleNameOfCachedSource == ModuleName)
+ return CachedResult;
+ else {
+ // Cached Result is invalid. Clear it.
+
+ std::lock_guard<std::mutex> Lock(CacheMutex);
+ ModuleNameToSourceCache.erase(ModuleName);
+ }
+ }
+
+ auto Result = MDB->getSourceForModuleName(ModuleName, RequiredSrcFile);
+
+ {
+ std::lock_guard<std::mutex> Lock(CacheMutex);
+ ModuleNameToSourceCache.insert({ModuleName, Result});
+ }
+
+ return Result;
+ }
+
+private:
+ const GlobalCompilationDatabase &CDB;
+
+ std::mutex CacheMutex;
+ llvm::StringMap<std::string> ModuleNameToSourceCache;
+};
+
} // namespace
class ModulesBuilder::ModulesBuilderImpl {
public:
- ModulesBuilderImpl(const GlobalCompilationDatabase &CDB) : Cache(CDB) {}
+ ModulesBuilderImpl(const GlobalCompilationDatabase &CDB)
+ : CachedProjectModules(CDB), Cache(CDB) {}
+
+ CachingProjectModules &getCachedProjectModules() {
+ return CachedProjectModules;
+ }
const GlobalCompilationDatabase &getCDB() const { return Cache.getCDB(); }
llvm::Error
- getOrBuildModuleFile(StringRef ModuleName, const ThreadsafeFS &TFS,
- ProjectModules &MDB,
+ getOrBuildModuleFile(PathRef RequiredSource, StringRef ModuleName,
+ const ThreadsafeFS &TFS, ProjectModules &MDB,
ReusablePrerequisiteModules &BuiltModuleFiles);
private:
+ CachingProjectModules CachedProjectModules;
ModuleFileCache Cache;
};
llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile(
- StringRef ModuleName, const ThreadsafeFS &TFS, ProjectModules &MDB,
- ReusablePrerequisiteModules &BuiltModuleFiles) {
+ PathRef RequiredSource, StringRef ModuleName, const ThreadsafeFS &TFS,
+ ProjectModules &MDB, ReusablePrerequisiteModules &BuiltModuleFiles) {
if (BuiltModuleFiles.isModuleUnitBuilt(ModuleName))
return llvm::Error::success();
- PathRef ModuleUnitFileName = MDB.getSourceForModuleName(ModuleName);
+ std::string ModuleUnitFileName =
+ MDB.getSourceForModuleName(ModuleName, RequiredSource);
/// It is possible that we're meeting third party modules (modules whose
/// source are not in the project. e.g, the std module may be a third-party
/// module for most project) or something wrong with the implementation of
@@ -416,7 +501,7 @@ llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile(
llvm::formatv("Don't get the module unit for module {0}", ModuleName));
// Get Required modules in topological order.
- auto ReqModuleNames = getAllRequiredModules(MDB, ModuleName);
+ auto ReqModuleNames = getAllRequiredModules(RequiredSource, MDB, ModuleName);
for (llvm::StringRef ReqModuleName : ReqModuleNames) {
if (BuiltModuleFiles.isModuleUnitBuilt(ModuleName))
continue;
@@ -449,13 +534,9 @@ llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile(
std::unique_ptr<PrerequisiteModules>
ModulesBuilder::buildPrerequisiteModulesFor(PathRef File,
const ThreadsafeFS &TFS) {
- std::unique_ptr<ProjectModules> MDB = Impl->getCDB().getProjectModules(File);
- if (!MDB) {
- elog("Failed to get Project Modules information for {0}", File);
- return std::make_unique<FailedPrerequisiteModules>();
- }
+ ProjectModules &MDB = Impl->getCachedProjectModules();
- std::vector<std::string> RequiredModuleNames = MDB->getRequiredModules(File);
+ std::vector<std::string> RequiredModuleNames = MDB.getRequiredModules(File);
if (RequiredModuleNames.empty())
return std::make_unique<ReusablePrerequisiteModules>();
@@ -463,7 +544,7 @@ ModulesBuilder::buildPrerequisiteModulesFor(PathRef File,
for (llvm::StringRef RequiredModuleName : RequiredModuleNames) {
// Return early if there is any error.
if (llvm::Error Err = Impl->getOrBuildModuleFile(
- RequiredModuleName, TFS, *MDB.get(), *RequiredModules.get())) {
+ File, RequiredModuleName, TFS, MDB, *RequiredModules.get())) {
elog("Failed to build module {0}; due to {1}", RequiredModuleName,
toString(std::move(Err)));
return std::make_unique<FailedPrerequisiteModules>();
diff --git a/clang-tools-extra/clangd/ProjectModules.h b/clang-tools-extra/clangd/ProjectModules.h
index 48d52ac9deb89..41812674f12f4 100644
--- a/clang-tools-extra/clangd/ProjectModules.h
+++ b/clang-tools-extra/clangd/ProjectModules.h
@@ -42,9 +42,9 @@ class ProjectModules {
llvm::unique_function<void(tooling::CompileCommand &, PathRef) const>;
virtual std::vector<std::string> getRequiredModules(PathRef File) = 0;
- virtual PathRef
- getSourceForModuleName(llvm::StringRef ModuleName,
- PathRef RequiredSrcFile = PathRef()) = 0;
+ virtual std::string getModuleNameForSource(PathRef File) = 0;
+ virtual std::string getSourceForModuleName(llvm::StringRef ModuleName,
+ PathRef RequiredSrcFile) = 0;
virtual void setCommandMangler(CommandMangler Mangler) {}
diff --git a/clang-tools-extra/clangd/ScanningProjectModules.cpp b/clang-tools-extra/clangd/ScanningProjectModules.cpp
index e4dc11c1c2895..b99d35989cebf 100644
--- a/clang-tools-extra/clangd/ScanningProjectModules.cpp
+++ b/clang-tools-extra/clangd/ScanningProjectModules.cpp
@@ -189,11 +189,18 @@ class ScanningAllProjectModules : public ProjectModules {
/// RequiredSourceFile is not used intentionally. See the comments of
/// ModuleDependencyScanner for detail.
- PathRef
- getSourceForModuleName(llvm::StringRef ModuleName,
- PathRef RequiredSourceFile = PathRef()) override {
+ std::string getSourceForModuleName(llvm::StringRef ModuleName,
+ PathRef RequiredSourceFile) override {
Scanner.globalScan(Mangler);
- return Scanner.getSourceForModuleName(ModuleName);
+ return Scanner.getSourceForModuleName(ModuleName).str();
+ }
+
+ std::string getModuleNameForSource(PathRef File) override {
+ auto ScanningResult = Scanner.scan(File, Mangler);
+ if (!ScanningResult || !ScanningResult->ModuleName)
+ return {};
+
+ return *ScanningResult->ModuleName;
}
private:
>From 5de01442644acafa9c1844080dd43315849b81ed Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Fri, 14 Feb 2025 10:42:41 +0800
Subject: [PATCH 2/3] Update
---
clang-tools-extra/clangd/ModulesBuilder.cpp | 149 +++++++++---------
.../unittests/PrerequisiteModulesTest.cpp | 60 ++++++-
2 files changed, 131 insertions(+), 78 deletions(-)
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index 121a4cec4c8c2..08a7b250a8119 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -357,74 +357,51 @@ void ModuleFileCache::remove(StringRef ModuleName) {
ModuleFiles.erase(ModuleName);
}
-/// Collect the directly and indirectly required module names for \param
-/// ModuleName in topological order. The \param ModuleName is guaranteed to
-/// be the last element in \param ModuleNames.
-llvm::SmallVector<StringRef> getAllRequiredModules(PathRef RequiredSource,
- ProjectModules &MDB,
- StringRef ModuleName) {
- llvm::SmallVector<llvm::StringRef> ModuleNames;
- llvm::StringSet<> ModuleNamesSet;
-
- auto VisitDeps = [&](StringRef ModuleName, auto Visitor) -> void {
- ModuleNamesSet.insert(ModuleName);
+class ModuleNameToSourceCache {
+public:
+ std::string getSourceForModuleName(llvm::StringRef ModuleName) {
+ std::lock_guard<std::mutex> Lock(CacheMutex);
+ auto Iter = ModuleNameToSourceCache.find(ModuleName);
+ if (Iter != ModuleNameToSourceCache.end())
+ return Iter->second;
+ return "";
+ }
- for (StringRef RequiredModuleName : MDB.getRequiredModules(
- MDB.getSourceForModuleName(ModuleName, RequiredSource)))
- if (ModuleNamesSet.insert(RequiredModuleName).second)
- Visitor(RequiredModuleName, Visitor);
+ void addEntry(llvm::StringRef ModuleName, PathRef Source) {
+ std::lock_guard<std::mutex> Lock(CacheMutex);
+ ModuleNameToSourceCache[ModuleName] = Source.str();
+ }
- ModuleNames.push_back(ModuleName);
- };
- VisitDeps(ModuleName, VisitDeps);
+ void eraseEntry(llvm::StringRef ModuleName) {
+ std::lock_guard<std::mutex> Lock(CacheMutex);
+ ModuleNameToSourceCache.erase(ModuleName);
+ }
- return ModuleNames;
-}
+private:
+ std::mutex CacheMutex;
+ llvm::StringMap<std::string> ModuleNameToSourceCache;
+};
class CachingProjectModules : public ProjectModules {
public:
- CachingProjectModules(const GlobalCompilationDatabase &CDB) : CDB(CDB) {}
+ CachingProjectModules(std::unique_ptr<ProjectModules> MDB,
+ ModuleNameToSourceCache &Cache)
+ : MDB(std::move(MDB)), Cache(Cache) {
+ assert(this->MDB && "CachingProjectModules should only be created with a "
+ "valid underlying ProjectModules");
+ }
std::vector<std::string> getRequiredModules(PathRef File) override {
- std::unique_ptr<ProjectModules> MDB = CDB.getProjectModules(File);
- if (!MDB) {
- elog("Failed to get Project Modules information for {0}", File);
- return {};
- }
return MDB->getRequiredModules(File);
}
std::string getModuleNameForSource(PathRef File) override {
- std::unique_ptr<ProjectModules> MDB = CDB.getProjectModules(File);
- if (!MDB) {
- elog("Failed to get Project Modules information for {0}", File);
- return {};
- }
return MDB->getModuleNameForSource(File);
}
- void setCommandMangler(CommandMangler M) override {
- // GlobalCompilationDatabase::getProjectModules() will set mangler
- // for the underlying ProjectModules.
- }
-
std::string getSourceForModuleName(llvm::StringRef ModuleName,
PathRef RequiredSrcFile) override {
- std::string CachedResult;
- {
- std::lock_guard<std::mutex> Lock(CacheMutex);
- auto Iter = ModuleNameToSourceCache.find(ModuleName);
- if (Iter != ModuleNameToSourceCache.end())
- CachedResult = Iter->second;
- }
-
- std::unique_ptr<ProjectModules> MDB =
- CDB.getProjectModules(RequiredSrcFile);
- if (!MDB) {
- elog("Failed to get Project Modules information for {0}",
- RequiredSrcFile);
- return {};
- }
+ std::string CachedResult = Cache.getSourceForModuleName(ModuleName);
// Verify Cached Result by seeing if the source declaring the same module
// as we query.
@@ -433,57 +410,70 @@ class CachingProjectModules : public ProjectModules {
MDB->getModuleNameForSource(CachedResult);
if (ModuleNameOfCachedSource == ModuleName)
return CachedResult;
- else {
- // Cached Result is invalid. Clear it.
- std::lock_guard<std::mutex> Lock(CacheMutex);
- ModuleNameToSourceCache.erase(ModuleName);
- }
+ // Cached Result is invalid. Clear it.
+ Cache.eraseEntry(ModuleName);
}
auto Result = MDB->getSourceForModuleName(ModuleName, RequiredSrcFile);
-
- {
- std::lock_guard<std::mutex> Lock(CacheMutex);
- ModuleNameToSourceCache.insert({ModuleName, Result});
- }
+ Cache.addEntry(ModuleName, Result);
return Result;
}
private:
- const GlobalCompilationDatabase &CDB;
-
- std::mutex CacheMutex;
- llvm::StringMap<std::string> ModuleNameToSourceCache;
+ std::unique_ptr<ProjectModules> MDB;
+ ModuleNameToSourceCache &Cache;
};
+/// Collect the directly and indirectly required module names for \param
+/// ModuleName in topological order. The \param ModuleName is guaranteed to
+/// be the last element in \param ModuleNames.
+llvm::SmallVector<StringRef> getAllRequiredModules(PathRef RequiredSource,
+ CachingProjectModules &MDB,
+ StringRef ModuleName) {
+ llvm::SmallVector<llvm::StringRef> ModuleNames;
+ llvm::StringSet<> ModuleNamesSet;
+
+ auto VisitDeps = [&](StringRef ModuleName, auto Visitor) -> void {
+ ModuleNamesSet.insert(ModuleName);
+
+ for (StringRef RequiredModuleName : MDB.getRequiredModules(
+ MDB.getSourceForModuleName(ModuleName, RequiredSource)))
+ if (ModuleNamesSet.insert(RequiredModuleName).second)
+ Visitor(RequiredModuleName, Visitor);
+
+ ModuleNames.push_back(ModuleName);
+ };
+ VisitDeps(ModuleName, VisitDeps);
+
+ return ModuleNames;
+}
+
} // namespace
class ModulesBuilder::ModulesBuilderImpl {
public:
- ModulesBuilderImpl(const GlobalCompilationDatabase &CDB)
- : CachedProjectModules(CDB), Cache(CDB) {}
+ ModulesBuilderImpl(const GlobalCompilationDatabase &CDB) : Cache(CDB) {}
- CachingProjectModules &getCachedProjectModules() {
- return CachedProjectModules;
+ ModuleNameToSourceCache &getProjectModulesCache() {
+ return ProjectModulesCache;
}
-
const GlobalCompilationDatabase &getCDB() const { return Cache.getCDB(); }
llvm::Error
getOrBuildModuleFile(PathRef RequiredSource, StringRef ModuleName,
- const ThreadsafeFS &TFS, ProjectModules &MDB,
+ const ThreadsafeFS &TFS, CachingProjectModules &MDB,
ReusablePrerequisiteModules &BuiltModuleFiles);
private:
- CachingProjectModules CachedProjectModules;
ModuleFileCache Cache;
+ ModuleNameToSourceCache ProjectModulesCache;
};
llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile(
PathRef RequiredSource, StringRef ModuleName, const ThreadsafeFS &TFS,
- ProjectModules &MDB, ReusablePrerequisiteModules &BuiltModuleFiles) {
+ CachingProjectModules &MDB, ReusablePrerequisiteModules &BuiltModuleFiles) {
if (BuiltModuleFiles.isModuleUnitBuilt(ModuleName))
return llvm::Error::success();
@@ -534,9 +524,16 @@ llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile(
std::unique_ptr<PrerequisiteModules>
ModulesBuilder::buildPrerequisiteModulesFor(PathRef File,
const ThreadsafeFS &TFS) {
- ProjectModules &MDB = Impl->getCachedProjectModules();
+ std::unique_ptr<ProjectModules> MDB = Impl->getCDB().getProjectModules(File);
+ if (!MDB) {
+ elog("Failed to get Project Modules information for {0}", File);
+ return std::make_unique<FailedPrerequisiteModules>();
+ }
+ CachingProjectModules CachedMDB(std::move(MDB),
+ Impl->getProjectModulesCache());
- std::vector<std::string> RequiredModuleNames = MDB.getRequiredModules(File);
+ std::vector<std::string> RequiredModuleNames =
+ CachedMDB.getRequiredModules(File);
if (RequiredModuleNames.empty())
return std::make_unique<ReusablePrerequisiteModules>();
@@ -544,7 +541,7 @@ ModulesBuilder::buildPrerequisiteModulesFor(PathRef File,
for (llvm::StringRef RequiredModuleName : RequiredModuleNames) {
// Return early if there is any error.
if (llvm::Error Err = Impl->getOrBuildModuleFile(
- File, RequiredModuleName, TFS, MDB, *RequiredModules.get())) {
+ File, RequiredModuleName, TFS, CachedMDB, *RequiredModules.get())) {
elog("Failed to build module {0}; due to {1}", RequiredModuleName,
toString(std::move(Err)));
return std::make_unique<FailedPrerequisiteModules>();
diff --git a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp
index 51723c797eabc..27f4c817a8ff3 100644
--- a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp
+++ b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp
@@ -27,12 +27,41 @@
namespace clang::clangd {
namespace {
+class GlobalScanningCounterProjectModules : public ProjectModules {
+public:
+ GlobalScanningCounterProjectModules(
+ std::unique_ptr<ProjectModules> Underlying, std::atomic<unsigned> &Count)
+ : Underlying(std::move(Underlying)), Count(Count) {}
+
+ std::vector<std::string> getRequiredModules(PathRef File) override {
+ return Underlying->getRequiredModules(File);
+ }
+
+ std::string getModuleNameForSource(PathRef File) override {
+ return Underlying->getModuleNameForSource(File);
+ }
+
+ void setCommandMangler(CommandMangler Mangler) override {
+ Underlying->setCommandMangler(std::move(Mangler));
+ }
+
+ std::string getSourceForModuleName(llvm::StringRef ModuleName,
+ PathRef RequiredSrcFile) override {
+ Count++;
+ return Underlying->getSourceForModuleName(ModuleName, RequiredSrcFile);
+ }
+
+private:
+ std::unique_ptr<ProjectModules> Underlying;
+ std::atomic<unsigned> &Count;
+};
+
class MockDirectoryCompilationDatabase : public MockCompilationDatabase {
public:
MockDirectoryCompilationDatabase(StringRef TestDir, const ThreadsafeFS &TFS)
: MockCompilationDatabase(TestDir),
MockedCDBPtr(std::make_shared<MockClangCompilationDatabase>(*this)),
- TFS(TFS) {
+ TFS(TFS), GlobalScanningCount(0) {
this->ExtraClangFlags.push_back("-std=c++20");
this->ExtraClangFlags.push_back("-c");
}
@@ -40,9 +69,12 @@ class MockDirectoryCompilationDatabase : public MockCompilationDatabase {
void addFile(llvm::StringRef Path, llvm::StringRef Contents);
std::unique_ptr<ProjectModules> getProjectModules(PathRef) const override {
- return scanningProjectModules(MockedCDBPtr, TFS);
+ return std::make_unique<GlobalScanningCounterProjectModules>(
+ scanningProjectModules(MockedCDBPtr, TFS), GlobalScanningCount);
}
+ unsigned getGlobalScanningCount() const { return GlobalScanningCount; }
+
private:
class MockClangCompilationDatabase : public tooling::CompilationDatabase {
public:
@@ -68,6 +100,8 @@ class MockDirectoryCompilationDatabase : public MockCompilationDatabase {
std::shared_ptr<MockClangCompilationDatabase> MockedCDBPtr;
const ThreadsafeFS &TFS;
+
+ mutable std::atomic<unsigned> GlobalScanningCount;
};
// Add files to the working testing directory and the compilation database.
@@ -590,6 +624,28 @@ export constexpr int M = 43;
EXPECT_NE(NewHSOptsA.PrebuiltModuleFiles, HSOptsA.PrebuiltModuleFiles);
}
+TEST_F(PrerequisiteModulesTests, ScanningCacheTest) {
+ MockDirectoryCompilationDatabase CDB(TestDir, FS);
+
+ CDB.addFile("M.cppm", R"cpp(
+export module M;
+ )cpp");
+ CDB.addFile("A.cppm", R"cpp(
+export module A;
+import M;
+ )cpp");
+ CDB.addFile("B.cppm", R"cpp(
+export module B;
+import M;
+ )cpp");
+
+ ModulesBuilder Builder(CDB);
+
+ Builder.buildPrerequisiteModulesFor(getFullPath("A.cppm"), FS);
+ Builder.buildPrerequisiteModulesFor(getFullPath("B.cppm"), FS);
+ EXPECT_EQ(CDB.getGlobalScanningCount(), 1u);
+}
+
} // namespace
} // namespace clang::clangd
>From b5b11c5a8aa6e89e9cb898645d0fca724a8bc3c9 Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Fri, 14 Feb 2025 15:28:59 +0800
Subject: [PATCH 3/3] ask Scanner to not run again after global scanned
---
clang-tools-extra/clangd/ScanningProjectModules.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang-tools-extra/clangd/ScanningProjectModules.cpp b/clang-tools-extra/clangd/ScanningProjectModules.cpp
index b99d35989cebf..e561513fe687f 100644
--- a/clang-tools-extra/clangd/ScanningProjectModules.cpp
+++ b/clang-tools-extra/clangd/ScanningProjectModules.cpp
@@ -134,6 +134,9 @@ ModuleDependencyScanner::scan(PathRef FilePath,
void ModuleDependencyScanner::globalScan(
const ProjectModules::CommandMangler &Mangler) {
+ if (GlobalScanned)
+ return;
+
for (auto &File : CDB->getAllFiles())
scan(File, Mangler);
More information about the cfe-commits
mailing list