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