10#include "llvm/Support/MemoryBuffer.h"
11#include "llvm/Support/SmallVectorMemoryBuffer.h"
12#include "llvm/Support/Threading.h"
16using namespace tooling;
17using namespace dependencies;
19llvm::ErrorOr<DependencyScanningWorkerFilesystem::TentativeEntry>
20DependencyScanningWorkerFilesystem::readFile(StringRef
Filename) {
22 auto MaybeFile = getUnderlyingFS().openFileForRead(
Filename);
24 return MaybeFile.getError();
25 auto File = std::move(*MaybeFile);
27 auto MaybeStat =
File->status();
29 return MaybeStat.getError();
30 auto Stat = std::move(*MaybeStat);
32 auto MaybeBuffer =
File->getBuffer(Stat.getName());
34 return MaybeBuffer.getError();
35 auto Buffer = std::move(*MaybeBuffer);
38 if (Stat.getSize() != Buffer->getBufferSize())
39 Stat = llvm::vfs::Status::copyWithNewSize(Stat, Buffer->getBufferSize());
41 return TentativeEntry(Stat, std::move(Buffer));
44EntryRef DependencyScanningWorkerFilesystem::scanForDirectivesIfNecessary(
51 assert(Contents &&
"contents not initialized");
57 std::lock_guard<std::mutex> GuardLock(Contents->
ValueLock);
71 Contents->
DepDirectives.store(
new std::optional<DependencyDirectivesTy>());
80 new std::optional<DependencyDirectivesTy>(std::move(Directives)));
92 std::max(2u, llvm::hardware_concurrency().compute_thread_count() / 4);
93 CacheShards = std::make_unique<CacheShard[]>(NumShards);
99 return CacheShards[llvm::hash_value(
Filename) % NumShards];
104 llvm::sys::fs::UniqueID UID)
const {
105 auto Hash = llvm::hash_combine(UID.getDevice(), UID.getFile());
106 return CacheShards[Hash % NumShards];
112 std::lock_guard<std::mutex> LockGuard(
CacheLock);
119 llvm::sys::fs::UniqueID UID)
const {
120 std::lock_guard<std::mutex> LockGuard(CacheLock);
121 auto It = EntriesByUID.find(UID);
122 return It == EntriesByUID.end() ? nullptr : It->getSecond();
128 llvm::ErrorOr<llvm::vfs::Status> Stat) {
129 std::lock_guard<std::mutex> LockGuard(CacheLock);
130 auto Insertion = EntriesByFilename.insert({
Filename,
nullptr});
131 if (Insertion.second)
132 Insertion.first->second =
134 return *Insertion.first->second;
139 llvm::sys::fs::UniqueID UID, llvm::vfs::Status Stat,
140 std::unique_ptr<llvm::MemoryBuffer> Contents) {
141 std::lock_guard<std::mutex> LockGuard(CacheLock);
142 auto Insertion = EntriesByUID.insert({UID,
nullptr});
143 if (Insertion.second) {
146 StoredContents =
new (ContentsStorage.Allocate())
148 Insertion.first->second =
new (EntryStorage.Allocate())
151 return *Insertion.first->second;
158 std::lock_guard<std::mutex> LockGuard(CacheLock);
159 return *EntriesByFilename.insert({
Filename, &Entry}).first->getValue();
168 StringRef Ext = llvm::sys::path::extension(
Filename);
171 return llvm::StringSwitch<bool>(Ext)
172 .CasesLower(
".c",
".cc",
".cpp",
".c++",
".cxx",
true)
173 .CasesLower(
".h",
".hh",
".hpp",
".h++",
".hxx",
true)
174 .CasesLower(
".m",
".mm",
true)
175 .CasesLower(
".i",
".ii",
".mi",
".mmi",
true)
176 .CasesLower(
".def",
".inc",
true)
181 StringRef Ext = llvm::sys::path::extension(
Filename);
186 StringRef FName = llvm::sys::path::filename(
Filename);
187 if (FName ==
"module.modulemap" || FName ==
"module.map")
192bool DependencyScanningWorkerFilesystem::shouldScanForDirectives(
198DependencyScanningWorkerFilesystem::getOrEmplaceSharedEntryForUID(
199 TentativeEntry TEntry) {
200 auto &Shard = SharedCache.getShardForUID(TEntry.Status.getUniqueID());
201 return Shard.getOrEmplaceEntryForUID(TEntry.Status.getUniqueID(),
202 std::move(TEntry.Status),
203 std::move(TEntry.Contents));
207DependencyScanningWorkerFilesystem::findEntryByFilenameWithWriteThrough(
209 if (
const auto *Entry = LocalCache.findEntryByFilename(
Filename))
211 auto &Shard = SharedCache.getShardForFilename(
Filename);
212 if (
const auto *Entry = Shard.findEntryByFilename(
Filename))
213 return &LocalCache.insertEntryForFilename(
Filename, *Entry);
217llvm::ErrorOr<const CachedFileSystemEntry &>
218DependencyScanningWorkerFilesystem::computeAndStoreResult(StringRef
Filename) {
219 llvm::ErrorOr<llvm::vfs::Status> Stat = getUnderlyingFS().status(
Filename);
224 getOrEmplaceSharedEntryForFilename(
Filename, Stat.getError());
225 return insertLocalEntryForFilename(
Filename, Entry);
228 if (
const auto *Entry = findSharedEntryByUID(*Stat))
229 return insertLocalEntryForFilename(
Filename, *Entry);
232 Stat->isDirectory() ? TentativeEntry(*Stat) : readFile(
Filename);
236 const auto &UIDEntry = getOrEmplaceSharedEntryForUID(std::move(*TEntry));
237 return &getOrInsertSharedEntryForFilename(
Filename, UIDEntry);
239 return &getOrEmplaceSharedEntryForFilename(
Filename, TEntry.getError());
242 return insertLocalEntryForFilename(
Filename, *SharedEntry);
245llvm::ErrorOr<EntryRef>
247 StringRef
Filename,
bool DisableDirectivesScanning) {
248 if (
const auto *Entry = findEntryByFilenameWithWriteThrough(
Filename))
249 return scanForDirectivesIfNecessary(*Entry,
Filename,
250 DisableDirectivesScanning)
252 auto MaybeEntry = computeAndStoreResult(
Filename);
254 return MaybeEntry.getError();
255 return scanForDirectivesIfNecessary(*MaybeEntry,
Filename,
256 DisableDirectivesScanning)
260llvm::ErrorOr<llvm::vfs::Status>
263 StringRef
Filename = Path.toStringRef(OwnedFilename);
266 return getUnderlyingFS().status(Path);
268 llvm::ErrorOr<EntryRef>
Result = getOrCreateFileSystemEntry(
Filename);
271 return Result->getStatus();
278class DepScanFile final :
public llvm::vfs::File {
280 DepScanFile(std::unique_ptr<llvm::MemoryBuffer> Buffer,
281 llvm::vfs::Status Stat)
282 : Buffer(
std::move(Buffer)), Stat(
std::move(Stat)) {}
284 static llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> create(
EntryRef Entry);
286 llvm::ErrorOr<llvm::vfs::Status> status()
override {
return Stat; }
288 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
289 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
290 bool IsVolatile)
override {
291 return std::move(Buffer);
294 std::error_code close()
override {
return {}; }
297 std::unique_ptr<llvm::MemoryBuffer> Buffer;
298 llvm::vfs::Status Stat;
303llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
304DepScanFile::create(
EntryRef Entry) {
305 assert(!Entry.
isError() &&
"error");
308 return std::make_error_code(std::errc::is_a_directory);
310 auto Result = std::make_unique<DepScanFile>(
311 llvm::MemoryBuffer::getMemBuffer(Entry.
getContents(),
316 return llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>(
317 std::unique_ptr<llvm::vfs::File>(std::move(
Result)));
320llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
323 StringRef
Filename = Path.toStringRef(OwnedFilename);
326 return getUnderlyingFS().openFileForRead(Path);
328 llvm::ErrorOr<EntryRef>
Result = getOrCreateFileSystemEntry(
Filename);
331 return DepScanFile::create(
Result.get());
static bool shouldCacheStatFailures(StringRef Filename)
static bool shouldScanForDirectivesBasedOnExtension(StringRef Filename)
Whitelist file extensions that should be minimized, treating no extension as a source file that shoul...
An in-memory representation of a file system entity that is of interest to the dependency scanning fi...
std::error_code getError() const
CachedFileContents * getCachedContents() const
Reference to a CachedFileSystemEntry.
llvm::vfs::Status getStatus() const
StringRef getContents() const
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.
Contents and directive tokens of a cached file entry.
std::mutex ValueLock
The mutex that must be locked before mutating directive tokens.
std::atomic< const std::optional< DependencyDirectivesTy > * > DepDirectives
Accessor to the directive tokens that's atomic to avoid data races.
std::unique_ptr< llvm::MemoryBuffer > Original
Owning storage for the original contents.
SmallVector< dependency_directives_scan::Token, 10 > DepDirectiveTokens