1 //===--- GlobalCompilationDatabase.cpp ---------------------------*- C++-*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "GlobalCompilationDatabase.h"
10 #include "Config.h"
11 #include "FS.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/Frontend/CompilerInvocation.h"
18 #include "clang/Tooling/ArgumentsAdjusters.h"
19 #include "clang/Tooling/CompilationDatabase.h"
20 #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
21 #include "clang/Tooling/JSONCompilationDatabase.h"
22 #include "llvm/ADT/None.h"
23 #include "llvm/ADT/Optional.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/FileSystem.h"
30 #include "llvm/Support/FileUtilities.h"
31 #include "llvm/Support/Path.h"
32 #include "llvm/Support/Program.h"
33 #include "llvm/Support/VirtualFileSystem.h"
34 #include <atomic>
35 #include <chrono>
36 #include <condition_variable>
37 #include <string>
38 #include <tuple>
39 #include <vector>
40 
41 namespace clang {
42 namespace clangd {
43 namespace {
44 
45 // Variant of parent_path that operates only on absolute paths.
46 PathRef absoluteParent(PathRef Path) {
47   assert(llvm::sys::path::is_absolute(Path));
48 #if defined(_WIN32)
49   // llvm::sys says "C:\" is absolute, and its parent is "C:" which is relative.
50   // This unhelpful behavior seems to have been inherited from boost.
51   if (llvm::sys::path::relative_path(Path).empty()) {
52     return PathRef();
53   }
54 #endif
55   PathRef Result = llvm::sys::path::parent_path(Path);
56   assert(Result.empty() || llvm::sys::path::is_absolute(Result));
57   return Result;
58 }
59 
60 // Runs the given action on all parent directories of filename, starting from
61 // deepest directory and going up to root. Stops whenever action succeeds.
62 void actOnAllParentDirectories(PathRef FileName,
63                                llvm::function_ref<bool(PathRef)> Action) {
64   for (auto Path = absoluteParent(FileName); !Path.empty() && !Action(Path);
65        Path = absoluteParent(Path))
66     ;
67 }
68 
69 } // namespace
70 
71 tooling::CompileCommand
72 GlobalCompilationDatabase::getFallbackCommand(PathRef File) const {
73   std::vector<std::string> Argv = {"clang"};
74   // Clang treats .h files as C by default and files without extension as linker
75   // input, resulting in unhelpful diagnostics.
76   // Parsing as Objective C++ is friendly to more cases.
77   auto FileExtension = llvm::sys::path::extension(File);
78   if (FileExtension.empty() || FileExtension == ".h")
79     Argv.push_back("-xobjective-c++-header");
80   Argv.push_back(std::string(File));
81   tooling::CompileCommand Cmd(llvm::sys::path::parent_path(File),
82                               llvm::sys::path::filename(File), std::move(Argv),
83                               /*Output=*/"");
84   Cmd.Heuristic = "clangd fallback";
85   return Cmd;
86 }
87 
88 // Loads and caches the CDB from a single directory.
89 //
90 // This class is threadsafe, which is to say we have independent locks for each
91 // directory we're searching for a CDB.
92 // Loading is deferred until first access.
93 //
94 // The DirectoryBasedCDB keeps a map from path => DirectoryCache.
95 // Typical usage is to:
96 //  - 1) determine all the paths that might be searched
97 //  - 2) acquire the map lock and get-or-create all the DirectoryCache entries
98 //  - 3) release the map lock and query the caches as desired
99 class DirectoryBasedGlobalCompilationDatabase::DirectoryCache {
100   using stopwatch = std::chrono::steady_clock;
101 
102   // CachedFile is used to read a CDB file on disk (e.g. compile_commands.json).
103   // It specializes in being able to quickly bail out if the file is unchanged,
104   // which is the common case.
105   // Internally, it stores file metadata so a stat() can verify it's unchanged.
106   // We don't actually cache the content as it's not needed - if the file is
107   // unchanged then the previous CDB is valid.
108   struct CachedFile {
109     CachedFile(llvm::StringRef Parent, llvm::StringRef Rel) {
110       llvm::SmallString<256> Path = Parent;
111       llvm::sys::path::append(Path, Rel);
112       this->Path = Path.str().str();
113     }
114     std::string Path;
115     size_t Size = NoFileCached;
116     llvm::sys::TimePoint<> ModifiedTime;
117     FileDigest ContentHash;
118 
119     static constexpr size_t NoFileCached = -1;
120 
121     struct LoadResult {
122       enum {
123         FileNotFound,
124         TransientError,
125         FoundSameData,
126         FoundNewData,
127       } Result;
128       std::unique_ptr<llvm::MemoryBuffer> Buffer; // Set only if FoundNewData
129     };
130 
131     LoadResult load(llvm::vfs::FileSystem &FS, bool HasOldData);
132   };
133 
134   // If we've looked for a CDB here and found none, the time when that happened.
135   // (Atomics make it possible for get() to return without taking a lock)
136   std::atomic<stopwatch::rep> NoCDBAt = {
137       stopwatch::time_point::min().time_since_epoch().count()};
138 
139   // Guards the following cache state.
140   std::mutex Mu;
141   // When was the cache last known to be in sync with disk state?
142   stopwatch::time_point CachePopulatedAt = stopwatch::time_point::min();
143   // Whether a new CDB has been loaded but not broadcast yet.
144   bool NeedsBroadcast = false;
145   // Last loaded CDB, meaningful if CachePopulatedAt was ever set.
146   // shared_ptr so we can overwrite this when callers are still using the CDB.
147   std::shared_ptr<tooling::CompilationDatabase> CDB;
148   // File metadata for the CDB files we support tracking directly.
149   CachedFile CompileCommandsJson;
150   CachedFile BuildCompileCommandsJson;
151   CachedFile CompileFlagsTxt;
152   // CachedFile member corresponding to CDB.
153   //   CDB  | ACF  | Scenario
154   //   null | null | no CDB found, or initial empty cache
155   //   set  | null | CDB was loaded via generic plugin interface
156   //   null | set  | found known CDB file, but parsing it failed
157   //   set  | set  | CDB was parsed from a known file
158   CachedFile *ActiveCachedFile = nullptr;
159 
160 public:
161   DirectoryCache(llvm::StringRef Path)
162       : CompileCommandsJson(Path, "compile_commands.json"),
163         BuildCompileCommandsJson(Path, "build/compile_commands.json"),
164         CompileFlagsTxt(Path, "compile_flags.txt"), Path(Path) {
165     assert(llvm::sys::path::is_absolute(Path));
166   }
167 
168   // Absolute canonical path that we're the cache for. (Not case-folded).
169   const std::string Path;
170 
171   // Get the CDB associated with this directory.
172   // ShouldBroadcast:
173   //  - as input, signals whether the caller is willing to broadcast a
174   //    newly-discovered CDB. (e.g. to trigger background indexing)
175   //  - as output, signals whether the caller should do so.
176   // (If a new CDB is discovered and ShouldBroadcast is false, we mark the
177   // CDB as needing broadcast, and broadcast it next time we can).
178   std::shared_ptr<const tooling::CompilationDatabase>
179   get(const ThreadsafeFS &TFS, bool &ShouldBroadcast,
180       stopwatch::time_point FreshTime, stopwatch::time_point FreshTimeMissing) {
181     // Fast path for common case without taking lock.
182     if (stopwatch::time_point(stopwatch::duration(NoCDBAt.load())) >
183         FreshTimeMissing) {
184       ShouldBroadcast = false;
185       return nullptr;
186     }
187 
188     std::lock_guard<std::mutex> Lock(Mu);
189     auto RequestBroadcast = llvm::make_scope_exit([&, OldCDB(CDB.get())] {
190       // If we loaded a new CDB, it should be broadcast at some point.
191       if (CDB != nullptr && CDB.get() != OldCDB)
192         NeedsBroadcast = true;
193       else if (CDB == nullptr) // nothing to broadcast anymore!
194         NeedsBroadcast = false;
195       // If we have something to broadcast, then do so iff allowed.
196       if (!ShouldBroadcast)
197         return;
198       ShouldBroadcast = NeedsBroadcast;
199       NeedsBroadcast = false;
200     });
201 
202     // If our cache is valid, serve from it.
203     if (CachePopulatedAt > FreshTime)
204       return CDB;
205 
206     if (/*MayCache=*/load(*TFS.view(/*CWD=*/llvm::None))) {
207       // Use new timestamp, as loading may be slow.
208       CachePopulatedAt = stopwatch::now();
209       NoCDBAt.store((CDB ? stopwatch::time_point::min() : CachePopulatedAt)
210                         .time_since_epoch()
211                         .count());
212     }
213 
214     return CDB;
215   }
216 
217 private:
218   // Updates `CDB` from disk state. Returns false on failure.
219   bool load(llvm::vfs::FileSystem &FS);
220 };
221 
222 DirectoryBasedGlobalCompilationDatabase::DirectoryCache::CachedFile::LoadResult
223 DirectoryBasedGlobalCompilationDatabase::DirectoryCache::CachedFile::load(
224     llvm::vfs::FileSystem &FS, bool HasOldData) {
225   auto Stat = FS.status(Path);
226   if (!Stat || !Stat->isRegularFile()) {
227     Size = NoFileCached;
228     ContentHash = {};
229     return {LoadResult::FileNotFound, nullptr};
230   }
231   // If both the size and mtime match, presume unchanged without reading.
232   if (HasOldData && Stat->getLastModificationTime() == ModifiedTime &&
233       Stat->getSize() == Size)
234     return {LoadResult::FoundSameData, nullptr};
235   auto Buf = FS.getBufferForFile(Path);
236   if (!Buf || (*Buf)->getBufferSize() != Stat->getSize()) {
237     // Don't clear the cache - possible we're seeing inconsistent size as the
238     // file is being recreated. If it ends up identical later, great!
239     //
240     // This isn't a complete solution: if we see a partial file but stat/read
241     // agree on its size, we're ultimately going to have spurious CDB reloads.
242     // May be worth fixing if generators don't write atomically (CMake does).
243     elog("Failed to read {0}: {1}", Path,
244          Buf ? "size changed" : Buf.getError().message());
245     return {LoadResult::TransientError, nullptr};
246   }
247 
248   FileDigest NewContentHash = digest((*Buf)->getBuffer());
249   if (HasOldData && NewContentHash == ContentHash) {
250     // mtime changed but data is the same: avoid rebuilding the CDB.
251     ModifiedTime = Stat->getLastModificationTime();
252     return {LoadResult::FoundSameData, nullptr};
253   }
254 
255   Size = (*Buf)->getBufferSize();
256   ModifiedTime = Stat->getLastModificationTime();
257   ContentHash = NewContentHash;
258   return {LoadResult::FoundNewData, std::move(*Buf)};
259 }
260 
261 // Adapt CDB-loading functions to a common interface for DirectoryCache::load().
262 static std::unique_ptr<tooling::CompilationDatabase>
263 parseJSON(PathRef Path, llvm::StringRef Data, std::string &Error) {
264   if (auto CDB = tooling::JSONCompilationDatabase::loadFromBuffer(
265           Data, Error, tooling::JSONCommandLineSyntax::AutoDetect)) {
266     // FS used for expanding response files.
267     // FIXME: ExpandResponseFilesDatabase appears not to provide the usual
268     // thread-safety guarantees, as the access to FS is not locked!
269     // For now, use the real FS, which is known to be threadsafe (if we don't
270     // use/change working directory, which ExpandResponseFilesDatabase doesn't).
271     auto FS = llvm::vfs::getRealFileSystem();
272     return tooling::inferTargetAndDriverMode(
273         tooling::inferMissingCompileCommands(
274             expandResponseFiles(std::move(CDB), std::move(FS))));
275   }
276   return nullptr;
277 }
278 static std::unique_ptr<tooling::CompilationDatabase>
279 parseFixed(PathRef Path, llvm::StringRef Data, std::string &Error) {
280   return tooling::FixedCompilationDatabase::loadFromBuffer(
281       llvm::sys::path::parent_path(Path), Data, Error);
282 }
283 
284 bool DirectoryBasedGlobalCompilationDatabase::DirectoryCache::load(
285     llvm::vfs::FileSystem &FS) {
286   dlog("Probing directory {0}", Path);
287   std::string Error;
288 
289   // Load from the specially-supported compilation databases (JSON + Fixed).
290   // For these, we know the files they read and cache their metadata so we can
291   // cheaply validate whether they've changed, and hot-reload if they have.
292   // (As a bonus, these are also VFS-clean)!
293   struct CDBFile {
294     CachedFile *File;
295     // Wrapper for {Fixed,JSON}CompilationDatabase::loadFromBuffer.
296     llvm::function_ref<std::unique_ptr<tooling::CompilationDatabase>(
297         PathRef,
298         /*Data*/ llvm::StringRef,
299         /*ErrorMsg*/ std::string &)>
300         Parser;
301   };
302   for (const auto &Entry : {CDBFile{&CompileCommandsJson, parseJSON},
303                             CDBFile{&BuildCompileCommandsJson, parseJSON},
304                             CDBFile{&CompileFlagsTxt, parseFixed}}) {
305     bool Active = ActiveCachedFile == Entry.File;
306     auto Loaded = Entry.File->load(FS, Active);
307     switch (Loaded.Result) {
308     case CachedFile::LoadResult::FileNotFound:
309       if (Active) {
310         log("Unloaded compilation database from {0}", Entry.File->Path);
311         ActiveCachedFile = nullptr;
312         CDB = nullptr;
313       }
314       // Continue looking at other candidates.
315       break;
316     case CachedFile::LoadResult::TransientError:
317       // File existed but we couldn't read it. Reuse the cache, retry later.
318       return false; // Load again next time.
319     case CachedFile::LoadResult::FoundSameData:
320       assert(Active && "CachedFile may not return 'same data' if !HasOldData");
321       // This is the critical file, and it hasn't changed.
322       return true;
323     case CachedFile::LoadResult::FoundNewData:
324       // We have a new CDB!
325       CDB = Entry.Parser(Entry.File->Path, Loaded.Buffer->getBuffer(), Error);
326       if (CDB)
327         log("{0} compilation database from {1}", Active ? "Reloaded" : "Loaded",
328             Entry.File->Path);
329       else
330         elog("Failed to load compilation database from {0}: {1}",
331              Entry.File->Path, Error);
332       ActiveCachedFile = Entry.File;
333       return true;
334     }
335   }
336 
337   // Fall back to generic handling of compilation databases.
338   // We don't know what files they read, so can't efficiently check whether
339   // they need to be reloaded. So we never do that.
340   // FIXME: the interface doesn't provide a way to virtualize FS access.
341 
342   // Don't try these more than once. If we've scanned before, we're done.
343   if (CachePopulatedAt > stopwatch::time_point::min())
344     return true;
345   for (const auto &Entry :
346        tooling::CompilationDatabasePluginRegistry::entries()) {
347     // Avoid duplicating the special cases handled above.
348     if (Entry.getName() == "fixed-compilation-database" ||
349         Entry.getName() == "json-compilation-database")
350       continue;
351     auto Plugin = Entry.instantiate();
352     if (auto CDB = Plugin->loadFromDirectory(Path, Error)) {
353       log("Loaded compilation database from {0} with plugin {1}", Path,
354           Entry.getName());
355       this->CDB = std::move(CDB);
356       return true;
357     }
358     // Don't log Error here, it's usually just "couldn't find <file>".
359   }
360   dlog("No compilation database at {0}", Path);
361   return true;
362 }
363 
364 DirectoryBasedGlobalCompilationDatabase::
365     DirectoryBasedGlobalCompilationDatabase(const Options &Opts)
366     : Opts(Opts), Broadcaster(std::make_unique<BroadcastThread>(*this)) {
367   if (!this->Opts.ContextProvider)
368     this->Opts.ContextProvider = [](llvm::StringRef) {
369       return Context::current().clone();
370     };
371 }
372 
373 DirectoryBasedGlobalCompilationDatabase::
374     ~DirectoryBasedGlobalCompilationDatabase() = default;
375 
376 llvm::Optional<tooling::CompileCommand>
377 DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File) const {
378   CDBLookupRequest Req;
379   Req.FileName = File;
380   Req.ShouldBroadcast = true;
381   auto Now = std::chrono::steady_clock::now();
382   Req.FreshTime = Now - Opts.RevalidateAfter;
383   Req.FreshTimeMissing = Now - Opts.RevalidateMissingAfter;
384 
385   auto Res = lookupCDB(Req);
386   if (!Res) {
387     log("Failed to find compilation database for {0}", File);
388     return llvm::None;
389   }
390 
391   auto Candidates = Res->CDB->getCompileCommands(File);
392   if (!Candidates.empty())
393     return std::move(Candidates.front());
394 
395   return None;
396 }
397 
398 // For platforms where paths are case-insensitive (but case-preserving),
399 // we need to do case-insensitive comparisons and use lowercase keys.
400 // FIXME: Make Path a real class with desired semantics instead.
401 //        This class is not the only place this problem exists.
402 // FIXME: Mac filesystems default to case-insensitive, but may be sensitive.
403 
404 static std::string maybeCaseFoldPath(PathRef Path) {
405 #if defined(_WIN32) || defined(__APPLE__)
406   return Path.lower();
407 #else
408   return std::string(Path);
409 #endif
410 }
411 
412 std::vector<DirectoryBasedGlobalCompilationDatabase::DirectoryCache *>
413 DirectoryBasedGlobalCompilationDatabase::getDirectoryCaches(
414     llvm::ArrayRef<llvm::StringRef> Dirs) const {
415   std::vector<std::string> FoldedDirs;
416   FoldedDirs.reserve(Dirs.size());
417   for (const auto &Dir : Dirs) {
418 #ifndef NDEBUG
419     if (!llvm::sys::path::is_absolute(Dir))
420       elog("Trying to cache CDB for relative {0}");
421 #endif
422     FoldedDirs.push_back(maybeCaseFoldPath(Dir));
423   }
424 
425   std::vector<DirectoryCache *> Ret;
426   Ret.reserve(Dirs.size());
427 
428   std::lock_guard<std::mutex> Lock(DirCachesMutex);
429   for (unsigned I = 0; I < Dirs.size(); ++I)
430     Ret.push_back(&DirCaches.try_emplace(FoldedDirs[I], Dirs[I]).first->second);
431   return Ret;
432 }
433 
434 llvm::Optional<DirectoryBasedGlobalCompilationDatabase::CDBLookupResult>
435 DirectoryBasedGlobalCompilationDatabase::lookupCDB(
436     CDBLookupRequest Request) const {
437   assert(llvm::sys::path::is_absolute(Request.FileName) &&
438          "path must be absolute");
439 
440   std::string Storage;
441   std::vector<llvm::StringRef> SearchDirs;
442   if (Opts.CompileCommandsDir) // FIXME: unify this case with config.
443     SearchDirs = {Opts.CompileCommandsDir.getValue()};
444   else {
445     WithContext WithProvidedContext(Opts.ContextProvider(Request.FileName));
446     const auto &Spec = Config::current().CompileFlags.CDBSearch;
447     switch (Spec.Policy) {
448     case Config::CDBSearchSpec::NoCDBSearch:
449       return llvm::None;
450     case Config::CDBSearchSpec::FixedDir:
451       Storage = Spec.FixedCDBPath.getValue();
452       SearchDirs = {Storage};
453       break;
454     case Config::CDBSearchSpec::Ancestors:
455       // Traverse the canonical version to prevent false positives. i.e.:
456       // src/build/../a.cc can detect a CDB in /src/build if not
457       // canonicalized.
458       Storage = removeDots(Request.FileName);
459       actOnAllParentDirectories(Storage, [&](llvm::StringRef Dir) {
460         SearchDirs.push_back(Dir);
461         return false;
462       });
463     }
464   }
465 
466   std::shared_ptr<const tooling::CompilationDatabase> CDB = nullptr;
467   bool ShouldBroadcast = false;
468   DirectoryCache *DirCache = nullptr;
469   for (DirectoryCache *Candidate : getDirectoryCaches(SearchDirs)) {
470     bool CandidateShouldBroadcast = Request.ShouldBroadcast;
471     if ((CDB = Candidate->get(Opts.TFS, CandidateShouldBroadcast,
472                               Request.FreshTime, Request.FreshTimeMissing))) {
473       DirCache = Candidate;
474       ShouldBroadcast = CandidateShouldBroadcast;
475       break;
476     }
477   }
478 
479   if (!CDB)
480     return llvm::None;
481 
482   CDBLookupResult Result;
483   Result.CDB = std::move(CDB);
484   Result.PI.SourceRoot = DirCache->Path;
485 
486   if (ShouldBroadcast)
487     broadcastCDB(Result);
488   return Result;
489 }
490 
491 // The broadcast thread announces files with new compile commands to the world.
492 // Primarily this is used to enqueue them for background indexing.
493 //
494 // It's on a separate thread because:
495 //  - otherwise it would block the first parse of the initial file
496 //  - we need to enumerate all files in the CDB, of which there are many
497 //  - we (will) have to evaluate config for every file in the CDB, which is slow
498 class DirectoryBasedGlobalCompilationDatabase::BroadcastThread {
499   class Filter;
500   DirectoryBasedGlobalCompilationDatabase &Parent;
501 
502   std::mutex Mu;
503   std::condition_variable CV;
504   // Shutdown flag (CV is notified after writing).
505   // This is atomic so that broadcasts can also observe it and abort early.
506   std::atomic<bool> ShouldStop = {false};
507   struct Task {
508     CDBLookupResult Lookup;
509     Context Ctx;
510   };
511   std::deque<Task> Queue;
512   llvm::Optional<Task> ActiveTask;
513   std::thread Thread; // Must be last member.
514 
515   // Thread body: this is just the basic queue procesing boilerplate.
516   void run() {
517     std::unique_lock<std::mutex> Lock(Mu);
518     while (true) {
519       bool Stopping = false;
520       CV.wait(Lock, [&] {
521         return (Stopping = ShouldStop.load(std::memory_order_acquire)) ||
522                !Queue.empty();
523       });
524       if (Stopping) {
525         Queue.clear();
526         CV.notify_all();
527         return;
528       }
529       ActiveTask = std::move(Queue.front());
530       Queue.pop_front();
531 
532       Lock.unlock();
533       {
534         WithContext WithCtx(std::move(ActiveTask->Ctx));
535         process(ActiveTask->Lookup);
536       }
537       Lock.lock();
538       ActiveTask.reset();
539       CV.notify_all();
540     }
541   }
542 
543   // Inspects a new CDB and broadcasts the files it owns.
544   void process(const CDBLookupResult &T);
545 
546 public:
547   BroadcastThread(DirectoryBasedGlobalCompilationDatabase &Parent)
548       : Parent(Parent), Thread([this] { run(); }) {}
549 
550   void enqueue(CDBLookupResult Lookup) {
551     {
552       assert(!Lookup.PI.SourceRoot.empty());
553       std::lock_guard<std::mutex> Lock(Mu);
554       // New CDB takes precedence over any queued one for the same directory.
555       llvm::erase_if(Queue, [&](const Task &T) {
556         return T.Lookup.PI.SourceRoot == Lookup.PI.SourceRoot;
557       });
558       Queue.push_back({std::move(Lookup), Context::current().clone()});
559     }
560     CV.notify_all();
561   }
562 
563   bool blockUntilIdle(Deadline Timeout) {
564     std::unique_lock<std::mutex> Lock(Mu);
565     return wait(Lock, CV, Timeout,
566                 [&] { return Queue.empty() && !ActiveTask.hasValue(); });
567   }
568 
569   ~BroadcastThread() {
570     ShouldStop.store(true, std::memory_order_release);
571     CV.notify_all();
572     Thread.join();
573   }
574 };
575 
576 // The DirBasedCDB associates each file with a specific CDB.
577 // When a CDB is discovered, it may claim to describe files that we associate
578 // with a different CDB. We do not want to broadcast discovery of these, and
579 // trigger background indexing of them.
580 //
581 // We must filter the list, and check whether they are associated with this CDB.
582 // This class attempts to do so efficiently.
583 //
584 // Roughly, it:
585 //  - loads the config for each file, and determines the relevant search path
586 //  - gathers all directories that are part of any search path
587 //  - (lazily) checks for a CDB in each such directory at most once
588 //  - walks the search path for each file and determines whether to include it.
589 class DirectoryBasedGlobalCompilationDatabase::BroadcastThread::Filter {
590   llvm::StringRef ThisDir;
591   DirectoryBasedGlobalCompilationDatabase &Parent;
592 
593   // Keep track of all directories we might check for CDBs.
594   struct DirInfo {
595     DirectoryCache *Cache = nullptr;
596     enum { Unknown, Missing, TargetCDB, OtherCDB } State = Unknown;
597     DirInfo *Parent = nullptr;
598   };
599   llvm::StringMap<DirInfo> Dirs;
600 
601   // A search path starts at a directory, and either includes ancestors or not.
602   using SearchPath = llvm::PointerIntPair<DirInfo *, 1>;
603 
604   // Add all ancestor directories of FilePath to the tracked set.
605   // Returns the immediate parent of the file.
606   DirInfo *addParents(llvm::StringRef FilePath) {
607     DirInfo *Leaf = nullptr;
608     DirInfo *Child = nullptr;
609     actOnAllParentDirectories(FilePath, [&](llvm::StringRef Dir) {
610       auto &Info = Dirs[Dir];
611       // If this is the first iteration, then this node is the overall result.
612       if (!Leaf)
613         Leaf = &Info;
614       // Fill in the parent link from the previous iteration to this parent.
615       if (Child)
616         Child->Parent = &Info;
617       // Keep walking, whether we inserted or not, if parent link is missing.
618       // (If it's present, parent links must be present up to the root, so stop)
619       Child = &Info;
620       return Info.Parent != nullptr;
621     });
622     return Leaf;
623   }
624 
625   // Populates DirInfo::Cache (and State, if it is TargetCDB).
626   void grabCaches() {
627     // Fast path out if there were no files, or CDB loading is off.
628     if (Dirs.empty())
629       return;
630 
631     std::vector<llvm::StringRef> DirKeys;
632     std::vector<DirInfo *> DirValues;
633     DirKeys.reserve(Dirs.size() + 1);
634     DirValues.reserve(Dirs.size());
635     for (auto &E : Dirs) {
636       DirKeys.push_back(E.first());
637       DirValues.push_back(&E.second);
638     }
639 
640     // Also look up the cache entry for the CDB we're broadcasting.
641     // Comparing DirectoryCache pointers is more robust than checking string
642     // equality, e.g. reuses the case-sensitivity handling.
643     DirKeys.push_back(ThisDir);
644     auto DirCaches = Parent.getDirectoryCaches(DirKeys);
645     const DirectoryCache *ThisCache = DirCaches.back();
646     DirCaches.pop_back();
647     DirKeys.pop_back();
648 
649     for (unsigned I = 0; I < DirKeys.size(); ++I) {
650       DirValues[I]->Cache = DirCaches[I];
651       if (DirCaches[I] == ThisCache)
652         DirValues[I]->State = DirInfo::TargetCDB;
653     }
654   }
655 
656   // Should we include a file from this search path?
657   bool shouldInclude(SearchPath P) {
658     DirInfo *Info = P.getPointer();
659     if (!Info)
660       return false;
661     if (Info->State == DirInfo::Unknown) {
662       assert(Info->Cache && "grabCaches() should have filled this");
663       // Given that we know that CDBs have been moved/generated, don't trust
664       // caches. (This should be rare, so it's OK to add a little latency).
665       constexpr auto IgnoreCache = std::chrono::steady_clock::time_point::max();
666       // Don't broadcast CDBs discovered while broadcasting!
667       bool ShouldBroadcast = false;
668       bool Exists =
669           nullptr != Info->Cache->get(Parent.Opts.TFS, ShouldBroadcast,
670                                       /*FreshTime=*/IgnoreCache,
671                                       /*FreshTimeMissing=*/IgnoreCache);
672       Info->State = Exists ? DirInfo::OtherCDB : DirInfo::Missing;
673     }
674     // If we have a CDB, include the file if it's the target CDB only.
675     if (Info->State != DirInfo::Missing)
676       return Info->State == DirInfo::TargetCDB;
677     // If we have no CDB and no relevant parent, don't include the file.
678     if (!P.getInt() || !Info->Parent)
679       return false;
680     // Walk up to the next parent.
681     return shouldInclude(SearchPath(Info->Parent, 1));
682   }
683 
684 public:
685   Filter(llvm::StringRef ThisDir,
686          DirectoryBasedGlobalCompilationDatabase &Parent)
687       : ThisDir(ThisDir), Parent(Parent) {}
688 
689   std::vector<std::string> filter(std::vector<std::string> AllFiles,
690                                   std::atomic<bool> &ShouldStop) {
691     std::vector<std::string> Filtered;
692     // Allow for clean early-exit of the slow parts.
693     auto ExitEarly = [&] {
694       if (ShouldStop.load(std::memory_order_acquire)) {
695         log("Giving up on broadcasting CDB, as we're shutting down");
696         Filtered.clear();
697         return true;
698       }
699       return false;
700     };
701     // Compute search path for each file.
702     std::vector<SearchPath> SearchPaths(AllFiles.size());
703     for (unsigned I = 0; I < AllFiles.size(); ++I) {
704       if (Parent.Opts.CompileCommandsDir) { // FIXME: unify with config
705         SearchPaths[I].setPointer(
706             &Dirs[Parent.Opts.CompileCommandsDir.getValue()]);
707         continue;
708       }
709       if (ExitEarly()) // loading config may be slow
710         return Filtered;
711       WithContext WithProvidedContent(Parent.Opts.ContextProvider(AllFiles[I]));
712       const Config::CDBSearchSpec &Spec =
713           Config::current().CompileFlags.CDBSearch;
714       switch (Spec.Policy) {
715       case Config::CDBSearchSpec::NoCDBSearch:
716         break;
717       case Config::CDBSearchSpec::Ancestors:
718         SearchPaths[I].setInt(/*Recursive=*/1);
719         SearchPaths[I].setPointer(addParents(AllFiles[I]));
720         break;
721       case Config::CDBSearchSpec::FixedDir:
722         SearchPaths[I].setPointer(&Dirs[Spec.FixedCDBPath.getValue()]);
723         break;
724       }
725     }
726     // Get the CDB cache for each dir on the search path, but don't load yet.
727     grabCaches();
728     // Now work out which files we want to keep, loading CDBs where needed.
729     for (unsigned I = 0; I < AllFiles.size(); ++I) {
730       if (ExitEarly()) // loading CDBs may be slow
731         return Filtered;
732       if (shouldInclude(SearchPaths[I]))
733         Filtered.push_back(std::move(AllFiles[I]));
734     }
735     return Filtered;
736   }
737 };
738 
739 void DirectoryBasedGlobalCompilationDatabase::BroadcastThread::process(
740     const CDBLookupResult &T) {
741   vlog("Broadcasting compilation database from {0}", T.PI.SourceRoot);
742   std::vector<std::string> GovernedFiles =
743       Filter(T.PI.SourceRoot, Parent).filter(T.CDB->getAllFiles(), ShouldStop);
744   if (!GovernedFiles.empty())
745     Parent.OnCommandChanged.broadcast(std::move(GovernedFiles));
746 }
747 
748 void DirectoryBasedGlobalCompilationDatabase::broadcastCDB(
749     CDBLookupResult Result) const {
750   assert(Result.CDB && "Trying to broadcast an invalid CDB!");
751   Broadcaster->enqueue(Result);
752 }
753 
754 bool DirectoryBasedGlobalCompilationDatabase::blockUntilIdle(
755     Deadline Timeout) const {
756   return Broadcaster->blockUntilIdle(Timeout);
757 }
758 
759 llvm::Optional<ProjectInfo>
760 DirectoryBasedGlobalCompilationDatabase::getProjectInfo(PathRef File) const {
761   CDBLookupRequest Req;
762   Req.FileName = File;
763   Req.ShouldBroadcast = false;
764   Req.FreshTime = Req.FreshTimeMissing =
765       std::chrono::steady_clock::time_point::min();
766   auto Res = lookupCDB(Req);
767   if (!Res)
768     return llvm::None;
769   return Res->PI;
770 }
771 
772 OverlayCDB::OverlayCDB(const GlobalCompilationDatabase *Base,
773                        std::vector<std::string> FallbackFlags,
774                        tooling::ArgumentsAdjuster Adjuster)
775     : DelegatingCDB(Base), ArgsAdjuster(std::move(Adjuster)),
776       FallbackFlags(std::move(FallbackFlags)) {}
777 
778 llvm::Optional<tooling::CompileCommand>
779 OverlayCDB::getCompileCommand(PathRef File) const {
780   llvm::Optional<tooling::CompileCommand> Cmd;
781   {
782     std::lock_guard<std::mutex> Lock(Mutex);
783     auto It = Commands.find(removeDots(File));
784     if (It != Commands.end())
785       Cmd = It->second;
786   }
787   if (!Cmd)
788     Cmd = DelegatingCDB::getCompileCommand(File);
789   if (!Cmd)
790     return llvm::None;
791   if (ArgsAdjuster)
792     Cmd->CommandLine = ArgsAdjuster(Cmd->CommandLine, Cmd->Filename);
793   return Cmd;
794 }
795 
796 tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File) const {
797   auto Cmd = DelegatingCDB::getFallbackCommand(File);
798   std::lock_guard<std::mutex> Lock(Mutex);
799   Cmd.CommandLine.insert(Cmd.CommandLine.end(), FallbackFlags.begin(),
800                          FallbackFlags.end());
801   if (ArgsAdjuster)
802     Cmd.CommandLine = ArgsAdjuster(Cmd.CommandLine, Cmd.Filename);
803   return Cmd;
804 }
805 
806 void OverlayCDB::setCompileCommand(
807     PathRef File, llvm::Optional<tooling::CompileCommand> Cmd) {
808   // We store a canonical version internally to prevent mismatches between set
809   // and get compile commands. Also it assures clients listening to broadcasts
810   // doesn't receive different names for the same file.
811   std::string CanonPath = removeDots(File);
812   {
813     std::unique_lock<std::mutex> Lock(Mutex);
814     if (Cmd)
815       Commands[CanonPath] = std::move(*Cmd);
816     else
817       Commands.erase(CanonPath);
818   }
819   OnCommandChanged.broadcast({CanonPath});
820 }
821 
822 DelegatingCDB::DelegatingCDB(const GlobalCompilationDatabase *Base)
823     : Base(Base) {
824   if (Base)
825     BaseChanged = Base->watch([this](const std::vector<std::string> Changes) {
826       OnCommandChanged.broadcast(Changes);
827     });
828 }
829 
830 DelegatingCDB::DelegatingCDB(std::unique_ptr<GlobalCompilationDatabase> Base)
831     : DelegatingCDB(Base.get()) {
832   BaseOwner = std::move(Base);
833 }
834 
835 llvm::Optional<tooling::CompileCommand>
836 DelegatingCDB::getCompileCommand(PathRef File) const {
837   if (!Base)
838     return llvm::None;
839   return Base->getCompileCommand(File);
840 }
841 
842 llvm::Optional<ProjectInfo> DelegatingCDB::getProjectInfo(PathRef File) const {
843   if (!Base)
844     return llvm::None;
845   return Base->getProjectInfo(File);
846 }
847 
848 tooling::CompileCommand DelegatingCDB::getFallbackCommand(PathRef File) const {
849   if (!Base)
850     return GlobalCompilationDatabase::getFallbackCommand(File);
851   return Base->getFallbackCommand(File);
852 }
853 
854 bool DelegatingCDB::blockUntilIdle(Deadline D) const {
855   if (!Base)
856     return true;
857   return Base->blockUntilIdle(D);
858 }
859 
860 } // namespace clangd
861 } // namespace clang
862