49 #include "clang/Frontend/CompilerInvocation.h" 50 #include "clang/Frontend/PCHContainerOperations.h" 51 #include "llvm/ADT/ScopeExit.h" 52 #include "llvm/Support/Errc.h" 53 #include "llvm/Support/Path.h" 61 using std::chrono::steady_clock;
71 return llvm::StringRef(*
File);
81 using Key =
const ASTWorker *;
83 ASTCache(
unsigned MaxRetainedASTs) : MaxRetainedASTs(MaxRetainedASTs) {}
88 std::lock_guard<std::mutex> Lock(Mut);
89 auto It = findByKey(K);
90 if (It == LRU.end() || !It->second)
92 return It->second->getUsedBytes();
97 void put(
Key K, std::unique_ptr<ParsedAST> V) {
98 std::unique_lock<std::mutex> Lock(Mut);
99 assert(findByKey(K) == LRU.end());
101 LRU.insert(LRU.begin(), {K, std::move(V)});
102 if (LRU.size() <= MaxRetainedASTs)
105 std::unique_ptr<ParsedAST> ForCleanup = std::move(LRU.back().second);
115 llvm::Optional<std::unique_ptr<ParsedAST>>
take(
Key K) {
116 std::unique_lock<std::mutex> Lock(Mut);
117 auto Existing = findByKey(K);
118 if (Existing == LRU.end())
120 std::unique_ptr<ParsedAST> V = std::move(Existing->second);
125 return llvm::Optional<std::unique_ptr<ParsedAST>>(std::move(V));
129 using KVPair = std::pair<Key, std::unique_ptr<ParsedAST>>;
131 std::vector<KVPair>::iterator findByKey(
Key K) {
132 return llvm::find_if(LRU, [K](
const KVPair &P) {
return P.first == K; });
136 unsigned MaxRetainedASTs;
139 std::vector<KVPair> LRU;
143 class ASTWorkerHandle;
156 friend class ASTWorkerHandle;
159 steady_clock::duration UpdateDebounce,
160 std::shared_ptr<PCHContainerOperations>
PCHs,
169 static ASTWorkerHandle create(
PathRef FileName,
172 steady_clock::duration UpdateDebounce,
173 std::shared_ptr<PCHContainerOperations> PCHs,
174 bool StorePreamblesInMemory,
181 llvm::unique_function<
void(llvm::Expected<InputsAndAST>)>
Action);
184 std::shared_ptr<const PreambleData> getPossiblyStalePreamble()
const;
187 void getCurrentPreamble(
188 llvm::unique_function<
void(std::shared_ptr<const PreambleData>)>);
193 void waitForFirstPreamble()
const;
195 std::size_t getUsedBytes()
const;
196 bool isASTCached()
const;
206 void startTask(llvm::StringRef Name, llvm::unique_function<
void()> Task,
218 bool shouldSkipHeadLocked()
const;
229 TUScheduler::ASTCache &IdleASTs;
232 const steady_clock::duration UpdateDebounce;
236 const bool StorePreambleInMemory;
238 ParsingCallbacks &Callbacks;
240 const std::shared_ptr<PCHContainerOperations>
PCHs;
246 ParseInputs FileInputs;
249 bool DiagsWereReported =
false;
252 mutable std::mutex Mutex;
253 std::shared_ptr<const PreambleData> LastBuiltPreamble;
255 Notification PreambleWasBuilt;
258 std::deque<Request> Requests;
259 mutable std::condition_variable RequestsCV;
268 bool ReportDiagnostics =
true;
275 class ASTWorkerHandle {
276 friend class ASTWorker;
277 ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)
278 : Worker(std::move(Worker)) {
279 assert(this->Worker);
283 ASTWorkerHandle(
const ASTWorkerHandle &) =
delete;
284 ASTWorkerHandle &operator=(
const ASTWorkerHandle &) =
delete;
285 ASTWorkerHandle(ASTWorkerHandle &&) =
default;
286 ASTWorkerHandle &operator=(ASTWorkerHandle &&) =
default;
293 ASTWorker &operator*() {
294 assert(Worker &&
"Handle was moved from");
298 ASTWorker *operator->() {
299 assert(Worker &&
"Handle was moved from");
307 std::shared_ptr<const ASTWorker> lock() {
return Worker; }
310 std::shared_ptr<ASTWorker> Worker;
314 TUScheduler::ASTCache &IdleASTs,
315 AsyncTaskRunner *Tasks, Semaphore &Barrier,
316 steady_clock::duration UpdateDebounce,
317 std::shared_ptr<PCHContainerOperations>
PCHs,
318 bool StorePreamblesInMemory,
319 ParsingCallbacks &Callbacks) {
320 std::shared_ptr<ASTWorker> Worker(
new ASTWorker(
321 FileName, IdleASTs, Barrier, !Tasks, UpdateDebounce,
322 std::move(PCHs), StorePreamblesInMemory, Callbacks));
324 Tasks->runAsync(
"worker:" + llvm::sys::path::filename(FileName),
325 [Worker]() { Worker->run(); });
327 return ASTWorkerHandle(std::move(Worker));
330 ASTWorker::ASTWorker(
PathRef FileName, TUScheduler::ASTCache &LRUCache,
331 Semaphore &Barrier,
bool RunSync,
332 steady_clock::duration UpdateDebounce,
333 std::shared_ptr<PCHContainerOperations> PCHs,
334 bool StorePreamblesInMemory, ParsingCallbacks &Callbacks)
335 : IdleASTs(LRUCache), RunSync(RunSync), UpdateDebounce(UpdateDebounce),
336 FileName(FileName), StorePreambleInMemory(StorePreamblesInMemory),
337 Callbacks(Callbacks),
339 TUStatus::BuildDetails()},
340 Barrier(Barrier), Done(
false) {}
342 ASTWorker::~ASTWorker() {
346 std::lock_guard<std::mutex> Lock(Mutex);
347 assert(Done &&
"handle was not destroyed");
348 assert(Requests.empty() &&
"unprocessed requests when destroying ASTWorker");
352 void ASTWorker::update(ParseInputs Inputs,
WantDiagnostics WantDiags) {
353 llvm::StringRef TaskName =
"Update";
354 auto Task = [=]()
mutable {
356 bool InputsAreTheSame =
357 std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
358 std::tie(Inputs.CompileCommand, Inputs.Contents);
360 tooling::CompileCommand OldCommand = std::move(FileInputs.CompileCommand);
361 bool PrevDiagsWereReported = DiagsWereReported;
363 DiagsWereReported =
false;
365 log(
"Updating file {0} with command [{1}] {2}", FileName,
366 Inputs.CompileCommand.Directory,
367 llvm::join(Inputs.CompileCommand.CommandLine,
" "));
369 std::unique_ptr<CompilerInvocation> Invocation =
372 elog(
"Could not build CompilerInvocation for file {0}", FileName);
375 TUStatus::BuildDetails Details;
376 Details.BuildFailed =
true;
380 PreambleWasBuilt.notify();
384 std::shared_ptr<const PreambleData> OldPreamble =
385 getPossiblyStalePreamble();
386 std::shared_ptr<const PreambleData> NewPreamble =
buildPreamble(
387 FileName, *Invocation, OldPreamble, OldCommand, Inputs, PCHs,
388 StorePreambleInMemory,
389 [
this](ASTContext &
Ctx, std::shared_ptr<clang::Preprocessor> PP) {
390 Callbacks.onPreambleAST(FileName, Ctx, std::move(PP));
393 bool CanReuseAST = InputsAreTheSame && (OldPreamble == NewPreamble);
395 std::lock_guard<std::mutex> Lock(Mutex);
396 LastBuiltPreamble = NewPreamble;
402 PreambleWasBuilt.notify();
409 if (PrevDiagsWereReported) {
410 DiagsWereReported =
true;
418 log(
"Skipping rebuild of the AST for {0}, inputs are the same.",
420 TUStatus::BuildDetails Details;
421 Details.ReuseAST =
true;
432 std::lock_guard<std::mutex> Lock(DiagsMu);
435 if (!ReportDiagnostics)
440 llvm::Optional<std::unique_ptr<ParsedAST>>
AST = IdleASTs.take(
this);
442 llvm::Optional<ParsedAST> NewAST =
443 buildAST(FileName, std::move(Invocation), Inputs, NewPreamble, PCHs);
444 AST = NewAST ? llvm::make_unique<ParsedAST>(std::move(*NewAST)) :
nullptr;
446 TUStatus::BuildDetails Details;
447 Details.BuildFailed =
true;
452 TUStatus::BuildDetails Details;
453 Details.ReuseAST =
true;
462 std::lock_guard<std::mutex> Lock(DiagsMu);
463 if (ReportDiagnostics)
464 Callbacks.onDiagnostics(FileName, (*AST)->getDiagnostics());
466 trace::Span Span(
"Running main AST callback");
467 Callbacks.onMainAST(FileName, **AST);
468 DiagsWereReported =
true;
471 IdleASTs.put(
this, std::move(*AST));
473 startTask(TaskName, std::move(Task), WantDiags);
476 void ASTWorker::runWithAST(
477 llvm::StringRef
Name,
478 llvm::unique_function<
void(llvm::Expected<InputsAndAST>)>
Action) {
481 return Action(llvm::make_error<CancelledError>());
482 llvm::Optional<std::unique_ptr<ParsedAST>>
AST = IdleASTs.take(
this);
484 std::unique_ptr<CompilerInvocation> Invocation =
487 llvm::Optional<ParsedAST> NewAST =
490 llvm::make_unique<CompilerInvocation>(*Invocation),
491 FileInputs, getPossiblyStalePreamble(), PCHs)
493 AST = NewAST ? llvm::make_unique<ParsedAST>(std::move(*NewAST)) :
nullptr;
496 auto _ = llvm::make_scope_exit(
497 [&AST,
this]() { IdleASTs.put(
this, std::move(*AST)); });
500 return Action(llvm::make_error<llvm::StringError>(
501 "invalid AST", llvm::errc::invalid_argument));
502 Action(InputsAndAST{FileInputs, **AST});
504 startTask(Name,
Bind(Task, std::move(
Action)),
508 std::shared_ptr<const PreambleData>
509 ASTWorker::getPossiblyStalePreamble()
const {
510 std::lock_guard<std::mutex> Lock(Mutex);
511 return LastBuiltPreamble;
514 void ASTWorker::getCurrentPreamble(
515 llvm::unique_function<
void(std::shared_ptr<const PreambleData>)>
Callback) {
519 std::unique_lock<std::mutex> Lock(Mutex);
521 std::find_if(Requests.rbegin(), Requests.rend(),
522 [](
const Request &R) {
return R.UpdateType.hasValue(); });
524 if (LastUpdate == Requests.rend()) {
526 return Callback(getPossiblyStalePreamble());
528 assert(!RunSync &&
"Running synchronously, but queue is non-empty!");
529 Requests.insert(LastUpdate.base(),
532 Callback(getPossiblyStalePreamble());
534 std::move(Callback)),
535 "GetPreamble", steady_clock::now(),
539 RequestsCV.notify_all();
542 void ASTWorker::waitForFirstPreamble()
const { PreambleWasBuilt.wait(); }
544 std::size_t ASTWorker::getUsedBytes()
const {
548 std::size_t
Result = IdleASTs.getUsedBytes(
this);
549 if (
auto Preamble = getPossiblyStalePreamble())
550 Result +=
Preamble->Preamble.getSize();
554 bool ASTWorker::isASTCached()
const {
return IdleASTs.getUsedBytes(
this) != 0; }
556 void ASTWorker::stop() {
558 std::lock_guard<std::mutex> Lock(DiagsMu);
559 ReportDiagnostics =
false;
562 std::lock_guard<std::mutex> Lock(Mutex);
563 assert(!Done &&
"stop() called twice");
566 RequestsCV.notify_all();
569 void ASTWorker::startTask(llvm::StringRef Name,
570 llvm::unique_function<
void()> Task,
573 assert(!Done &&
"running a task after stop()");
574 trace::Span Tracer(Name +
":" + llvm::sys::path::filename(FileName));
580 std::lock_guard<std::mutex> Lock(Mutex);
581 assert(!Done &&
"running a task after stop()");
583 {std::move(Task),
Name, steady_clock::now(),
586 RequestsCV.notify_all();
589 void ASTWorker::emitTUStatus(TUAction
Action,
590 const TUStatus::BuildDetails *Details) {
591 Status.Action = std::move(Action);
593 Status.Details = *Details;
594 std::lock_guard<std::mutex> Lock(DiagsMu);
596 if (ReportDiagnostics) {
597 Callbacks.onFileUpdated(FileName, Status);
601 void ASTWorker::run() {
605 std::unique_lock<std::mutex> Lock(Mutex);
606 for (
auto Wait = scheduleLocked(); !Wait.expired();
607 Wait = scheduleLocked()) {
609 if (Requests.empty())
616 llvm::Optional<WithContext>
Ctx;
617 llvm::Optional<trace::Span> Tracer;
618 if (!Requests.empty()) {
619 Ctx.emplace(Requests.front().Ctx.clone());
620 Tracer.emplace(
"Debounce");
621 SPAN_ATTACH(*Tracer,
"next_request", Requests.front().Name);
625 std::chrono::duration_cast<std::chrono::milliseconds>(
626 Wait.time() - steady_clock::now())
631 wait(Lock, RequestsCV, Wait);
633 Req = std::move(Requests.front());
638 std::unique_lock<Semaphore> Lock(Barrier, std::try_to_lock);
639 if (!Lock.owns_lock()) {
643 WithContext Guard(std::move(Req.Ctx));
644 trace::Span Tracer(Req.Name);
649 bool IsEmpty =
false;
651 std::lock_guard<std::mutex> Lock(Mutex);
652 Requests.pop_front();
653 IsEmpty = Requests.empty();
657 RequestsCV.notify_all();
661 Deadline ASTWorker::scheduleLocked() {
662 if (Requests.empty())
665 for (
auto I = Requests.begin(), E = Requests.end(); I != E; ++I) {
668 if (I->UpdateType ==
None)
673 if (I->UpdateType ==
None) {
674 Request R = std::move(*I);
676 Requests.push_front(std::move(R));
684 while (shouldSkipHeadLocked())
685 Requests.pop_front();
686 assert(!Requests.empty() &&
"skipped the whole queue");
691 for (
const auto &R : Requests)
695 Deadline
D(Requests.front().AddTime + UpdateDebounce);
700 bool ASTWorker::shouldSkipHeadLocked()
const {
701 assert(!Requests.empty());
702 auto Next = Requests.begin();
703 auto UpdateType = Next->UpdateType;
709 if (Next == Requests.end() || !Next->UpdateType)
712 switch (*UpdateType) {
719 for (; Next != Requests.end(); ++Next)
725 llvm_unreachable(
"Unknown WantDiagnostics");
728 bool ASTWorker::blockUntilIdle(Deadline Timeout)
const {
729 std::unique_lock<std::mutex> Lock(Mutex);
730 return wait(Lock, RequestsCV, Timeout, [&] {
return Requests.empty(); });
737 std::string renderTUAction(
const TUAction &Action) {
739 llvm::raw_string_ostream OS(Result);
742 OS <<
"file is queued";
745 OS <<
"running " << Action.Name;
748 OS <<
"parsing includes";
751 OS <<
"parsing main file";
763 unsigned HardwareConcurrency = std::thread::hardware_concurrency();
767 if (HardwareConcurrency == 0)
769 return HardwareConcurrency;
787 bool StorePreamblesInMemory,
788 std::unique_ptr<ParsingCallbacks> Callbacks,
789 std::chrono::steady_clock::duration UpdateDebounce,
791 : StorePreamblesInMemory(StorePreamblesInMemory),
792 PCHOps(std::make_shared<PCHContainerOperations>()),
793 Callbacks(Callbacks ? move(Callbacks)
795 Barrier(AsyncThreadsCount),
796 IdleASTs(
llvm::make_unique<
ASTCache>(RetentionPolicy.MaxRetainedASTs)),
797 UpdateDebounce(UpdateDebounce) {
798 if (0 < AsyncThreadsCount) {
799 PreambleTasks.emplace();
800 WorkerThreads.emplace();
810 PreambleTasks->wait();
812 WorkerThreads->wait();
816 for (
auto &
File : Files)
817 if (!
File.getValue()->Worker->blockUntilIdle(D))
820 if (!PreambleTasks->wait(D))
827 std::unique_ptr<FileData> &FD = Files[
File];
830 ASTWorkerHandle Worker = ASTWorker::create(
831 File, *IdleASTs, WorkerThreads ? WorkerThreads.getPointer() :
nullptr,
832 Barrier, UpdateDebounce, PCHOps, StorePreamblesInMemory, *Callbacks);
833 FD = std::unique_ptr<FileData>(
new FileData{
839 FD->Worker->update(std::move(Inputs), WantDiags);
843 bool Removed = Files.erase(File);
845 elog(
"Trying to remove file from TUScheduler that is not tracked: {0}",
850 llvm::unique_function<
void()>
Action) {
853 PreambleTasks->runAsync(Name, std::move(
Action));
858 llvm::unique_function<
void(llvm::Expected<InputsAndAST>)>
Action) {
859 auto It = Files.find(File);
860 if (It == Files.end()) {
861 Action(llvm::make_error<LSPError>(
866 It->second->Worker->runWithAST(Name, std::move(
Action));
871 llvm::unique_function<
void(llvm::Expected<InputsAndPreamble>)>
Action) {
872 auto It = Files.find(File);
873 if (It == Files.end()) {
874 Action(llvm::make_error<LSPError>(
875 "trying to get preamble for non-added document",
880 if (!PreambleTasks) {
883 std::shared_ptr<const PreambleData>
Preamble =
884 It->second->Worker->getPossiblyStalePreamble();
891 std::future<std::shared_ptr<const PreambleData>> ConsistentPreamble;
893 std::promise<std::shared_ptr<const PreambleData>> Promise;
894 ConsistentPreamble = Promise.get_future();
895 It->second->Worker->getCurrentPreamble(
Bind(
896 [](decltype(Promise) Promise,
897 std::shared_ptr<const PreambleData>
Preamble) {
898 Promise.set_value(std::move(Preamble));
900 std::move(Promise)));
903 std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
904 auto Task = [Worker,
this](std::string
Name, std::string
File,
907 decltype(ConsistentPreamble) ConsistentPreamble,
909 std::shared_ptr<const PreambleData>
Preamble;
910 if (ConsistentPreamble.valid()) {
911 Preamble = ConsistentPreamble.get();
916 Worker->waitForFirstPreamble();
917 Preamble = Worker->getPossiblyStalePreamble();
920 std::lock_guard<Semaphore> BarrierLock(Barrier);
927 PreambleTasks->runAsync(
928 "task:" + llvm::sys::path::filename(File),
929 Bind(Task, std::string(Name), std::string(File), It->second->Contents,
932 std::move(ConsistentPreamble), std::move(
Action)));
935 std::vector<std::pair<Path, std::size_t>>
937 std::vector<std::pair<Path, std::size_t>>
Result;
938 Result.reserve(Files.size());
939 for (
auto &&PathAndFile : Files)
941 {PathAndFile.first(), PathAndFile.second->Worker->getUsedBytes()});
947 for (
auto &&PathAndFile : Files) {
948 if (!PathAndFile.second->Worker->isASTCached())
950 Result.push_back(PathAndFile.first());
PreambleConsistency
Controls whether preamble reads wait for the preamble to be up-to-date.
const tooling::CompileCommand & Command
WantDiagnostics
Determines whether diagnostics should be generated for a file snapshot.
Some operations such as code completion produce a set of candidates.
Diagnostics must be generated for this snapshot.
FileStatus render(PathRef File) const
Serialize this to an LSP file status item.
static llvm::Optional< llvm::StringRef > getFileBeingProcessedInContext()
bool blockUntilIdle(Deadline D) const
Wait until there are no scheduled or running tasks.
llvm::Optional< ParsedAST > buildAST(PathRef FileName, std::unique_ptr< CompilerInvocation > Invocation, const ParseInputs &Inputs, std::shared_ptr< const PreambleData > Preamble, std::shared_ptr< PCHContainerOperations > PCHs)
Build an AST from provided user inputs.
void remove(PathRef File)
Remove File from the list of tracked files and schedule removal of its resources. ...
std::string state
The human-readable string presents the current state of the file, can be shown in the UI (e...
llvm::StringRef PathRef
A typedef to represent a ref to file path.
void update(PathRef File, ParseInputs Inputs, WantDiagnostics WD)
Schedule an update for File.
Values in a Context are indexed by typed keys.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Documents should not be synced at all.
Limits the number of threads that can acquire the lock at the same time.
URIForFile uri
The text document's URI.
void elog(const char *Fmt, Ts &&... Vals)
TUScheduler(unsigned AsyncThreadsCount, bool StorePreamblesInMemory, std::unique_ptr< ParsingCallbacks > ASTCallbacks, std::chrono::steady_clock::duration UpdateDebounce, ASTRetentionPolicy RetentionPolicy)
Configuration of the AST retention policy.
bool isCancelled(const Context &Ctx)
True if the current context is within a cancelable task which was cancelled.
Context clone() const
Clone this context object.
ForwardBinder< Func, Args... > Bind(Func F, Args &&... As)
Creates an object that stores a callable (F) and first arguments to the callable (As) and allows to c...
llvm::Optional< WantDiagnostics > UpdateType
static Deadline infinity()
llvm::unique_function< void()> Action
void log(const char *Fmt, Ts &&... Vals)
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.
static const Context & current()
Returns the context for the current thread, creating it if needed.
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs)
Builds compiler invocation that could be used to build AST or preamble.
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
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.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
std::vector< Path > getFilesWithCachedAST() const
Returns a list of files with ASTs currently stored in memory.
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation &CI, std::shared_ptr< const PreambleData > OldPreamble, const tooling::CompileCommand &OldCompileCommand, const ParseInputs &Inputs, std::shared_ptr< PCHContainerOperations > PCHs, bool StoreInMemory, PreambleParsedCallback PreambleCallback)
Rebuild the preamble for the new inputs unless the old one can be reused.
void wait(std::unique_lock< std::mutex > &Lock, std::condition_variable &CV, Deadline D)
Wait once on CV for the specified duration.
Runs tasks on separate (detached) threads and wait for all tasks to finish.
A context is an immutable container for per-request data that must be propagated through layers that ...
unsigned getDefaultAsyncThreadsCount()
Returns a number of a default async threads to use for TUScheduler.
WithContext replaces Context::current() with a provided scope.
std::string Contents
Latest inputs, passed to TUScheduler::update().
ASTCache(unsigned MaxRetainedASTs)
const PreambleData * Preamble
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
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()...
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.
std::shared_ptr< PCHContainerOperations > PCHs
steady_clock::time_point AddTime
tooling::CompileCommand Command
static clang::clangd::Key< std::string > kFileBeingProcessed
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.
Clangd extension: indicates the current state of the file in clangd, sent from server via the textDoc...
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
An LRU cache of idle ASTs.
Records an event whose duration is the lifetime of the Span object.
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
Diagnostics must not be generated for this snapshot.
The preamble is generated from the current version of the file.
std::size_t getUsedBytes(Key K)
Returns result of getUsedBytes() for the AST cached by K.
void run(llvm::StringRef Name, llvm::unique_function< void()> Action)
Schedule an async task with no dependencies.