1a7dea167SDimitry Andric //===- DependencyScanningFilesystem.cpp - clang-scan-deps fs --------------===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric 9a7dea167SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h" 10a7dea167SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 110eae32dcSDimitry Andric #include "llvm/Support/SmallVectorMemoryBuffer.h" 12a7dea167SDimitry Andric #include "llvm/Support/Threading.h" 13bdd1243dSDimitry Andric #include <optional> 14a7dea167SDimitry Andric 15a7dea167SDimitry Andric using namespace clang; 16a7dea167SDimitry Andric using namespace tooling; 17a7dea167SDimitry Andric using namespace dependencies; 18a7dea167SDimitry Andric 1904eeddc0SDimitry Andric llvm::ErrorOr<DependencyScanningWorkerFilesystem::TentativeEntry> 2004eeddc0SDimitry Andric DependencyScanningWorkerFilesystem::readFile(StringRef Filename) { 21a7dea167SDimitry Andric // Load the file and its content from the file system. 2204eeddc0SDimitry Andric auto MaybeFile = getUnderlyingFS().openFileForRead(Filename); 23a7dea167SDimitry Andric if (!MaybeFile) 24a7dea167SDimitry Andric return MaybeFile.getError(); 250eae32dcSDimitry Andric auto File = std::move(*MaybeFile); 26a7dea167SDimitry Andric 270eae32dcSDimitry Andric auto MaybeStat = File->status(); 280eae32dcSDimitry Andric if (!MaybeStat) 290eae32dcSDimitry Andric return MaybeStat.getError(); 300eae32dcSDimitry Andric auto Stat = std::move(*MaybeStat); 310eae32dcSDimitry Andric 320eae32dcSDimitry Andric auto MaybeBuffer = File->getBuffer(Stat.getName()); 33a7dea167SDimitry Andric if (!MaybeBuffer) 34a7dea167SDimitry Andric return MaybeBuffer.getError(); 350eae32dcSDimitry Andric auto Buffer = std::move(*MaybeBuffer); 360eae32dcSDimitry Andric 3704eeddc0SDimitry Andric // If the file size changed between read and stat, pretend it didn't. 3804eeddc0SDimitry Andric if (Stat.getSize() != Buffer->getBufferSize()) 3904eeddc0SDimitry Andric Stat = llvm::vfs::Status::copyWithNewSize(Stat, Buffer->getBufferSize()); 4004eeddc0SDimitry Andric 4104eeddc0SDimitry Andric return TentativeEntry(Stat, std::move(Buffer)); 420eae32dcSDimitry Andric } 430eae32dcSDimitry Andric 4481ad6265SDimitry Andric EntryRef DependencyScanningWorkerFilesystem::scanForDirectivesIfNecessary( 4504eeddc0SDimitry Andric const CachedFileSystemEntry &Entry, StringRef Filename, bool Disable) { 4604eeddc0SDimitry Andric if (Entry.isError() || Entry.isDirectory() || Disable || 4781ad6265SDimitry Andric !shouldScanForDirectives(Filename)) 4881ad6265SDimitry Andric return EntryRef(Filename, Entry); 4904eeddc0SDimitry Andric 5081ad6265SDimitry Andric CachedFileContents *Contents = Entry.getCachedContents(); 5104eeddc0SDimitry Andric assert(Contents && "contents not initialized"); 5204eeddc0SDimitry Andric 5304eeddc0SDimitry Andric // Double-checked locking. 5481ad6265SDimitry Andric if (Contents->DepDirectives.load()) 5581ad6265SDimitry Andric return EntryRef(Filename, Entry); 5604eeddc0SDimitry Andric 5704eeddc0SDimitry Andric std::lock_guard<std::mutex> GuardLock(Contents->ValueLock); 5804eeddc0SDimitry Andric 5904eeddc0SDimitry Andric // Double-checked locking. 6081ad6265SDimitry Andric if (Contents->DepDirectives.load()) 6181ad6265SDimitry Andric return EntryRef(Filename, Entry); 62a7dea167SDimitry Andric 6381ad6265SDimitry Andric SmallVector<dependency_directives_scan::Directive, 64> Directives; 6481ad6265SDimitry Andric // Scan the file for preprocessor directives that might affect the 6581ad6265SDimitry Andric // dependencies. 6681ad6265SDimitry Andric if (scanSourceForDependencyDirectives(Contents->Original->getBuffer(), 6781ad6265SDimitry Andric Contents->DepDirectiveTokens, 6881ad6265SDimitry Andric Directives)) { 6981ad6265SDimitry Andric Contents->DepDirectiveTokens.clear(); 700eae32dcSDimitry Andric // FIXME: Propagate the diagnostic if desired by the client. 71bdd1243dSDimitry Andric Contents->DepDirectives.store(new std::optional<DependencyDirectivesTy>()); 7281ad6265SDimitry Andric return EntryRef(Filename, Entry); 73a7dea167SDimitry Andric } 74a7dea167SDimitry Andric 7581ad6265SDimitry Andric // This function performed double-checked locking using `DepDirectives`. 7681ad6265SDimitry Andric // Assigning it must be the last thing this function does, otherwise other 7781ad6265SDimitry Andric // threads may skip the 7881ad6265SDimitry Andric // critical section (`DepDirectives != nullptr`), leading to a data race. 7981ad6265SDimitry Andric Contents->DepDirectives.store( 80bdd1243dSDimitry Andric new std::optional<DependencyDirectivesTy>(std::move(Directives))); 8181ad6265SDimitry Andric return EntryRef(Filename, Entry); 82a7dea167SDimitry Andric } 83a7dea167SDimitry Andric 840eae32dcSDimitry Andric DependencyScanningFilesystemSharedCache:: 850eae32dcSDimitry Andric DependencyScanningFilesystemSharedCache() { 86a7dea167SDimitry Andric // This heuristic was chosen using a empirical testing on a 87a7dea167SDimitry Andric // reasonably high core machine (iMacPro 18 cores / 36 threads). The cache 88a7dea167SDimitry Andric // sharding gives a performance edge by reducing the lock contention. 89a7dea167SDimitry Andric // FIXME: A better heuristic might also consider the OS to account for 90a7dea167SDimitry Andric // the different cost of lock contention on different OSes. 915ffd83dbSDimitry Andric NumShards = 925ffd83dbSDimitry Andric std::max(2u, llvm::hardware_concurrency().compute_thread_count() / 4); 93a7dea167SDimitry Andric CacheShards = std::make_unique<CacheShard[]>(NumShards); 94a7dea167SDimitry Andric } 95a7dea167SDimitry Andric 9604eeddc0SDimitry Andric DependencyScanningFilesystemSharedCache::CacheShard & 9704eeddc0SDimitry Andric DependencyScanningFilesystemSharedCache::getShardForFilename( 9804eeddc0SDimitry Andric StringRef Filename) const { 994542f901SDimitry Andric assert(llvm::sys::path::is_absolute_gnu(Filename)); 10004eeddc0SDimitry Andric return CacheShards[llvm::hash_value(Filename) % NumShards]; 10104eeddc0SDimitry Andric } 10204eeddc0SDimitry Andric 10304eeddc0SDimitry Andric DependencyScanningFilesystemSharedCache::CacheShard & 10404eeddc0SDimitry Andric DependencyScanningFilesystemSharedCache::getShardForUID( 10504eeddc0SDimitry Andric llvm::sys::fs::UniqueID UID) const { 10604eeddc0SDimitry Andric auto Hash = llvm::hash_combine(UID.getDevice(), UID.getFile()); 10704eeddc0SDimitry Andric return CacheShards[Hash % NumShards]; 10804eeddc0SDimitry Andric } 10904eeddc0SDimitry Andric 11004eeddc0SDimitry Andric const CachedFileSystemEntry * 11104eeddc0SDimitry Andric DependencyScanningFilesystemSharedCache::CacheShard::findEntryByFilename( 11204eeddc0SDimitry Andric StringRef Filename) const { 1134542f901SDimitry Andric assert(llvm::sys::path::is_absolute_gnu(Filename)); 11404eeddc0SDimitry Andric std::lock_guard<std::mutex> LockGuard(CacheLock); 11504eeddc0SDimitry Andric auto It = EntriesByFilename.find(Filename); 11604eeddc0SDimitry Andric return It == EntriesByFilename.end() ? nullptr : It->getValue(); 11704eeddc0SDimitry Andric } 11804eeddc0SDimitry Andric 11904eeddc0SDimitry Andric const CachedFileSystemEntry * 12004eeddc0SDimitry Andric DependencyScanningFilesystemSharedCache::CacheShard::findEntryByUID( 12104eeddc0SDimitry Andric llvm::sys::fs::UniqueID UID) const { 12204eeddc0SDimitry Andric std::lock_guard<std::mutex> LockGuard(CacheLock); 12304eeddc0SDimitry Andric auto It = EntriesByUID.find(UID); 12404eeddc0SDimitry Andric return It == EntriesByUID.end() ? nullptr : It->getSecond(); 12504eeddc0SDimitry Andric } 12604eeddc0SDimitry Andric 12704eeddc0SDimitry Andric const CachedFileSystemEntry & 12804eeddc0SDimitry Andric DependencyScanningFilesystemSharedCache::CacheShard:: 12904eeddc0SDimitry Andric getOrEmplaceEntryForFilename(StringRef Filename, 13004eeddc0SDimitry Andric llvm::ErrorOr<llvm::vfs::Status> Stat) { 13104eeddc0SDimitry Andric std::lock_guard<std::mutex> LockGuard(CacheLock); 13204eeddc0SDimitry Andric auto Insertion = EntriesByFilename.insert({Filename, nullptr}); 13304eeddc0SDimitry Andric if (Insertion.second) 13404eeddc0SDimitry Andric Insertion.first->second = 13504eeddc0SDimitry Andric new (EntryStorage.Allocate()) CachedFileSystemEntry(std::move(Stat)); 13604eeddc0SDimitry Andric return *Insertion.first->second; 13704eeddc0SDimitry Andric } 13804eeddc0SDimitry Andric 13904eeddc0SDimitry Andric const CachedFileSystemEntry & 14004eeddc0SDimitry Andric DependencyScanningFilesystemSharedCache::CacheShard::getOrEmplaceEntryForUID( 14104eeddc0SDimitry Andric llvm::sys::fs::UniqueID UID, llvm::vfs::Status Stat, 14204eeddc0SDimitry Andric std::unique_ptr<llvm::MemoryBuffer> Contents) { 14304eeddc0SDimitry Andric std::lock_guard<std::mutex> LockGuard(CacheLock); 14404eeddc0SDimitry Andric auto Insertion = EntriesByUID.insert({UID, nullptr}); 14504eeddc0SDimitry Andric if (Insertion.second) { 14604eeddc0SDimitry Andric CachedFileContents *StoredContents = nullptr; 14704eeddc0SDimitry Andric if (Contents) 14804eeddc0SDimitry Andric StoredContents = new (ContentsStorage.Allocate()) 14904eeddc0SDimitry Andric CachedFileContents(std::move(Contents)); 15004eeddc0SDimitry Andric Insertion.first->second = new (EntryStorage.Allocate()) 15104eeddc0SDimitry Andric CachedFileSystemEntry(std::move(Stat), StoredContents); 15204eeddc0SDimitry Andric } 15304eeddc0SDimitry Andric return *Insertion.first->second; 15404eeddc0SDimitry Andric } 15504eeddc0SDimitry Andric 15604eeddc0SDimitry Andric const CachedFileSystemEntry & 15704eeddc0SDimitry Andric DependencyScanningFilesystemSharedCache::CacheShard:: 15804eeddc0SDimitry Andric getOrInsertEntryForFilename(StringRef Filename, 15904eeddc0SDimitry Andric const CachedFileSystemEntry &Entry) { 16004eeddc0SDimitry Andric std::lock_guard<std::mutex> LockGuard(CacheLock); 16104eeddc0SDimitry Andric return *EntriesByFilename.insert({Filename, &Entry}).first->getValue(); 162a7dea167SDimitry Andric } 163a7dea167SDimitry Andric 164480093f4SDimitry Andric /// Whitelist file extensions that should be minimized, treating no extension as 165480093f4SDimitry Andric /// a source file that should be minimized. 166480093f4SDimitry Andric /// 167480093f4SDimitry Andric /// This is kinda hacky, it would be better if we knew what kind of file Clang 168480093f4SDimitry Andric /// was expecting instead. 16981ad6265SDimitry Andric static bool shouldScanForDirectivesBasedOnExtension(StringRef Filename) { 170480093f4SDimitry Andric StringRef Ext = llvm::sys::path::extension(Filename); 171480093f4SDimitry Andric if (Ext.empty()) 172480093f4SDimitry Andric return true; // C++ standard library 173480093f4SDimitry Andric return llvm::StringSwitch<bool>(Ext) 174480093f4SDimitry Andric .CasesLower(".c", ".cc", ".cpp", ".c++", ".cxx", true) 175480093f4SDimitry Andric .CasesLower(".h", ".hh", ".hpp", ".h++", ".hxx", true) 176480093f4SDimitry Andric .CasesLower(".m", ".mm", true) 177480093f4SDimitry Andric .CasesLower(".i", ".ii", ".mi", ".mmi", true) 178480093f4SDimitry Andric .CasesLower(".def", ".inc", true) 179480093f4SDimitry Andric .Default(false); 180480093f4SDimitry Andric } 181480093f4SDimitry Andric 182480093f4SDimitry Andric static bool shouldCacheStatFailures(StringRef Filename) { 183480093f4SDimitry Andric StringRef Ext = llvm::sys::path::extension(Filename); 184480093f4SDimitry Andric if (Ext.empty()) 185480093f4SDimitry Andric return false; // This may be the module cache directory. 18606c3fb27SDimitry Andric // Only cache stat failures on files that are not expected to change during 18706c3fb27SDimitry Andric // the build. 18806c3fb27SDimitry Andric StringRef FName = llvm::sys::path::filename(Filename); 18906c3fb27SDimitry Andric if (FName == "module.modulemap" || FName == "module.map") 19006c3fb27SDimitry Andric return true; 19181ad6265SDimitry Andric return shouldScanForDirectivesBasedOnExtension(Filename); 192480093f4SDimitry Andric } 193480093f4SDimitry Andric 1944542f901SDimitry Andric DependencyScanningWorkerFilesystem::DependencyScanningWorkerFilesystem( 1954542f901SDimitry Andric DependencyScanningFilesystemSharedCache &SharedCache, 1964542f901SDimitry Andric IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) 1974542f901SDimitry Andric : ProxyFileSystem(std::move(FS)), SharedCache(SharedCache), 1984542f901SDimitry Andric WorkingDirForCacheLookup(llvm::errc::invalid_argument) { 1994542f901SDimitry Andric updateWorkingDirForCacheLookup(); 2004542f901SDimitry Andric } 2014542f901SDimitry Andric 20281ad6265SDimitry Andric bool DependencyScanningWorkerFilesystem::shouldScanForDirectives( 20304eeddc0SDimitry Andric StringRef Filename) { 20481ad6265SDimitry Andric return shouldScanForDirectivesBasedOnExtension(Filename); 2054824e7fdSDimitry Andric } 2064824e7fdSDimitry Andric 20704eeddc0SDimitry Andric const CachedFileSystemEntry & 20804eeddc0SDimitry Andric DependencyScanningWorkerFilesystem::getOrEmplaceSharedEntryForUID( 20904eeddc0SDimitry Andric TentativeEntry TEntry) { 21004eeddc0SDimitry Andric auto &Shard = SharedCache.getShardForUID(TEntry.Status.getUniqueID()); 21104eeddc0SDimitry Andric return Shard.getOrEmplaceEntryForUID(TEntry.Status.getUniqueID(), 21204eeddc0SDimitry Andric std::move(TEntry.Status), 21304eeddc0SDimitry Andric std::move(TEntry.Contents)); 21404eeddc0SDimitry Andric } 21504eeddc0SDimitry Andric 21604eeddc0SDimitry Andric const CachedFileSystemEntry * 21704eeddc0SDimitry Andric DependencyScanningWorkerFilesystem::findEntryByFilenameWithWriteThrough( 21804eeddc0SDimitry Andric StringRef Filename) { 21904eeddc0SDimitry Andric if (const auto *Entry = LocalCache.findEntryByFilename(Filename)) 22004eeddc0SDimitry Andric return Entry; 22104eeddc0SDimitry Andric auto &Shard = SharedCache.getShardForFilename(Filename); 22204eeddc0SDimitry Andric if (const auto *Entry = Shard.findEntryByFilename(Filename)) 22304eeddc0SDimitry Andric return &LocalCache.insertEntryForFilename(Filename, *Entry); 22404eeddc0SDimitry Andric return nullptr; 22504eeddc0SDimitry Andric } 22604eeddc0SDimitry Andric 22704eeddc0SDimitry Andric llvm::ErrorOr<const CachedFileSystemEntry &> 2284542f901SDimitry Andric DependencyScanningWorkerFilesystem::computeAndStoreResult( 2294542f901SDimitry Andric StringRef OriginalFilename, StringRef FilenameForLookup) { 2304542f901SDimitry Andric llvm::ErrorOr<llvm::vfs::Status> Stat = 2314542f901SDimitry Andric getUnderlyingFS().status(OriginalFilename); 23204eeddc0SDimitry Andric if (!Stat) { 2334542f901SDimitry Andric if (!shouldCacheStatFailures(OriginalFilename)) 23404eeddc0SDimitry Andric return Stat.getError(); 23504eeddc0SDimitry Andric const auto &Entry = 2364542f901SDimitry Andric getOrEmplaceSharedEntryForFilename(FilenameForLookup, Stat.getError()); 2374542f901SDimitry Andric return insertLocalEntryForFilename(FilenameForLookup, Entry); 23804eeddc0SDimitry Andric } 23904eeddc0SDimitry Andric 24004eeddc0SDimitry Andric if (const auto *Entry = findSharedEntryByUID(*Stat)) 2414542f901SDimitry Andric return insertLocalEntryForFilename(FilenameForLookup, *Entry); 24204eeddc0SDimitry Andric 24304eeddc0SDimitry Andric auto TEntry = 2444542f901SDimitry Andric Stat->isDirectory() ? TentativeEntry(*Stat) : readFile(OriginalFilename); 24504eeddc0SDimitry Andric 24604eeddc0SDimitry Andric const CachedFileSystemEntry *SharedEntry = [&]() { 24704eeddc0SDimitry Andric if (TEntry) { 24804eeddc0SDimitry Andric const auto &UIDEntry = getOrEmplaceSharedEntryForUID(std::move(*TEntry)); 2494542f901SDimitry Andric return &getOrInsertSharedEntryForFilename(FilenameForLookup, UIDEntry); 25004eeddc0SDimitry Andric } 2514542f901SDimitry Andric return &getOrEmplaceSharedEntryForFilename(FilenameForLookup, 2524542f901SDimitry Andric TEntry.getError()); 25304eeddc0SDimitry Andric }(); 25404eeddc0SDimitry Andric 2554542f901SDimitry Andric return insertLocalEntryForFilename(FilenameForLookup, *SharedEntry); 256fe6060f1SDimitry Andric } 257fe6060f1SDimitry Andric 2580eae32dcSDimitry Andric llvm::ErrorOr<EntryRef> 259a7dea167SDimitry Andric DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry( 2604542f901SDimitry Andric StringRef OriginalFilename, bool DisableDirectivesScanning) { 2614542f901SDimitry Andric StringRef FilenameForLookup; 2624542f901SDimitry Andric SmallString<256> PathBuf; 2634542f901SDimitry Andric if (llvm::sys::path::is_absolute_gnu(OriginalFilename)) { 2644542f901SDimitry Andric FilenameForLookup = OriginalFilename; 2654542f901SDimitry Andric } else if (!WorkingDirForCacheLookup) { 2664542f901SDimitry Andric return WorkingDirForCacheLookup.getError(); 2674542f901SDimitry Andric } else { 2684542f901SDimitry Andric StringRef RelFilename = OriginalFilename; 2694542f901SDimitry Andric RelFilename.consume_front("./"); 2704542f901SDimitry Andric PathBuf = *WorkingDirForCacheLookup; 2714542f901SDimitry Andric llvm::sys::path::append(PathBuf, RelFilename); 2724542f901SDimitry Andric FilenameForLookup = PathBuf.str(); 2734542f901SDimitry Andric } 2744542f901SDimitry Andric assert(llvm::sys::path::is_absolute_gnu(FilenameForLookup)); 2754542f901SDimitry Andric if (const auto *Entry = 2764542f901SDimitry Andric findEntryByFilenameWithWriteThrough(FilenameForLookup)) 2774542f901SDimitry Andric return scanForDirectivesIfNecessary(*Entry, OriginalFilename, 27881ad6265SDimitry Andric DisableDirectivesScanning) 27904eeddc0SDimitry Andric .unwrapError(); 2804542f901SDimitry Andric auto MaybeEntry = computeAndStoreResult(OriginalFilename, FilenameForLookup); 28104eeddc0SDimitry Andric if (!MaybeEntry) 28204eeddc0SDimitry Andric return MaybeEntry.getError(); 2834542f901SDimitry Andric return scanForDirectivesIfNecessary(*MaybeEntry, OriginalFilename, 28481ad6265SDimitry Andric DisableDirectivesScanning) 28504eeddc0SDimitry Andric .unwrapError(); 286a7dea167SDimitry Andric } 287a7dea167SDimitry Andric 288a7dea167SDimitry Andric llvm::ErrorOr<llvm::vfs::Status> 289a7dea167SDimitry Andric DependencyScanningWorkerFilesystem::status(const Twine &Path) { 290a7dea167SDimitry Andric SmallString<256> OwnedFilename; 291a7dea167SDimitry Andric StringRef Filename = Path.toStringRef(OwnedFilename); 2920eae32dcSDimitry Andric 293*5f757f3fSDimitry Andric if (Filename.ends_with(".pcm")) 29406c3fb27SDimitry Andric return getUnderlyingFS().status(Path); 29506c3fb27SDimitry Andric 2960eae32dcSDimitry Andric llvm::ErrorOr<EntryRef> Result = getOrCreateFileSystemEntry(Filename); 297a7dea167SDimitry Andric if (!Result) 298a7dea167SDimitry Andric return Result.getError(); 2990eae32dcSDimitry Andric return Result->getStatus(); 300a7dea167SDimitry Andric } 301a7dea167SDimitry Andric 302a7dea167SDimitry Andric namespace { 303a7dea167SDimitry Andric 304a7dea167SDimitry Andric /// The VFS that is used by clang consumes the \c CachedFileSystemEntry using 305a7dea167SDimitry Andric /// this subclass. 30681ad6265SDimitry Andric class DepScanFile final : public llvm::vfs::File { 307a7dea167SDimitry Andric public: 30881ad6265SDimitry Andric DepScanFile(std::unique_ptr<llvm::MemoryBuffer> Buffer, 309a7dea167SDimitry Andric llvm::vfs::Status Stat) 310a7dea167SDimitry Andric : Buffer(std::move(Buffer)), Stat(std::move(Stat)) {} 311a7dea167SDimitry Andric 31281ad6265SDimitry Andric static llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> create(EntryRef Entry); 313a7dea167SDimitry Andric 314e8d8bef9SDimitry Andric llvm::ErrorOr<llvm::vfs::Status> status() override { return Stat; } 315a7dea167SDimitry Andric 316a7dea167SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> 317a7dea167SDimitry Andric getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, 318a7dea167SDimitry Andric bool IsVolatile) override { 319a7dea167SDimitry Andric return std::move(Buffer); 320a7dea167SDimitry Andric } 321a7dea167SDimitry Andric 322a7dea167SDimitry Andric std::error_code close() override { return {}; } 323a7dea167SDimitry Andric 324a7dea167SDimitry Andric private: 325a7dea167SDimitry Andric std::unique_ptr<llvm::MemoryBuffer> Buffer; 326a7dea167SDimitry Andric llvm::vfs::Status Stat; 327a7dea167SDimitry Andric }; 328a7dea167SDimitry Andric 329e8d8bef9SDimitry Andric } // end anonymous namespace 330e8d8bef9SDimitry Andric 33181ad6265SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> 33281ad6265SDimitry Andric DepScanFile::create(EntryRef Entry) { 33304eeddc0SDimitry Andric assert(!Entry.isError() && "error"); 33404eeddc0SDimitry Andric 3350eae32dcSDimitry Andric if (Entry.isDirectory()) 3360eae32dcSDimitry Andric return std::make_error_code(std::errc::is_a_directory); 3370eae32dcSDimitry Andric 33881ad6265SDimitry Andric auto Result = std::make_unique<DepScanFile>( 33904eeddc0SDimitry Andric llvm::MemoryBuffer::getMemBuffer(Entry.getContents(), 34004eeddc0SDimitry Andric Entry.getStatus().getName(), 341a7dea167SDimitry Andric /*RequiresNullTerminator=*/false), 34204eeddc0SDimitry Andric Entry.getStatus()); 3430eae32dcSDimitry Andric 344a7dea167SDimitry Andric return llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>( 345a7dea167SDimitry Andric std::unique_ptr<llvm::vfs::File>(std::move(Result))); 346a7dea167SDimitry Andric } 347a7dea167SDimitry Andric 348a7dea167SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> 349a7dea167SDimitry Andric DependencyScanningWorkerFilesystem::openFileForRead(const Twine &Path) { 350a7dea167SDimitry Andric SmallString<256> OwnedFilename; 351a7dea167SDimitry Andric StringRef Filename = Path.toStringRef(OwnedFilename); 352a7dea167SDimitry Andric 353*5f757f3fSDimitry Andric if (Filename.ends_with(".pcm")) 35406c3fb27SDimitry Andric return getUnderlyingFS().openFileForRead(Path); 35506c3fb27SDimitry Andric 3560eae32dcSDimitry Andric llvm::ErrorOr<EntryRef> Result = getOrCreateFileSystemEntry(Filename); 357a7dea167SDimitry Andric if (!Result) 358a7dea167SDimitry Andric return Result.getError(); 35981ad6265SDimitry Andric return DepScanFile::create(Result.get()); 360a7dea167SDimitry Andric } 3614542f901SDimitry Andric 3624542f901SDimitry Andric std::error_code DependencyScanningWorkerFilesystem::setCurrentWorkingDirectory( 3634542f901SDimitry Andric const Twine &Path) { 3644542f901SDimitry Andric std::error_code EC = ProxyFileSystem::setCurrentWorkingDirectory(Path); 3654542f901SDimitry Andric updateWorkingDirForCacheLookup(); 3664542f901SDimitry Andric return EC; 3674542f901SDimitry Andric } 3684542f901SDimitry Andric 3694542f901SDimitry Andric void DependencyScanningWorkerFilesystem::updateWorkingDirForCacheLookup() { 3704542f901SDimitry Andric llvm::ErrorOr<std::string> CWD = 3714542f901SDimitry Andric getUnderlyingFS().getCurrentWorkingDirectory(); 3724542f901SDimitry Andric if (!CWD) { 3734542f901SDimitry Andric WorkingDirForCacheLookup = CWD.getError(); 3744542f901SDimitry Andric } else if (!llvm::sys::path::is_absolute_gnu(*CWD)) { 3754542f901SDimitry Andric WorkingDirForCacheLookup = llvm::errc::invalid_argument; 3764542f901SDimitry Andric } else { 3774542f901SDimitry Andric WorkingDirForCacheLookup = *CWD; 3784542f901SDimitry Andric } 3794542f901SDimitry Andric assert(!WorkingDirForCacheLookup || 3804542f901SDimitry Andric llvm::sys::path::is_absolute_gnu(*WorkingDirForCacheLookup)); 3814542f901SDimitry Andric } 382