51 #include "clang/Frontend/CompilerInvocation.h" 52 #include "clang/Tooling/CompilationDatabase.h" 53 #include "llvm/ADT/Optional.h" 54 #include "llvm/ADT/ScopeExit.h" 55 #include "llvm/Support/Errc.h" 56 #include "llvm/Support/Path.h" 57 #include "llvm/Support/Threading.h" 65 using std::chrono::steady_clock;
75 return llvm::StringRef(*
File);
85 using Key =
const ASTWorker *;
87 ASTCache(
unsigned MaxRetainedASTs) : MaxRetainedASTs(MaxRetainedASTs) {}
92 std::lock_guard<std::mutex> Lock(Mut);
93 auto It = findByKey(K);
94 if (It == LRU.end() || !It->second)
96 return It->second->getUsedBytes();
101 void put(
Key K, std::unique_ptr<ParsedAST> V) {
102 std::unique_lock<std::mutex> Lock(Mut);
103 assert(findByKey(K) == LRU.end());
105 LRU.insert(LRU.begin(), {K, std::move(V)});
106 if (LRU.size() <= MaxRetainedASTs)
109 std::unique_ptr<ParsedAST> ForCleanup = std::move(LRU.back().second);
119 llvm::Optional<std::unique_ptr<ParsedAST>>
take(
Key K) {
120 std::unique_lock<std::mutex> Lock(Mut);
121 auto Existing = findByKey(K);
122 if (Existing == LRU.end())
124 std::unique_ptr<ParsedAST> V = std::move(Existing->second);
129 return llvm::Optional<std::unique_ptr<ParsedAST>>(std::move(V));
133 using KVPair = std::pair<Key, std::unique_ptr<ParsedAST>>;
135 std::vector<KVPair>::iterator findByKey(
Key K) {
136 return llvm::find_if(LRU, [K](
const KVPair &P) {
return P.first == K; });
140 unsigned MaxRetainedASTs;
143 std::vector<KVPair> LRU;
147 class ASTWorkerHandle;
160 friend class ASTWorkerHandle;
163 steady_clock::duration UpdateDebounce,
bool StorePreamblesInMemory,
172 static ASTWorkerHandle
175 Semaphore &Barrier, steady_clock::duration UpdateDebounce,
182 llvm::unique_function<
void(llvm::Expected<InputsAndAST>)>
Action);
185 std::shared_ptr<const PreambleData> getPossiblyStalePreamble()
const;
189 void getCurrentPreamble(
190 llvm::unique_function<
void(std::shared_ptr<const PreambleData>)>);
192 tooling::CompileCommand getCurrentCompileCommand()
const;
198 void waitForFirstPreamble()
const;
200 std::size_t getUsedBytes()
const;
201 bool isASTCached()
const;
211 void startTask(llvm::StringRef Name, llvm::unique_function<
void()> Task,
223 bool shouldSkipHeadLocked()
const;
227 std::shared_ptr<const ParseInputs> getCurrentFileInputs()
const;
238 TUScheduler::ASTCache &IdleASTs;
241 const steady_clock::duration UpdateDebounce;
244 const GlobalCompilationDatabase &CDB;
246 const bool StorePreambleInMemory;
248 ParsingCallbacks &Callbacks;
255 bool DiagsWereReported =
false;
257 mutable std::mutex Mutex;
261 std::shared_ptr<const ParseInputs> FileInputs;
262 std::shared_ptr<const PreambleData> LastBuiltPreamble;
264 Notification PreambleWasBuilt;
267 std::deque<Request> Requests;
268 mutable std::condition_variable RequestsCV;
277 bool ReportDiagnostics =
true;
284 class ASTWorkerHandle {
285 friend class ASTWorker;
286 ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)
287 : Worker(std::move(Worker)) {
288 assert(this->Worker);
292 ASTWorkerHandle(
const ASTWorkerHandle &) =
delete;
293 ASTWorkerHandle &operator=(
const ASTWorkerHandle &) =
delete;
294 ASTWorkerHandle(ASTWorkerHandle &&) =
default;
295 ASTWorkerHandle &operator=(ASTWorkerHandle &&) =
default;
302 ASTWorker &operator*() {
303 assert(Worker &&
"Handle was moved from");
307 ASTWorker *operator->() {
308 assert(Worker &&
"Handle was moved from");
316 std::shared_ptr<const ASTWorker> lock() {
return Worker; }
319 std::shared_ptr<ASTWorker> Worker;
323 ASTWorker::create(
PathRef FileName,
const GlobalCompilationDatabase &CDB,
324 TUScheduler::ASTCache &IdleASTs, AsyncTaskRunner *Tasks,
325 Semaphore &Barrier, steady_clock::duration UpdateDebounce,
326 bool StorePreamblesInMemory, ParsingCallbacks &Callbacks) {
327 std::shared_ptr<ASTWorker> Worker(
328 new ASTWorker(FileName, CDB, IdleASTs, Barrier, !Tasks,
329 UpdateDebounce, StorePreamblesInMemory, Callbacks));
331 Tasks->runAsync(
"worker:" + llvm::sys::path::filename(FileName),
332 [Worker]() { Worker->run(); });
334 return ASTWorkerHandle(std::move(Worker));
337 ASTWorker::ASTWorker(
PathRef FileName,
const GlobalCompilationDatabase &CDB,
338 TUScheduler::ASTCache &LRUCache, Semaphore &Barrier,
339 bool RunSync, steady_clock::duration UpdateDebounce,
340 bool StorePreamblesInMemory, ParsingCallbacks &Callbacks)
341 : IdleASTs(LRUCache), RunSync(RunSync), UpdateDebounce(UpdateDebounce),
342 FileName(FileName), CDB(CDB),
343 StorePreambleInMemory(StorePreamblesInMemory),
345 TUStatus::BuildDetails()},
346 Barrier(Barrier), Done(
false) {
347 auto Inputs = std::make_shared<ParseInputs>();
351 Inputs->CompileCommand = CDB.getFallbackCommand(FileName);
352 FileInputs = std::move(Inputs);
355 ASTWorker::~ASTWorker() {
359 std::lock_guard<std::mutex> Lock(Mutex);
360 assert(Done &&
"handle was not destroyed");
361 assert(Requests.empty() &&
"unprocessed requests when destroying ASTWorker");
365 void ASTWorker::update(ParseInputs Inputs,
WantDiagnostics WantDiags) {
366 llvm::StringRef TaskName =
"Update";
367 auto Task = [=]()
mutable {
373 if (
auto Cmd = CDB.getCompileCommand(FileName))
374 Inputs.CompileCommand = *Cmd;
377 Inputs.CompileCommand = CDB.getFallbackCommand(FileName);
378 auto PrevInputs = getCurrentFileInputs();
380 bool InputsAreTheSame =
381 std::tie(PrevInputs->CompileCommand, PrevInputs->Contents) ==
382 std::tie(Inputs.CompileCommand, Inputs.Contents);
384 tooling::CompileCommand OldCommand = PrevInputs->CompileCommand;
385 bool PrevDiagsWereReported = DiagsWereReported;
387 std::lock_guard<std::mutex> Lock(Mutex);
388 FileInputs = std::make_shared<ParseInputs>(Inputs);
390 DiagsWereReported =
false;
392 log(
"Updating file {0} with command {1}\n[{2}]\n{3}", FileName,
393 Inputs.CompileCommand.Heuristic,
394 Inputs.CompileCommand.Directory,
395 llvm::join(Inputs.CompileCommand.CommandLine,
" "));
397 std::unique_ptr<CompilerInvocation> Invocation =
400 elog(
"Could not build CompilerInvocation for file {0}", FileName);
403 TUStatus::BuildDetails Details;
404 Details.BuildFailed =
true;
408 PreambleWasBuilt.notify();
412 std::shared_ptr<const PreambleData> OldPreamble =
413 getPossiblyStalePreamble();
414 std::shared_ptr<const PreambleData> NewPreamble =
buildPreamble(
415 FileName, *Invocation, OldPreamble, OldCommand, Inputs,
416 StorePreambleInMemory,
417 [
this](ASTContext &
Ctx, std::shared_ptr<clang::Preprocessor> PP,
418 const CanonicalIncludes &CanonIncludes) {
419 Callbacks.onPreambleAST(FileName, Ctx, std::move(PP), CanonIncludes);
422 bool CanReuseAST = InputsAreTheSame && (OldPreamble == NewPreamble);
424 std::lock_guard<std::mutex> Lock(Mutex);
425 LastBuiltPreamble = NewPreamble;
431 PreambleWasBuilt.notify();
438 if (PrevDiagsWereReported) {
439 DiagsWereReported =
true;
447 log(
"Skipping rebuild of the AST for {0}, inputs are the same.",
449 TUStatus::BuildDetails Details;
450 Details.ReuseAST =
true;
461 std::lock_guard<std::mutex> Lock(DiagsMu);
464 if (!ReportDiagnostics)
469 llvm::Optional<std::unique_ptr<ParsedAST>>
AST = IdleASTs.take(
this);
471 llvm::Optional<ParsedAST> NewAST =
472 buildAST(FileName, std::move(Invocation), Inputs, NewPreamble);
473 AST = NewAST ? llvm::make_unique<ParsedAST>(std::move(*NewAST)) :
nullptr;
475 TUStatus::BuildDetails Details;
476 Details.BuildFailed =
true;
481 TUStatus::BuildDetails Details;
482 Details.ReuseAST =
true;
491 std::lock_guard<std::mutex> Lock(DiagsMu);
492 if (ReportDiagnostics)
493 Callbacks.onDiagnostics(FileName, (*AST)->getDiagnostics());
495 trace::Span Span(
"Running main AST callback");
496 Callbacks.onMainAST(FileName, **AST);
497 DiagsWereReported =
true;
500 IdleASTs.put(
this, std::move(*AST));
502 startTask(TaskName, std::move(Task), WantDiags);
505 void ASTWorker::runWithAST(
506 llvm::StringRef
Name,
507 llvm::unique_function<
void(llvm::Expected<InputsAndAST>)>
Action) {
510 return Action(llvm::make_error<CancelledError>());
511 llvm::Optional<std::unique_ptr<ParsedAST>>
AST = IdleASTs.take(
this);
512 auto CurrentInputs = getCurrentFileInputs();
514 std::unique_ptr<CompilerInvocation> Invocation =
517 llvm::Optional<ParsedAST> NewAST =
520 llvm::make_unique<CompilerInvocation>(*Invocation),
521 *CurrentInputs, getPossiblyStalePreamble())
523 AST = NewAST ? llvm::make_unique<ParsedAST>(std::move(*NewAST)) :
nullptr;
526 auto _ = llvm::make_scope_exit(
527 [&AST,
this]() { IdleASTs.put(
this, std::move(*AST)); });
530 return Action(llvm::make_error<llvm::StringError>(
531 "invalid AST", llvm::errc::invalid_argument));
532 Action(InputsAndAST{*CurrentInputs, **AST});
534 startTask(Name,
Bind(Task, std::move(
Action)),
538 std::shared_ptr<const PreambleData>
539 ASTWorker::getPossiblyStalePreamble()
const {
540 std::lock_guard<std::mutex> Lock(Mutex);
541 return LastBuiltPreamble;
544 void ASTWorker::getCurrentPreamble(
545 llvm::unique_function<
void(std::shared_ptr<const PreambleData>)>
Callback) {
549 std::unique_lock<std::mutex> Lock(Mutex);
551 std::find_if(Requests.rbegin(), Requests.rend(),
552 [](
const Request &R) {
return R.UpdateType.hasValue(); });
554 if (LastUpdate == Requests.rend()) {
556 return Callback(getPossiblyStalePreamble());
558 assert(!RunSync &&
"Running synchronously, but queue is non-empty!");
559 Requests.insert(LastUpdate.base(),
562 Callback(getPossiblyStalePreamble());
564 std::move(Callback)),
565 "GetPreamble", steady_clock::now(),
569 RequestsCV.notify_all();
572 void ASTWorker::waitForFirstPreamble()
const { PreambleWasBuilt.wait(); }
574 std::shared_ptr<const ParseInputs> ASTWorker::getCurrentFileInputs()
const {
575 std::unique_lock<std::mutex> Lock(Mutex);
579 tooling::CompileCommand ASTWorker::getCurrentCompileCommand()
const {
580 std::unique_lock<std::mutex> Lock(Mutex);
581 return FileInputs->CompileCommand;
584 std::size_t ASTWorker::getUsedBytes()
const {
588 std::size_t
Result = IdleASTs.getUsedBytes(
this);
589 if (
auto Preamble = getPossiblyStalePreamble())
590 Result +=
Preamble->Preamble.getSize();
594 bool ASTWorker::isASTCached()
const {
return IdleASTs.getUsedBytes(
this) != 0; }
596 void ASTWorker::stop() {
598 std::lock_guard<std::mutex> Lock(DiagsMu);
599 ReportDiagnostics =
false;
602 std::lock_guard<std::mutex> Lock(Mutex);
603 assert(!Done &&
"stop() called twice");
606 RequestsCV.notify_all();
609 void ASTWorker::startTask(llvm::StringRef Name,
610 llvm::unique_function<
void()> Task,
613 assert(!Done &&
"running a task after stop()");
614 trace::Span Tracer(Name +
":" + llvm::sys::path::filename(FileName));
620 std::lock_guard<std::mutex> Lock(Mutex);
621 assert(!Done &&
"running a task after stop()");
623 {std::move(Task),
Name, steady_clock::now(),
626 RequestsCV.notify_all();
629 void ASTWorker::emitTUStatus(TUAction
Action,
630 const TUStatus::BuildDetails *Details) {
631 Status.Action = std::move(Action);
633 Status.Details = *Details;
634 std::lock_guard<std::mutex> Lock(DiagsMu);
636 if (ReportDiagnostics) {
637 Callbacks.onFileUpdated(FileName, Status);
641 void ASTWorker::run() {
645 std::unique_lock<std::mutex> Lock(Mutex);
646 for (
auto Wait = scheduleLocked(); !Wait.expired();
647 Wait = scheduleLocked()) {
649 if (Requests.empty())
656 llvm::Optional<WithContext>
Ctx;
657 llvm::Optional<trace::Span> Tracer;
658 if (!Requests.empty()) {
659 Ctx.emplace(Requests.front().Ctx.clone());
660 Tracer.emplace(
"Debounce");
661 SPAN_ATTACH(*Tracer,
"next_request", Requests.front().Name);
665 std::chrono::duration_cast<std::chrono::milliseconds>(
666 Wait.time() - steady_clock::now())
671 wait(Lock, RequestsCV, Wait);
673 Req = std::move(Requests.front());
678 std::unique_lock<Semaphore> Lock(Barrier, std::try_to_lock);
679 if (!Lock.owns_lock()) {
683 WithContext Guard(std::move(Req.Ctx));
684 trace::Span Tracer(Req.Name);
689 bool IsEmpty =
false;
691 std::lock_guard<std::mutex> Lock(Mutex);
692 Requests.pop_front();
693 IsEmpty = Requests.empty();
697 RequestsCV.notify_all();
701 Deadline ASTWorker::scheduleLocked() {
702 if (Requests.empty())
705 for (
auto I = Requests.begin(), E = Requests.end(); I != E; ++I) {
708 if (I->UpdateType ==
None)
713 if (I->UpdateType ==
None) {
714 Request R = std::move(*I);
716 Requests.push_front(std::move(R));
724 while (shouldSkipHeadLocked())
725 Requests.pop_front();
726 assert(!Requests.empty() &&
"skipped the whole queue");
731 for (
const auto &R : Requests)
735 Deadline
D(Requests.front().AddTime + UpdateDebounce);
740 bool ASTWorker::shouldSkipHeadLocked()
const {
741 assert(!Requests.empty());
742 auto Next = Requests.begin();
743 auto UpdateType = Next->UpdateType;
749 if (Next == Requests.end() || !Next->UpdateType)
752 switch (*UpdateType) {
759 for (; Next != Requests.end(); ++Next)
765 llvm_unreachable(
"Unknown WantDiagnostics");
768 bool ASTWorker::blockUntilIdle(Deadline Timeout)
const {
769 std::unique_lock<std::mutex> Lock(Mutex);
770 return wait(Lock, RequestsCV, Timeout, [&] {
return Requests.empty(); });
777 std::string renderTUAction(
const TUAction &Action) {
779 llvm::raw_string_ostream OS(Result);
782 OS <<
"file is queued";
785 OS <<
"running " << Action.Name;
788 OS <<
"parsing includes";
791 OS <<
"parsing main file";
803 unsigned HardwareConcurrency = llvm::heavyweight_hardware_concurrency();
807 if (HardwareConcurrency == 0)
809 return HardwareConcurrency;
826 unsigned AsyncThreadsCount,
827 bool StorePreamblesInMemory,
828 std::unique_ptr<ParsingCallbacks> Callbacks,
829 std::chrono::steady_clock::duration UpdateDebounce,
831 : CDB(CDB), StorePreamblesInMemory(StorePreamblesInMemory),
832 Callbacks(Callbacks ? move(Callbacks)
834 Barrier(AsyncThreadsCount),
835 IdleASTs(
llvm::make_unique<
ASTCache>(RetentionPolicy.MaxRetainedASTs)),
836 UpdateDebounce(UpdateDebounce) {
837 if (0 < AsyncThreadsCount) {
838 PreambleTasks.emplace();
839 WorkerThreads.emplace();
849 PreambleTasks->wait();
851 WorkerThreads->wait();
855 for (
auto &
File : Files)
856 if (!
File.getValue()->Worker->blockUntilIdle(D))
859 if (!PreambleTasks->wait(D))
866 std::unique_ptr<FileData> &FD = Files[
File];
867 bool NewFile = FD ==
nullptr;
870 ASTWorkerHandle Worker = ASTWorker::create(
871 File, CDB, *IdleASTs,
872 WorkerThreads ? WorkerThreads.getPointer() :
nullptr, Barrier,
873 UpdateDebounce, StorePreamblesInMemory, *Callbacks);
874 FD = std::unique_ptr<FileData>(
879 FD->Worker->update(std::move(Inputs), WantDiags);
884 bool Removed = Files.erase(File);
886 elog(
"Trying to remove file from TUScheduler that is not tracked: {0}",
891 auto It = Files.find(File);
892 if (It == Files.end()) {
893 elog(
"getContents() for untracked file: {0}", File);
896 return It->second->Contents;
900 llvm::unique_function<
void()>
Action) {
903 PreambleTasks->runAsync(Name, std::move(
Action));
908 llvm::unique_function<
void(llvm::Expected<InputsAndAST>)>
Action) {
909 auto It = Files.find(File);
910 if (It == Files.end()) {
911 Action(llvm::make_error<LSPError>(
916 It->second->Worker->runWithAST(Name, std::move(
Action));
922 auto It = Files.find(File);
923 if (It == Files.end()) {
924 Action(llvm::make_error<LSPError>(
925 "trying to get preamble for non-added document",
930 if (!PreambleTasks) {
933 std::shared_ptr<const PreambleData>
Preamble =
934 It->second->Worker->getPossiblyStalePreamble();
936 It->second->Worker->getCurrentCompileCommand(),
942 std::future<std::shared_ptr<const PreambleData>> ConsistentPreamble;
944 std::promise<std::shared_ptr<const PreambleData>> Promise;
945 ConsistentPreamble = Promise.get_future();
946 It->second->Worker->getCurrentPreamble(
Bind(
947 [](decltype(Promise) Promise,
948 std::shared_ptr<const PreambleData>
Preamble) {
949 Promise.set_value(std::move(Preamble));
951 std::move(Promise)));
954 std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
955 auto Task = [Worker, Consistency,
958 decltype(ConsistentPreamble) ConsistentPreamble,
959 decltype(Action)
Action)
mutable {
960 std::shared_ptr<const PreambleData>
Preamble;
961 if (ConsistentPreamble.valid()) {
962 Preamble = ConsistentPreamble.get();
964 if (Consistency != PreambleConsistency::StaleOrAbsent) {
968 Worker->waitForFirstPreamble();
970 Preamble = Worker->getPossiblyStalePreamble();
973 std::lock_guard<Semaphore> BarrierLock(Barrier);
980 PreambleTasks->runAsync(
981 "task:" + llvm::sys::path::filename(File),
982 Bind(Task, std::string(Name), std::string(File), It->second->Contents,
983 Worker->getCurrentCompileCommand(),
985 std::move(ConsistentPreamble), std::move(Action)));
988 std::vector<std::pair<Path, std::size_t>>
990 std::vector<std::pair<Path, std::size_t>>
Result;
991 Result.reserve(Files.size());
992 for (
auto &&PathAndFile : Files)
994 {PathAndFile.first(), PathAndFile.second->Worker->getUsedBytes()});
1000 for (
auto &&PathAndFile : Files) {
1001 if (!PathAndFile.second->Worker->isASTCached())
1003 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.
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...
llvm::StringRef PathRef
A typedef to represent a ref to file path.
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.
bool update(PathRef File, ParseInputs Inputs, WantDiagnostics WD)
Schedule an update for File.
void elog(const char *Fmt, Ts &&... Vals)
Configuration of the AST retention policy.
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)
Rebuild the preamble for the new inputs unless the old one can be reused.
Provides compilation arguments used for parsing C and C++ files.
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.
llvm::Optional< ParsedAST > buildAST(PathRef FileName, std::unique_ptr< CompilerInvocation > Invocation, const ParseInputs &Inputs, std::shared_ptr< const PreambleData > Preamble)
Build an AST from provided user inputs.
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.
std::vector< Path > getFilesWithCachedAST() const
Returns a list of files with ASTs currently stored in memory.
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.
steady_clock::time_point AddTime
static clang::clangd::Key< std::string > kFileBeingProcessed
void runWithAST(llvm::StringRef Name, PathRef File, Callback< InputsAndAST > Action)
Schedule an async read of the AST.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
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.
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.
#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.