clang-tools  10.0.0
TUScheduler.cpp
Go to the documentation of this file.
1 //===--- TUScheduler.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 // For each file, managed by TUScheduler, we create a single ASTWorker that
9 // manages an AST for that file. All operations that modify or read the AST are
10 // run on a separate dedicated thread asynchronously in FIFO order.
11 //
12 // We start processing each update immediately after we receive it. If two or
13 // more updates come subsequently without reads in-between, we attempt to drop
14 // an older one to not waste time building the ASTs we don't need.
15 //
16 // The processing thread of the ASTWorker is also responsible for building the
17 // preamble. However, unlike AST, the same preamble can be read concurrently, so
18 // we run each of async preamble reads on its own thread.
19 //
20 // To limit the concurrent load that clangd produces we maintain a semaphore
21 // that keeps more than a fixed number of threads from running concurrently.
22 //
23 // Rationale for cancelling updates.
24 // LSP clients can send updates to clangd on each keystroke. Some files take
25 // significant time to parse (e.g. a few seconds) and clangd can get starved by
26 // the updates to those files. Therefore we try to process only the last update,
27 // if possible.
28 // Our current strategy to do that is the following:
29 // - For each update we immediately schedule rebuild of the AST.
30 // - Rebuild of the AST checks if it was cancelled before doing any actual work.
31 // If it was, it does not do an actual rebuild, only reports llvm::None to the
32 // callback
33 // - When adding an update, we cancel the last update in the queue if it didn't
34 // have any reads.
35 // There is probably a optimal ways to do that. One approach we might take is
36 // the following:
37 // - For each update we remember the pending inputs, but delay rebuild of the
38 // AST for some timeout.
39 // - If subsequent updates come before rebuild was started, we replace the
40 // pending inputs and reset the timer.
41 // - If any reads of the AST are scheduled, we start building the AST
42 // immediately.
43 
44 #include "TUScheduler.h"
45 #include "Cancellation.h"
46 #include "Compiler.h"
47 #include "Context.h"
48 #include "Diagnostics.h"
50 #include "Logger.h"
51 #include "ParsedAST.h"
52 #include "Preamble.h"
53 #include "Trace.h"
55 #include "clang/Frontend/CompilerInvocation.h"
56 #include "clang/Tooling/CompilationDatabase.h"
57 #include "llvm/ADT/Optional.h"
58 #include "llvm/ADT/ScopeExit.h"
59 #include "llvm/Support/Errc.h"
60 #include "llvm/Support/Path.h"
61 #include "llvm/Support/Threading.h"
62 #include <algorithm>
63 #include <memory>
64 #include <queue>
65 #include <thread>
66 
67 namespace clang {
68 namespace clangd {
69 using std::chrono::steady_clock;
70 
71 namespace {
72 class ASTWorker;
73 } // namespace
74 
76 
77 llvm::Optional<llvm::StringRef> TUScheduler::getFileBeingProcessedInContext() {
78  if (auto *File = Context::current().get(kFileBeingProcessed))
79  return llvm::StringRef(*File);
80  return None;
81 }
82 
83 /// An LRU cache of idle ASTs.
84 /// Because we want to limit the overall number of these we retain, the cache
85 /// owns ASTs (and may evict them) while their workers are idle.
86 /// Workers borrow ASTs when active, and return them when done.
88 public:
89  using Key = const ASTWorker *;
90 
91  ASTCache(unsigned MaxRetainedASTs) : MaxRetainedASTs(MaxRetainedASTs) {}
92 
93  /// Returns result of getUsedBytes() for the AST cached by \p K.
94  /// If no AST is cached, 0 is returned.
95  std::size_t getUsedBytes(Key K) {
96  std::lock_guard<std::mutex> Lock(Mut);
97  auto It = findByKey(K);
98  if (It == LRU.end() || !It->second)
99  return 0;
100  return It->second->getUsedBytes();
101  }
102 
103  /// Store the value in the pool, possibly removing the last used AST.
104  /// The value should not be in the pool when this function is called.
105  void put(Key K, std::unique_ptr<ParsedAST> V) {
106  std::unique_lock<std::mutex> Lock(Mut);
107  assert(findByKey(K) == LRU.end());
108 
109  LRU.insert(LRU.begin(), {K, std::move(V)});
110  if (LRU.size() <= MaxRetainedASTs)
111  return;
112  // We're past the limit, remove the last element.
113  std::unique_ptr<ParsedAST> ForCleanup = std::move(LRU.back().second);
114  LRU.pop_back();
115  // Run the expensive destructor outside the lock.
116  Lock.unlock();
117  ForCleanup.reset();
118  }
119 
120  /// Returns the cached value for \p K, or llvm::None if the value is not in
121  /// the cache anymore. If nullptr was cached for \p K, this function will
122  /// return a null unique_ptr wrapped into an optional.
123  llvm::Optional<std::unique_ptr<ParsedAST>> take(Key K) {
124  std::unique_lock<std::mutex> Lock(Mut);
125  auto Existing = findByKey(K);
126  if (Existing == LRU.end())
127  return None;
128  std::unique_ptr<ParsedAST> V = std::move(Existing->second);
129  LRU.erase(Existing);
130  // GCC 4.8 fails to compile `return V;`, as it tries to call the copy
131  // constructor of unique_ptr, so we call the move ctor explicitly to avoid
132  // this miscompile.
133  return llvm::Optional<std::unique_ptr<ParsedAST>>(std::move(V));
134  }
135 
136 private:
137  using KVPair = std::pair<Key, std::unique_ptr<ParsedAST>>;
138 
139  std::vector<KVPair>::iterator findByKey(Key K) {
140  return llvm::find_if(LRU, [K](const KVPair &P) { return P.first == K; });
141  }
142 
143  std::mutex Mut;
144  unsigned MaxRetainedASTs;
145  /// Items sorted in LRU order, i.e. first item is the most recently accessed
146  /// one.
147  std::vector<KVPair> LRU; /* GUARDED_BY(Mut) */
148 };
149 
150 namespace {
151 class ASTWorkerHandle;
152 
153 /// Owns one instance of the AST, schedules updates and reads of it.
154 /// Also responsible for building and providing access to the preamble.
155 /// Each ASTWorker processes the async requests sent to it on a separate
156 /// dedicated thread.
157 /// The ASTWorker that manages the AST is shared by both the processing thread
158 /// and the TUScheduler. The TUScheduler should discard an ASTWorker when
159 /// remove() is called, but its thread may be busy and we don't want to block.
160 /// So the workers are accessed via an ASTWorkerHandle. Destroying the handle
161 /// signals the worker to exit its run loop and gives up shared ownership of the
162 /// worker.
163 class ASTWorker {
164  friend class ASTWorkerHandle;
165  ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB,
166  TUScheduler::ASTCache &LRUCache, Semaphore &Barrier, bool RunSync,
167  steady_clock::duration UpdateDebounce, bool StorePreamblesInMemory,
168  ParsingCallbacks &Callbacks);
169 
170 public:
171  /// Create a new ASTWorker and return a handle to it.
172  /// The processing thread is spawned using \p Tasks. However, when \p Tasks
173  /// is null, all requests will be processed on the calling thread
174  /// synchronously instead. \p Barrier is acquired when processing each
175  /// request, it is used to limit the number of actively running threads.
176  static ASTWorkerHandle
177  create(PathRef FileName, const GlobalCompilationDatabase &CDB,
178  TUScheduler::ASTCache &IdleASTs, AsyncTaskRunner *Tasks,
179  Semaphore &Barrier, steady_clock::duration UpdateDebounce,
180  bool StorePreamblesInMemory, ParsingCallbacks &Callbacks);
181  ~ASTWorker();
182 
183  void update(ParseInputs Inputs, WantDiagnostics);
184  void
185  runWithAST(llvm::StringRef Name,
186  llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action);
187  bool blockUntilIdle(Deadline Timeout) const;
188 
189  std::shared_ptr<const PreambleData> getPossiblyStalePreamble() const;
190 
191  /// Obtain a preamble reflecting all updates so far. Threadsafe.
192  /// It may be delivered immediately, or later on the worker thread.
193  void getCurrentPreamble(
194  llvm::unique_function<void(std::shared_ptr<const PreambleData>)>);
195  /// Returns compile command from the current file inputs.
196  tooling::CompileCommand getCurrentCompileCommand() const;
197 
198  /// Wait for the first build of preamble to finish. Preamble itself can be
199  /// accessed via getPossiblyStalePreamble(). Note that this function will
200  /// return after an unsuccessful build of the preamble too, i.e. result of
201  /// getPossiblyStalePreamble() can be null even after this function returns.
202  void waitForFirstPreamble() const;
203 
204  std::size_t getUsedBytes() const;
205  bool isASTCached() const;
206 
207 private:
208  // Must be called exactly once on processing thread. Will return after
209  // stop() is called on a separate thread and all pending requests are
210  // processed.
211  void run();
212  /// Signal that run() should finish processing pending requests and exit.
213  void stop();
214  /// Adds a new task to the end of the request queue.
215  void startTask(llvm::StringRef Name, llvm::unique_function<void()> Task,
216  llvm::Optional<WantDiagnostics> UpdateType);
217  /// Updates the TUStatus and emits it. Only called in the worker thread.
218  void emitTUStatus(TUAction FAction,
219  const TUStatus::BuildDetails *Detail = nullptr);
220 
221  /// Determines the next action to perform.
222  /// All actions that should never run are discarded.
223  /// Returns a deadline for the next action. If it's expired, run now.
224  /// scheduleLocked() is called again at the deadline, or if requests arrive.
225  Deadline scheduleLocked();
226  /// Should the first task in the queue be skipped instead of run?
227  bool shouldSkipHeadLocked() const;
228  /// This is private because `FileInputs.FS` is not thread-safe and thus not
229  /// safe to share. Callers should make sure not to expose `FS` via a public
230  /// interface.
231  std::shared_ptr<const ParseInputs> getCurrentFileInputs() const;
232 
233  struct Request {
234  llvm::unique_function<void()> Action;
235  std::string Name;
236  steady_clock::time_point AddTime;
237  Context Ctx;
238  llvm::Optional<WantDiagnostics> UpdateType;
239  };
240 
241  /// Handles retention of ASTs.
242  TUScheduler::ASTCache &IdleASTs;
243  const bool RunSync;
244  /// Time to wait after an update to see whether another update obsoletes it.
245  const steady_clock::duration UpdateDebounce;
246  /// File that ASTWorker is responsible for.
247  const Path FileName;
248  const GlobalCompilationDatabase &CDB;
249  /// Whether to keep the built preambles in memory or on disk.
250  const bool StorePreambleInMemory;
251  /// Callback invoked when preamble or main file AST is built.
252  ParsingCallbacks &Callbacks;
253  /// Only accessed by the worker thread.
254  TUStatus Status;
255 
256  Semaphore &Barrier;
257  /// Whether the 'onMainAST' callback ran for the current FileInputs.
258  bool RanASTCallback = false;
259  /// Guards members used by both TUScheduler and the worker thread.
260  mutable std::mutex Mutex;
261  /// File inputs, currently being used by the worker.
262  /// Inputs are written and read by the worker thread, compile command can also
263  /// be consumed by clients of ASTWorker.
264  std::shared_ptr<const ParseInputs> FileInputs; /* GUARDED_BY(Mutex) */
265  std::shared_ptr<const PreambleData> LastBuiltPreamble; /* GUARDED_BY(Mutex) */
266  /// Becomes ready when the first preamble build finishes.
267  Notification PreambleWasBuilt;
268  /// Set to true to signal run() to finish processing.
269  bool Done; /* GUARDED_BY(Mutex) */
270  std::deque<Request> Requests; /* GUARDED_BY(Mutex) */
271  mutable std::condition_variable RequestsCV;
272  /// Guards the callback that publishes results of AST-related computations
273  /// (diagnostics, highlightings) and file statuses.
274  std::mutex PublishMu;
275  // Used to prevent remove document + add document races that lead to
276  // out-of-order callbacks for publishing results of onMainAST callback.
277  //
278  // The lifetime of the old/new ASTWorkers will overlap, but their handles
279  // don't. When the old handle is destroyed, the old worker will stop reporting
280  // any results to the user.
281  bool CanPublishResults = true; /* GUARDED_BY(PublishMu) */
282 };
283 
284 /// A smart-pointer-like class that points to an active ASTWorker.
285 /// In destructor, signals to the underlying ASTWorker that no new requests will
286 /// be sent and the processing loop may exit (after running all pending
287 /// requests).
288 class ASTWorkerHandle {
289  friend class ASTWorker;
290  ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)
291  : Worker(std::move(Worker)) {
292  assert(this->Worker);
293  }
294 
295 public:
296  ASTWorkerHandle(const ASTWorkerHandle &) = delete;
297  ASTWorkerHandle &operator=(const ASTWorkerHandle &) = delete;
298  ASTWorkerHandle(ASTWorkerHandle &&) = default;
299  ASTWorkerHandle &operator=(ASTWorkerHandle &&) = default;
300 
301  ~ASTWorkerHandle() {
302  if (Worker)
303  Worker->stop();
304  }
305 
306  ASTWorker &operator*() {
307  assert(Worker && "Handle was moved from");
308  return *Worker;
309  }
310 
311  ASTWorker *operator->() {
312  assert(Worker && "Handle was moved from");
313  return Worker.get();
314  }
315 
316  /// Returns an owning reference to the underlying ASTWorker that can outlive
317  /// the ASTWorkerHandle. However, no new requests to an active ASTWorker can
318  /// be schedule via the returned reference, i.e. only reads of the preamble
319  /// are possible.
320  std::shared_ptr<const ASTWorker> lock() { return Worker; }
321 
322 private:
323  std::shared_ptr<ASTWorker> Worker;
324 };
325 
326 ASTWorkerHandle
327 ASTWorker::create(PathRef FileName, const GlobalCompilationDatabase &CDB,
328  TUScheduler::ASTCache &IdleASTs, AsyncTaskRunner *Tasks,
329  Semaphore &Barrier, steady_clock::duration UpdateDebounce,
330  bool StorePreamblesInMemory, ParsingCallbacks &Callbacks) {
331  std::shared_ptr<ASTWorker> Worker(
332  new ASTWorker(FileName, CDB, IdleASTs, Barrier, /*RunSync=*/!Tasks,
333  UpdateDebounce, StorePreamblesInMemory, Callbacks));
334  if (Tasks)
335  Tasks->runAsync("worker:" + llvm::sys::path::filename(FileName),
336  [Worker]() { Worker->run(); });
337 
338  return ASTWorkerHandle(std::move(Worker));
339 }
340 
341 ASTWorker::ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB,
342  TUScheduler::ASTCache &LRUCache, Semaphore &Barrier,
343  bool RunSync, steady_clock::duration UpdateDebounce,
344  bool StorePreamblesInMemory, ParsingCallbacks &Callbacks)
345  : IdleASTs(LRUCache), RunSync(RunSync), UpdateDebounce(UpdateDebounce),
346  FileName(FileName), CDB(CDB),
347  StorePreambleInMemory(StorePreamblesInMemory),
348  Callbacks(Callbacks), Status{TUAction(TUAction::Idle, ""),
349  TUStatus::BuildDetails()},
350  Barrier(Barrier), Done(false) {
351  auto Inputs = std::make_shared<ParseInputs>();
352  // Set a fallback command because compile command can be accessed before
353  // `Inputs` is initialized. Other fields are only used after initialization
354  // from client inputs.
355  Inputs->CompileCommand = CDB.getFallbackCommand(FileName);
356  FileInputs = std::move(Inputs);
357 }
358 
359 ASTWorker::~ASTWorker() {
360  // Make sure we remove the cached AST, if any.
361  IdleASTs.take(this);
362 #ifndef NDEBUG
363  std::lock_guard<std::mutex> Lock(Mutex);
364  assert(Done && "handle was not destroyed");
365  assert(Requests.empty() && "unprocessed requests when destroying ASTWorker");
366 #endif
367 }
368 
369 void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags) {
370  llvm::StringRef TaskName = "Update";
371  auto Task = [=]() mutable {
372  auto RunPublish = [&](llvm::function_ref<void()> Publish) {
373  // Ensure we only publish results from the worker if the file was not
374  // removed, making sure there are not race conditions.
375  std::lock_guard<std::mutex> Lock(PublishMu);
376  if (CanPublishResults)
377  Publish();
378  };
379 
380  // Get the actual command as `Inputs` does not have a command.
381  // FIXME: some build systems like Bazel will take time to preparing
382  // environment to build the file, it would be nice if we could emit a
383  // "PreparingBuild" status to inform users, it is non-trivial given the
384  // current implementation.
385  if (auto Cmd = CDB.getCompileCommand(FileName))
386  Inputs.CompileCommand = *Cmd;
387  else
388  // FIXME: consider using old command if it's not a fallback one.
389  Inputs.CompileCommand = CDB.getFallbackCommand(FileName);
390  auto PrevInputs = getCurrentFileInputs();
391  // Will be used to check if we can avoid rebuilding the AST.
392  bool InputsAreTheSame =
393  std::tie(PrevInputs->CompileCommand, PrevInputs->Contents) ==
394  std::tie(Inputs.CompileCommand, Inputs.Contents);
395 
396  tooling::CompileCommand OldCommand = PrevInputs->CompileCommand;
397  bool RanCallbackForPrevInputs = RanASTCallback;
398  {
399  std::lock_guard<std::mutex> Lock(Mutex);
400  FileInputs = std::make_shared<ParseInputs>(Inputs);
401  }
402  RanASTCallback = false;
403  emitTUStatus({TUAction::BuildingPreamble, TaskName});
404  log("Updating file {0} with command {1}\n[{2}]\n{3}", FileName,
405  Inputs.CompileCommand.Heuristic,
406  Inputs.CompileCommand.Directory,
407  llvm::join(Inputs.CompileCommand.CommandLine, " "));
408  // Rebuild the preamble and the AST.
409  StoreDiags CompilerInvocationDiagConsumer;
410  std::vector<std::string> CC1Args;
411  std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation(
412  Inputs, CompilerInvocationDiagConsumer, &CC1Args);
413  // Log cc1 args even (especially!) if creating invocation failed.
414  if (!CC1Args.empty())
415  vlog("Driver produced command: cc1 {0}", llvm::join(CC1Args, " "));
416  std::vector<Diag> CompilerInvocationDiags =
417  CompilerInvocationDiagConsumer.take();
418  if (!Invocation) {
419  elog("Could not build CompilerInvocation for file {0}", FileName);
420  // Remove the old AST if it's still in cache.
421  IdleASTs.take(this);
422  TUStatus::BuildDetails Details;
423  Details.BuildFailed = true;
424  emitTUStatus({TUAction::BuildingPreamble, TaskName}, &Details);
425  // Report the diagnostics we collected when parsing the command line.
426  Callbacks.onFailedAST(FileName, std::move(CompilerInvocationDiags),
427  RunPublish);
428  // Make sure anyone waiting for the preamble gets notified it could not
429  // be built.
430  PreambleWasBuilt.notify();
431  return;
432  }
433 
434  std::shared_ptr<const PreambleData> OldPreamble =
435  getPossiblyStalePreamble();
436  std::shared_ptr<const PreambleData> NewPreamble = buildPreamble(
437  FileName, *Invocation, OldPreamble, OldCommand, Inputs,
438  StorePreambleInMemory,
439  [this](ASTContext &Ctx, std::shared_ptr<clang::Preprocessor> PP,
440  const CanonicalIncludes &CanonIncludes) {
441  Callbacks.onPreambleAST(FileName, Ctx, std::move(PP), CanonIncludes);
442  });
443 
444  bool CanReuseAST = InputsAreTheSame && (OldPreamble == NewPreamble);
445  {
446  std::lock_guard<std::mutex> Lock(Mutex);
447  LastBuiltPreamble = NewPreamble;
448  }
449  // Before doing the expensive AST reparse, we want to release our reference
450  // to the old preamble, so it can be freed if there are no other references
451  // to it.
452  OldPreamble.reset();
453  PreambleWasBuilt.notify();
454  emitTUStatus({TUAction::BuildingFile, TaskName});
455  if (!CanReuseAST) {
456  IdleASTs.take(this); // Remove the old AST if it's still in cache.
457  } else {
458  // We don't need to rebuild the AST, check if we need to run the callback.
459  if (RanCallbackForPrevInputs) {
460  RanASTCallback = true;
461  // Take a shortcut and don't report the diagnostics, since they should
462  // not changed. All the clients should handle the lack of OnUpdated()
463  // call anyway to handle empty result from buildAST.
464  // FIXME(ibiryukov): the AST could actually change if non-preamble
465  // includes changed, but we choose to ignore it.
466  // FIXME(ibiryukov): should we refresh the cache in IdleASTs for the
467  // current file at this point?
468  log("Skipping rebuild of the AST for {0}, inputs are the same.",
469  FileName);
470  TUStatus::BuildDetails Details;
471  Details.ReuseAST = true;
472  emitTUStatus({TUAction::BuildingFile, TaskName}, &Details);
473  return;
474  }
475  }
476 
477  // We only need to build the AST if diagnostics were requested.
478  if (WantDiags == WantDiagnostics::No)
479  return;
480 
481  {
482  std::lock_guard<std::mutex> Lock(PublishMu);
483  // No need to rebuild the AST if we won't send the diagnostics. However,
484  // note that we don't prevent preamble rebuilds.
485  if (!CanPublishResults)
486  return;
487  }
488 
489  // Get the AST for diagnostics.
490  llvm::Optional<std::unique_ptr<ParsedAST>> AST = IdleASTs.take(this);
491  if (!AST) {
492  llvm::Optional<ParsedAST> NewAST =
493  buildAST(FileName, std::move(Invocation), CompilerInvocationDiags,
494  Inputs, NewPreamble);
495  AST = NewAST ? std::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
496  if (!(*AST)) { // buildAST fails.
497  TUStatus::BuildDetails Details;
498  Details.BuildFailed = true;
499  emitTUStatus({TUAction::BuildingFile, TaskName}, &Details);
500  }
501  } else {
502  // We are reusing the AST.
503  TUStatus::BuildDetails Details;
504  Details.ReuseAST = true;
505  emitTUStatus({TUAction::BuildingFile, TaskName}, &Details);
506  }
507 
508  // We want to report the diagnostics even if this update was cancelled.
509  // It seems more useful than making the clients wait indefinitely if they
510  // spam us with updates.
511  // Note *AST can still be null if buildAST fails.
512  if (*AST) {
513  trace::Span Span("Running main AST callback");
514 
515  Callbacks.onMainAST(FileName, **AST, RunPublish);
516  RanASTCallback = true;
517  } else {
518  // Failed to build the AST, at least report diagnostics from the command
519  // line if there were any.
520  // FIXME: we might have got more errors while trying to build the AST,
521  // surface them too.
522  Callbacks.onFailedAST(FileName, CompilerInvocationDiags, RunPublish);
523  }
524  // Stash the AST in the cache for further use.
525  IdleASTs.put(this, std::move(*AST));
526  };
527  startTask(TaskName, std::move(Task), WantDiags);
528 }
529 
530 void ASTWorker::runWithAST(
531  llvm::StringRef Name,
532  llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action) {
533  auto Task = [=, Action = std::move(Action)]() mutable {
534  if (isCancelled())
535  return Action(llvm::make_error<CancelledError>());
536  llvm::Optional<std::unique_ptr<ParsedAST>> AST = IdleASTs.take(this);
537  auto CurrentInputs = getCurrentFileInputs();
538  if (!AST) {
539  StoreDiags CompilerInvocationDiagConsumer;
540  std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation(
541  *CurrentInputs, CompilerInvocationDiagConsumer);
542  // Try rebuilding the AST.
543  llvm::Optional<ParsedAST> NewAST =
544  Invocation
545  ? buildAST(FileName,
546  std::make_unique<CompilerInvocation>(*Invocation),
547  CompilerInvocationDiagConsumer.take(), *CurrentInputs,
548  getPossiblyStalePreamble())
549  : None;
550  AST = NewAST ? std::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
551  }
552  // Make sure we put the AST back into the LRU cache.
553  auto _ = llvm::make_scope_exit(
554  [&AST, this]() { IdleASTs.put(this, std::move(*AST)); });
555  // Run the user-provided action.
556  if (!*AST)
557  return Action(llvm::make_error<llvm::StringError>(
558  "invalid AST", llvm::errc::invalid_argument));
559  Action(InputsAndAST{*CurrentInputs, **AST});
560  };
561  startTask(Name, std::move(Task), /*UpdateType=*/None);
562 }
563 
564 std::shared_ptr<const PreambleData>
565 ASTWorker::getPossiblyStalePreamble() const {
566  std::lock_guard<std::mutex> Lock(Mutex);
567  return LastBuiltPreamble;
568 }
569 
570 void ASTWorker::getCurrentPreamble(
571  llvm::unique_function<void(std::shared_ptr<const PreambleData>)> Callback) {
572  // We could just call startTask() to throw the read on the queue, knowing
573  // it will run after any updates. But we know this task is cheap, so to
574  // improve latency we cheat: insert it on the queue after the last update.
575  std::unique_lock<std::mutex> Lock(Mutex);
576  auto LastUpdate =
577  std::find_if(Requests.rbegin(), Requests.rend(),
578  [](const Request &R) { return R.UpdateType.hasValue(); });
579  // If there were no writes in the queue, the preamble is ready now.
580  if (LastUpdate == Requests.rend()) {
581  Lock.unlock();
582  return Callback(getPossiblyStalePreamble());
583  }
584  assert(!RunSync && "Running synchronously, but queue is non-empty!");
585  Requests.insert(LastUpdate.base(),
586  Request{[Callback = std::move(Callback), this]() mutable {
587  Callback(getPossiblyStalePreamble());
588  },
589  "GetPreamble", steady_clock::now(),
591  /*UpdateType=*/None});
592  Lock.unlock();
593  RequestsCV.notify_all();
594 }
595 
596 void ASTWorker::waitForFirstPreamble() const { PreambleWasBuilt.wait(); }
597 
598 std::shared_ptr<const ParseInputs> ASTWorker::getCurrentFileInputs() const {
599  std::unique_lock<std::mutex> Lock(Mutex);
600  return FileInputs;
601 }
602 
603 tooling::CompileCommand ASTWorker::getCurrentCompileCommand() const {
604  std::unique_lock<std::mutex> Lock(Mutex);
605  return FileInputs->CompileCommand;
606 }
607 
608 std::size_t ASTWorker::getUsedBytes() const {
609  // Note that we don't report the size of ASTs currently used for processing
610  // the in-flight requests. We used this information for debugging purposes
611  // only, so this should be fine.
612  std::size_t Result = IdleASTs.getUsedBytes(this);
613  if (auto Preamble = getPossiblyStalePreamble())
614  Result += Preamble->Preamble.getSize();
615  return Result;
616 }
617 
618 bool ASTWorker::isASTCached() const { return IdleASTs.getUsedBytes(this) != 0; }
619 
620 void ASTWorker::stop() {
621  {
622  std::lock_guard<std::mutex> Lock(PublishMu);
623  CanPublishResults = false;
624  }
625  {
626  std::lock_guard<std::mutex> Lock(Mutex);
627  assert(!Done && "stop() called twice");
628  Done = true;
629  }
630  RequestsCV.notify_all();
631 }
632 
633 void ASTWorker::startTask(llvm::StringRef Name,
634  llvm::unique_function<void()> Task,
635  llvm::Optional<WantDiagnostics> UpdateType) {
636  if (RunSync) {
637  assert(!Done && "running a task after stop()");
638  trace::Span Tracer(Name + ":" + llvm::sys::path::filename(FileName));
639  Task();
640  return;
641  }
642 
643  {
644  std::lock_guard<std::mutex> Lock(Mutex);
645  assert(!Done && "running a task after stop()");
646  Requests.push_back(
647  {std::move(Task), Name, steady_clock::now(),
648  Context::current().derive(kFileBeingProcessed, FileName), UpdateType});
649  }
650  RequestsCV.notify_all();
651 }
652 
653 void ASTWorker::emitTUStatus(TUAction Action,
654  const TUStatus::BuildDetails *Details) {
655  Status.Action = std::move(Action);
656  if (Details)
657  Status.Details = *Details;
658  std::lock_guard<std::mutex> Lock(PublishMu);
659  // Do not emit TU statuses when the ASTWorker is shutting down.
660  if (CanPublishResults) {
661  Callbacks.onFileUpdated(FileName, Status);
662  }
663 }
664 
665 void ASTWorker::run() {
666  while (true) {
667  Request Req;
668  {
669  std::unique_lock<std::mutex> Lock(Mutex);
670  for (auto Wait = scheduleLocked(); !Wait.expired();
671  Wait = scheduleLocked()) {
672  if (Done) {
673  if (Requests.empty())
674  return;
675  else // Even though Done is set, finish pending requests.
676  break; // However, skip delays to shutdown fast.
677  }
678 
679  // Tracing: we have a next request, attribute this sleep to it.
680  llvm::Optional<WithContext> Ctx;
681  llvm::Optional<trace::Span> Tracer;
682  if (!Requests.empty()) {
683  Ctx.emplace(Requests.front().Ctx.clone());
684  Tracer.emplace("Debounce");
685  SPAN_ATTACH(*Tracer, "next_request", Requests.front().Name);
686  if (!(Wait == Deadline::infinity())) {
687  emitTUStatus({TUAction::Queued, Req.Name});
688  SPAN_ATTACH(*Tracer, "sleep_ms",
689  std::chrono::duration_cast<std::chrono::milliseconds>(
690  Wait.time() - steady_clock::now())
691  .count());
692  }
693  }
694 
695  wait(Lock, RequestsCV, Wait);
696  }
697  Req = std::move(Requests.front());
698  // Leave it on the queue for now, so waiters don't see an empty queue.
699  } // unlock Mutex
700 
701  {
702  std::unique_lock<Semaphore> Lock(Barrier, std::try_to_lock);
703  if (!Lock.owns_lock()) {
704  emitTUStatus({TUAction::Queued, Req.Name});
705  Lock.lock();
706  }
707  WithContext Guard(std::move(Req.Ctx));
708  trace::Span Tracer(Req.Name);
709  emitTUStatus({TUAction::RunningAction, Req.Name});
710  Req.Action();
711  }
712 
713  bool IsEmpty = false;
714  {
715  std::lock_guard<std::mutex> Lock(Mutex);
716  Requests.pop_front();
717  IsEmpty = Requests.empty();
718  }
719  if (IsEmpty)
720  emitTUStatus({TUAction::Idle, /*Name*/ ""});
721  RequestsCV.notify_all();
722  }
723 }
724 
725 Deadline ASTWorker::scheduleLocked() {
726  if (Requests.empty())
727  return Deadline::infinity(); // Wait for new requests.
728  // Handle cancelled requests first so the rest of the scheduler doesn't.
729  for (auto I = Requests.begin(), E = Requests.end(); I != E; ++I) {
730  if (!isCancelled(I->Ctx)) {
731  // Cancellations after the first read don't affect current scheduling.
732  if (I->UpdateType == None)
733  break;
734  continue;
735  }
736  // Cancelled reads are moved to the front of the queue and run immediately.
737  if (I->UpdateType == None) {
738  Request R = std::move(*I);
739  Requests.erase(I);
740  Requests.push_front(std::move(R));
741  return Deadline::zero();
742  }
743  // Cancelled updates are downgraded to auto-diagnostics, and may be elided.
744  if (I->UpdateType == WantDiagnostics::Yes)
745  I->UpdateType = WantDiagnostics::Auto;
746  }
747 
748  while (shouldSkipHeadLocked())
749  Requests.pop_front();
750  assert(!Requests.empty() && "skipped the whole queue");
751  // Some updates aren't dead yet, but never end up being used.
752  // e.g. the first keystroke is live until obsoleted by the second.
753  // We debounce "maybe-unused" writes, sleeping 500ms in case they become dead.
754  // But don't delay reads (including updates where diagnostics are needed).
755  for (const auto &R : Requests)
756  if (R.UpdateType == None || R.UpdateType == WantDiagnostics::Yes)
757  return Deadline::zero();
758  // Front request needs to be debounced, so determine when we're ready.
759  Deadline D(Requests.front().AddTime + UpdateDebounce);
760  return D;
761 }
762 
763 // Returns true if Requests.front() is a dead update that can be skipped.
764 bool ASTWorker::shouldSkipHeadLocked() const {
765  assert(!Requests.empty());
766  auto Next = Requests.begin();
767  auto UpdateType = Next->UpdateType;
768  if (!UpdateType) // Only skip updates.
769  return false;
770  ++Next;
771  // An update is live if its AST might still be read.
772  // That is, if it's not immediately followed by another update.
773  if (Next == Requests.end() || !Next->UpdateType)
774  return false;
775  // The other way an update can be live is if its diagnostics might be used.
776  switch (*UpdateType) {
778  return false; // Always used.
779  case WantDiagnostics::No:
780  return true; // Always dead.
782  // Used unless followed by an update that generates diagnostics.
783  for (; Next != Requests.end(); ++Next)
784  if (Next->UpdateType == WantDiagnostics::Yes ||
785  Next->UpdateType == WantDiagnostics::Auto)
786  return true; // Prefer later diagnostics.
787  return false;
788  }
789  llvm_unreachable("Unknown WantDiagnostics");
790 }
791 
792 bool ASTWorker::blockUntilIdle(Deadline Timeout) const {
793  std::unique_lock<std::mutex> Lock(Mutex);
794  return wait(Lock, RequestsCV, Timeout, [&] { return Requests.empty(); });
795 }
796 
797 // Render a TUAction to a user-facing string representation.
798 // TUAction represents clangd-internal states, we don't intend to expose them
799 // to users (say C++ programmers) directly to avoid confusion, we use terms that
800 // are familiar by C++ programmers.
801 std::string renderTUAction(const TUAction &Action) {
802  std::string Result;
803  llvm::raw_string_ostream OS(Result);
804  switch (Action.S) {
805  case TUAction::Queued:
806  OS << "file is queued";
807  break;
809  OS << "running " << Action.Name;
810  break;
812  OS << "parsing includes";
813  break;
815  OS << "parsing main file";
816  break;
817  case TUAction::Idle:
818  OS << "idle";
819  break;
820  }
821  return OS.str();
822 }
823 
824 } // namespace
825 
827  unsigned HardwareConcurrency = llvm::heavyweight_hardware_concurrency();
828  // heavyweight_hardware_concurrency may fall back to hardware_concurrency.
829  // C++ standard says that hardware_concurrency() may return 0; fallback to 1
830  // worker thread in that case.
831  if (HardwareConcurrency == 0)
832  return 1;
833  return HardwareConcurrency;
834 }
835 
837  FileStatus FStatus;
838  FStatus.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
839  FStatus.state = renderTUAction(Action);
840  return FStatus;
841 }
842 
844  /// Latest inputs, passed to TUScheduler::update().
845  std::string Contents;
846  ASTWorkerHandle Worker;
847 };
848 
850  unsigned AsyncThreadsCount,
851  bool StorePreamblesInMemory,
852  std::unique_ptr<ParsingCallbacks> Callbacks,
853  std::chrono::steady_clock::duration UpdateDebounce,
854  ASTRetentionPolicy RetentionPolicy)
855  : CDB(CDB), StorePreamblesInMemory(StorePreamblesInMemory),
856  Callbacks(Callbacks ? move(Callbacks)
857  : std::make_unique<ParsingCallbacks>()),
858  Barrier(AsyncThreadsCount),
859  IdleASTs(std::make_unique<ASTCache>(RetentionPolicy.MaxRetainedASTs)),
860  UpdateDebounce(UpdateDebounce) {
861  if (0 < AsyncThreadsCount) {
862  PreambleTasks.emplace();
863  WorkerThreads.emplace();
864  }
865 }
866 
868  // Notify all workers that they need to stop.
869  Files.clear();
870 
871  // Wait for all in-flight tasks to finish.
872  if (PreambleTasks)
873  PreambleTasks->wait();
874  if (WorkerThreads)
875  WorkerThreads->wait();
876 }
877 
879  for (auto &File : Files)
880  if (!File.getValue()->Worker->blockUntilIdle(D))
881  return false;
882  if (PreambleTasks)
883  if (!PreambleTasks->wait(D))
884  return false;
885  return true;
886 }
887 
889  WantDiagnostics WantDiags) {
890  std::unique_ptr<FileData> &FD = Files[File];
891  bool NewFile = FD == nullptr;
892  if (!FD) {
893  // Create a new worker to process the AST-related tasks.
894  ASTWorkerHandle Worker = ASTWorker::create(
895  File, CDB, *IdleASTs,
896  WorkerThreads ? WorkerThreads.getPointer() : nullptr, Barrier,
897  UpdateDebounce, StorePreamblesInMemory, *Callbacks);
898  FD = std::unique_ptr<FileData>(
899  new FileData{Inputs.Contents, std::move(Worker)});
900  } else {
901  FD->Contents = Inputs.Contents;
902  }
903  FD->Worker->update(std::move(Inputs), WantDiags);
904  return NewFile;
905 }
906 
908  bool Removed = Files.erase(File);
909  if (!Removed)
910  elog("Trying to remove file from TUScheduler that is not tracked: {0}",
911  File);
912 }
913 
914 llvm::StringRef TUScheduler::getContents(PathRef File) const {
915  auto It = Files.find(File);
916  if (It == Files.end()) {
917  elog("getContents() for untracked file: {0}", File);
918  return "";
919  }
920  return It->second->Contents;
921 }
922 
923 llvm::StringMap<std::string> TUScheduler::getAllFileContents() const {
924  llvm::StringMap<std::string> Results;
925  for (auto &It : Files)
926  Results.try_emplace(It.getKey(), It.getValue()->Contents);
927  return Results;
928 }
929 
930 void TUScheduler::run(llvm::StringRef Name,
931  llvm::unique_function<void()> Action) {
932  if (!PreambleTasks)
933  return Action();
934  PreambleTasks->runAsync(Name, [Ctx = Context::current().clone(),
935  Action = std::move(Action)]() mutable {
936  WithContext WC(std::move(Ctx));
937  Action();
938  });
939 }
940 
942  llvm::StringRef Name, PathRef File,
943  llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action) {
944  auto It = Files.find(File);
945  if (It == Files.end()) {
946  Action(llvm::make_error<LSPError>(
947  "trying to get AST for non-added document", ErrorCode::InvalidParams));
948  return;
949  }
950 
951  It->second->Worker->runWithAST(Name, std::move(Action));
952 }
953 
954 void TUScheduler::runWithPreamble(llvm::StringRef Name, PathRef File,
955  PreambleConsistency Consistency,
957  auto It = Files.find(File);
958  if (It == Files.end()) {
959  Action(llvm::make_error<LSPError>(
960  "trying to get preamble for non-added document",
962  return;
963  }
964 
965  if (!PreambleTasks) {
966  trace::Span Tracer(Name);
967  SPAN_ATTACH(Tracer, "file", File);
968  std::shared_ptr<const PreambleData> Preamble =
969  It->second->Worker->getPossiblyStalePreamble();
970  Action(InputsAndPreamble{It->second->Contents,
971  It->second->Worker->getCurrentCompileCommand(),
972  Preamble.get()});
973  return;
974  }
975 
976  // Future is populated if the task needs a specific preamble.
977  std::future<std::shared_ptr<const PreambleData>> ConsistentPreamble;
978  if (Consistency == Consistent) {
979  std::promise<std::shared_ptr<const PreambleData>> Promise;
980  ConsistentPreamble = Promise.get_future();
981  It->second->Worker->getCurrentPreamble(
982  [Promise = std::move(Promise)](
983  std::shared_ptr<const PreambleData> Preamble) mutable {
984  Promise.set_value(std::move(Preamble));
985  });
986  }
987 
988  std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
989  auto Task = [Worker, Consistency, Name = Name.str(), File = File.str(),
990  Contents = It->second->Contents,
991  Command = Worker->getCurrentCompileCommand(),
992  Ctx = Context::current().derive(kFileBeingProcessed, File),
993  ConsistentPreamble = std::move(ConsistentPreamble),
994  Action = std::move(Action), this]() mutable {
995  std::shared_ptr<const PreambleData> Preamble;
996  if (ConsistentPreamble.valid()) {
997  Preamble = ConsistentPreamble.get();
998  } else {
999  if (Consistency != PreambleConsistency::StaleOrAbsent) {
1000  // Wait until the preamble is built for the first time, if preamble is
1001  // required. This avoids extra work of processing the preamble headers
1002  // in parallel multiple times.
1003  Worker->waitForFirstPreamble();
1004  }
1005  Preamble = Worker->getPossiblyStalePreamble();
1006  }
1007 
1008  std::lock_guard<Semaphore> BarrierLock(Barrier);
1009  WithContext Guard(std::move(Ctx));
1010  trace::Span Tracer(Name);
1011  SPAN_ATTACH(Tracer, "file", File);
1012  Action(InputsAndPreamble{Contents, Command, Preamble.get()});
1013  };
1014 
1015  PreambleTasks->runAsync("task:" + llvm::sys::path::filename(File),
1016  std::move(Task));
1017 }
1018 
1019 std::vector<std::pair<Path, std::size_t>>
1021  std::vector<std::pair<Path, std::size_t>> Result;
1022  Result.reserve(Files.size());
1023  for (auto &&PathAndFile : Files)
1024  Result.push_back(
1025  {PathAndFile.first(), PathAndFile.second->Worker->getUsedBytes()});
1026  return Result;
1027 }
1028 
1029 std::vector<Path> TUScheduler::getFilesWithCachedAST() const {
1030  std::vector<Path> Result;
1031  for (auto &&PathAndFile : Files) {
1032  if (!PathAndFile.second->Worker->isASTCached())
1033  continue;
1034  Result.push_back(PathAndFile.first());
1035  }
1036  return Result;
1037 }
1038 
1039 } // namespace clangd
1040 } // namespace clang
PreambleConsistency
Controls whether preamble reads wait for the preamble to be up-to-date.
Definition: TUScheduler.h:201
const tooling::CompileCommand & Command
WantDiagnostics
Determines whether diagnostics should be generated for a file snapshot.
Definition: TUScheduler.h:47
llvm::StringRef Contents
Diagnostics must be generated for this snapshot.
llvm::Optional< ParsedAST > buildAST(PathRef FileName, std::unique_ptr< CompilerInvocation > Invocation, llvm::ArrayRef< Diag > CompilerInvocationDiags, const ParseInputs &Inputs, std::shared_ptr< const PreambleData > Preamble)
Build an AST from provided user inputs.
Definition: ParsedAST.cpp:505
FileStatus render(PathRef File) const
Serialize this to an LSP file status item.
static llvm::Optional< llvm::StringRef > getFileBeingProcessedInContext()
Definition: TUScheduler.cpp:77
bool blockUntilIdle(Deadline D) const
Wait until there are no scheduled or running tasks.
void remove(PathRef File)
Remove File from the list of tracked files and schedule removal of its resources. ...
TUScheduler(const GlobalCompilationDatabase &CDB, unsigned AsyncThreadsCount, bool StorePreamblesInMemory, std::unique_ptr< ParsingCallbacks > ASTCallbacks, std::chrono::steady_clock::duration UpdateDebounce, ASTRetentionPolicy RetentionPolicy)
std::string state
The human-readable string presents the current state of the file, can be shown in the UI (e...
Definition: Protocol.h:1207
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:23
std::vector< CodeCompletionResult > Results
Values in a Context are indexed by typed keys.
Definition: Context.h:40
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:28
Documents should not be synced at all.
Limits the number of threads that can acquire the lock at the same time.
Definition: Threading.h:41
URIForFile uri
The text document&#39;s URI.
Definition: Protocol.h:1204
void vlog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:67
bool update(PathRef File, ParseInputs Inputs, WantDiagnostics WD)
Schedule an update for File.
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:56
Configuration of the AST retention policy.
Definition: TUScheduler.h:57
bool isCancelled(const Context &Ctx)
True if the current context is within a cancelable task which was cancelled.
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation &CI, std::shared_ptr< const PreambleData > OldPreamble, const tooling::CompileCommand &OldCompileCommand, const ParseInputs &Inputs, bool StoreInMemory, PreambleParsedCallback PreambleCallback)
Build a preamble for the new inputs unless an old one can be reused.
Definition: Preamble.cpp:89
Provides compilation arguments used for parsing C and C++ files.
Context Ctx
Context clone() const
Clone this context object.
Definition: Context.cpp:20
llvm::Optional< WantDiagnostics > UpdateType
static Deadline infinity()
Definition: Threading.h:63
llvm::unique_function< void()> Action
void log(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:62
void put(Key K, std::unique_ptr< ParsedAST > V)
Store the value in the pool, possibly removing the last used AST.
std::string Path
A typedef to represent a file path.
Definition: Path.h:20
static const Context & current()
Returns the context for the current thread, creating it if needed.
Definition: Context.cpp:27
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Definition: Protocol.cpp:32
std::vector< std::pair< Path, std::size_t > > getUsedBytesPerFile() const
Returns estimated memory usage for each of the currently open files.
void runWithPreamble(llvm::StringRef Name, PathRef File, PreambleConsistency Consistency, Callback< InputsAndPreamble > Action)
Schedule an async read of the preamble.
std::vector< Path > getFilesWithCachedAST() const
Returns a list of files with ASTs currently stored in memory.
PathRef FileName
void wait(std::unique_lock< std::mutex > &Lock, std::condition_variable &CV, Deadline D)
Wait once on CV for the specified duration.
Definition: Threading.cpp:107
Runs tasks on separate (detached) threads and wait for all tasks to finish.
Definition: Threading.h:105
std::string Name
unsigned getDefaultAsyncThreadsCount()
Returns a number of a default async threads to use for TUScheduler.
WithContext replaces Context::current() with a provided scope.
Definition: Context.h:189
std::string Contents
Latest inputs, passed to TUScheduler::update().
Information required to run clang, e.g. to parse AST or do code completion.
Definition: Compiler.h:44
ASTCache(unsigned MaxRetainedASTs)
Definition: TUScheduler.cpp:91
const PreambleData * Preamble
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static Deadline zero()
Definition: Threading.h:62
Context derive(const Key< Type > &Key, typename std::decay< Type >::type Value) const &
Derives a child context It is safe to move or destroy a parent context after calling derive()...
Definition: Context.h:121
llvm::Optional< std::unique_ptr< ParsedAST > > take(Key K)
Returns the cached value for K, or llvm::None if the value is not in the cache anymore.
steady_clock::time_point AddTime
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
Definition: Compiler.cpp:44
static clang::clangd::Key< std::string > kFileBeingProcessed
Definition: TUScheduler.cpp:75
void runWithAST(llvm::StringRef Name, PathRef File, Callback< InputsAndAST > Action)
Schedule an async read of the AST.
A point in time we can wait for.
Definition: Threading.h:58
const Expr * E
Clangd extension: indicates the current state of the file in clangd, sent from server via the textDoc...
Definition: Protocol.h:1202
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
An LRU cache of idle ASTs.
Definition: TUScheduler.cpp:87
llvm::StringRef getContents(PathRef File) const
Returns the current contents of the buffer for File, per last update().
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:81
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
Definition: Trace.h:97
Diagnostics must not be generated for this snapshot.
The preamble is generated from the current version of the file.
Definition: TUScheduler.h:206
llvm::StringMap< std::string > getAllFileContents() const
Returns a snapshot of all file buffer contents, per last update().
std::size_t getUsedBytes(Key K)
Returns result of getUsedBytes() for the AST cached by K.
Definition: TUScheduler.cpp:95
void run(llvm::StringRef Name, llvm::unique_function< void()> Action)
Schedule an async task with no dependencies.