1 //===--- GlobalCompilationDatabase.cpp ---------------------------*- C++-*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "GlobalCompilationDatabase.h"
12 #include "SourceCode.h"
13 #include "support/Logger.h"
14 #include "support/Path.h"
15 #include "support/Threading.h"
16 #include "support/ThreadsafeFS.h"
17 #include "clang/Tooling/ArgumentsAdjusters.h"
18 #include "clang/Tooling/CompilationDatabase.h"
19 #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
20 #include "clang/Tooling/JSONCompilationDatabase.h"
21 #include "llvm/ADT/None.h"
22 #include "llvm/ADT/Optional.h"
23 #include "llvm/ADT/PointerIntPair.h"
24 #include "llvm/ADT/STLExtras.h"
25 #include "llvm/ADT/ScopeExit.h"
26 #include "llvm/ADT/SmallString.h"
27 #include "llvm/ADT/StringMap.h"
28 #include "llvm/Support/Path.h"
29 #include "llvm/Support/VirtualFileSystem.h"
32 #include <condition_variable>
42 // Runs the given action on all parent directories of filename, starting from
43 // deepest directory and going up to root. Stops whenever action succeeds.
44 void actOnAllParentDirectories(PathRef FileName
,
45 llvm::function_ref
<bool(PathRef
)> Action
) {
46 for (auto Path
= absoluteParent(FileName
); !Path
.empty() && !Action(Path
);
47 Path
= absoluteParent(Path
))
53 tooling::CompileCommand
54 GlobalCompilationDatabase::getFallbackCommand(PathRef File
) const {
55 std::vector
<std::string
> Argv
= {"clang"};
56 // Clang treats .h files as C by default and files without extension as linker
57 // input, resulting in unhelpful diagnostics.
58 // Parsing as Objective C++ is friendly to more cases.
59 auto FileExtension
= llvm::sys::path::extension(File
);
60 if (FileExtension
.empty() || FileExtension
== ".h")
61 Argv
.push_back("-xobjective-c++-header");
62 Argv
.push_back(std::string(File
));
63 tooling::CompileCommand
Cmd(llvm::sys::path::parent_path(File
),
64 llvm::sys::path::filename(File
), std::move(Argv
),
66 Cmd
.Heuristic
= "clangd fallback";
70 // Loads and caches the CDB from a single directory.
72 // This class is threadsafe, which is to say we have independent locks for each
73 // directory we're searching for a CDB.
74 // Loading is deferred until first access.
76 // The DirectoryBasedCDB keeps a map from path => DirectoryCache.
77 // Typical usage is to:
78 // - 1) determine all the paths that might be searched
79 // - 2) acquire the map lock and get-or-create all the DirectoryCache entries
80 // - 3) release the map lock and query the caches as desired
81 class DirectoryBasedGlobalCompilationDatabase::DirectoryCache
{
82 using stopwatch
= std::chrono::steady_clock
;
84 // CachedFile is used to read a CDB file on disk (e.g. compile_commands.json).
85 // It specializes in being able to quickly bail out if the file is unchanged,
86 // which is the common case.
87 // Internally, it stores file metadata so a stat() can verify it's unchanged.
88 // We don't actually cache the content as it's not needed - if the file is
89 // unchanged then the previous CDB is valid.
91 CachedFile(llvm::StringRef Parent
, llvm::StringRef Rel
) {
92 llvm::SmallString
<256> Path
= Parent
;
93 llvm::sys::path::append(Path
, Rel
);
94 this->Path
= Path
.str().str();
97 size_t Size
= NoFileCached
;
98 llvm::sys::TimePoint
<> ModifiedTime
;
99 FileDigest ContentHash
;
101 static constexpr size_t NoFileCached
= -1;
110 std::unique_ptr
<llvm::MemoryBuffer
> Buffer
; // Set only if FoundNewData
113 LoadResult
load(llvm::vfs::FileSystem
&FS
, bool HasOldData
);
116 // If we've looked for a CDB here and found none, the time when that happened.
117 // (Atomics make it possible for get() to return without taking a lock)
118 std::atomic
<stopwatch::rep
> NoCDBAt
= {
119 stopwatch::time_point::min().time_since_epoch().count()};
121 // Guards the following cache state.
123 // When was the cache last known to be in sync with disk state?
124 stopwatch::time_point CachePopulatedAt
= stopwatch::time_point::min();
125 // Whether a new CDB has been loaded but not broadcast yet.
126 bool NeedsBroadcast
= false;
127 // Last loaded CDB, meaningful if CachePopulatedAt was ever set.
128 // shared_ptr so we can overwrite this when callers are still using the CDB.
129 std::shared_ptr
<tooling::CompilationDatabase
> CDB
;
130 // File metadata for the CDB files we support tracking directly.
131 CachedFile CompileCommandsJson
;
132 CachedFile BuildCompileCommandsJson
;
133 CachedFile CompileFlagsTxt
;
134 // CachedFile member corresponding to CDB.
135 // CDB | ACF | Scenario
136 // null | null | no CDB found, or initial empty cache
137 // set | null | CDB was loaded via generic plugin interface
138 // null | set | found known CDB file, but parsing it failed
139 // set | set | CDB was parsed from a known file
140 CachedFile
*ActiveCachedFile
= nullptr;
143 DirectoryCache(llvm::StringRef Path
)
144 : CompileCommandsJson(Path
, "compile_commands.json"),
145 BuildCompileCommandsJson(Path
, "build/compile_commands.json"),
146 CompileFlagsTxt(Path
, "compile_flags.txt"), Path(Path
) {
147 assert(llvm::sys::path::is_absolute(Path
));
150 // Absolute canonical path that we're the cache for. (Not case-folded).
151 const std::string Path
;
153 // Get the CDB associated with this directory.
155 // - as input, signals whether the caller is willing to broadcast a
156 // newly-discovered CDB. (e.g. to trigger background indexing)
157 // - as output, signals whether the caller should do so.
158 // (If a new CDB is discovered and ShouldBroadcast is false, we mark the
159 // CDB as needing broadcast, and broadcast it next time we can).
160 std::shared_ptr
<const tooling::CompilationDatabase
>
161 get(const ThreadsafeFS
&TFS
, bool &ShouldBroadcast
,
162 stopwatch::time_point FreshTime
, stopwatch::time_point FreshTimeMissing
) {
163 // Fast path for common case without taking lock.
164 if (stopwatch::time_point(stopwatch::duration(NoCDBAt
.load())) >
166 ShouldBroadcast
= false;
170 std::lock_guard
<std::mutex
> Lock(Mu
);
171 auto RequestBroadcast
= llvm::make_scope_exit([&, OldCDB(CDB
.get())] {
172 // If we loaded a new CDB, it should be broadcast at some point.
173 if (CDB
!= nullptr && CDB
.get() != OldCDB
)
174 NeedsBroadcast
= true;
175 else if (CDB
== nullptr) // nothing to broadcast anymore!
176 NeedsBroadcast
= false;
177 // If we have something to broadcast, then do so iff allowed.
178 if (!ShouldBroadcast
)
180 ShouldBroadcast
= NeedsBroadcast
;
181 NeedsBroadcast
= false;
184 // If our cache is valid, serve from it.
185 if (CachePopulatedAt
> FreshTime
)
188 if (/*MayCache=*/load(*TFS
.view(/*CWD=*/llvm::None
))) {
189 // Use new timestamp, as loading may be slow.
190 CachePopulatedAt
= stopwatch::now();
191 NoCDBAt
.store((CDB
? stopwatch::time_point::min() : CachePopulatedAt
)
200 // Updates `CDB` from disk state. Returns false on failure.
201 bool load(llvm::vfs::FileSystem
&FS
);
204 DirectoryBasedGlobalCompilationDatabase::DirectoryCache::CachedFile::LoadResult
205 DirectoryBasedGlobalCompilationDatabase::DirectoryCache::CachedFile::load(
206 llvm::vfs::FileSystem
&FS
, bool HasOldData
) {
207 auto Stat
= FS
.status(Path
);
208 if (!Stat
|| !Stat
->isRegularFile()) {
211 return {LoadResult::FileNotFound
, nullptr};
213 // If both the size and mtime match, presume unchanged without reading.
214 if (HasOldData
&& Stat
->getLastModificationTime() == ModifiedTime
&&
215 Stat
->getSize() == Size
)
216 return {LoadResult::FoundSameData
, nullptr};
217 auto Buf
= FS
.getBufferForFile(Path
);
218 if (!Buf
|| (*Buf
)->getBufferSize() != Stat
->getSize()) {
219 // Don't clear the cache - possible we're seeing inconsistent size as the
220 // file is being recreated. If it ends up identical later, great!
222 // This isn't a complete solution: if we see a partial file but stat/read
223 // agree on its size, we're ultimately going to have spurious CDB reloads.
224 // May be worth fixing if generators don't write atomically (CMake does).
225 elog("Failed to read {0}: {1}", Path
,
226 Buf
? "size changed" : Buf
.getError().message());
227 return {LoadResult::TransientError
, nullptr};
230 FileDigest NewContentHash
= digest((*Buf
)->getBuffer());
231 if (HasOldData
&& NewContentHash
== ContentHash
) {
232 // mtime changed but data is the same: avoid rebuilding the CDB.
233 ModifiedTime
= Stat
->getLastModificationTime();
234 return {LoadResult::FoundSameData
, nullptr};
237 Size
= (*Buf
)->getBufferSize();
238 ModifiedTime
= Stat
->getLastModificationTime();
239 ContentHash
= NewContentHash
;
240 return {LoadResult::FoundNewData
, std::move(*Buf
)};
243 // Adapt CDB-loading functions to a common interface for DirectoryCache::load().
244 static std::unique_ptr
<tooling::CompilationDatabase
>
245 parseJSON(PathRef Path
, llvm::StringRef Data
, std::string
&Error
) {
246 if (auto CDB
= tooling::JSONCompilationDatabase::loadFromBuffer(
247 Data
, Error
, tooling::JSONCommandLineSyntax::AutoDetect
)) {
248 // FS used for expanding response files.
249 // FIXME: ExpandResponseFilesDatabase appears not to provide the usual
250 // thread-safety guarantees, as the access to FS is not locked!
251 // For now, use the real FS, which is known to be threadsafe (if we don't
252 // use/change working directory, which ExpandResponseFilesDatabase doesn't).
253 auto FS
= llvm::vfs::getRealFileSystem();
254 return tooling::inferTargetAndDriverMode(
255 tooling::inferMissingCompileCommands(
256 expandResponseFiles(std::move(CDB
), std::move(FS
))));
260 static std::unique_ptr
<tooling::CompilationDatabase
>
261 parseFixed(PathRef Path
, llvm::StringRef Data
, std::string
&Error
) {
262 return tooling::FixedCompilationDatabase::loadFromBuffer(
263 llvm::sys::path::parent_path(Path
), Data
, Error
);
266 bool DirectoryBasedGlobalCompilationDatabase::DirectoryCache::load(
267 llvm::vfs::FileSystem
&FS
) {
268 dlog("Probing directory {0}", Path
);
271 // Load from the specially-supported compilation databases (JSON + Fixed).
272 // For these, we know the files they read and cache their metadata so we can
273 // cheaply validate whether they've changed, and hot-reload if they have.
274 // (As a bonus, these are also VFS-clean)!
277 // Wrapper for {Fixed,JSON}CompilationDatabase::loadFromBuffer.
278 std::unique_ptr
<tooling::CompilationDatabase
> (*Parser
)(
280 /*Data*/ llvm::StringRef
,
281 /*ErrorMsg*/ std::string
&);
283 for (const auto &Entry
: {CDBFile
{&CompileCommandsJson
, parseJSON
},
284 CDBFile
{&BuildCompileCommandsJson
, parseJSON
},
285 CDBFile
{&CompileFlagsTxt
, parseFixed
}}) {
286 bool Active
= ActiveCachedFile
== Entry
.File
;
287 auto Loaded
= Entry
.File
->load(FS
, Active
);
288 switch (Loaded
.Result
) {
289 case CachedFile::LoadResult::FileNotFound
:
291 log("Unloaded compilation database from {0}", Entry
.File
->Path
);
292 ActiveCachedFile
= nullptr;
295 // Continue looking at other candidates.
297 case CachedFile::LoadResult::TransientError
:
298 // File existed but we couldn't read it. Reuse the cache, retry later.
299 return false; // Load again next time.
300 case CachedFile::LoadResult::FoundSameData
:
301 assert(Active
&& "CachedFile may not return 'same data' if !HasOldData");
302 // This is the critical file, and it hasn't changed.
304 case CachedFile::LoadResult::FoundNewData
:
305 // We have a new CDB!
306 CDB
= Entry
.Parser(Entry
.File
->Path
, Loaded
.Buffer
->getBuffer(), Error
);
308 log("{0} compilation database from {1}", Active
? "Reloaded" : "Loaded",
311 elog("Failed to load compilation database from {0}: {1}",
312 Entry
.File
->Path
, Error
);
313 ActiveCachedFile
= Entry
.File
;
318 // Fall back to generic handling of compilation databases.
319 // We don't know what files they read, so can't efficiently check whether
320 // they need to be reloaded. So we never do that.
321 // FIXME: the interface doesn't provide a way to virtualize FS access.
323 // Don't try these more than once. If we've scanned before, we're done.
324 if (CachePopulatedAt
> stopwatch::time_point::min())
326 for (const auto &Entry
:
327 tooling::CompilationDatabasePluginRegistry::entries()) {
328 // Avoid duplicating the special cases handled above.
329 if (Entry
.getName() == "fixed-compilation-database" ||
330 Entry
.getName() == "json-compilation-database")
332 auto Plugin
= Entry
.instantiate();
333 if (auto CDB
= Plugin
->loadFromDirectory(Path
, Error
)) {
334 log("Loaded compilation database from {0} with plugin {1}", Path
,
336 this->CDB
= std::move(CDB
);
339 // Don't log Error here, it's usually just "couldn't find <file>".
341 dlog("No compilation database at {0}", Path
);
345 DirectoryBasedGlobalCompilationDatabase::
346 DirectoryBasedGlobalCompilationDatabase(const Options
&Opts
)
347 : Opts(Opts
), Broadcaster(std::make_unique
<BroadcastThread
>(*this)) {
348 if (!this->Opts
.ContextProvider
)
349 this->Opts
.ContextProvider
= [](llvm::StringRef
) {
350 return Context::current().clone();
354 DirectoryBasedGlobalCompilationDatabase::
355 ~DirectoryBasedGlobalCompilationDatabase() = default;
357 llvm::Optional
<tooling::CompileCommand
>
358 DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File
) const {
359 CDBLookupRequest Req
;
361 Req
.ShouldBroadcast
= true;
362 auto Now
= std::chrono::steady_clock::now();
363 Req
.FreshTime
= Now
- Opts
.RevalidateAfter
;
364 Req
.FreshTimeMissing
= Now
- Opts
.RevalidateMissingAfter
;
366 auto Res
= lookupCDB(Req
);
368 log("Failed to find compilation database for {0}", File
);
372 auto Candidates
= Res
->CDB
->getCompileCommands(File
);
373 if (!Candidates
.empty())
374 return std::move(Candidates
.front());
379 std::vector
<DirectoryBasedGlobalCompilationDatabase::DirectoryCache
*>
380 DirectoryBasedGlobalCompilationDatabase::getDirectoryCaches(
381 llvm::ArrayRef
<llvm::StringRef
> Dirs
) const {
382 std::vector
<std::string
> FoldedDirs
;
383 FoldedDirs
.reserve(Dirs
.size());
384 for (const auto &Dir
: Dirs
) {
386 if (!llvm::sys::path::is_absolute(Dir
))
387 elog("Trying to cache CDB for relative {0}");
389 FoldedDirs
.push_back(maybeCaseFoldPath(Dir
));
392 std::vector
<DirectoryCache
*> Ret
;
393 Ret
.reserve(Dirs
.size());
395 std::lock_guard
<std::mutex
> Lock(DirCachesMutex
);
396 for (unsigned I
= 0; I
< Dirs
.size(); ++I
)
397 Ret
.push_back(&DirCaches
.try_emplace(FoldedDirs
[I
], Dirs
[I
]).first
->second
);
401 llvm::Optional
<DirectoryBasedGlobalCompilationDatabase::CDBLookupResult
>
402 DirectoryBasedGlobalCompilationDatabase::lookupCDB(
403 CDBLookupRequest Request
) const {
404 assert(llvm::sys::path::is_absolute(Request
.FileName
) &&
405 "path must be absolute");
408 std::vector
<llvm::StringRef
> SearchDirs
;
409 if (Opts
.CompileCommandsDir
) // FIXME: unify this case with config.
410 SearchDirs
= {*Opts
.CompileCommandsDir
};
412 WithContext
WithProvidedContext(Opts
.ContextProvider(Request
.FileName
));
413 const auto &Spec
= Config::current().CompileFlags
.CDBSearch
;
414 switch (Spec
.Policy
) {
415 case Config::CDBSearchSpec::NoCDBSearch
:
417 case Config::CDBSearchSpec::FixedDir
:
418 Storage
= *Spec
.FixedCDBPath
;
419 SearchDirs
= {Storage
};
421 case Config::CDBSearchSpec::Ancestors
:
422 // Traverse the canonical version to prevent false positives. i.e.:
423 // src/build/../a.cc can detect a CDB in /src/build if not
425 Storage
= removeDots(Request
.FileName
);
426 actOnAllParentDirectories(Storage
, [&](llvm::StringRef Dir
) {
427 SearchDirs
.push_back(Dir
);
433 std::shared_ptr
<const tooling::CompilationDatabase
> CDB
= nullptr;
434 bool ShouldBroadcast
= false;
435 DirectoryCache
*DirCache
= nullptr;
436 for (DirectoryCache
*Candidate
: getDirectoryCaches(SearchDirs
)) {
437 bool CandidateShouldBroadcast
= Request
.ShouldBroadcast
;
438 if ((CDB
= Candidate
->get(Opts
.TFS
, CandidateShouldBroadcast
,
439 Request
.FreshTime
, Request
.FreshTimeMissing
))) {
440 DirCache
= Candidate
;
441 ShouldBroadcast
= CandidateShouldBroadcast
;
449 CDBLookupResult Result
;
450 Result
.CDB
= std::move(CDB
);
451 Result
.PI
.SourceRoot
= DirCache
->Path
;
454 broadcastCDB(Result
);
458 // The broadcast thread announces files with new compile commands to the world.
459 // Primarily this is used to enqueue them for background indexing.
461 // It's on a separate thread because:
462 // - otherwise it would block the first parse of the initial file
463 // - we need to enumerate all files in the CDB, of which there are many
464 // - we (will) have to evaluate config for every file in the CDB, which is slow
465 class DirectoryBasedGlobalCompilationDatabase::BroadcastThread
{
467 DirectoryBasedGlobalCompilationDatabase
&Parent
;
470 std::condition_variable CV
;
471 // Shutdown flag (CV is notified after writing).
472 // This is atomic so that broadcasts can also observe it and abort early.
473 std::atomic
<bool> ShouldStop
= {false};
475 CDBLookupResult Lookup
;
478 std::deque
<Task
> Queue
;
479 llvm::Optional
<Task
> ActiveTask
;
480 std::thread Thread
; // Must be last member.
482 // Thread body: this is just the basic queue procesing boilerplate.
484 std::unique_lock
<std::mutex
> Lock(Mu
);
486 bool Stopping
= false;
488 return (Stopping
= ShouldStop
.load(std::memory_order_acquire
)) ||
496 ActiveTask
= std::move(Queue
.front());
501 WithContext
WithCtx(std::move(ActiveTask
->Ctx
));
502 process(ActiveTask
->Lookup
);
510 // Inspects a new CDB and broadcasts the files it owns.
511 void process(const CDBLookupResult
&T
);
514 BroadcastThread(DirectoryBasedGlobalCompilationDatabase
&Parent
)
515 : Parent(Parent
), Thread([this] { run(); }) {}
517 void enqueue(CDBLookupResult Lookup
) {
519 assert(!Lookup
.PI
.SourceRoot
.empty());
520 std::lock_guard
<std::mutex
> Lock(Mu
);
521 // New CDB takes precedence over any queued one for the same directory.
522 llvm::erase_if(Queue
, [&](const Task
&T
) {
523 return T
.Lookup
.PI
.SourceRoot
== Lookup
.PI
.SourceRoot
;
525 Queue
.push_back({std::move(Lookup
), Context::current().clone()});
530 bool blockUntilIdle(Deadline Timeout
) {
531 std::unique_lock
<std::mutex
> Lock(Mu
);
532 return wait(Lock
, CV
, Timeout
,
533 [&] { return Queue
.empty() && !ActiveTask
; });
538 std::lock_guard
<std::mutex
> Lock(Mu
);
539 ShouldStop
.store(true, std::memory_order_release
);
546 // The DirBasedCDB associates each file with a specific CDB.
547 // When a CDB is discovered, it may claim to describe files that we associate
548 // with a different CDB. We do not want to broadcast discovery of these, and
549 // trigger background indexing of them.
551 // We must filter the list, and check whether they are associated with this CDB.
552 // This class attempts to do so efficiently.
555 // - loads the config for each file, and determines the relevant search path
556 // - gathers all directories that are part of any search path
557 // - (lazily) checks for a CDB in each such directory at most once
558 // - walks the search path for each file and determines whether to include it.
559 class DirectoryBasedGlobalCompilationDatabase::BroadcastThread::Filter
{
560 llvm::StringRef ThisDir
;
561 DirectoryBasedGlobalCompilationDatabase
&Parent
;
563 // Keep track of all directories we might check for CDBs.
565 DirectoryCache
*Cache
= nullptr;
566 enum { Unknown
, Missing
, TargetCDB
, OtherCDB
} State
= Unknown
;
567 DirInfo
*Parent
= nullptr;
569 llvm::StringMap
<DirInfo
> Dirs
;
571 // A search path starts at a directory, and either includes ancestors or not.
572 using SearchPath
= llvm::PointerIntPair
<DirInfo
*, 1>;
574 // Add all ancestor directories of FilePath to the tracked set.
575 // Returns the immediate parent of the file.
576 DirInfo
*addParents(llvm::StringRef FilePath
) {
577 DirInfo
*Leaf
= nullptr;
578 DirInfo
*Child
= nullptr;
579 actOnAllParentDirectories(FilePath
, [&](llvm::StringRef Dir
) {
580 auto &Info
= Dirs
[Dir
];
581 // If this is the first iteration, then this node is the overall result.
584 // Fill in the parent link from the previous iteration to this parent.
586 Child
->Parent
= &Info
;
587 // Keep walking, whether we inserted or not, if parent link is missing.
588 // (If it's present, parent links must be present up to the root, so stop)
590 return Info
.Parent
!= nullptr;
595 // Populates DirInfo::Cache (and State, if it is TargetCDB).
597 // Fast path out if there were no files, or CDB loading is off.
601 std::vector
<llvm::StringRef
> DirKeys
;
602 std::vector
<DirInfo
*> DirValues
;
603 DirKeys
.reserve(Dirs
.size() + 1);
604 DirValues
.reserve(Dirs
.size());
605 for (auto &E
: Dirs
) {
606 DirKeys
.push_back(E
.first());
607 DirValues
.push_back(&E
.second
);
610 // Also look up the cache entry for the CDB we're broadcasting.
611 // Comparing DirectoryCache pointers is more robust than checking string
612 // equality, e.g. reuses the case-sensitivity handling.
613 DirKeys
.push_back(ThisDir
);
614 auto DirCaches
= Parent
.getDirectoryCaches(DirKeys
);
615 const DirectoryCache
*ThisCache
= DirCaches
.back();
616 DirCaches
.pop_back();
619 for (unsigned I
= 0; I
< DirKeys
.size(); ++I
) {
620 DirValues
[I
]->Cache
= DirCaches
[I
];
621 if (DirCaches
[I
] == ThisCache
)
622 DirValues
[I
]->State
= DirInfo::TargetCDB
;
626 // Should we include a file from this search path?
627 bool shouldInclude(SearchPath P
) {
628 DirInfo
*Info
= P
.getPointer();
631 if (Info
->State
== DirInfo::Unknown
) {
632 assert(Info
->Cache
&& "grabCaches() should have filled this");
633 // Given that we know that CDBs have been moved/generated, don't trust
634 // caches. (This should be rare, so it's OK to add a little latency).
635 constexpr auto IgnoreCache
= std::chrono::steady_clock::time_point::max();
636 // Don't broadcast CDBs discovered while broadcasting!
637 bool ShouldBroadcast
= false;
639 nullptr != Info
->Cache
->get(Parent
.Opts
.TFS
, ShouldBroadcast
,
640 /*FreshTime=*/IgnoreCache
,
641 /*FreshTimeMissing=*/IgnoreCache
);
642 Info
->State
= Exists
? DirInfo::OtherCDB
: DirInfo::Missing
;
644 // If we have a CDB, include the file if it's the target CDB only.
645 if (Info
->State
!= DirInfo::Missing
)
646 return Info
->State
== DirInfo::TargetCDB
;
647 // If we have no CDB and no relevant parent, don't include the file.
648 if (!P
.getInt() || !Info
->Parent
)
650 // Walk up to the next parent.
651 return shouldInclude(SearchPath(Info
->Parent
, 1));
655 Filter(llvm::StringRef ThisDir
,
656 DirectoryBasedGlobalCompilationDatabase
&Parent
)
657 : ThisDir(ThisDir
), Parent(Parent
) {}
659 std::vector
<std::string
> filter(std::vector
<std::string
> AllFiles
,
660 std::atomic
<bool> &ShouldStop
) {
661 std::vector
<std::string
> Filtered
;
662 // Allow for clean early-exit of the slow parts.
663 auto ExitEarly
= [&] {
664 if (ShouldStop
.load(std::memory_order_acquire
)) {
665 log("Giving up on broadcasting CDB, as we're shutting down");
671 // Compute search path for each file.
672 std::vector
<SearchPath
> SearchPaths(AllFiles
.size());
673 for (unsigned I
= 0; I
< AllFiles
.size(); ++I
) {
674 if (Parent
.Opts
.CompileCommandsDir
) { // FIXME: unify with config
675 SearchPaths
[I
].setPointer(&Dirs
[*Parent
.Opts
.CompileCommandsDir
]);
678 if (ExitEarly()) // loading config may be slow
680 WithContext
WithProvidedContent(Parent
.Opts
.ContextProvider(AllFiles
[I
]));
681 const Config::CDBSearchSpec
&Spec
=
682 Config::current().CompileFlags
.CDBSearch
;
683 switch (Spec
.Policy
) {
684 case Config::CDBSearchSpec::NoCDBSearch
:
686 case Config::CDBSearchSpec::Ancestors
:
687 SearchPaths
[I
].setInt(/*Recursive=*/1);
688 SearchPaths
[I
].setPointer(addParents(AllFiles
[I
]));
690 case Config::CDBSearchSpec::FixedDir
:
691 SearchPaths
[I
].setPointer(&Dirs
[*Spec
.FixedCDBPath
]);
695 // Get the CDB cache for each dir on the search path, but don't load yet.
697 // Now work out which files we want to keep, loading CDBs where needed.
698 for (unsigned I
= 0; I
< AllFiles
.size(); ++I
) {
699 if (ExitEarly()) // loading CDBs may be slow
701 if (shouldInclude(SearchPaths
[I
]))
702 Filtered
.push_back(std::move(AllFiles
[I
]));
708 void DirectoryBasedGlobalCompilationDatabase::BroadcastThread::process(
709 const CDBLookupResult
&T
) {
710 vlog("Broadcasting compilation database from {0}", T
.PI
.SourceRoot
);
711 std::vector
<std::string
> GovernedFiles
=
712 Filter(T
.PI
.SourceRoot
, Parent
).filter(T
.CDB
->getAllFiles(), ShouldStop
);
713 if (!GovernedFiles
.empty())
714 Parent
.OnCommandChanged
.broadcast(std::move(GovernedFiles
));
717 void DirectoryBasedGlobalCompilationDatabase::broadcastCDB(
718 CDBLookupResult Result
) const {
719 assert(Result
.CDB
&& "Trying to broadcast an invalid CDB!");
720 Broadcaster
->enqueue(Result
);
723 bool DirectoryBasedGlobalCompilationDatabase::blockUntilIdle(
724 Deadline Timeout
) const {
725 return Broadcaster
->blockUntilIdle(Timeout
);
728 llvm::Optional
<ProjectInfo
>
729 DirectoryBasedGlobalCompilationDatabase::getProjectInfo(PathRef File
) const {
730 CDBLookupRequest Req
;
732 Req
.ShouldBroadcast
= false;
733 Req
.FreshTime
= Req
.FreshTimeMissing
=
734 std::chrono::steady_clock::time_point::min();
735 auto Res
= lookupCDB(Req
);
741 OverlayCDB::OverlayCDB(const GlobalCompilationDatabase
*Base
,
742 std::vector
<std::string
> FallbackFlags
,
743 tooling::ArgumentsAdjuster Adjuster
)
744 : DelegatingCDB(Base
), ArgsAdjuster(std::move(Adjuster
)),
745 FallbackFlags(std::move(FallbackFlags
)) {}
747 llvm::Optional
<tooling::CompileCommand
>
748 OverlayCDB::getCompileCommand(PathRef File
) const {
749 llvm::Optional
<tooling::CompileCommand
> Cmd
;
751 std::lock_guard
<std::mutex
> Lock(Mutex
);
752 auto It
= Commands
.find(removeDots(File
));
753 if (It
!= Commands
.end())
757 Cmd
= DelegatingCDB::getCompileCommand(File
);
761 Cmd
->CommandLine
= ArgsAdjuster(Cmd
->CommandLine
, File
);
765 tooling::CompileCommand
OverlayCDB::getFallbackCommand(PathRef File
) const {
766 auto Cmd
= DelegatingCDB::getFallbackCommand(File
);
767 std::lock_guard
<std::mutex
> Lock(Mutex
);
768 Cmd
.CommandLine
.insert(Cmd
.CommandLine
.end(), FallbackFlags
.begin(),
769 FallbackFlags
.end());
771 Cmd
.CommandLine
= ArgsAdjuster(Cmd
.CommandLine
, File
);
775 void OverlayCDB::setCompileCommand(
776 PathRef File
, llvm::Optional
<tooling::CompileCommand
> Cmd
) {
777 // We store a canonical version internally to prevent mismatches between set
778 // and get compile commands. Also it assures clients listening to broadcasts
779 // doesn't receive different names for the same file.
780 std::string CanonPath
= removeDots(File
);
782 std::unique_lock
<std::mutex
> Lock(Mutex
);
784 Commands
[CanonPath
] = std::move(*Cmd
);
786 Commands
.erase(CanonPath
);
788 OnCommandChanged
.broadcast({CanonPath
});
791 DelegatingCDB::DelegatingCDB(const GlobalCompilationDatabase
*Base
)
794 BaseChanged
= Base
->watch([this](const std::vector
<std::string
> Changes
) {
795 OnCommandChanged
.broadcast(Changes
);
799 DelegatingCDB::DelegatingCDB(std::unique_ptr
<GlobalCompilationDatabase
> Base
)
800 : DelegatingCDB(Base
.get()) {
801 BaseOwner
= std::move(Base
);
804 llvm::Optional
<tooling::CompileCommand
>
805 DelegatingCDB::getCompileCommand(PathRef File
) const {
808 return Base
->getCompileCommand(File
);
811 llvm::Optional
<ProjectInfo
> DelegatingCDB::getProjectInfo(PathRef File
) const {
814 return Base
->getProjectInfo(File
);
817 tooling::CompileCommand
DelegatingCDB::getFallbackCommand(PathRef File
) const {
819 return GlobalCompilationDatabase::getFallbackCommand(File
);
820 return Base
->getFallbackCommand(File
);
823 bool DelegatingCDB::blockUntilIdle(Deadline D
) const {
826 return Base
->blockUntilIdle(D
);
829 } // namespace clangd