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