clang-tools 23.0.0git
ProjectModules.cpp
Go to the documentation of this file.
1//===------------------ ProjectModules.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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ProjectModules.h"
10#include "Compiler.h"
11#include "support/Logger.h"
12#include "clang/DependencyScanning/DependencyScanningService.h"
13#include "clang/Tooling/DependencyScanningTool.h"
14#include "clang/Tooling/Tooling.h"
15#include "llvm/ADT/SmallString.h"
16#include "llvm/ADT/StringMap.h"
17#include "llvm/ADT/StringSet.h"
18#include "llvm/Support/CommandLine.h"
19#include "llvm/Support/Path.h"
20#include "llvm/TargetParser/Host.h"
21
22namespace clang::clangd {
23namespace {
24
25llvm::SmallString<128> normalizePath(PathRef Path) {
26 llvm::SmallString<128> Result(Path);
27 llvm::sys::path::remove_dots(Result, /*remove_dot_dot=*/true);
28 llvm::sys::path::native(Result, llvm::sys::path::Style::posix);
29 return Result;
30}
31
32std::string normalizePath(PathRef Path, PathRef WorkingDir) {
33 if (Path.empty())
34 return {};
35
36 llvm::SmallString<128> Result;
37 if (llvm::sys::path::is_absolute(Path) || WorkingDir.empty())
38 Result = Path;
39 else {
40 Result = WorkingDir;
41 llvm::sys::path::append(Result, Path);
42 }
43
44 return normalizePath(Result).str().str();
45}
46
47/// The information related to modules parsed from compile commands.
48/// Including the source file, the module file it produces (if it is a
49/// producer), and the module and the corresponding module files it
50/// requires (if it is a consumer)
51struct ParsedCompileCommandInfo {
52 std::string SourceFile;
53 std::optional<std::string> OutputModuleFile;
54 // Map from required module name to the module file path.
55 llvm::StringMap<std::string> RequiredModuleFiles;
56};
57
58/// Get ParsedCompileCommandInfo by looking at the '--precompile',
59/// '-fmodule-file=' and '-fmodule-file=' commands in the compile command.
60std::optional<ParsedCompileCommandInfo>
61parseCompileCommandInfo(tooling::CompileCommand Cmd, const ThreadsafeFS &TFS) {
62 auto FS = TFS.view(std::nullopt);
63 auto Tokenizer = llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows()
64 ? llvm::cl::TokenizeWindowsCommandLine
65 : llvm::cl::TokenizeGNUCommandLine;
66 tooling::addExpandedResponseFiles(Cmd.CommandLine, Cmd.Directory, Tokenizer,
67 *FS);
68
69 ParsedCompileCommandInfo Result;
70 Result.SourceFile = normalizePath(Cmd.Filename, Cmd.Directory);
71
72 bool SawPrecompile = false;
73 for (size_t I = 1; I < Cmd.CommandLine.size(); ++I) {
74 llvm::StringRef Arg = Cmd.CommandLine[I];
75 if (Arg == "--precompile") {
76 SawPrecompile = true;
77 continue;
78 }
79
80 if (Arg.consume_front("-fmodule-output=")) {
81 Result.OutputModuleFile = normalizePath(Arg, Cmd.Directory);
82 continue;
83 }
84 if (Arg == "-fmodule-output" && I + 1 < Cmd.CommandLine.size()) {
85 Result.OutputModuleFile =
86 normalizePath(Cmd.CommandLine[++I], Cmd.Directory);
87 continue;
88 }
89 if (SawPrecompile && Arg == "-o" && I + 1 < Cmd.CommandLine.size()) {
90 Result.OutputModuleFile =
91 normalizePath(Cmd.CommandLine[++I], Cmd.Directory);
92 continue;
93 }
94 if (SawPrecompile && Arg.starts_with("-o") && Arg.size() > 2) {
95 Result.OutputModuleFile = normalizePath(Arg.drop_front(2), Cmd.Directory);
96 continue;
97 }
98
99 if (!Arg.consume_front("-fmodule-file="))
100 continue;
101
102 auto Sep = Arg.find('=');
103 if (Sep == llvm::StringRef::npos || Sep == 0 || Sep + 1 == Arg.size())
104 continue;
105
106 Result.RequiredModuleFiles[Arg.take_front(Sep)] =
107 normalizePath(Arg.drop_front(Sep + 1), Cmd.Directory);
108 }
109
110 return Result;
111}
112
113std::optional<tooling::CompileCommand>
114getCompileCommandForFile(const clang::tooling::CompilationDatabase &CDB,
115 PathRef FilePath,
116 const ProjectModules::CommandMangler &Mangler) {
117 auto Candidates = CDB.getCompileCommands(FilePath);
118 if (Candidates.empty())
119 return std::nullopt;
120
121 // Choose the first candidates as the compile commands as the file.
122 // Following the same logic with
123 // DirectoryBasedGlobalCompilationDatabase::getCompileCommand.
124 tooling::CompileCommand Cmd = std::move(Candidates.front());
125
126 if (Mangler)
127 Mangler(Cmd, FilePath);
128
129 return Cmd;
130}
131
132/// A scanner to query the dependency information for C++20 Modules.
133///
134/// The scanner can scan a single file with `scan(PathRef)` member function
135/// or scan the whole project with `globalScan(vector<PathRef>)` member
136/// function. See the comments of `globalScan` to see the details.
137///
138/// The ModuleDependencyScanner can get the directly required module names for a
139/// specific source file. Also the ModuleDependencyScanner can get the source
140/// file declaring the primary module interface for a specific module name.
141///
142/// IMPORTANT NOTE: we assume that every module unit is only declared once in a
143/// source file in the project. But the assumption is not strictly true even
144/// besides the invalid projects. The language specification requires that every
145/// module unit should be unique in a valid program. But a project can contain
146/// multiple programs. Then it is valid that we can have multiple source files
147/// declaring the same module in a project as long as these source files don't
148/// interfere with each other.
149class ModuleDependencyScanner {
150public:
151 ModuleDependencyScanner(
152 std::shared_ptr<const clang::tooling::CompilationDatabase> CDB,
153 const ThreadsafeFS &TFS)
154 : CDB(CDB), Service([&TFS] {
155 dependencies::DependencyScanningServiceOptions Opts;
156 Opts.MakeVFS = [&] { return TFS.view(std::nullopt); };
157 Opts.Mode = dependencies::ScanningMode::CanonicalPreprocessing;
158 Opts.EmitWarnings = false;
159 Opts.ReportAbsolutePaths = false;
160 return Opts;
161 }()) {}
162
163 /// The scanned modules dependency information for a specific source file.
164 struct ModuleDependencyInfo {
165 /// The name of the module if the file is a module unit.
166 std::optional<std::string> ModuleName;
167 /// A list of names for the modules that the file directly depends.
168 std::vector<std::string> RequiredModules;
169 };
170
171 /// Scanning the single file specified by \param FilePath.
172 std::optional<ModuleDependencyInfo>
173 scan(PathRef FilePath, const ProjectModules::CommandMangler &Mangler);
174
175 /// Scanning every source file in the current project to get the
176 /// <module-name> to <module-unit-source> map.
177 /// TODO: We should find an efficient method to get the <module-name>
178 /// to <module-unit-source> map. We can make it either by providing
179 /// a global module dependency scanner to monitor every file. Or we
180 /// can simply require the build systems (or even the end users)
181 /// to provide the map.
182 void globalScan(const ProjectModules::CommandMangler &Mangler);
183
184 /// Get the source file from the module name. Note that the language
185 /// guarantees all the module names are unique in a valid program.
186 /// This function should only be called after globalScan.
187 ///
188 /// TODO: We should handle the case that there are multiple source files
189 /// declaring the same module.
190 PathRef getSourceForModuleName(llvm::StringRef ModuleName) const;
191
192 /// Return the direct required modules. Indirect required modules are not
193 /// included.
194 std::vector<std::string>
195 getRequiredModules(PathRef File,
196 const ProjectModules::CommandMangler &Mangler);
197
198private:
199 std::shared_ptr<const clang::tooling::CompilationDatabase> CDB;
200
201 // Whether the scanner has scanned the project globally.
202 bool GlobalScanned = false;
203
204 clang::dependencies::DependencyScanningService Service;
205
206 // TODO: Add a scanning cache.
207
208 // Map module name to source file path.
209 llvm::StringMap<std::string> ModuleNameToSource;
210};
211
212std::optional<ModuleDependencyScanner::ModuleDependencyInfo>
213ModuleDependencyScanner::scan(PathRef FilePath,
214 const ProjectModules::CommandMangler &Mangler) {
215 auto Cmd = getCompileCommandForFile(*CDB, FilePath, Mangler);
216 if (!Cmd)
217 return std::nullopt;
218
219 using namespace clang::tooling;
220
221 DependencyScanningTool ScanningTool(Service);
222
223 std::string S;
224 llvm::raw_string_ostream OS(S);
225 DiagnosticOptions DiagOpts;
226 DiagOpts.ShowCarets = false;
227 TextDiagnosticPrinter DiagConsumer(OS, DiagOpts);
228
229 std::optional<P1689Rule> ScanningResult =
230 ScanningTool.getP1689ModuleDependencyFile(*Cmd, Cmd->Directory,
231 DiagConsumer);
232
233 if (!ScanningResult) {
234 elog("Scanning modules dependencies for {0} failed: {1}", FilePath, S);
235 std::string Cmdline;
236 for (auto &Arg : Cmd->CommandLine)
237 Cmdline += Arg + " ";
238 elog("The command line the scanning tool use is: {0}", Cmdline);
239 return std::nullopt;
240 }
241
242 ModuleDependencyInfo Result;
243
244 if (ScanningResult->Provides) {
245 Result.ModuleName = ScanningResult->Provides->ModuleName;
246
247 auto [Iter, Inserted] = ModuleNameToSource.try_emplace(
248 ScanningResult->Provides->ModuleName, FilePath);
249
250 if (!Inserted &&
251 !pathEqual(normalizePath(Iter->second), normalizePath(FilePath))) {
252 elog("Detected multiple source files ({0}, {1}) declaring the same "
253 "module: '{2}'. "
254 "Now clangd may find the wrong source in such case.",
255 Iter->second, FilePath, ScanningResult->Provides->ModuleName);
256 }
257 }
258
259 for (auto &Required : ScanningResult->Requires)
260 Result.RequiredModules.push_back(Required.ModuleName);
261
262 return Result;
263}
264
265void ModuleDependencyScanner::globalScan(
266 const ProjectModules::CommandMangler &Mangler) {
267 if (GlobalScanned)
268 return;
269
270 for (auto &File : CDB->getAllFiles())
271 scan(File, Mangler);
272
273 GlobalScanned = true;
274}
275
276PathRef ModuleDependencyScanner::getSourceForModuleName(
277 llvm::StringRef ModuleName) const {
278 assert(
279 GlobalScanned &&
280 "We should only call getSourceForModuleName after calling globalScan()");
281
282 if (auto It = ModuleNameToSource.find(ModuleName);
283 It != ModuleNameToSource.end())
284 return It->second;
285
286 return {};
287}
288
289std::vector<std::string> ModuleDependencyScanner::getRequiredModules(
291 auto ScanningResult = scan(File, Mangler);
292 if (!ScanningResult)
293 return {};
294
295 return ScanningResult->RequiredModules;
296}
297} // namespace
298
299/// TODO: The existing `ScanningAllProjectModules` is not efficient. See the
300/// comments in ModuleDependencyScanner for detail.
301///
302/// In the future, we wish the build system can provide a well design
303/// compilation database for modules then we can query that new compilation
304/// database directly. Or we need to have a global long-live scanner to detect
305/// the state of each file.
307public:
309 std::shared_ptr<const clang::tooling::CompilationDatabase> CDB,
310 const ThreadsafeFS &TFS)
311 : Scanner(CDB, TFS) {}
312
313 ~ScanningAllProjectModules() override = default;
314
315 std::vector<std::string> getRequiredModules(PathRef File) override {
316 return Scanner.getRequiredModules(File, Mangler);
317 }
318
319 void setCommandMangler(CommandMangler Mangler) override {
320 this->Mangler = std::move(Mangler);
321 }
322
323 /// RequiredSourceFile is not used intentionally. See the comments of
324 /// ModuleDependencyScanner for detail.
325 std::string getSourceForModuleName(llvm::StringRef ModuleName,
326 PathRef RequiredSourceFile) override {
327 Scanner.globalScan(Mangler);
328 return Scanner.getSourceForModuleName(ModuleName).str();
329 }
330
331 std::string getModuleNameForSource(PathRef File) override {
332 auto ScanningResult = Scanner.scan(File, Mangler);
333 if (!ScanningResult || !ScanningResult->ModuleName)
334 return {};
335
336 return *ScanningResult->ModuleName;
337 }
338
339 // Determining Unique/Multiple needs a global scan; return Unknown for cost
340 // reasons. We will have other ProjectModules implementations can determine
341 // this more efficiently.
342 ModuleNameState getModuleNameState(llvm::StringRef /*ModuleName*/) override {
344 }
345
346private:
347 ModuleDependencyScanner Scanner;
348 CommandMangler Mangler;
349};
350
351/// Reads project module information directly from compile commands.
352///
353/// The key observation is that compile commands may already encode the mapping
354/// between a TU, the module names it imports, and the BMI paths it uses:
355/// - producers may spell the BMI path with `--precompile -o <bmi>` or
356/// `-fmodule-output=<bmi>`
357/// - consumers may spell the mapping from module name to BMI path with
358/// `-fmodule-file=<module>=<bmi>`
359///
360/// When that information is present, we can answer
361/// `getSourceForModuleName(ModuleName, RequiredSourceFile)` by first looking up
362/// the BMI path the consumer TU uses for `ModuleName`, and then mapping that
363/// BMI path back to the module unit source that produced it. This avoids the
364/// older scanning-only approach of guessing the module unit from the module
365/// name alone.
366///
367/// One subtle point is that producer commands alone do not reliably tell us the
368/// module name associated with a BMI path. In practice this backend learns that
369/// association from consumer `-fmodule-file=` entries, and then uses the BMI
370/// path to recover the producer source file. That is why indexing is built from
371/// both producer and consumer commands.
372///
373/// Note that compilation database can be stale, so results from this backend
374/// should be treated as preferred hints rather than unquestionable truth.
375/// The compound layer below validates or falls back when needed.
377public:
379 std::shared_ptr<const clang::tooling::CompilationDatabase> CDB,
380 const ThreadsafeFS &TFS)
381 : CDB(std::move(CDB)), TFS(TFS) {}
382
383 std::vector<std::string> getRequiredModules(PathRef File) override {
384 auto Parsed = parseFileCommand(File);
385 if (!Parsed)
386 return {};
387
388 std::vector<std::string> Result;
389 Result.reserve(Parsed->RequiredModuleFiles.size());
390 for (const auto &Required : Parsed->RequiredModuleFiles)
391 Result.push_back(Required.getKey().str());
392 return Result;
393 }
394
395 std::string getModuleNameForSource(PathRef File) override {
396 indexProducerCommands();
397 auto It = SourceToModuleName.find(
398 maybeCaseFoldPath(normalizePath(File, /*WorkingDir=*/{})));
399 if (It == SourceToModuleName.end() || It->second.Ambiguous)
400 return {};
401 return It->second.Name;
402 }
403
404 ModuleNameState getModuleNameState(llvm::StringRef ModuleName) override {
405 indexProducerCommands();
406 auto It = ModuleNameToDistinctSources.find(ModuleName);
407 if (It == ModuleNameToDistinctSources.end())
409 return It->second.size() > 1 ? ModuleNameState::Multiple
411 }
412
413 std::string getSourceForModuleName(llvm::StringRef ModuleName,
414 PathRef RequiredSourceFile) override {
415 auto Parsed = parseFileCommand(RequiredSourceFile);
416 if (!Parsed)
417 return {};
418
419 auto It = Parsed->RequiredModuleFiles.find(ModuleName);
420 if (It == Parsed->RequiredModuleFiles.end())
421 return {};
422
423 indexProducerCommands();
424 auto SourceIt = PCMToSource.find(maybeCaseFoldPath(It->second));
425 if (SourceIt == PCMToSource.end())
426 return {};
427
428 return SourceIt->second;
429 }
430
431 void setCommandMangler(CommandMangler Mangler) override {
432 this->Mangler = std::move(Mangler);
433 ProducerCommandsIndexed = false;
434 PCMToSource.clear();
435 ModuleNameToDistinctSources.clear();
436 SourceToModuleName.clear();
437 }
438
439private:
440 /// Parses the compile command for \p File into the module information
441 /// encoded in the command line.
442 std::optional<ParsedCompileCommandInfo> parseFileCommand(PathRef File) const {
443 auto Cmd = getCompileCommandForFile(*CDB, File, Mangler);
444 if (!Cmd)
445 return std::nullopt;
446 return parseCompileCommandInfo(std::move(*Cmd), TFS);
447 }
448
449 /// Builds indexes from producer and consumer compile commands.
450 ///
451 /// Compile commands are parsed once up front. The first pass records which
452 /// source file produces each BMI path. The second pass walks consumer
453 /// commands, uses `-fmodule-file=` information to associate module names with
454 /// those BMI paths, and then records which producer source files are
455 /// referenced for each module name.
456 void indexProducerCommands() {
457 if (ProducerCommandsIndexed)
458 return;
459
460 std::vector<ParsedCompileCommandInfo> ParsedCommands;
461 auto AllFiles = CDB->getAllFiles();
462 ParsedCommands.reserve(AllFiles.size());
463 for (const auto &File : AllFiles) {
464 auto Parsed = parseFileCommand(File);
465 if (!Parsed)
466 continue;
467
468 if (Parsed->OutputModuleFile)
469 PCMToSource[maybeCaseFoldPath(*Parsed->OutputModuleFile)] =
470 Parsed->SourceFile;
471
472 ParsedCommands.push_back(std::move(*Parsed));
473 }
474
475 for (const auto &Parsed : ParsedCommands) {
476 for (const auto &Required : Parsed.RequiredModuleFiles) {
477 auto SourceIt =
478 PCMToSource.find(maybeCaseFoldPath(Required.getValue()));
479 if (SourceIt == PCMToSource.end())
480 continue;
481 ModuleNameToDistinctSources[Required.getKey()].insert(
482 maybeCaseFoldPath(SourceIt->second));
483
484 auto &Recovered =
485 SourceToModuleName[maybeCaseFoldPath(SourceIt->second)];
486 if (Recovered.Name.empty())
487 Recovered.Name = Required.getKey().str();
488 else if (Recovered.Name != Required.getKey()) {
489 if (!Recovered.Ambiguous) {
490 elog("Detected conflicting module names ('{0}' and '{1}') for "
491 "the same module file {2} produced by source {3}",
492 Recovered.Name, Required.getKey(), Required.getValue(),
493 SourceIt->second);
494 }
495 Recovered.Ambiguous = true;
496 }
497 }
498 }
499
500 ProducerCommandsIndexed = true;
501 }
502
503 std::shared_ptr<const clang::tooling::CompilationDatabase> CDB;
504 const ThreadsafeFS &TFS;
505 CommandMangler Mangler;
506 bool ProducerCommandsIndexed = false;
507
508 llvm::StringMap<std::string> PCMToSource;
509
510 using DistinctSourceSet = llvm::StringSet<>;
511 llvm::StringMap<DistinctSourceSet> ModuleNameToDistinctSources;
512
513 struct RecoveredModuleName {
514 std::string Name;
515 bool Ambiguous = false;
516 };
517 llvm::StringMap<RecoveredModuleName> SourceToModuleName;
518};
519
520/// Combines the compile-commands backend with the scanning backend.
521///
522/// For getSourceForModuleName, it prefers compile-command-derived results when
523/// available to avoid scanning the whole project, but validates them against
524/// scanning results to avoid returning stale information. For other queries,
525/// it returns scanning results directly as scanning information is update to
526/// date.
528public:
530 std::shared_ptr<const clang::tooling::CompilationDatabase> CDB,
531 const ThreadsafeFS &TFS)
532 : CompileCommands(
533 std::make_unique<CompileCommandsProjectModules>(CDB, TFS)),
534 Scanning(
535 std::make_unique<ScanningAllProjectModules>(std::move(CDB), TFS)) {}
536
537 std::vector<std::string> getRequiredModules(PathRef File) override {
538 // Return scanning results directly as it is fast enough and up to date.
539 return Scanning->getRequiredModules(File);
540 }
541
542 std::string getModuleNameForSource(PathRef File) override {
543 // Return scanning results directly as it is fast enough and up to date.
544 return Scanning->getModuleNameForSource(File);
545 }
546
547 std::string getSourceForModuleName(llvm::StringRef ModuleName,
548 PathRef RequiredSourceFile) override {
549 auto FromCompileCommands =
550 CompileCommands->getSourceForModuleName(ModuleName, RequiredSourceFile);
551 // Check if the source still declares the module.
552 // This is to validate compile-command-derived results may be stale and
553 // scan a single file is fast enough. We just don't want to scan the project
554 // entirely.
555 if (!FromCompileCommands.empty() &&
556 Scanning->getModuleNameForSource(FromCompileCommands) == ModuleName)
557 return FromCompileCommands;
558
559 return Scanning->getSourceForModuleName(ModuleName, RequiredSourceFile);
560 }
561
562 ModuleNameState getModuleNameState(llvm::StringRef ModuleName) override {
563 auto FromCompileCommands = CompileCommands->getModuleNameState(ModuleName);
564 if (FromCompileCommands != ModuleNameState::Unknown)
565 return FromCompileCommands;
566 return Scanning->getModuleNameState(ModuleName);
567 }
568
569 void setCommandMangler(CommandMangler Mangler) override {
570 this->Mangler = std::move(Mangler);
571 auto ForwardMangler = [this](tooling::CompileCommand &Command,
572 PathRef CommandPath) {
573 if (this->Mangler)
574 this->Mangler(Command, CommandPath);
575 };
576 CompileCommands->setCommandMangler(ForwardMangler);
577 Scanning->setCommandMangler(std::move(ForwardMangler));
578 }
579
580private:
581 std::unique_ptr<CompileCommandsProjectModules> CompileCommands;
582 std::unique_ptr<ScanningAllProjectModules> Scanning;
583 CommandMangler Mangler;
584};
585
586/// Creates the project-modules facade used by clangd.
587///
588/// The implementation is intentionally layered:
589///
590/// CompoundProjectModules
591/// / \
592/// v v
593/// CompileCommands ScanningAllProjectModules
594/// ProjectModules |
595/// | v
596/// | ModuleDependencyScanner
597/// |
598/// +-- preferred specifically for recovering the source file for a module
599/// | name in the context of a consumer TU, because compile commands
600/// | encode `module name -> BMI -> producer source`
601/// |
602/// +-- scanning remains fallback/validation for stale or missing data
603///
604/// - `CompileCommandsProjectModules` reads module relationships that the build
605/// system already made explicit in compile commands. In particular, it uses
606/// producer-side BMI output paths together with consumer-side
607/// `-fmodule-file=<module>=<bmi>` entries to recover the module unit source a
608/// TU actually depends on. This is the preferred source because it can
609/// distinguish different module producers for the same module name when
610/// different translation units reference different BMIs.
611/// - `ScanningAllProjectModules` derives module information by scanning source
612/// files. It is more expensive, but it can still answer queries that are not
613/// present in compile commands and validate compile-command-derived results.
614/// - `CompoundProjectModules` arbitrates between the two backends on a
615/// per-query basis. Compile commands are especially valuable for
616/// `getSourceForModuleName()` because they preserve the consumer TU's actual
617/// `module name -> BMI` choice. Other queries may still fall back to, or be
618/// validated by, scanning because compile-command information may be
619/// incomplete or stale.
620///
621/// This split keeps the logic simple: compile commands provide precision when
622/// available, while scanning preserves compatibility with projects that have
623/// incomplete module information in their compilation database.
624std::unique_ptr<ProjectModules> getProjectModules(
625 std::shared_ptr<const clang::tooling::CompilationDatabase> CDB,
626 const ThreadsafeFS &TFS) {
627 return std::make_unique<CompoundProjectModules>(std::move(CDB), TFS);
628}
629
630} // namespace clang::clangd
void elog(const char *Fmt, Ts &&... Vals)
Definition Logger.h:61
Reads project module information directly from compile commands.
CompileCommandsProjectModules(std::shared_ptr< const clang::tooling::CompilationDatabase > CDB, const ThreadsafeFS &TFS)
std::string getModuleNameForSource(PathRef File) override
void setCommandMangler(CommandMangler Mangler) override
std::string getSourceForModuleName(llvm::StringRef ModuleName, PathRef RequiredSourceFile) override
ModuleNameState getModuleNameState(llvm::StringRef ModuleName) override
std::vector< std::string > getRequiredModules(PathRef File) override
std::vector< std::string > getRequiredModules(PathRef File) override
ModuleNameState getModuleNameState(llvm::StringRef ModuleName) override
std::string getModuleNameForSource(PathRef File) override
void setCommandMangler(CommandMangler Mangler) override
std::string getSourceForModuleName(llvm::StringRef ModuleName, PathRef RequiredSourceFile) override
CompoundProjectModules(std::shared_ptr< const clang::tooling::CompilationDatabase > CDB, const ThreadsafeFS &TFS)
An interface to query the modules information in the project.
llvm::unique_function< void(tooling::CompileCommand &, PathRef) const > CommandMangler
TODO: The existing ScanningAllProjectModules is not efficient.
void setCommandMangler(CommandMangler Mangler) override
ScanningAllProjectModules(std::shared_ptr< const clang::tooling::CompilationDatabase > CDB, const ThreadsafeFS &TFS)
std::string getModuleNameForSource(PathRef File) override
std::vector< std::string > getRequiredModules(PathRef File) override
ModuleNameState getModuleNameState(llvm::StringRef) override
std::string getSourceForModuleName(llvm::StringRef ModuleName, PathRef RequiredSourceFile) override
RequiredSourceFile is not used intentionally.
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
std::string maybeCaseFoldPath(PathRef Path)
Definition Path.cpp:18
bool pathEqual(PathRef A, PathRef B)
Definition Path.cpp:19
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition Path.h:29
std::string Path
A typedef to represent a file path.
Definition Path.h:26
std::unique_ptr< ProjectModules > getProjectModules(std::shared_ptr< const clang::tooling::CompilationDatabase > CDB, const ThreadsafeFS &TFS)
Creates the project-modules facade used by clangd.