clang 23.0.0git
DependencyScanningFilesystem.cpp
Go to the documentation of this file.
1//===- DependencyScanningFilesystem.cpp - Optimized Scanning FS -----------===//
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
11#include "llvm/Support/MemoryBuffer.h"
12#include "llvm/Support/Threading.h"
13#include <optional>
14
15using namespace clang;
16using namespace dependencies;
17
18llvm::ErrorOr<DependencyScanningWorkerFilesystem::TentativeEntry>
19DependencyScanningWorkerFilesystem::readFile(StringRef Filename) {
20 // Load the file and its content from the file system.
21 auto MaybeFile = getUnderlyingFS().openFileForRead(Filename);
22 if (!MaybeFile)
23 return MaybeFile.getError();
24 auto File = std::move(*MaybeFile);
25
26 auto MaybeStat = File->status();
27 if (!MaybeStat)
28 return MaybeStat.getError();
29 auto Stat = std::move(*MaybeStat);
30
31 auto MaybeBuffer = File->getBuffer(Stat.getName());
32 if (!MaybeBuffer)
33 return MaybeBuffer.getError();
34 auto Buffer = std::move(*MaybeBuffer);
35
36 // If the file size changed between read and stat, pretend it didn't.
37 if (Stat.getSize() != Buffer->getBufferSize())
38 Stat = llvm::vfs::Status::copyWithNewSize(Stat, Buffer->getBufferSize());
39
40 return TentativeEntry(Stat, std::move(Buffer));
41}
42
44 EntryRef Ref) {
45 auto &Entry = Ref.Entry;
46
47 if (Entry.isError() || Entry.isDirectory())
48 return false;
49
50 CachedFileContents *Contents = Entry.getCachedContents();
51 assert(Contents && "contents not initialized");
52
53 // Double-checked locking.
54 if (Contents->DepDirectives.load())
55 return true;
56
57 std::lock_guard<std::mutex> GuardLock(Contents->ValueLock);
58
59 // Double-checked locking.
60 if (Contents->DepDirectives.load())
61 return true;
62
64 // Scan the file for preprocessor directives that might affect the
65 // dependencies.
66 if (scanSourceForDependencyDirectives(Contents->Original->getBuffer(),
67 Contents->DepDirectiveTokens,
68 Directives)) {
69 Contents->DepDirectiveTokens.clear();
70 // FIXME: Propagate the diagnostic if desired by the client.
71 Contents->DepDirectives.store(new std::optional<DependencyDirectivesTy>());
72 return false;
73 }
74
75 // This function performed double-checked locking using `DepDirectives`.
76 // Assigning it must be the last thing this function does, otherwise other
77 // threads may skip the critical section (`DepDirectives != nullptr`), leading
78 // to a data race.
79 Contents->DepDirectives.store(
80 new std::optional<DependencyDirectivesTy>(std::move(Directives)));
81 return true;
82}
83
86 // This heuristic was chosen using a empirical testing on a
87 // reasonably high core machine (iMacPro 18 cores / 36 threads). The cache
88 // sharding gives a performance edge by reducing the lock contention.
89 // FIXME: A better heuristic might also consider the OS to account for
90 // the different cost of lock contention on different OSes.
91 NumShards =
92 std::max(2u, llvm::hardware_concurrency().compute_thread_count() / 4);
93 CacheShards = std::make_unique<CacheShard[]>(NumShards);
94}
95
98 StringRef Filename) const {
99 assert(llvm::sys::path::is_absolute_gnu(Filename));
100 return CacheShards[llvm::hash_value(Filename) % NumShards];
101}
102
105 llvm::sys::fs::UniqueID UID) const {
106 auto Hash = llvm::hash_combine(UID.getDevice(), UID.getFile());
107 return CacheShards[Hash % NumShards];
108}
109
110std::vector<DependencyScanningFilesystemSharedCache::OutOfDateEntry>
112 llvm::vfs::FileSystem &UnderlyingFS) const {
113 // Iterate through all shards and look for cached stat errors.
114 std::vector<OutOfDateEntry> InvalidDiagInfo;
115 for (unsigned i = 0; i < NumShards; i++) {
116 const CacheShard &Shard = CacheShards[i];
117 std::lock_guard<std::mutex> LockGuard(Shard.CacheLock);
118 for (const auto &[Path, CachedPair] : Shard.CacheByFilename) {
119 const CachedFileSystemEntry *Entry = CachedPair.first;
120 llvm::ErrorOr<llvm::vfs::Status> Status = UnderlyingFS.status(Path);
121 if (Status) {
122 if (Entry->getError()) {
123 // This is the case where we have cached the non-existence
124 // of the file at Path first, and a file at the path is created
125 // later. The cache entry is not invalidated (as we have no good
126 // way to do it now), which may lead to missing file build errors.
127 InvalidDiagInfo.emplace_back(Path.data());
128 } else {
129 llvm::vfs::Status CachedStatus = Entry->getStatus();
130 if (Status->getType() == llvm::sys::fs::file_type::regular_file &&
131 Status->getType() == CachedStatus.getType()) {
132 // We only check regular files. Directory files sizes could change
133 // due to content changes, and reporting directory size changes can
134 // lead to false positives.
135 // TODO: At the moment, we do not detect symlinks to files whose
136 // size may change. We need to decide if we want to detect cached
137 // symlink size changes. We can also expand this to detect file
138 // type changes.
139 uint64_t CachedSize = CachedStatus.getSize();
140 uint64_t ActualSize = Status->getSize();
141 if (CachedSize != ActualSize) {
142 // This is the case where the cached file has a different size
143 // from the actual file that comes from the underlying FS.
144 InvalidDiagInfo.emplace_back(Path.data(), CachedSize, ActualSize);
145 }
146 }
147 }
148 }
149 }
150 }
151 return InvalidDiagInfo;
152}
153
156 StringRef Filename) const {
157 assert(llvm::sys::path::is_absolute_gnu(Filename));
158 std::lock_guard<std::mutex> LockGuard(CacheLock);
159 auto It = CacheByFilename.find(Filename);
160 return It == CacheByFilename.end() ? nullptr : It->getValue().first;
161}
162
165 llvm::sys::fs::UniqueID UID) const {
166 std::lock_guard<std::mutex> LockGuard(CacheLock);
167 auto It = EntriesByUID.find(UID);
168 return It == EntriesByUID.end() ? nullptr : It->getSecond();
169}
170
173 getOrEmplaceEntryForFilename(StringRef Filename,
174 llvm::ErrorOr<llvm::vfs::Status> Stat) {
175 std::lock_guard<std::mutex> LockGuard(CacheLock);
176 auto [It, Inserted] = CacheByFilename.insert({Filename, {nullptr, nullptr}});
177 auto &[CachedEntry, CachedRealPath] = It->getValue();
178 if (!CachedEntry) {
179 // The entry is not present in the shared cache. Either the cache doesn't
180 // know about the file at all, or it only knows about its real path.
181 assert((Inserted || CachedRealPath) && "existing file with empty pair");
182 CachedEntry =
183 new (EntryStorage.Allocate()) CachedFileSystemEntry(std::move(Stat));
184 }
185 return *CachedEntry;
186}
187
190 llvm::sys::fs::UniqueID UID, llvm::vfs::Status Stat,
191 std::unique_ptr<llvm::MemoryBuffer> Contents) {
192 std::lock_guard<std::mutex> LockGuard(CacheLock);
193 auto [It, Inserted] = EntriesByUID.try_emplace(UID);
194 auto &CachedEntry = It->getSecond();
195 if (Inserted) {
196 CachedFileContents *StoredContents = nullptr;
197 if (Contents)
198 StoredContents = new (ContentsStorage.Allocate())
199 CachedFileContents(std::move(Contents));
200 CachedEntry = new (EntryStorage.Allocate())
201 CachedFileSystemEntry(std::move(Stat), StoredContents);
202 }
203 return *CachedEntry;
204}
205
208 getOrInsertEntryForFilename(StringRef Filename,
209 const CachedFileSystemEntry &Entry) {
210 std::lock_guard<std::mutex> LockGuard(CacheLock);
211 auto [It, Inserted] = CacheByFilename.insert({Filename, {&Entry, nullptr}});
212 auto &[CachedEntry, CachedRealPath] = It->getValue();
213 if (!Inserted || !CachedEntry)
214 CachedEntry = &Entry;
215 return *CachedEntry;
216}
217
218const CachedRealPath *
220 StringRef Filename) const {
221 assert(llvm::sys::path::is_absolute_gnu(Filename));
222 std::lock_guard<std::mutex> LockGuard(CacheLock);
223 auto It = CacheByFilename.find(Filename);
224 return It == CacheByFilename.end() ? nullptr : It->getValue().second;
225}
226
228 getOrEmplaceRealPathForFilename(StringRef Filename,
229 llvm::ErrorOr<llvm::StringRef> RealPath) {
230 std::lock_guard<std::mutex> LockGuard(CacheLock);
231
232 const CachedRealPath *&StoredRealPath = CacheByFilename[Filename].second;
233 if (!StoredRealPath) {
234 auto OwnedRealPath = [&]() -> CachedRealPath {
235 if (!RealPath)
236 return RealPath.getError();
237 return RealPath->str();
238 }();
239
240 StoredRealPath = new (RealPathStorage.Allocate())
241 CachedRealPath(std::move(OwnedRealPath));
242 }
243
244 return *StoredRealPath;
245}
246
251 llvm::vfs::ProxyFileSystem>(std::move(FS)),
252 Service(Service), WorkingDirForCacheLookup(llvm::errc::invalid_argument) {
253 updateWorkingDirForCacheLookup();
254}
255
257DependencyScanningWorkerFilesystem::getOrEmplaceSharedEntryForUID(
258 TentativeEntry TEntry) {
259 auto &Shard =
260 Service.getSharedCache().getShardForUID(TEntry.Status.getUniqueID());
261 return Shard.getOrEmplaceEntryForUID(TEntry.Status.getUniqueID(),
262 std::move(TEntry.Status),
263 std::move(TEntry.Contents));
264}
265
267DependencyScanningWorkerFilesystem::findEntryByFilenameWithWriteThrough(
268 StringRef Filename) {
269 if (const auto *Entry = LocalCache.findEntryByFilename(Filename))
270 return Entry;
271 auto &Shard = Service.getSharedCache().getShardForFilename(Filename);
272 if (const auto *Entry = Shard.findEntryByFilename(Filename))
273 return &LocalCache.insertEntryForFilename(Filename, *Entry);
274 return nullptr;
275}
276
278DependencyScanningWorkerFilesystem::findSharedEntryByUID(
279 llvm::vfs::Status Stat) const {
280 return Service.getSharedCache()
281 .getShardForUID(Stat.getUniqueID())
282 .findEntryByUID(Stat.getUniqueID());
283}
284
286DependencyScanningWorkerFilesystem::getOrEmplaceSharedEntryForFilename(
287 StringRef Filename, std::error_code EC) {
288 return Service.getSharedCache()
289 .getShardForFilename(Filename)
290 .getOrEmplaceEntryForFilename(Filename, EC);
291}
292
294DependencyScanningWorkerFilesystem::getOrInsertSharedEntryForFilename(
295 StringRef Filename, const CachedFileSystemEntry &Entry) {
296 return Service.getSharedCache()
297 .getShardForFilename(Filename)
298 .getOrInsertEntryForFilename(Filename, Entry);
299}
300
301llvm::ErrorOr<const CachedFileSystemEntry &>
302DependencyScanningWorkerFilesystem::computeAndStoreResult(
303 StringRef OriginalFilename, StringRef FilenameForLookup) {
304 llvm::ErrorOr<llvm::vfs::Status> Stat =
305 getUnderlyingFS().status(OriginalFilename);
306 if (!Stat) {
307 if (!Service.getOpts().CacheNegativeStats ||
308 !shouldCacheNegativeStatsForPath(OriginalFilename))
309 return Stat.getError();
310
311 const auto &Entry =
312 getOrEmplaceSharedEntryForFilename(FilenameForLookup, Stat.getError());
313 return insertLocalEntryForFilename(FilenameForLookup, Entry);
314 }
315
316 if (const auto *Entry = findSharedEntryByUID(*Stat))
317 return insertLocalEntryForFilename(FilenameForLookup, *Entry);
318
319 auto TEntry =
320 Stat->isDirectory() ? TentativeEntry(*Stat) : readFile(OriginalFilename);
321
322 const CachedFileSystemEntry *SharedEntry = [&]() {
323 if (TEntry) {
324 const auto &UIDEntry = getOrEmplaceSharedEntryForUID(std::move(*TEntry));
325 return &getOrInsertSharedEntryForFilename(FilenameForLookup, UIDEntry);
326 }
327 return &getOrEmplaceSharedEntryForFilename(FilenameForLookup,
328 TEntry.getError());
329 }();
330
331 return insertLocalEntryForFilename(FilenameForLookup, *SharedEntry);
332}
333
334llvm::ErrorOr<EntryRef>
336 StringRef OriginalFilename) {
337 SmallString<256> PathBuf;
338 auto FilenameForLookup = tryGetFilenameForLookup(OriginalFilename, PathBuf);
339 if (!FilenameForLookup)
340 return FilenameForLookup.getError();
341
342 if (const auto *Entry =
343 findEntryByFilenameWithWriteThrough(*FilenameForLookup))
344 return EntryRef(OriginalFilename, *Entry).unwrapError();
345 auto MaybeEntry = computeAndStoreResult(OriginalFilename, *FilenameForLookup);
346 if (!MaybeEntry)
347 return MaybeEntry.getError();
348 return EntryRef(OriginalFilename, *MaybeEntry).unwrapError();
349}
350
351llvm::ErrorOr<llvm::vfs::Status>
353 SmallString<256> OwnedFilename;
354 StringRef Filename = Path.toStringRef(OwnedFilename);
355
356 llvm::ErrorOr<EntryRef> Result = getOrCreateFileSystemEntry(Filename);
357 if (!Result)
358 return Result.getError();
359 return Result->getStatus();
360}
361
363 // While some VFS overlay filesystems may implement more-efficient
364 // mechanisms for `exists` queries, `DependencyScanningWorkerFilesystem`
365 // typically wraps `RealFileSystem` which does not specialize `exists`,
366 // so it is not likely to benefit from such optimizations. Instead,
367 // it is more-valuable to have this query go through the
368 // cached-`status` code-path of the `DependencyScanningWorkerFilesystem`.
369 llvm::ErrorOr<llvm::vfs::Status> Status = status(Path);
370 return Status && Status->exists();
371}
372
373namespace {
374
375/// The VFS that is used by clang consumes the \c CachedFileSystemEntry using
376/// this subclass.
377class DepScanFile final : public llvm::vfs::File {
378public:
379 DepScanFile(std::unique_ptr<llvm::MemoryBuffer> Buffer,
380 llvm::vfs::Status Stat)
381 : Buffer(std::move(Buffer)), Stat(std::move(Stat)) {}
382
383 static llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> create(EntryRef Entry);
384
385 llvm::ErrorOr<llvm::vfs::Status> status() override { return Stat; }
386
387 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
388 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
389 bool IsVolatile) override {
390 return llvm::MemoryBuffer::getMemBuffer(Buffer->getMemBufferRef(),
391 RequiresNullTerminator);
392 }
393
394 std::error_code close() override { return {}; }
395
396private:
397 std::unique_ptr<llvm::MemoryBuffer> Buffer;
398 llvm::vfs::Status Stat;
399};
400
401} // end anonymous namespace
402
403llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
404DepScanFile::create(EntryRef Entry) {
405 assert(!Entry.isError() && "error");
406
407 if (Entry.isDirectory())
408 return std::make_error_code(std::errc::is_a_directory);
409
410 auto Result = std::make_unique<DepScanFile>(
411 llvm::MemoryBuffer::getMemBuffer(Entry.getContents(),
412 Entry.getStatus().getName(),
413 /*RequiresNullTerminator=*/false),
414 Entry.getStatus());
415
416 return llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>(
417 std::unique_ptr<llvm::vfs::File>(std::move(Result)));
418}
419
420llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
422 SmallString<256> OwnedFilename;
423 StringRef Filename = Path.toStringRef(OwnedFilename);
424
425 llvm::ErrorOr<EntryRef> Result = getOrCreateFileSystemEntry(Filename);
426 if (!Result)
427 return Result.getError();
428 return DepScanFile::create(Result.get());
429}
430
431std::error_code
433 SmallVectorImpl<char> &Output) {
434 SmallString<256> OwnedFilename;
435 StringRef OriginalFilename = Path.toStringRef(OwnedFilename);
436
437 SmallString<256> PathBuf;
438 auto FilenameForLookup = tryGetFilenameForLookup(OriginalFilename, PathBuf);
439 if (!FilenameForLookup)
440 return FilenameForLookup.getError();
441
442 auto HandleCachedRealPath =
443 [&Output](const CachedRealPath &RealPath) -> std::error_code {
444 if (!RealPath)
445 return RealPath.getError();
446 Output.assign(RealPath->begin(), RealPath->end());
447 return {};
448 };
449
450 // If we already have the result in local cache, no work required.
451 if (const auto *RealPath =
452 LocalCache.findRealPathByFilename(*FilenameForLookup))
453 return HandleCachedRealPath(*RealPath);
454
455 // If we have the result in the shared cache, cache it locally.
456 auto &Shard =
457 Service.getSharedCache().getShardForFilename(*FilenameForLookup);
458 if (const auto *ShardRealPath =
459 Shard.findRealPathByFilename(*FilenameForLookup)) {
460 const auto &RealPath = LocalCache.insertRealPathForFilename(
461 *FilenameForLookup, *ShardRealPath);
462 return HandleCachedRealPath(RealPath);
463 }
464
465 // If we don't know the real path, compute it...
466 std::error_code EC = getUnderlyingFS().getRealPath(OriginalFilename, Output);
467 llvm::ErrorOr<llvm::StringRef> ComputedRealPath = EC;
468 if (!EC)
469 ComputedRealPath = StringRef{Output.data(), Output.size()};
470
471 // ...and try to write it into the shared cache. In case some other thread won
472 // this race and already wrote its own result there, just adopt it. Write
473 // whatever is in the shared cache into the local one.
474 const auto &RealPath = Shard.getOrEmplaceRealPathForFilename(
475 *FilenameForLookup, ComputedRealPath);
476 return HandleCachedRealPath(
477 LocalCache.insertRealPathForFilename(*FilenameForLookup, RealPath));
478}
479
481 const Twine &Path) {
482 std::error_code EC = ProxyFileSystem::setCurrentWorkingDirectory(Path);
483 updateWorkingDirForCacheLookup();
484 return EC;
485}
486
487void DependencyScanningWorkerFilesystem::updateWorkingDirForCacheLookup() {
488 llvm::ErrorOr<std::string> CWD =
489 getUnderlyingFS().getCurrentWorkingDirectory();
490 if (!CWD) {
491 WorkingDirForCacheLookup = CWD.getError();
492 } else if (!llvm::sys::path::is_absolute_gnu(*CWD)) {
493 WorkingDirForCacheLookup = llvm::errc::invalid_argument;
494 } else {
495 WorkingDirForCacheLookup = *CWD;
496 }
497 assert(!WorkingDirForCacheLookup ||
498 llvm::sys::path::is_absolute_gnu(*WorkingDirForCacheLookup));
499}
500
501llvm::ErrorOr<StringRef>
502DependencyScanningWorkerFilesystem::tryGetFilenameForLookup(
503 StringRef OriginalFilename, llvm::SmallVectorImpl<char> &PathBuf) const {
504 StringRef FilenameForLookup;
505 if (llvm::sys::path::is_absolute_gnu(OriginalFilename)) {
506 FilenameForLookup = OriginalFilename;
507 } else if (!WorkingDirForCacheLookup) {
508 return WorkingDirForCacheLookup.getError();
509 } else {
510 StringRef RelFilename = OriginalFilename;
511 RelFilename.consume_front("./");
512 PathBuf.assign(WorkingDirForCacheLookup->begin(),
513 WorkingDirForCacheLookup->end());
514 llvm::sys::path::append(PathBuf, RelFilename);
515 FilenameForLookup = StringRef{PathBuf.begin(), PathBuf.size()};
516 }
517 assert(llvm::sys::path::is_absolute_gnu(FilenameForLookup));
518 return FilenameForLookup;
519}
520
An in-memory representation of a file system entity that is of interest to the dependency scanning fi...
const CachedFileSystemEntry & insertEntryForFilename(StringRef Filename, const CachedFileSystemEntry &Entry)
Associates the given entry with the filename and returns the given entry pointer (for convenience).
const CachedFileSystemEntry * findEntryByFilename(StringRef Filename) const
Returns entry associated with the filename or nullptr if none is found.
CacheShard & getShardForFilename(StringRef Filename) const
Returns shard for the given key.
std::vector< OutOfDateEntry > getOutOfDateEntries(llvm::vfs::FileSystem &UnderlyingFS) const
Visits all cached entries and re-stat an entry using UnderlyingFS to check if the cache contains out-...
The dependency scanning service contains shared configuration and state that is used by the individua...
DependencyScanningFilesystemSharedCache & getSharedCache()
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
bool ensureDirectiveTokensArePopulated(EntryRef Entry)
Ensure the directive tokens are populated for this file entry.
bool exists(const Twine &Path) override
Check whether Path exists.
DependencyScanningWorkerFilesystem(DependencyScanningService &Service, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS)
llvm::ErrorOr< EntryRef > getOrCreateFileSystemEntry(StringRef Filename)
Returns entry for the given filename.
llvm::ErrorOr< std::unique_ptr< llvm::vfs::File > > openFileForRead(const Twine &Path) override
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
llvm::ErrorOr< llvm::vfs::Status > status(const Twine &Path) override
Reference to a CachedFileSystemEntry.
llvm::ErrorOr< EntryRef > unwrapError() const
If the cached entry represents an error, promotes it into ErrorOr.
llvm::ErrorOr< std::string > CachedRealPath
bool shouldCacheNegativeStatsForPath(StringRef Path)
The JSON file list parser is used to communicate input to InstallAPI.
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
bool scanSourceForDependencyDirectives(StringRef Input, SmallVectorImpl< dependency_directives_scan::Token > &Tokens, SmallVectorImpl< dependency_directives_scan::Directive > &Directives, DiagnosticsEngine *Diags=nullptr, SourceLocation InputSourceLoc=SourceLocation())
Scan the input for the preprocessor directives that might have an effect on the dependencies for a co...
@ Result
The result type of a method or function.
Definition TypeBase.h:905
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
hash_code hash_value(const clang::dependencies::ModuleID &ID)
Contents and directive tokens of a cached file entry.
std::unique_ptr< llvm::MemoryBuffer > Original
Owning storage for the original contents.
SmallVector< dependency_directives_scan::Token, 10 > DepDirectiveTokens
std::atomic< const std::optional< DependencyDirectivesTy > * > DepDirectives
Accessor to the directive tokens that's atomic to avoid data races.
std::mutex ValueLock
The mutex that must be locked before mutating directive tokens.
const CachedFileSystemEntry & getOrEmplaceEntryForUID(llvm::sys::fs::UniqueID UID, llvm::vfs::Status Stat, std::unique_ptr< llvm::MemoryBuffer > Contents)
Returns entry associated with the unique ID if there is some.
llvm::SpecificBumpPtrAllocator< CachedFileSystemEntry > EntryStorage
The backing storage for cached entries.
llvm::SpecificBumpPtrAllocator< CachedFileContents > ContentsStorage
The backing storage for cached contents.
llvm::SpecificBumpPtrAllocator< CachedRealPath > RealPathStorage
The backing storage for cached real paths.
const CachedFileSystemEntry * findEntryByUID(llvm::sys::fs::UniqueID UID) const
Returns entry associated with the unique ID or nullptr if none is found.
const CachedRealPath * findRealPathByFilename(StringRef Filename) const
Returns the real path associated with the filename or nullptr if none is found.
std::mutex CacheLock
The mutex that needs to be locked before mutation of any member.
const CachedFileSystemEntry & getOrInsertEntryForFilename(StringRef Filename, const CachedFileSystemEntry &Entry)
Returns entry associated with the filename if there is some.
const CachedFileSystemEntry * findEntryByFilename(StringRef Filename) const
Returns entry associated with the filename or nullptr if none is found.
const CachedFileSystemEntry & getOrEmplaceEntryForFilename(StringRef Filename, llvm::ErrorOr< llvm::vfs::Status > Stat)
Returns entry associated with the filename if there is some.
llvm::StringMap< std::pair< const CachedFileSystemEntry *, const CachedRealPath * >, llvm::BumpPtrAllocator > CacheByFilename
Map from filenames to cached entries and real paths.
const CachedRealPath & getOrEmplaceRealPathForFilename(StringRef Filename, llvm::ErrorOr< StringRef > RealPath)
Returns the real path associated with the filename if there is some.
llvm::DenseMap< llvm::sys::fs::UniqueID, const CachedFileSystemEntry * > EntriesByUID
Map from unique IDs to cached entries.