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 "ProjectModules.h"
13 #include "ScanningProjectModules.h"
14 #include "SourceCode.h"
15 #include "support/Logger.h"
16 #include "support/Path.h"
17 #include "support/Threading.h"
18 #include "support/ThreadsafeFS.h"
19 #include "clang/Tooling/ArgumentsAdjusters.h"
20 #include "clang/Tooling/CompilationDatabase.h"
21 #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
22 #include "clang/Tooling/JSONCompilationDatabase.h"
23 #include "clang/Tooling/Tooling.h"
24 #include "llvm/ADT/PointerIntPair.h"
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/ADT/ScopeExit.h"
27 #include "llvm/ADT/SmallString.h"
28 #include "llvm/ADT/StringMap.h"
29 #include "llvm/Support/Path.h"
30 #include "llvm/Support/VirtualFileSystem.h"
31 #include "llvm/TargetParser/Host.h"
34 #include <condition_variable>
46 // Runs the given action on all parent directories of filename, starting from
47 // deepest directory and going up to root. Stops whenever action succeeds.
48 void actOnAllParentDirectories(PathRef FileName
,
49 llvm::function_ref
<bool(PathRef
)> Action
) {
50 for (auto Path
= absoluteParent(FileName
); !Path
.empty() && !Action(Path
);
51 Path
= absoluteParent(Path
))
57 tooling::CompileCommand
58 GlobalCompilationDatabase::getFallbackCommand(PathRef File
) const {
59 std::vector
<std::string
> Argv
= {"clang"};
60 // Clang treats .h files as C by default and files without extension as linker
61 // input, resulting in unhelpful diagnostics.
62 // Parsing as Objective C++ is friendly to more cases.
63 auto FileExtension
= llvm::sys::path::extension(File
);
64 if (FileExtension
.empty() || FileExtension
== ".h")
65 Argv
.push_back("-xobjective-c++-header");
66 Argv
.push_back(std::string(File
));
67 tooling::CompileCommand
Cmd(llvm::sys::path::parent_path(File
),
68 llvm::sys::path::filename(File
), std::move(Argv
),
70 Cmd
.Heuristic
= "clangd fallback";
74 // Loads and caches the CDB from a single directory.
76 // This class is threadsafe, which is to say we have independent locks for each
77 // directory we're searching for a CDB.
78 // Loading is deferred until first access.
80 // The DirectoryBasedCDB keeps a map from path => DirectoryCache.
81 // Typical usage is to:
82 // - 1) determine all the paths that might be searched
83 // - 2) acquire the map lock and get-or-create all the DirectoryCache entries
84 // - 3) release the map lock and query the caches as desired
85 class DirectoryBasedGlobalCompilationDatabase::DirectoryCache
{
86 using stopwatch
= std::chrono::steady_clock
;
88 // CachedFile is used to read a CDB file on disk (e.g. compile_commands.json).
89 // It specializes in being able to quickly bail out if the file is unchanged,
90 // which is the common case.
91 // Internally, it stores file metadata so a stat() can verify it's unchanged.
92 // We don't actually cache the content as it's not needed - if the file is
93 // unchanged then the previous CDB is valid.
95 CachedFile(llvm::StringRef Parent
, llvm::StringRef Rel
) {
96 llvm::SmallString
<256> Path
= Parent
;
97 llvm::sys::path::append(Path
, Rel
);
98 this->Path
= Path
.str().str();
101 size_t Size
= NoFileCached
;
102 llvm::sys::TimePoint
<> ModifiedTime
;
103 FileDigest ContentHash
;
105 static constexpr size_t NoFileCached
= -1;
114 std::unique_ptr
<llvm::MemoryBuffer
> Buffer
; // Set only if FoundNewData
117 LoadResult
load(llvm::vfs::FileSystem
&FS
, bool HasOldData
);
120 // If we've looked for a CDB here and found none, the time when that happened.
121 // (Atomics make it possible for get() to return without taking a lock)
122 std::atomic
<stopwatch::rep
> NoCDBAt
= {
123 stopwatch::time_point::min().time_since_epoch().count()};
125 // Guards the following cache state.
127 // When was the cache last known to be in sync with disk state?
128 stopwatch::time_point CachePopulatedAt
= stopwatch::time_point::min();
129 // Whether a new CDB has been loaded but not broadcast yet.
130 bool NeedsBroadcast
= false;
131 // Last loaded CDB, meaningful if CachePopulatedAt was ever set.
132 // shared_ptr so we can overwrite this when callers are still using the CDB.
133 std::shared_ptr
<tooling::CompilationDatabase
> CDB
;
134 // File metadata for the CDB files we support tracking directly.
135 CachedFile CompileCommandsJson
;
136 CachedFile BuildCompileCommandsJson
;
137 CachedFile CompileFlagsTxt
;
138 // CachedFile member corresponding to CDB.
139 // CDB | ACF | Scenario
140 // null | null | no CDB found, or initial empty cache
141 // set | null | CDB was loaded via generic plugin interface
142 // null | set | found known CDB file, but parsing it failed
143 // set | set | CDB was parsed from a known file
144 CachedFile
*ActiveCachedFile
= nullptr;
147 DirectoryCache(llvm::StringRef Path
)
148 : CompileCommandsJson(Path
, "compile_commands.json"),
149 BuildCompileCommandsJson(Path
, "build/compile_commands.json"),
150 CompileFlagsTxt(Path
, "compile_flags.txt"), Path(Path
) {
151 assert(llvm::sys::path::is_absolute(Path
));
154 // Absolute canonical path that we're the cache for. (Not case-folded).
155 const std::string Path
;
157 // Get the CDB associated with this directory.
159 // - as input, signals whether the caller is willing to broadcast a
160 // newly-discovered CDB. (e.g. to trigger background indexing)
161 // - as output, signals whether the caller should do so.
162 // (If a new CDB is discovered and ShouldBroadcast is false, we mark the
163 // CDB as needing broadcast, and broadcast it next time we can).
164 std::shared_ptr
<const tooling::CompilationDatabase
>
165 get(const ThreadsafeFS
&TFS
, bool &ShouldBroadcast
,
166 stopwatch::time_point FreshTime
, stopwatch::time_point FreshTimeMissing
) {
167 // Fast path for common case without taking lock.
168 if (stopwatch::time_point(stopwatch::duration(NoCDBAt
.load())) >
170 ShouldBroadcast
= false;
174 std::lock_guard
<std::mutex
> Lock(Mu
);
175 auto RequestBroadcast
= llvm::make_scope_exit([&, OldCDB(CDB
.get())] {
176 // If we loaded a new CDB, it should be broadcast at some point.
177 if (CDB
!= nullptr && CDB
.get() != OldCDB
)
178 NeedsBroadcast
= true;
179 else if (CDB
== nullptr) // nothing to broadcast anymore!
180 NeedsBroadcast
= false;
181 // If we have something to broadcast, then do so iff allowed.
182 if (!ShouldBroadcast
)
184 ShouldBroadcast
= NeedsBroadcast
;
185 NeedsBroadcast
= false;
188 // If our cache is valid, serve from it.
189 if (CachePopulatedAt
> FreshTime
)
192 if (/*MayCache=*/load(*TFS
.view(/*CWD=*/std::nullopt
))) {
193 // Use new timestamp, as loading may be slow.
194 CachePopulatedAt
= stopwatch::now();
195 NoCDBAt
.store((CDB
? stopwatch::time_point::min() : CachePopulatedAt
)
204 // Updates `CDB` from disk state. Returns false on failure.
205 bool load(llvm::vfs::FileSystem
&FS
);
208 DirectoryBasedGlobalCompilationDatabase::DirectoryCache::CachedFile::LoadResult
209 DirectoryBasedGlobalCompilationDatabase::DirectoryCache::CachedFile::load(
210 llvm::vfs::FileSystem
&FS
, bool HasOldData
) {
211 auto Stat
= FS
.status(Path
);
212 if (!Stat
|| !Stat
->isRegularFile()) {
215 return {LoadResult::FileNotFound
, nullptr};
217 // If both the size and mtime match, presume unchanged without reading.
218 if (HasOldData
&& Stat
->getLastModificationTime() == ModifiedTime
&&
219 Stat
->getSize() == Size
)
220 return {LoadResult::FoundSameData
, nullptr};
221 auto Buf
= FS
.getBufferForFile(Path
);
222 if (!Buf
|| (*Buf
)->getBufferSize() != Stat
->getSize()) {
223 // Don't clear the cache - possible we're seeing inconsistent size as the
224 // file is being recreated. If it ends up identical later, great!
226 // This isn't a complete solution: if we see a partial file but stat/read
227 // agree on its size, we're ultimately going to have spurious CDB reloads.
228 // May be worth fixing if generators don't write atomically (CMake does).
229 elog("Failed to read {0}: {1}", Path
,
230 Buf
? "size changed" : Buf
.getError().message());
231 return {LoadResult::TransientError
, nullptr};
234 FileDigest NewContentHash
= digest((*Buf
)->getBuffer());
235 if (HasOldData
&& NewContentHash
== ContentHash
) {
236 // mtime changed but data is the same: avoid rebuilding the CDB.
237 ModifiedTime
= Stat
->getLastModificationTime();
238 return {LoadResult::FoundSameData
, nullptr};
241 Size
= (*Buf
)->getBufferSize();
242 ModifiedTime
= Stat
->getLastModificationTime();
243 ContentHash
= NewContentHash
;
244 return {LoadResult::FoundNewData
, std::move(*Buf
)};
247 // Adapt CDB-loading functions to a common interface for DirectoryCache::load().
248 static std::unique_ptr
<tooling::CompilationDatabase
>
249 parseJSON(PathRef Path
, llvm::StringRef Data
, std::string
&Error
) {
250 if (auto CDB
= tooling::JSONCompilationDatabase::loadFromBuffer(
251 Data
, Error
, tooling::JSONCommandLineSyntax::AutoDetect
)) {
252 // FS used for expanding response files.
253 // FIXME: ExpandResponseFilesDatabase appears not to provide the usual
254 // thread-safety guarantees, as the access to FS is not locked!
255 // For now, use the real FS, which is known to be threadsafe (if we don't
256 // use/change working directory, which ExpandResponseFilesDatabase doesn't).
257 // NOTE: response files have to be expanded before inference because
258 // inference needs full command line to check/fix driver mode and file type.
259 auto FS
= llvm::vfs::getRealFileSystem();
260 return tooling::inferMissingCompileCommands(
261 expandResponseFiles(std::move(CDB
), std::move(FS
)));
265 static std::unique_ptr
<tooling::CompilationDatabase
>
266 parseFixed(PathRef Path
, llvm::StringRef Data
, std::string
&Error
) {
267 return tooling::FixedCompilationDatabase::loadFromBuffer(
268 llvm::sys::path::parent_path(Path
), Data
, Error
);
271 bool DirectoryBasedGlobalCompilationDatabase::DirectoryCache::load(
272 llvm::vfs::FileSystem
&FS
) {
273 dlog("Probing directory {0}", Path
);
276 // Load from the specially-supported compilation databases (JSON + Fixed).
277 // For these, we know the files they read and cache their metadata so we can
278 // cheaply validate whether they've changed, and hot-reload if they have.
279 // (As a bonus, these are also VFS-clean)!
282 // Wrapper for {Fixed,JSON}CompilationDatabase::loadFromBuffer.
283 std::unique_ptr
<tooling::CompilationDatabase
> (*Parser
)(
285 /*Data*/ llvm::StringRef
,
286 /*ErrorMsg*/ std::string
&);
288 for (const auto &Entry
: {CDBFile
{&CompileCommandsJson
, parseJSON
},
289 CDBFile
{&BuildCompileCommandsJson
, parseJSON
},
290 CDBFile
{&CompileFlagsTxt
, parseFixed
}}) {
291 bool Active
= ActiveCachedFile
== Entry
.File
;
292 auto Loaded
= Entry
.File
->load(FS
, Active
);
293 switch (Loaded
.Result
) {
294 case CachedFile::LoadResult::FileNotFound
:
296 log("Unloaded compilation database from {0}", Entry
.File
->Path
);
297 ActiveCachedFile
= nullptr;
300 // Continue looking at other candidates.
302 case CachedFile::LoadResult::TransientError
:
303 // File existed but we couldn't read it. Reuse the cache, retry later.
304 return false; // Load again next time.
305 case CachedFile::LoadResult::FoundSameData
:
306 assert(Active
&& "CachedFile may not return 'same data' if !HasOldData");
307 // This is the critical file, and it hasn't changed.
309 case CachedFile::LoadResult::FoundNewData
:
310 // We have a new CDB!
311 CDB
= Entry
.Parser(Entry
.File
->Path
, Loaded
.Buffer
->getBuffer(), Error
);
313 log("{0} compilation database from {1}", Active
? "Reloaded" : "Loaded",
316 elog("Failed to load compilation database from {0}: {1}",
317 Entry
.File
->Path
, Error
);
318 ActiveCachedFile
= Entry
.File
;
323 // Fall back to generic handling of compilation databases.
324 // We don't know what files they read, so can't efficiently check whether
325 // they need to be reloaded. So we never do that.
326 // FIXME: the interface doesn't provide a way to virtualize FS access.
328 // Don't try these more than once. If we've scanned before, we're done.
329 if (CachePopulatedAt
> stopwatch::time_point::min())
331 for (const auto &Entry
:
332 tooling::CompilationDatabasePluginRegistry::entries()) {
333 // Avoid duplicating the special cases handled above.
334 if (Entry
.getName() == "fixed-compilation-database" ||
335 Entry
.getName() == "json-compilation-database")
337 auto Plugin
= Entry
.instantiate();
338 if (auto CDB
= Plugin
->loadFromDirectory(Path
, Error
)) {
339 log("Loaded compilation database from {0} with plugin {1}", Path
,
341 this->CDB
= std::move(CDB
);
344 // Don't log Error here, it's usually just "couldn't find <file>".
346 dlog("No compilation database at {0}", Path
);
350 DirectoryBasedGlobalCompilationDatabase::
351 DirectoryBasedGlobalCompilationDatabase(const Options
&Opts
)
352 : Opts(Opts
), Broadcaster(std::make_unique
<BroadcastThread
>(*this)) {
353 if (!this->Opts
.ContextProvider
)
354 this->Opts
.ContextProvider
= [](llvm::StringRef
) {
355 return Context::current().clone();
359 DirectoryBasedGlobalCompilationDatabase::
360 ~DirectoryBasedGlobalCompilationDatabase() = default;
362 std::optional
<tooling::CompileCommand
>
363 DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File
) const {
364 CDBLookupRequest Req
;
366 Req
.ShouldBroadcast
= true;
367 auto Now
= std::chrono::steady_clock::now();
368 Req
.FreshTime
= Now
- Opts
.RevalidateAfter
;
369 Req
.FreshTimeMissing
= Now
- Opts
.RevalidateMissingAfter
;
371 auto Res
= lookupCDB(Req
);
373 log("Failed to find compilation database for {0}", File
);
377 auto Candidates
= Res
->CDB
->getCompileCommands(File
);
378 if (!Candidates
.empty())
379 return std::move(Candidates
.front());
384 std::vector
<DirectoryBasedGlobalCompilationDatabase::DirectoryCache
*>
385 DirectoryBasedGlobalCompilationDatabase::getDirectoryCaches(
386 llvm::ArrayRef
<llvm::StringRef
> Dirs
) const {
387 std::vector
<std::string
> FoldedDirs
;
388 FoldedDirs
.reserve(Dirs
.size());
389 for (const auto &Dir
: Dirs
) {
391 if (!llvm::sys::path::is_absolute(Dir
))
392 elog("Trying to cache CDB for relative {0}");
394 FoldedDirs
.push_back(maybeCaseFoldPath(Dir
));
397 std::vector
<DirectoryCache
*> Ret
;
398 Ret
.reserve(Dirs
.size());
400 std::lock_guard
<std::mutex
> Lock(DirCachesMutex
);
401 for (unsigned I
= 0; I
< Dirs
.size(); ++I
)
402 Ret
.push_back(&DirCaches
.try_emplace(FoldedDirs
[I
], Dirs
[I
]).first
->second
);
406 std::optional
<DirectoryBasedGlobalCompilationDatabase::CDBLookupResult
>
407 DirectoryBasedGlobalCompilationDatabase::lookupCDB(
408 CDBLookupRequest Request
) const {
409 assert(llvm::sys::path::is_absolute(Request
.FileName
) &&
410 "path must be absolute");
413 std::vector
<llvm::StringRef
> SearchDirs
;
414 if (Opts
.CompileCommandsDir
) // FIXME: unify this case with config.
415 SearchDirs
= {*Opts
.CompileCommandsDir
};
417 WithContext
WithProvidedContext(Opts
.ContextProvider(Request
.FileName
));
418 const auto &Spec
= Config::current().CompileFlags
.CDBSearch
;
419 switch (Spec
.Policy
) {
420 case Config::CDBSearchSpec::NoCDBSearch
:
422 case Config::CDBSearchSpec::FixedDir
:
423 Storage
= *Spec
.FixedCDBPath
;
424 SearchDirs
= {Storage
};
426 case Config::CDBSearchSpec::Ancestors
:
427 // Traverse the canonical version to prevent false positives. i.e.:
428 // src/build/../a.cc can detect a CDB in /src/build if not
430 Storage
= removeDots(Request
.FileName
);
431 actOnAllParentDirectories(Storage
, [&](llvm::StringRef Dir
) {
432 SearchDirs
.push_back(Dir
);
438 std::shared_ptr
<const tooling::CompilationDatabase
> CDB
= nullptr;
439 bool ShouldBroadcast
= false;
440 DirectoryCache
*DirCache
= nullptr;
441 for (DirectoryCache
*Candidate
: getDirectoryCaches(SearchDirs
)) {
442 bool CandidateShouldBroadcast
= Request
.ShouldBroadcast
;
443 if ((CDB
= Candidate
->get(Opts
.TFS
, CandidateShouldBroadcast
,
444 Request
.FreshTime
, Request
.FreshTimeMissing
))) {
445 DirCache
= Candidate
;
446 ShouldBroadcast
= CandidateShouldBroadcast
;
454 CDBLookupResult Result
;
455 Result
.CDB
= std::move(CDB
);
456 Result
.PI
.SourceRoot
= DirCache
->Path
;
459 broadcastCDB(Result
);
463 // The broadcast thread announces files with new compile commands to the world.
464 // Primarily this is used to enqueue them for background indexing.
466 // It's on a separate thread because:
467 // - otherwise it would block the first parse of the initial file
468 // - we need to enumerate all files in the CDB, of which there are many
469 // - we (will) have to evaluate config for every file in the CDB, which is slow
470 class DirectoryBasedGlobalCompilationDatabase::BroadcastThread
{
472 DirectoryBasedGlobalCompilationDatabase
&Parent
;
475 std::condition_variable CV
;
476 // Shutdown flag (CV is notified after writing).
477 // This is atomic so that broadcasts can also observe it and abort early.
478 std::atomic
<bool> ShouldStop
= {false};
480 CDBLookupResult Lookup
;
483 std::deque
<Task
> Queue
;
484 std::optional
<Task
> ActiveTask
;
485 std::thread Thread
; // Must be last member.
487 // Thread body: this is just the basic queue procesing boilerplate.
489 std::unique_lock
<std::mutex
> Lock(Mu
);
491 bool Stopping
= false;
493 return (Stopping
= ShouldStop
.load(std::memory_order_acquire
)) ||
501 ActiveTask
= std::move(Queue
.front());
506 WithContext
WithCtx(std::move(ActiveTask
->Ctx
));
507 process(ActiveTask
->Lookup
);
515 // Inspects a new CDB and broadcasts the files it owns.
516 void process(const CDBLookupResult
&T
);
519 BroadcastThread(DirectoryBasedGlobalCompilationDatabase
&Parent
)
520 : Parent(Parent
), Thread([this] { run(); }) {}
522 void enqueue(CDBLookupResult Lookup
) {
524 assert(!Lookup
.PI
.SourceRoot
.empty());
525 std::lock_guard
<std::mutex
> Lock(Mu
);
526 // New CDB takes precedence over any queued one for the same directory.
527 llvm::erase_if(Queue
, [&](const Task
&T
) {
528 return T
.Lookup
.PI
.SourceRoot
== Lookup
.PI
.SourceRoot
;
530 Queue
.push_back({std::move(Lookup
), Context::current().clone()});
535 bool blockUntilIdle(Deadline Timeout
) {
536 std::unique_lock
<std::mutex
> Lock(Mu
);
537 return wait(Lock
, CV
, Timeout
,
538 [&] { return Queue
.empty() && !ActiveTask
; });
543 std::lock_guard
<std::mutex
> Lock(Mu
);
544 ShouldStop
.store(true, std::memory_order_release
);
551 // The DirBasedCDB associates each file with a specific CDB.
552 // When a CDB is discovered, it may claim to describe files that we associate
553 // with a different CDB. We do not want to broadcast discovery of these, and
554 // trigger background indexing of them.
556 // We must filter the list, and check whether they are associated with this CDB.
557 // This class attempts to do so efficiently.
560 // - loads the config for each file, and determines the relevant search path
561 // - gathers all directories that are part of any search path
562 // - (lazily) checks for a CDB in each such directory at most once
563 // - walks the search path for each file and determines whether to include it.
564 class DirectoryBasedGlobalCompilationDatabase::BroadcastThread::Filter
{
565 llvm::StringRef ThisDir
;
566 DirectoryBasedGlobalCompilationDatabase
&Parent
;
568 // Keep track of all directories we might check for CDBs.
570 DirectoryCache
*Cache
= nullptr;
571 enum { Unknown
, Missing
, TargetCDB
, OtherCDB
} State
= Unknown
;
572 DirInfo
*Parent
= nullptr;
574 llvm::StringMap
<DirInfo
> Dirs
;
576 // A search path starts at a directory, and either includes ancestors or not.
577 using SearchPath
= llvm::PointerIntPair
<DirInfo
*, 1>;
579 // Add all ancestor directories of FilePath to the tracked set.
580 // Returns the immediate parent of the file.
581 DirInfo
*addParents(llvm::StringRef FilePath
) {
582 DirInfo
*Leaf
= nullptr;
583 DirInfo
*Child
= nullptr;
584 actOnAllParentDirectories(FilePath
, [&](llvm::StringRef Dir
) {
585 auto &Info
= Dirs
[Dir
];
586 // If this is the first iteration, then this node is the overall result.
589 // Fill in the parent link from the previous iteration to this parent.
591 Child
->Parent
= &Info
;
592 // Keep walking, whether we inserted or not, if parent link is missing.
593 // (If it's present, parent links must be present up to the root, so stop)
595 return Info
.Parent
!= nullptr;
600 // Populates DirInfo::Cache (and State, if it is TargetCDB).
602 // Fast path out if there were no files, or CDB loading is off.
606 std::vector
<llvm::StringRef
> DirKeys
;
607 std::vector
<DirInfo
*> DirValues
;
608 DirKeys
.reserve(Dirs
.size() + 1);
609 DirValues
.reserve(Dirs
.size());
610 for (auto &E
: Dirs
) {
611 DirKeys
.push_back(E
.first());
612 DirValues
.push_back(&E
.second
);
615 // Also look up the cache entry for the CDB we're broadcasting.
616 // Comparing DirectoryCache pointers is more robust than checking string
617 // equality, e.g. reuses the case-sensitivity handling.
618 DirKeys
.push_back(ThisDir
);
619 auto DirCaches
= Parent
.getDirectoryCaches(DirKeys
);
620 const DirectoryCache
*ThisCache
= DirCaches
.back();
621 DirCaches
.pop_back();
624 for (unsigned I
= 0; I
< DirKeys
.size(); ++I
) {
625 DirValues
[I
]->Cache
= DirCaches
[I
];
626 if (DirCaches
[I
] == ThisCache
)
627 DirValues
[I
]->State
= DirInfo::TargetCDB
;
631 // Should we include a file from this search path?
632 bool shouldInclude(SearchPath P
) {
633 DirInfo
*Info
= P
.getPointer();
636 if (Info
->State
== DirInfo::Unknown
) {
637 assert(Info
->Cache
&& "grabCaches() should have filled this");
638 // Given that we know that CDBs have been moved/generated, don't trust
639 // caches. (This should be rare, so it's OK to add a little latency).
640 constexpr auto IgnoreCache
= std::chrono::steady_clock::time_point::max();
641 // Don't broadcast CDBs discovered while broadcasting!
642 bool ShouldBroadcast
= false;
644 nullptr != Info
->Cache
->get(Parent
.Opts
.TFS
, ShouldBroadcast
,
645 /*FreshTime=*/IgnoreCache
,
646 /*FreshTimeMissing=*/IgnoreCache
);
647 Info
->State
= Exists
? DirInfo::OtherCDB
: DirInfo::Missing
;
649 // If we have a CDB, include the file if it's the target CDB only.
650 if (Info
->State
!= DirInfo::Missing
)
651 return Info
->State
== DirInfo::TargetCDB
;
652 // If we have no CDB and no relevant parent, don't include the file.
653 if (!P
.getInt() || !Info
->Parent
)
655 // Walk up to the next parent.
656 return shouldInclude(SearchPath(Info
->Parent
, 1));
660 Filter(llvm::StringRef ThisDir
,
661 DirectoryBasedGlobalCompilationDatabase
&Parent
)
662 : ThisDir(ThisDir
), Parent(Parent
) {}
664 std::vector
<std::string
> filter(std::vector
<std::string
> AllFiles
,
665 std::atomic
<bool> &ShouldStop
) {
666 std::vector
<std::string
> Filtered
;
667 // Allow for clean early-exit of the slow parts.
668 auto ExitEarly
= [&] {
669 if (ShouldStop
.load(std::memory_order_acquire
)) {
670 log("Giving up on broadcasting CDB, as we're shutting down");
676 // Compute search path for each file.
677 std::vector
<SearchPath
> SearchPaths(AllFiles
.size());
678 for (unsigned I
= 0; I
< AllFiles
.size(); ++I
) {
679 if (Parent
.Opts
.CompileCommandsDir
) { // FIXME: unify with config
680 SearchPaths
[I
].setPointer(&Dirs
[*Parent
.Opts
.CompileCommandsDir
]);
683 if (ExitEarly()) // loading config may be slow
685 WithContext
WithProvidedContent(Parent
.Opts
.ContextProvider(AllFiles
[I
]));
686 const Config::CDBSearchSpec
&Spec
=
687 Config::current().CompileFlags
.CDBSearch
;
688 switch (Spec
.Policy
) {
689 case Config::CDBSearchSpec::NoCDBSearch
:
691 case Config::CDBSearchSpec::Ancestors
:
692 SearchPaths
[I
].setInt(/*Recursive=*/1);
693 SearchPaths
[I
].setPointer(addParents(AllFiles
[I
]));
695 case Config::CDBSearchSpec::FixedDir
:
696 SearchPaths
[I
].setPointer(&Dirs
[*Spec
.FixedCDBPath
]);
700 // Get the CDB cache for each dir on the search path, but don't load yet.
702 // Now work out which files we want to keep, loading CDBs where needed.
703 for (unsigned I
= 0; I
< AllFiles
.size(); ++I
) {
704 if (ExitEarly()) // loading CDBs may be slow
706 if (shouldInclude(SearchPaths
[I
]))
707 Filtered
.push_back(std::move(AllFiles
[I
]));
713 void DirectoryBasedGlobalCompilationDatabase::BroadcastThread::process(
714 const CDBLookupResult
&T
) {
715 vlog("Broadcasting compilation database from {0}", T
.PI
.SourceRoot
);
716 std::vector
<std::string
> GovernedFiles
=
717 Filter(T
.PI
.SourceRoot
, Parent
).filter(T
.CDB
->getAllFiles(), ShouldStop
);
718 if (!GovernedFiles
.empty())
719 Parent
.OnCommandChanged
.broadcast(std::move(GovernedFiles
));
722 void DirectoryBasedGlobalCompilationDatabase::broadcastCDB(
723 CDBLookupResult Result
) const {
724 assert(Result
.CDB
&& "Trying to broadcast an invalid CDB!");
725 Broadcaster
->enqueue(Result
);
728 bool DirectoryBasedGlobalCompilationDatabase::blockUntilIdle(
729 Deadline Timeout
) const {
730 return Broadcaster
->blockUntilIdle(Timeout
);
733 std::optional
<ProjectInfo
>
734 DirectoryBasedGlobalCompilationDatabase::getProjectInfo(PathRef File
) const {
735 CDBLookupRequest Req
;
737 Req
.ShouldBroadcast
= false;
738 Req
.FreshTime
= Req
.FreshTimeMissing
=
739 std::chrono::steady_clock::time_point::min();
740 auto Res
= lookupCDB(Req
);
746 std::unique_ptr
<ProjectModules
>
747 DirectoryBasedGlobalCompilationDatabase::getProjectModules(PathRef File
) const {
748 CDBLookupRequest Req
;
750 Req
.ShouldBroadcast
= false;
751 Req
.FreshTime
= Req
.FreshTimeMissing
=
752 std::chrono::steady_clock::time_point::min();
753 auto Res
= lookupCDB(Req
);
757 return scanningProjectModules(Res
->CDB
, Opts
.TFS
);
760 OverlayCDB::OverlayCDB(const GlobalCompilationDatabase
*Base
,
761 std::vector
<std::string
> FallbackFlags
,
762 CommandMangler Mangler
)
763 : DelegatingCDB(Base
), Mangler(std::move(Mangler
)),
764 FallbackFlags(std::move(FallbackFlags
)) {}
766 std::optional
<tooling::CompileCommand
>
767 OverlayCDB::getCompileCommand(PathRef File
) const {
768 std::optional
<tooling::CompileCommand
> Cmd
;
770 std::lock_guard
<std::mutex
> Lock(Mutex
);
771 auto It
= Commands
.find(removeDots(File
));
772 if (It
!= Commands
.end())
776 // FS used for expanding response files.
777 // FIXME: ExpandResponseFiles appears not to provide the usual
778 // thread-safety guarantees, as the access to FS is not locked!
779 // For now, use the real FS, which is known to be threadsafe (if we don't
780 // use/change working directory, which ExpandResponseFiles doesn't).
781 auto FS
= llvm::vfs::getRealFileSystem();
782 auto Tokenizer
= llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows()
783 ? llvm::cl::TokenizeWindowsCommandLine
784 : llvm::cl::TokenizeGNUCommandLine
;
785 // Compile command pushed via LSP protocol may have response files that need
786 // to be expanded before further processing. For CDB for files it happens in
787 // the main CDB when reading it from the JSON file.
788 tooling::addExpandedResponseFiles(Cmd
->CommandLine
, Cmd
->Directory
,
792 Cmd
= DelegatingCDB::getCompileCommand(File
);
800 tooling::CompileCommand
OverlayCDB::getFallbackCommand(PathRef File
) const {
801 auto Cmd
= DelegatingCDB::getFallbackCommand(File
);
802 std::lock_guard
<std::mutex
> Lock(Mutex
);
803 Cmd
.CommandLine
.insert(Cmd
.CommandLine
.end(), FallbackFlags
.begin(),
804 FallbackFlags
.end());
810 bool OverlayCDB::setCompileCommand(PathRef File
,
811 std::optional
<tooling::CompileCommand
> Cmd
) {
812 // We store a canonical version internally to prevent mismatches between set
813 // and get compile commands. Also it assures clients listening to broadcasts
814 // doesn't receive different names for the same file.
815 std::string CanonPath
= removeDots(File
);
817 std::unique_lock
<std::mutex
> Lock(Mutex
);
819 if (auto [It
, Inserted
] =
820 Commands
.try_emplace(CanonPath
, std::move(*Cmd
));
822 if (It
->second
== *Cmd
)
827 Commands
.erase(CanonPath
);
829 OnCommandChanged
.broadcast({CanonPath
});
833 DelegatingCDB::DelegatingCDB(const GlobalCompilationDatabase
*Base
)
836 BaseChanged
= Base
->watch([this](const std::vector
<std::string
> Changes
) {
837 OnCommandChanged
.broadcast(Changes
);
841 DelegatingCDB::DelegatingCDB(std::unique_ptr
<GlobalCompilationDatabase
> Base
)
842 : DelegatingCDB(Base
.get()) {
843 BaseOwner
= std::move(Base
);
846 std::optional
<tooling::CompileCommand
>
847 DelegatingCDB::getCompileCommand(PathRef File
) const {
850 return Base
->getCompileCommand(File
);
853 std::optional
<ProjectInfo
> DelegatingCDB::getProjectInfo(PathRef File
) const {
856 return Base
->getProjectInfo(File
);
859 std::unique_ptr
<ProjectModules
>
860 DelegatingCDB::getProjectModules(PathRef File
) const {
863 return Base
->getProjectModules(File
);
866 tooling::CompileCommand
DelegatingCDB::getFallbackCommand(PathRef File
) const {
868 return GlobalCompilationDatabase::getFallbackCommand(File
);
869 return Base
->getFallbackCommand(File
);
872 bool DelegatingCDB::blockUntilIdle(Deadline D
) const {
875 return Base
->blockUntilIdle(D
);
878 } // namespace clangd