1e1f4c4aaSAlex Lorenz //===- DependencyScanningFilesystem.cpp - clang-scan-deps fs --------------===//
2e1f4c4aaSAlex Lorenz //
3e1f4c4aaSAlex Lorenz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e1f4c4aaSAlex Lorenz // See https://llvm.org/LICENSE.txt for license information.
5e1f4c4aaSAlex Lorenz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e1f4c4aaSAlex Lorenz //
7e1f4c4aaSAlex Lorenz //===----------------------------------------------------------------------===//
8e1f4c4aaSAlex Lorenz
9e1f4c4aaSAlex Lorenz #include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h"
10e1f4c4aaSAlex Lorenz #include "llvm/Support/MemoryBuffer.h"
1113a351e8SJan Svoboda #include "llvm/Support/SmallVectorMemoryBuffer.h"
12e1f4c4aaSAlex Lorenz #include "llvm/Support/Threading.h"
13e1f4c4aaSAlex Lorenz
14e1f4c4aaSAlex Lorenz using namespace clang;
15e1f4c4aaSAlex Lorenz using namespace tooling;
16e1f4c4aaSAlex Lorenz using namespace dependencies;
17e1f4c4aaSAlex Lorenz
185daeada3SJan Svoboda llvm::ErrorOr<DependencyScanningWorkerFilesystem::TentativeEntry>
readFile(StringRef Filename)195daeada3SJan Svoboda DependencyScanningWorkerFilesystem::readFile(StringRef Filename) {
20e1f4c4aaSAlex Lorenz // Load the file and its content from the file system.
215daeada3SJan Svoboda auto MaybeFile = getUnderlyingFS().openFileForRead(Filename);
22e1f4c4aaSAlex Lorenz if (!MaybeFile)
23e1f4c4aaSAlex Lorenz return MaybeFile.getError();
243f3b5c3eSJan Svoboda auto File = std::move(*MaybeFile);
25da920c3bSJan Svoboda
263f3b5c3eSJan Svoboda auto MaybeStat = File->status();
273f3b5c3eSJan Svoboda if (!MaybeStat)
283f3b5c3eSJan Svoboda return MaybeStat.getError();
293f3b5c3eSJan Svoboda auto Stat = std::move(*MaybeStat);
30e1f4c4aaSAlex Lorenz
313f3b5c3eSJan Svoboda auto MaybeBuffer = File->getBuffer(Stat.getName());
32e1f4c4aaSAlex Lorenz if (!MaybeBuffer)
33e1f4c4aaSAlex Lorenz return MaybeBuffer.getError();
343f3b5c3eSJan Svoboda auto Buffer = std::move(*MaybeBuffer);
35e1f4c4aaSAlex Lorenz
365daeada3SJan Svoboda // If the file size changed between read and stat, pretend it didn't.
375daeada3SJan Svoboda if (Stat.getSize() != Buffer->getBufferSize())
385daeada3SJan Svoboda Stat = llvm::vfs::Status::copyWithNewSize(Stat, Buffer->getBufferSize());
395daeada3SJan Svoboda
405daeada3SJan Svoboda return TentativeEntry(Stat, std::move(Buffer));
41e1f4c4aaSAlex Lorenz }
42e1f4c4aaSAlex Lorenz
scanForDirectivesIfNecessary(const CachedFileSystemEntry & Entry,StringRef Filename,bool Disable)43b58a420fSArgyrios Kyrtzidis EntryRef DependencyScanningWorkerFilesystem::scanForDirectivesIfNecessary(
448cc2a137SJan Svoboda const CachedFileSystemEntry &Entry, StringRef Filename, bool Disable) {
458cc2a137SJan Svoboda if (Entry.isError() || Entry.isDirectory() || Disable ||
46*b4c83a13SArgyrios Kyrtzidis !shouldScanForDirectives(Filename))
47*b4c83a13SArgyrios Kyrtzidis return EntryRef(Filename, Entry);
485daeada3SJan Svoboda
49b58a420fSArgyrios Kyrtzidis CachedFileContents *Contents = Entry.getCachedContents();
505daeada3SJan Svoboda assert(Contents && "contents not initialized");
515daeada3SJan Svoboda
525daeada3SJan Svoboda // Double-checked locking.
53*b4c83a13SArgyrios Kyrtzidis if (Contents->DepDirectives.load())
54*b4c83a13SArgyrios Kyrtzidis return EntryRef(Filename, Entry);
555daeada3SJan Svoboda
565daeada3SJan Svoboda std::lock_guard<std::mutex> GuardLock(Contents->ValueLock);
575daeada3SJan Svoboda
585daeada3SJan Svoboda // Double-checked locking.
59*b4c83a13SArgyrios Kyrtzidis if (Contents->DepDirectives.load())
60*b4c83a13SArgyrios Kyrtzidis return EntryRef(Filename, Entry);
61f6680345SJan Svoboda
62*b4c83a13SArgyrios Kyrtzidis SmallVector<dependency_directives_scan::Directive, 64> Directives;
63*b4c83a13SArgyrios Kyrtzidis // Scan the file for preprocessor directives that might affect the
64*b4c83a13SArgyrios Kyrtzidis // dependencies.
65b58a420fSArgyrios Kyrtzidis if (scanSourceForDependencyDirectives(Contents->Original->getBuffer(),
66*b4c83a13SArgyrios Kyrtzidis Contents->DepDirectiveTokens,
67*b4c83a13SArgyrios Kyrtzidis Directives)) {
68*b4c83a13SArgyrios Kyrtzidis Contents->DepDirectiveTokens.clear();
69f6680345SJan Svoboda // FIXME: Propagate the diagnostic if desired by the client.
70*b4c83a13SArgyrios Kyrtzidis Contents->DepDirectives.store(new Optional<DependencyDirectivesTy>());
71*b4c83a13SArgyrios Kyrtzidis return EntryRef(Filename, Entry);
72f6680345SJan Svoboda }
73f6680345SJan Svoboda
74*b4c83a13SArgyrios Kyrtzidis // This function performed double-checked locking using `DepDirectives`.
75*b4c83a13SArgyrios Kyrtzidis // Assigning it must be the last thing this function does, otherwise other
76*b4c83a13SArgyrios Kyrtzidis // threads may skip the
77*b4c83a13SArgyrios Kyrtzidis // critical section (`DepDirectives != nullptr`), leading to a data race.
78*b4c83a13SArgyrios Kyrtzidis Contents->DepDirectives.store(
79*b4c83a13SArgyrios Kyrtzidis new Optional<DependencyDirectivesTy>(std::move(Directives)));
80*b4c83a13SArgyrios Kyrtzidis return EntryRef(Filename, Entry);
81e1f4c4aaSAlex Lorenz }
82e1f4c4aaSAlex Lorenz
83f6680345SJan Svoboda DependencyScanningFilesystemSharedCache::
DependencyScanningFilesystemSharedCache()84f6680345SJan Svoboda DependencyScanningFilesystemSharedCache() {
85e1f4c4aaSAlex Lorenz // This heuristic was chosen using a empirical testing on a
86e1f4c4aaSAlex Lorenz // reasonably high core machine (iMacPro 18 cores / 36 threads). The cache
87e1f4c4aaSAlex Lorenz // sharding gives a performance edge by reducing the lock contention.
88e1f4c4aaSAlex Lorenz // FIXME: A better heuristic might also consider the OS to account for
89e1f4c4aaSAlex Lorenz // the different cost of lock contention on different OSes.
908404aeb5SAlexandre Ganea NumShards =
918404aeb5SAlexandre Ganea std::max(2u, llvm::hardware_concurrency().compute_thread_count() / 4);
922b3d49b6SJonas Devlieghere CacheShards = std::make_unique<CacheShard[]>(NumShards);
93e1f4c4aaSAlex Lorenz }
94e1f4c4aaSAlex Lorenz
955daeada3SJan Svoboda DependencyScanningFilesystemSharedCache::CacheShard &
getShardForFilename(StringRef Filename) const965daeada3SJan Svoboda DependencyScanningFilesystemSharedCache::getShardForFilename(
975daeada3SJan Svoboda StringRef Filename) const {
985daeada3SJan Svoboda return CacheShards[llvm::hash_value(Filename) % NumShards];
995daeada3SJan Svoboda }
1005daeada3SJan Svoboda
1015daeada3SJan Svoboda DependencyScanningFilesystemSharedCache::CacheShard &
getShardForUID(llvm::sys::fs::UniqueID UID) const1025daeada3SJan Svoboda DependencyScanningFilesystemSharedCache::getShardForUID(
1035daeada3SJan Svoboda llvm::sys::fs::UniqueID UID) const {
1045daeada3SJan Svoboda auto Hash = llvm::hash_combine(UID.getDevice(), UID.getFile());
1055daeada3SJan Svoboda return CacheShards[Hash % NumShards];
1065daeada3SJan Svoboda }
1075daeada3SJan Svoboda
1085daeada3SJan Svoboda const CachedFileSystemEntry *
findEntryByFilename(StringRef Filename) const1095daeada3SJan Svoboda DependencyScanningFilesystemSharedCache::CacheShard::findEntryByFilename(
1105daeada3SJan Svoboda StringRef Filename) const {
1115daeada3SJan Svoboda std::lock_guard<std::mutex> LockGuard(CacheLock);
1125daeada3SJan Svoboda auto It = EntriesByFilename.find(Filename);
1135daeada3SJan Svoboda return It == EntriesByFilename.end() ? nullptr : It->getValue();
1145daeada3SJan Svoboda }
1155daeada3SJan Svoboda
1165daeada3SJan Svoboda const CachedFileSystemEntry *
findEntryByUID(llvm::sys::fs::UniqueID UID) const1175daeada3SJan Svoboda DependencyScanningFilesystemSharedCache::CacheShard::findEntryByUID(
1185daeada3SJan Svoboda llvm::sys::fs::UniqueID UID) const {
1195daeada3SJan Svoboda std::lock_guard<std::mutex> LockGuard(CacheLock);
1205daeada3SJan Svoboda auto It = EntriesByUID.find(UID);
1215daeada3SJan Svoboda return It == EntriesByUID.end() ? nullptr : It->getSecond();
1225daeada3SJan Svoboda }
1235daeada3SJan Svoboda
1245daeada3SJan Svoboda const CachedFileSystemEntry &
1255daeada3SJan Svoboda DependencyScanningFilesystemSharedCache::CacheShard::
getOrEmplaceEntryForFilename(StringRef Filename,llvm::ErrorOr<llvm::vfs::Status> Stat)1265daeada3SJan Svoboda getOrEmplaceEntryForFilename(StringRef Filename,
1275daeada3SJan Svoboda llvm::ErrorOr<llvm::vfs::Status> Stat) {
1285daeada3SJan Svoboda std::lock_guard<std::mutex> LockGuard(CacheLock);
1295daeada3SJan Svoboda auto Insertion = EntriesByFilename.insert({Filename, nullptr});
1305daeada3SJan Svoboda if (Insertion.second)
1315daeada3SJan Svoboda Insertion.first->second =
1325daeada3SJan Svoboda new (EntryStorage.Allocate()) CachedFileSystemEntry(std::move(Stat));
1335daeada3SJan Svoboda return *Insertion.first->second;
1345daeada3SJan Svoboda }
1355daeada3SJan Svoboda
1365daeada3SJan Svoboda const CachedFileSystemEntry &
getOrEmplaceEntryForUID(llvm::sys::fs::UniqueID UID,llvm::vfs::Status Stat,std::unique_ptr<llvm::MemoryBuffer> Contents)1375daeada3SJan Svoboda DependencyScanningFilesystemSharedCache::CacheShard::getOrEmplaceEntryForUID(
1385daeada3SJan Svoboda llvm::sys::fs::UniqueID UID, llvm::vfs::Status Stat,
1395daeada3SJan Svoboda std::unique_ptr<llvm::MemoryBuffer> Contents) {
1405daeada3SJan Svoboda std::lock_guard<std::mutex> LockGuard(CacheLock);
1415daeada3SJan Svoboda auto Insertion = EntriesByUID.insert({UID, nullptr});
1425daeada3SJan Svoboda if (Insertion.second) {
1435daeada3SJan Svoboda CachedFileContents *StoredContents = nullptr;
1445daeada3SJan Svoboda if (Contents)
1455daeada3SJan Svoboda StoredContents = new (ContentsStorage.Allocate())
1465daeada3SJan Svoboda CachedFileContents(std::move(Contents));
1475daeada3SJan Svoboda Insertion.first->second = new (EntryStorage.Allocate())
1485daeada3SJan Svoboda CachedFileSystemEntry(std::move(Stat), StoredContents);
1495daeada3SJan Svoboda }
1505daeada3SJan Svoboda return *Insertion.first->second;
1515daeada3SJan Svoboda }
1525daeada3SJan Svoboda
1535daeada3SJan Svoboda const CachedFileSystemEntry &
1545daeada3SJan Svoboda DependencyScanningFilesystemSharedCache::CacheShard::
getOrInsertEntryForFilename(StringRef Filename,const CachedFileSystemEntry & Entry)1555daeada3SJan Svoboda getOrInsertEntryForFilename(StringRef Filename,
1565daeada3SJan Svoboda const CachedFileSystemEntry &Entry) {
1575daeada3SJan Svoboda std::lock_guard<std::mutex> LockGuard(CacheLock);
1585daeada3SJan Svoboda return *EntriesByFilename.insert({Filename, &Entry}).first->getValue();
159e1f4c4aaSAlex Lorenz }
160e1f4c4aaSAlex Lorenz
1619ab6d823SMichael Spencer /// Whitelist file extensions that should be minimized, treating no extension as
1629ab6d823SMichael Spencer /// a source file that should be minimized.
1639ab6d823SMichael Spencer ///
1649ab6d823SMichael Spencer /// This is kinda hacky, it would be better if we knew what kind of file Clang
1659ab6d823SMichael Spencer /// was expecting instead.
shouldScanForDirectivesBasedOnExtension(StringRef Filename)166b58a420fSArgyrios Kyrtzidis static bool shouldScanForDirectivesBasedOnExtension(StringRef Filename) {
1679ab6d823SMichael Spencer StringRef Ext = llvm::sys::path::extension(Filename);
1689ab6d823SMichael Spencer if (Ext.empty())
1699ab6d823SMichael Spencer return true; // C++ standard library
1709ab6d823SMichael Spencer return llvm::StringSwitch<bool>(Ext)
1719ab6d823SMichael Spencer .CasesLower(".c", ".cc", ".cpp", ".c++", ".cxx", true)
1729ab6d823SMichael Spencer .CasesLower(".h", ".hh", ".hpp", ".h++", ".hxx", true)
1739ab6d823SMichael Spencer .CasesLower(".m", ".mm", true)
1749ab6d823SMichael Spencer .CasesLower(".i", ".ii", ".mi", ".mmi", true)
1759ab6d823SMichael Spencer .CasesLower(".def", ".inc", true)
1769ab6d823SMichael Spencer .Default(false);
1779ab6d823SMichael Spencer }
1789ab6d823SMichael Spencer
shouldCacheStatFailures(StringRef Filename)1799ab6d823SMichael Spencer static bool shouldCacheStatFailures(StringRef Filename) {
1809ab6d823SMichael Spencer StringRef Ext = llvm::sys::path::extension(Filename);
1819ab6d823SMichael Spencer if (Ext.empty())
1829ab6d823SMichael Spencer return false; // This may be the module cache directory.
18312eafd94SJan Svoboda // Only cache stat failures on source files.
184b58a420fSArgyrios Kyrtzidis return shouldScanForDirectivesBasedOnExtension(Filename);
1859ab6d823SMichael Spencer }
1869ab6d823SMichael Spencer
shouldScanForDirectives(StringRef Filename)187b58a420fSArgyrios Kyrtzidis bool DependencyScanningWorkerFilesystem::shouldScanForDirectives(
188*b4c83a13SArgyrios Kyrtzidis StringRef Filename) {
189*b4c83a13SArgyrios Kyrtzidis return shouldScanForDirectivesBasedOnExtension(Filename);
19063fd109dSJan Svoboda }
19163fd109dSJan Svoboda
1925daeada3SJan Svoboda const CachedFileSystemEntry &
getOrEmplaceSharedEntryForUID(TentativeEntry TEntry)1935daeada3SJan Svoboda DependencyScanningWorkerFilesystem::getOrEmplaceSharedEntryForUID(
1945daeada3SJan Svoboda TentativeEntry TEntry) {
1955daeada3SJan Svoboda auto &Shard = SharedCache.getShardForUID(TEntry.Status.getUniqueID());
1965daeada3SJan Svoboda return Shard.getOrEmplaceEntryForUID(TEntry.Status.getUniqueID(),
1975daeada3SJan Svoboda std::move(TEntry.Status),
1985daeada3SJan Svoboda std::move(TEntry.Contents));
1995daeada3SJan Svoboda }
2005daeada3SJan Svoboda
2015daeada3SJan Svoboda const CachedFileSystemEntry *
findEntryByFilenameWithWriteThrough(StringRef Filename)2025daeada3SJan Svoboda DependencyScanningWorkerFilesystem::findEntryByFilenameWithWriteThrough(
2035daeada3SJan Svoboda StringRef Filename) {
2045daeada3SJan Svoboda if (const auto *Entry = LocalCache.findEntryByFilename(Filename))
2055daeada3SJan Svoboda return Entry;
2065daeada3SJan Svoboda auto &Shard = SharedCache.getShardForFilename(Filename);
2075daeada3SJan Svoboda if (const auto *Entry = Shard.findEntryByFilename(Filename))
2085daeada3SJan Svoboda return &LocalCache.insertEntryForFilename(Filename, *Entry);
2095daeada3SJan Svoboda return nullptr;
2105daeada3SJan Svoboda }
2115daeada3SJan Svoboda
2125daeada3SJan Svoboda llvm::ErrorOr<const CachedFileSystemEntry &>
computeAndStoreResult(StringRef Filename)2135daeada3SJan Svoboda DependencyScanningWorkerFilesystem::computeAndStoreResult(StringRef Filename) {
2145daeada3SJan Svoboda llvm::ErrorOr<llvm::vfs::Status> Stat = getUnderlyingFS().status(Filename);
2155daeada3SJan Svoboda if (!Stat) {
2165daeada3SJan Svoboda if (!shouldCacheStatFailures(Filename))
2175daeada3SJan Svoboda return Stat.getError();
2185daeada3SJan Svoboda const auto &Entry =
2195daeada3SJan Svoboda getOrEmplaceSharedEntryForFilename(Filename, Stat.getError());
2205daeada3SJan Svoboda return insertLocalEntryForFilename(Filename, Entry);
2215daeada3SJan Svoboda }
2225daeada3SJan Svoboda
2235daeada3SJan Svoboda if (const auto *Entry = findSharedEntryByUID(*Stat))
2245daeada3SJan Svoboda return insertLocalEntryForFilename(Filename, *Entry);
2255daeada3SJan Svoboda
2265daeada3SJan Svoboda auto TEntry =
2275daeada3SJan Svoboda Stat->isDirectory() ? TentativeEntry(*Stat) : readFile(Filename);
2285daeada3SJan Svoboda
2295daeada3SJan Svoboda const CachedFileSystemEntry *SharedEntry = [&]() {
2305daeada3SJan Svoboda if (TEntry) {
2315daeada3SJan Svoboda const auto &UIDEntry = getOrEmplaceSharedEntryForUID(std::move(*TEntry));
2325daeada3SJan Svoboda return &getOrInsertSharedEntryForFilename(Filename, UIDEntry);
2335daeada3SJan Svoboda }
2345daeada3SJan Svoboda return &getOrEmplaceSharedEntryForFilename(Filename, TEntry.getError());
2355daeada3SJan Svoboda }();
2365daeada3SJan Svoboda
2375daeada3SJan Svoboda return insertLocalEntryForFilename(Filename, *SharedEntry);
23897e504cfSJan Svoboda }
23997e504cfSJan Svoboda
240f6680345SJan Svoboda llvm::ErrorOr<EntryRef>
getOrCreateFileSystemEntry(StringRef Filename,bool DisableDirectivesScanning)2412f562662SMichael J. Spencer DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry(
242b58a420fSArgyrios Kyrtzidis StringRef Filename, bool DisableDirectivesScanning) {
2435daeada3SJan Svoboda if (const auto *Entry = findEntryByFilenameWithWriteThrough(Filename))
244b58a420fSArgyrios Kyrtzidis return scanForDirectivesIfNecessary(*Entry, Filename,
245b58a420fSArgyrios Kyrtzidis DisableDirectivesScanning)
2468cc2a137SJan Svoboda .unwrapError();
2475daeada3SJan Svoboda auto MaybeEntry = computeAndStoreResult(Filename);
2485daeada3SJan Svoboda if (!MaybeEntry)
2495daeada3SJan Svoboda return MaybeEntry.getError();
250b58a420fSArgyrios Kyrtzidis return scanForDirectivesIfNecessary(*MaybeEntry, Filename,
251b58a420fSArgyrios Kyrtzidis DisableDirectivesScanning)
2528cc2a137SJan Svoboda .unwrapError();
2534abac533SKousik Kumar }
2544abac533SKousik Kumar
2554abac533SKousik Kumar llvm::ErrorOr<llvm::vfs::Status>
status(const Twine & Path)2564abac533SKousik Kumar DependencyScanningWorkerFilesystem::status(const Twine &Path) {
2574abac533SKousik Kumar SmallString<256> OwnedFilename;
2584abac533SKousik Kumar StringRef Filename = Path.toStringRef(OwnedFilename);
259f6680345SJan Svoboda
260f6680345SJan Svoboda llvm::ErrorOr<EntryRef> Result = getOrCreateFileSystemEntry(Filename);
2614abac533SKousik Kumar if (!Result)
2624abac533SKousik Kumar return Result.getError();
263f6680345SJan Svoboda return Result->getStatus();
264e1f4c4aaSAlex Lorenz }
265e1f4c4aaSAlex Lorenz
266e1f4c4aaSAlex Lorenz namespace {
267e1f4c4aaSAlex Lorenz
268e1f4c4aaSAlex Lorenz /// The VFS that is used by clang consumes the \c CachedFileSystemEntry using
269e1f4c4aaSAlex Lorenz /// this subclass.
270b58a420fSArgyrios Kyrtzidis class DepScanFile final : public llvm::vfs::File {
271e1f4c4aaSAlex Lorenz public:
DepScanFile(std::unique_ptr<llvm::MemoryBuffer> Buffer,llvm::vfs::Status Stat)272b58a420fSArgyrios Kyrtzidis DepScanFile(std::unique_ptr<llvm::MemoryBuffer> Buffer,
273e1f4c4aaSAlex Lorenz llvm::vfs::Status Stat)
274e1f4c4aaSAlex Lorenz : Buffer(std::move(Buffer)), Stat(std::move(Stat)) {}
275e1f4c4aaSAlex Lorenz
276*b4c83a13SArgyrios Kyrtzidis static llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> create(EntryRef Entry);
277e1f4c4aaSAlex Lorenz
status()278d07b290eSDuncan P. N. Exon Smith llvm::ErrorOr<llvm::vfs::Status> status() override { return Stat; }
279e1f4c4aaSAlex Lorenz
280e1f4c4aaSAlex Lorenz llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBuffer(const Twine & Name,int64_t FileSize,bool RequiresNullTerminator,bool IsVolatile)281e1f4c4aaSAlex Lorenz getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
282e1f4c4aaSAlex Lorenz bool IsVolatile) override {
283e1f4c4aaSAlex Lorenz return std::move(Buffer);
284e1f4c4aaSAlex Lorenz }
285e1f4c4aaSAlex Lorenz
close()286e1f4c4aaSAlex Lorenz std::error_code close() override { return {}; }
287e1f4c4aaSAlex Lorenz
288e1f4c4aaSAlex Lorenz private:
289e1f4c4aaSAlex Lorenz std::unique_ptr<llvm::MemoryBuffer> Buffer;
290e1f4c4aaSAlex Lorenz llvm::vfs::Status Stat;
291e1f4c4aaSAlex Lorenz };
292e1f4c4aaSAlex Lorenz
293d07b290eSDuncan P. N. Exon Smith } // end anonymous namespace
294d07b290eSDuncan P. N. Exon Smith
295b58a420fSArgyrios Kyrtzidis llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
create(EntryRef Entry)296*b4c83a13SArgyrios Kyrtzidis DepScanFile::create(EntryRef Entry) {
297ced077e1SJan Svoboda assert(!Entry.isError() && "error");
298ced077e1SJan Svoboda
299f6680345SJan Svoboda if (Entry.isDirectory())
300af7a421eSJan Svoboda return std::make_error_code(std::errc::is_a_directory);
301af7a421eSJan Svoboda
302b58a420fSArgyrios Kyrtzidis auto Result = std::make_unique<DepScanFile>(
3035daeada3SJan Svoboda llvm::MemoryBuffer::getMemBuffer(Entry.getContents(),
3045daeada3SJan Svoboda Entry.getStatus().getName(),
305e1f4c4aaSAlex Lorenz /*RequiresNullTerminator=*/false),
306ced077e1SJan Svoboda Entry.getStatus());
307f6680345SJan Svoboda
308428d9283SAlex Lorenz return llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>(
309428d9283SAlex Lorenz std::unique_ptr<llvm::vfs::File>(std::move(Result)));
310e1f4c4aaSAlex Lorenz }
311e1f4c4aaSAlex Lorenz
312e1f4c4aaSAlex Lorenz llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
openFileForRead(const Twine & Path)313e1f4c4aaSAlex Lorenz DependencyScanningWorkerFilesystem::openFileForRead(const Twine &Path) {
314e1f4c4aaSAlex Lorenz SmallString<256> OwnedFilename;
315e1f4c4aaSAlex Lorenz StringRef Filename = Path.toStringRef(OwnedFilename);
316e1f4c4aaSAlex Lorenz
317f6680345SJan Svoboda llvm::ErrorOr<EntryRef> Result = getOrCreateFileSystemEntry(Filename);
3184abac533SKousik Kumar if (!Result)
3194abac533SKousik Kumar return Result.getError();
320*b4c83a13SArgyrios Kyrtzidis return DepScanFile::create(Result.get());
321e1f4c4aaSAlex Lorenz }
322