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" 69 using std::chrono::steady_clock;
79 return llvm::StringRef(*
File);
89 using Key =
const ASTWorker *;
91 ASTCache(
unsigned MaxRetainedASTs) : MaxRetainedASTs(MaxRetainedASTs) {}
96 std::lock_guard<std::mutex> Lock(Mut);
97 auto It = findByKey(K);
98 if (It == LRU.end() || !It->second)
100 return It->second->getUsedBytes();
105 void put(
Key K, std::unique_ptr<ParsedAST> V) {
106 std::unique_lock<std::mutex> Lock(Mut);
107 assert(findByKey(K) == LRU.end());
109 LRU.insert(LRU.begin(), {K, std::move(V)});
110 if (LRU.size() <= MaxRetainedASTs)
113 std::unique_ptr<ParsedAST> ForCleanup = std::move(LRU.back().second);
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())
128 std::unique_ptr<ParsedAST> V = std::move(Existing->second);
133 return llvm::Optional<std::unique_ptr<ParsedAST>>(std::move(V));
137 using KVPair = std::pair<Key, std::unique_ptr<ParsedAST>>;
139 std::vector<KVPair>::iterator findByKey(
Key K) {
140 return llvm::find_if(LRU, [K](
const KVPair &P) {
return P.first == K; });
144 unsigned MaxRetainedASTs;
147 std::vector<KVPair> LRU;
151 class ASTWorkerHandle;
164 friend class ASTWorkerHandle;
167 steady_clock::duration UpdateDebounce,
bool StorePreamblesInMemory,
176 static ASTWorkerHandle
179 Semaphore &Barrier, steady_clock::duration UpdateDebounce,
186 llvm::unique_function<
void(llvm::Expected<InputsAndAST>)>
Action);
189 std::shared_ptr<const PreambleData> getPossiblyStalePreamble()
const;
193 void getCurrentPreamble(
194 llvm::unique_function<
void(std::shared_ptr<const PreambleData>)>);
196 tooling::CompileCommand getCurrentCompileCommand()
const;
202 void waitForFirstPreamble()
const;
204 std::size_t getUsedBytes()
const;
205 bool isASTCached()
const;
215 void startTask(llvm::StringRef Name, llvm::unique_function<
void()> Task,
227 bool shouldSkipHeadLocked()
const;
231 std::shared_ptr<const ParseInputs> getCurrentFileInputs()
const;
242 TUScheduler::ASTCache &IdleASTs;
245 const steady_clock::duration UpdateDebounce;
248 const GlobalCompilationDatabase &CDB;
250 const bool StorePreambleInMemory;
252 ParsingCallbacks &Callbacks;
258 bool RanASTCallback =
false;
260 mutable std::mutex Mutex;
264 std::shared_ptr<const ParseInputs> FileInputs;
265 std::shared_ptr<const PreambleData> LastBuiltPreamble;
267 Notification PreambleWasBuilt;
270 std::deque<Request> Requests;
271 mutable std::condition_variable RequestsCV;
274 std::mutex PublishMu;
281 bool CanPublishResults =
true;
288 class ASTWorkerHandle {
289 friend class ASTWorker;
290 ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)
291 : Worker(std::move(Worker)) {
292 assert(this->Worker);
296 ASTWorkerHandle(
const ASTWorkerHandle &) =
delete;
297 ASTWorkerHandle &operator=(
const ASTWorkerHandle &) =
delete;
298 ASTWorkerHandle(ASTWorkerHandle &&) =
default;
299 ASTWorkerHandle &operator=(ASTWorkerHandle &&) =
default;
306 ASTWorker &operator*() {
307 assert(Worker &&
"Handle was moved from");
311 ASTWorker *operator->() {
312 assert(Worker &&
"Handle was moved from");
320 std::shared_ptr<const ASTWorker> lock() {
return Worker; }
323 std::shared_ptr<ASTWorker> Worker;
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, !Tasks,
333 UpdateDebounce, StorePreamblesInMemory, Callbacks));
335 Tasks->runAsync(
"worker:" + llvm::sys::path::filename(FileName),
336 [Worker]() { Worker->run(); });
338 return ASTWorkerHandle(std::move(Worker));
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),
349 TUStatus::BuildDetails()},
350 Barrier(Barrier), Done(
false) {
351 auto Inputs = std::make_shared<ParseInputs>();
355 Inputs->CompileCommand = CDB.getFallbackCommand(FileName);
356 FileInputs = std::move(Inputs);
359 ASTWorker::~ASTWorker() {
363 std::lock_guard<std::mutex> Lock(Mutex);
364 assert(Done &&
"handle was not destroyed");
365 assert(Requests.empty() &&
"unprocessed requests when destroying ASTWorker");
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) {
375 std::lock_guard<std::mutex> Lock(PublishMu);
376 if (CanPublishResults)
385 if (
auto Cmd = CDB.getCompileCommand(FileName))
386 Inputs.CompileCommand = *Cmd;
389 Inputs.CompileCommand = CDB.getFallbackCommand(FileName);
390 auto PrevInputs = getCurrentFileInputs();
392 bool InputsAreTheSame =
393 std::tie(PrevInputs->CompileCommand, PrevInputs->Contents) ==
394 std::tie(Inputs.CompileCommand, Inputs.Contents);
396 tooling::CompileCommand OldCommand = PrevInputs->CompileCommand;
397 bool RanCallbackForPrevInputs = RanASTCallback;
399 std::lock_guard<std::mutex> Lock(Mutex);
400 FileInputs = std::make_shared<ParseInputs>(Inputs);
402 RanASTCallback =
false;
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,
" "));
409 StoreDiags CompilerInvocationDiagConsumer;
410 std::vector<std::string> CC1Args;
412 Inputs, CompilerInvocationDiagConsumer, &CC1Args);
414 if (!CC1Args.empty())
415 vlog(
"Driver produced command: cc1 {0}",
llvm::join(CC1Args,
" "));
416 std::vector<Diag> CompilerInvocationDiags =
417 CompilerInvocationDiagConsumer.take();
419 elog(
"Could not build CompilerInvocation for file {0}", FileName);
422 TUStatus::BuildDetails Details;
423 Details.BuildFailed =
true;
426 Callbacks.onFailedAST(FileName, std::move(CompilerInvocationDiags),
430 PreambleWasBuilt.notify();
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);
444 bool CanReuseAST = InputsAreTheSame && (OldPreamble == NewPreamble);
446 std::lock_guard<std::mutex> Lock(Mutex);
447 LastBuiltPreamble = NewPreamble;
453 PreambleWasBuilt.notify();
459 if (RanCallbackForPrevInputs) {
460 RanASTCallback =
true;
468 log(
"Skipping rebuild of the AST for {0}, inputs are the same.",
470 TUStatus::BuildDetails Details;
471 Details.ReuseAST =
true;
482 std::lock_guard<std::mutex> Lock(PublishMu);
485 if (!CanPublishResults)
490 llvm::Optional<std::unique_ptr<ParsedAST>>
AST = IdleASTs.take(
this);
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;
497 TUStatus::BuildDetails Details;
498 Details.BuildFailed =
true;
503 TUStatus::BuildDetails Details;
504 Details.ReuseAST =
true;
513 trace::Span Span(
"Running main AST callback");
515 Callbacks.onMainAST(FileName, **AST, RunPublish);
516 RanASTCallback =
true;
522 Callbacks.onFailedAST(FileName, CompilerInvocationDiags, RunPublish);
525 IdleASTs.put(
this, std::move(*AST));
527 startTask(TaskName, std::move(Task), WantDiags);
530 void ASTWorker::runWithAST(
531 llvm::StringRef
Name,
532 llvm::unique_function<
void(llvm::Expected<InputsAndAST>)>
Action) {
535 return Action(llvm::make_error<CancelledError>());
536 llvm::Optional<std::unique_ptr<ParsedAST>>
AST = IdleASTs.take(
this);
537 auto CurrentInputs = getCurrentFileInputs();
539 StoreDiags CompilerInvocationDiagConsumer;
541 *CurrentInputs, CompilerInvocationDiagConsumer);
543 llvm::Optional<ParsedAST> NewAST =
546 std::make_unique<CompilerInvocation>(*Invocation),
547 CompilerInvocationDiagConsumer.take(), *CurrentInputs,
548 getPossiblyStalePreamble())
550 AST = NewAST ? std::make_unique<ParsedAST>(std::move(*NewAST)) :
nullptr;
553 auto _ = llvm::make_scope_exit(
554 [&AST,
this]() { IdleASTs.put(
this, std::move(*AST)); });
557 return Action(llvm::make_error<llvm::StringError>(
558 "invalid AST", llvm::errc::invalid_argument));
559 Action(InputsAndAST{*CurrentInputs, **AST});
561 startTask(Name, std::move(Task),
None);
564 std::shared_ptr<const PreambleData>
565 ASTWorker::getPossiblyStalePreamble()
const {
566 std::lock_guard<std::mutex> Lock(Mutex);
567 return LastBuiltPreamble;
570 void ASTWorker::getCurrentPreamble(
571 llvm::unique_function<
void(std::shared_ptr<const PreambleData>)>
Callback) {
575 std::unique_lock<std::mutex> Lock(Mutex);
577 std::find_if(Requests.rbegin(), Requests.rend(),
578 [](
const Request &R) {
return R.UpdateType.hasValue(); });
580 if (LastUpdate == Requests.rend()) {
582 return Callback(getPossiblyStalePreamble());
584 assert(!RunSync &&
"Running synchronously, but queue is non-empty!");
585 Requests.insert(LastUpdate.base(),
587 Callback(getPossiblyStalePreamble());
589 "GetPreamble", steady_clock::now(),
593 RequestsCV.notify_all();
596 void ASTWorker::waitForFirstPreamble()
const { PreambleWasBuilt.wait(); }
598 std::shared_ptr<const ParseInputs> ASTWorker::getCurrentFileInputs()
const {
599 std::unique_lock<std::mutex> Lock(Mutex);
603 tooling::CompileCommand ASTWorker::getCurrentCompileCommand()
const {
604 std::unique_lock<std::mutex> Lock(Mutex);
605 return FileInputs->CompileCommand;
608 std::size_t ASTWorker::getUsedBytes()
const {
612 std::size_t Result = IdleASTs.getUsedBytes(
this);
613 if (
auto Preamble = getPossiblyStalePreamble())
614 Result +=
Preamble->Preamble.getSize();
618 bool ASTWorker::isASTCached()
const {
return IdleASTs.getUsedBytes(
this) != 0; }
620 void ASTWorker::stop() {
622 std::lock_guard<std::mutex> Lock(PublishMu);
623 CanPublishResults =
false;
626 std::lock_guard<std::mutex> Lock(Mutex);
627 assert(!Done &&
"stop() called twice");
630 RequestsCV.notify_all();
633 void ASTWorker::startTask(llvm::StringRef Name,
634 llvm::unique_function<
void()> Task,
637 assert(!Done &&
"running a task after stop()");
638 trace::Span Tracer(Name +
":" + llvm::sys::path::filename(FileName));
644 std::lock_guard<std::mutex> Lock(Mutex);
645 assert(!Done &&
"running a task after stop()");
647 {std::move(Task),
Name, steady_clock::now(),
650 RequestsCV.notify_all();
653 void ASTWorker::emitTUStatus(TUAction
Action,
654 const TUStatus::BuildDetails *Details) {
655 Status.Action = std::move(Action);
657 Status.Details = *Details;
658 std::lock_guard<std::mutex> Lock(PublishMu);
660 if (CanPublishResults) {
661 Callbacks.onFileUpdated(FileName, Status);
665 void ASTWorker::run() {
669 std::unique_lock<std::mutex> Lock(Mutex);
670 for (
auto Wait = scheduleLocked(); !Wait.expired();
671 Wait = scheduleLocked()) {
673 if (Requests.empty())
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);
689 std::chrono::duration_cast<std::chrono::milliseconds>(
690 Wait.time() - steady_clock::now())
695 wait(Lock, RequestsCV, Wait);
697 Req = std::move(Requests.front());
702 std::unique_lock<Semaphore> Lock(Barrier, std::try_to_lock);
703 if (!Lock.owns_lock()) {
707 WithContext Guard(std::move(Req.Ctx));
708 trace::Span Tracer(Req.Name);
713 bool IsEmpty =
false;
715 std::lock_guard<std::mutex> Lock(Mutex);
716 Requests.pop_front();
717 IsEmpty = Requests.empty();
721 RequestsCV.notify_all();
725 Deadline ASTWorker::scheduleLocked() {
726 if (Requests.empty())
729 for (
auto I = Requests.begin(),
E = Requests.end(); I !=
E; ++I) {
732 if (I->UpdateType ==
None)
737 if (I->UpdateType ==
None) {
738 Request R = std::move(*I);
740 Requests.push_front(std::move(R));
748 while (shouldSkipHeadLocked())
749 Requests.pop_front();
750 assert(!Requests.empty() &&
"skipped the whole queue");
755 for (
const auto &R : Requests)
759 Deadline D(Requests.front().AddTime + UpdateDebounce);
764 bool ASTWorker::shouldSkipHeadLocked()
const {
765 assert(!Requests.empty());
766 auto Next = Requests.begin();
767 auto UpdateType = Next->UpdateType;
773 if (Next == Requests.end() || !Next->UpdateType)
776 switch (*UpdateType) {
783 for (; Next != Requests.end(); ++Next)
789 llvm_unreachable(
"Unknown WantDiagnostics");
792 bool ASTWorker::blockUntilIdle(Deadline Timeout)
const {
793 std::unique_lock<std::mutex> Lock(Mutex);
794 return wait(Lock, RequestsCV, Timeout, [&] {
return Requests.empty(); });
801 std::string renderTUAction(
const TUAction &Action) {
803 llvm::raw_string_ostream OS(Result);
806 OS <<
"file is queued";
809 OS <<
"running " << Action.Name;
812 OS <<
"parsing includes";
815 OS <<
"parsing main file";
827 unsigned HardwareConcurrency = llvm::heavyweight_hardware_concurrency();
831 if (HardwareConcurrency == 0)
833 return HardwareConcurrency;
850 unsigned AsyncThreadsCount,
851 bool StorePreamblesInMemory,
852 std::unique_ptr<ParsingCallbacks> Callbacks,
853 std::chrono::steady_clock::duration UpdateDebounce,
855 : CDB(CDB), StorePreamblesInMemory(StorePreamblesInMemory),
856 Callbacks(Callbacks ? move(Callbacks)
858 Barrier(AsyncThreadsCount),
859 IdleASTs(std::make_unique<
ASTCache>(RetentionPolicy.MaxRetainedASTs)),
860 UpdateDebounce(UpdateDebounce) {
861 if (0 < AsyncThreadsCount) {
862 PreambleTasks.emplace();
863 WorkerThreads.emplace();
873 PreambleTasks->wait();
875 WorkerThreads->wait();
879 for (
auto &
File : Files)
880 if (!
File.getValue()->Worker->blockUntilIdle(D))
883 if (!PreambleTasks->wait(D))
890 std::unique_ptr<FileData> &FD = Files[
File];
891 bool NewFile = FD ==
nullptr;
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>(
903 FD->Worker->update(std::move(Inputs), WantDiags);
908 bool Removed = Files.erase(File);
910 elog(
"Trying to remove file from TUScheduler that is not tracked: {0}",
915 auto It = Files.find(File);
916 if (It == Files.end()) {
917 elog(
"getContents() for untracked file: {0}", File);
920 return It->second->Contents;
924 llvm::StringMap<std::string>
Results;
925 for (
auto &It : Files)
926 Results.try_emplace(It.getKey(), It.getValue()->Contents);
931 llvm::unique_function<
void()>
Action) {
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>(
951 It->second->Worker->runWithAST(Name, std::move(
Action));
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",
965 if (!PreambleTasks) {
968 std::shared_ptr<const PreambleData>
Preamble =
969 It->second->Worker->getPossiblyStalePreamble();
971 It->second->Worker->getCurrentCompileCommand(),
977 std::future<std::shared_ptr<const PreambleData>> ConsistentPreamble;
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));
988 std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
989 auto Task = [Worker, Consistency, Name = Name.str(), File = File.str(),
991 Command = Worker->getCurrentCompileCommand(),
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();
999 if (Consistency != PreambleConsistency::StaleOrAbsent) {
1003 Worker->waitForFirstPreamble();
1005 Preamble = Worker->getPossiblyStalePreamble();
1008 std::lock_guard<Semaphore> BarrierLock(Barrier);
1015 PreambleTasks->runAsync(
"task:" + llvm::sys::path::filename(File),
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)
1025 {PathAndFile.first(), PathAndFile.second->Worker->getUsedBytes()});
1030 std::vector<Path> Result;
1031 for (
auto &&PathAndFile : Files) {
1032 if (!PathAndFile.second->Worker->isASTCached())
1034 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.
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.
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.
std::vector< CodeCompletionResult > Results
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 vlog(const char *Fmt, Ts &&... Vals)
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)
Build a preamble for the new inputs unless an old one can be reused.
Provides compilation arguments used for parsing C and C++ files.
Context clone() const
Clone this context object.
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.
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.
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
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.
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.
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.
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.
void run(llvm::StringRef Name, llvm::unique_function< void()> Action)
Schedule an async task with no dependencies.