11#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
12#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
33class ModuleDependencyScanner {
35 ModuleDependencyScanner(
36 std::shared_ptr<const clang::tooling::CompilationDatabase> CDB,
37 const ThreadsafeFS &TFS)
39 Service(tooling::dependencies::ScanningMode::CanonicalPreprocessing,
40 tooling::dependencies::ScanningOutputFormat::P1689) {}
43 struct ModuleDependencyInfo {
47 std::vector<std::string> RequiredModules;
51 std::optional<ModuleDependencyInfo> scan(
PathRef FilePath);
72 std::vector<std::string> getRequiredModules(
PathRef File);
75 std::shared_ptr<const clang::tooling::CompilationDatabase> CDB;
76 const ThreadsafeFS &TFS;
79 bool GlobalScanned =
false;
81 clang::tooling::dependencies::DependencyScanningService Service;
86 llvm::StringMap<std::string> ModuleNameToSource;
89std::optional<ModuleDependencyScanner::ModuleDependencyInfo>
90ModuleDependencyScanner::scan(
PathRef FilePath) {
91 auto Candidates = CDB->getCompileCommands(FilePath);
92 if (Candidates.empty())
98 tooling::CompileCommand Cmd = std::move(Candidates.front());
100 static int StaticForMainAddr;
101 Cmd.CommandLine.push_back(
"-resource-dir=" +
102 CompilerInvocation::GetResourcesPath(
103 "clangd", (
void *)&StaticForMainAddr));
105 using namespace clang::tooling::dependencies;
107 llvm::SmallString<128> FilePathDir(FilePath);
108 llvm::sys::path::remove_filename(FilePathDir);
109 DependencyScanningTool ScanningTool(Service, TFS.
view(FilePathDir));
111 llvm::Expected<P1689Rule> ScanningResult =
112 ScanningTool.getP1689ModuleDependencyFile(Cmd, Cmd.Directory);
114 if (
auto E = ScanningResult.takeError()) {
115 elog(
"Scanning modules dependencies for {0} failed: {1}", FilePath,
116 llvm::toString(std::move(
E)));
120 ModuleDependencyInfo Result;
122 if (ScanningResult->Provides) {
123 ModuleNameToSource[ScanningResult->Provides->ModuleName] = FilePath;
124 Result.ModuleName = ScanningResult->Provides->ModuleName;
127 for (
auto &Required : ScanningResult->Requires)
128 Result.RequiredModules.push_back(Required.ModuleName);
133void ModuleDependencyScanner::globalScan() {
134 for (
auto &
File : CDB->getAllFiles())
137 GlobalScanned =
true;
140PathRef ModuleDependencyScanner::getSourceForModuleName(
144 "We should only call getSourceForModuleName after calling globalScan()");
146 if (
auto It = ModuleNameToSource.find(
ModuleName);
147 It != ModuleNameToSource.end())
153std::vector<std::string>
154ModuleDependencyScanner::getRequiredModules(
PathRef File) {
155 auto ScanningResult = scan(
File);
159 return ScanningResult->RequiredModules;
173 std::shared_ptr<const clang::tooling::CompilationDatabase> CDB,
175 : Scanner(CDB, TFS) {}
180 return Scanner.getRequiredModules(
File);
188 Scanner.globalScan();
189 return Scanner.getSourceForModuleName(
ModuleName);
193 ModuleDependencyScanner Scanner;
197 std::shared_ptr<const clang::tooling::CompilationDatabase> CDB,
199 return std::make_unique<ScanningAllProjectModules>(CDB, TFS);
An interface to query the modules information in the project.
TODO: The existing ScanningAllProjectModules is not efficient.
PathRef getSourceForModuleName(llvm::StringRef ModuleName, PathRef RequiredSourceFile=PathRef()) override
RequiredSourceFile is not used intentionally.
ScanningAllProjectModules(std::shared_ptr< const clang::tooling::CompilationDatabase > CDB, const ThreadsafeFS &TFS)
std::vector< std::string > getRequiredModules(PathRef File) override
~ScanningAllProjectModules() override=default
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > view(std::nullopt_t CWD) const
Obtain a vfs::FileSystem with an arbitrary initial working directory.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
std::unique_ptr< ProjectModules > scanningProjectModules(std::shared_ptr< const clang::tooling::CompilationDatabase > CDB, const ThreadsafeFS &TFS)
Providing modules information for the project by scanning every file.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
void elog(const char *Fmt, Ts &&... Vals)