37 #include "clang/Format/Format.h"
38 #include "clang/Lex/Preprocessor.h"
39 #include "clang/Tooling/CompilationDatabase.h"
40 #include "clang/Tooling/Core/Replacement.h"
41 #include "llvm/ADT/ArrayRef.h"
42 #include "llvm/ADT/Optional.h"
43 #include "llvm/ADT/STLExtras.h"
44 #include "llvm/ADT/StringRef.h"
45 #include "llvm/Support/Error.h"
46 #include "llvm/Support/Path.h"
47 #include "llvm/Support/raw_ostream.h"
54 #include <type_traits>
61 struct UpdateIndexCallbacks :
public ParsingCallbacks {
62 UpdateIndexCallbacks(FileIndex *FIndex,
63 ClangdServer::Callbacks *ServerCallbacks,
64 const ThreadsafeFS &TFS, AsyncTaskRunner *Tasks)
65 : FIndex(FIndex), ServerCallbacks(ServerCallbacks), TFS(TFS),
68 void onPreambleAST(
PathRef Path, llvm::StringRef Version,
69 const CompilerInvocation &
CI, ASTContext &
Ctx,
71 const CanonicalIncludes &CanonIncludes)
override {
74 if (
auto Loc = Stdlib.add(*
CI.getLangOpts(),
PP.getHeaderSearchInfo()))
75 indexStdlib(
CI, std::move(*
Loc));
78 FIndex->updatePreamble(
Path, Version,
Ctx,
PP, CanonIncludes);
81 void indexStdlib(
const CompilerInvocation &
CI, StdLibLocation
Loc) {
82 auto Task = [
this, LO(*
CI.getLangOpts()),
Loc(std::move(
Loc)),
83 CI(std::make_unique<CompilerInvocation>(
CI))]()
mutable {
86 if (Stdlib.isBest(LO))
87 FIndex->updatePreamble(std::move(IF));
91 Tasks->runAsync(
"IndexStdlib", std::move(Task));
96 void onMainAST(
PathRef Path, ParsedAST &AST, PublishFn Publish)
override {
98 FIndex->updateMain(
Path, AST);
100 assert(AST.getDiagnostics() &&
101 "We issue callback only with fresh preambles");
102 std::vector<Diag>
Diagnostics = *AST.getDiagnostics();
105 ServerCallbacks->onDiagnosticsReady(
Path, AST.version(),
110 void onFailedAST(
PathRef Path, llvm::StringRef Version,
111 std::vector<Diag>
Diags, PublishFn Publish)
override {
114 [&]() { ServerCallbacks->onDiagnosticsReady(
Path, Version,
Diags); });
117 void onFileUpdated(
PathRef File,
const TUStatus &Status)
override {
119 ServerCallbacks->onFileUpdated(File, Status);
122 void onPreamblePublished(
PathRef File)
override {
124 ServerCallbacks->onSemanticsMaybeChanged(File);
129 ClangdServer::Callbacks *ServerCallbacks;
130 const ThreadsafeFS &TFS;
132 AsyncTaskRunner *Tasks;
135 class DraftStoreFS :
public ThreadsafeFS {
137 DraftStoreFS(
const ThreadsafeFS &
Base,
const DraftStore &Drafts)
141 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
142 auto OFS = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(
143 Base.view(llvm::None));
144 OFS->pushOverlay(DirtyFiles.asVFS());
148 const ThreadsafeFS &
Base;
149 const DraftStore &DirtyFiles;
157 Opts.StorePreamblesInMemory =
true;
158 Opts.AsyncThreadsCount = 4;
164 Opts.AsyncThreadsCount = AsyncThreadsCount;
165 Opts.RetentionPolicy = RetentionPolicy;
166 Opts.StorePreamblesInMemory = StorePreamblesInMemory;
167 Opts.UpdateDebounce = UpdateDebounce;
168 Opts.ContextProvider = ContextProvider;
176 DynamicIdx(Opts.BuildDynamicSymbolIndex ? new
FileIndex() : nullptr),
177 ClangTidyProvider(Opts.ClangTidyProvider),
178 UseDirtyHeaders(Opts.UseDirtyHeaders),
179 PreambleParseForwardingFunctions(Opts.PreambleParseForwardingFunctions),
180 WorkspaceRoot(Opts.WorkspaceRoot),
181 Transient(Opts.ImplicitCancellation ?
TUScheduler::InvalidateOnUpdate
183 DirtyFS(std::make_unique<DraftStoreFS>(TFS, DraftMgr)) {
184 if (Opts.AsyncThreadsCount != 0)
185 IndexTasks.emplace();
190 std::make_unique<UpdateIndexCallbacks>(
192 IndexTasks ? IndexTasks.getPointer() :
nullptr));
195 if (this->Index !=
nullptr) {
196 MergedIdx.push_back(std::make_unique<MergedIndex>(Idx, this->Index));
197 this->Index = MergedIdx.back().get();
202 if (Opts.StaticIndex)
203 AddIndex(Opts.StaticIndex);
204 if (Opts.BackgroundIndex) {
212 BackgroundIdx = std::make_unique<BackgroundIndex>(
215 [&CDB](llvm::StringRef File) {
return CDB.getProjectInfo(File); }),
217 AddIndex(BackgroundIdx.get());
220 AddIndex(DynamicIdx.get());
222 if (Opts.FeatureModules) {
224 *this->WorkScheduler,
228 for (
auto &Mod : *Opts.FeatureModules)
237 WorkScheduler.reset();
239 if (FeatureModules) {
240 for (
auto &Mod : *FeatureModules)
248 llvm::StringRef Version,
250 std::string ActualVersion = DraftMgr.
addDraft(File, Version, Contents);
252 Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions;
256 Inputs.TFS = &getHeaderFS();
257 Inputs.Contents = std::string(Contents);
258 Inputs.Version = std::move(ActualVersion);
259 Inputs.ForceRebuild = ForceRebuild;
260 Inputs.Opts = std::move(Opts);
262 Inputs.ClangTidyProvider = ClangTidyProvider;
263 Inputs.FeatureModules = FeatureModules;
266 if (NewFile && BackgroundIdx)
267 BackgroundIdx->boostRelated(File);
271 llvm::function_ref<
bool(llvm::StringRef File)> Filter) {
274 if (Filter(FilePath))
275 if (
auto Draft = DraftMgr.
getDraft(FilePath))
276 addDocument(FilePath, *Draft->Contents, Draft->Version,
281 auto Draft = DraftMgr.
getDraft(File);
284 return std::move(Draft->Contents);
296 std::mutex PublishMu;
299 : Provider(Provider), Publish(Publish) {}
301 Context operator()(llvm::StringRef File) {
306 std::chrono::steady_clock::now() - std::chrono::seconds(5);
307 llvm::SmallString<256> PosixPath;
309 assert(llvm::sys::path::is_absolute(File));
310 llvm::sys::path::native(File, PosixPath, llvm::sys::path::Style::posix);
311 Params.
Path = PosixPath.str();
314 llvm::StringMap<std::vector<Diag>> ReportableDiagnostics;
319 handleDiagnostic(
D, !Publish ||
D.getFilename().empty()
321 : &ReportableDiagnostics[
D.getFilename()]);
326 if (!ReportableDiagnostics.empty()) {
327 std::lock_guard<std::mutex> Lock(PublishMu);
328 for (
auto &
Entry : ReportableDiagnostics)
330 std::move(
Entry.second));
335 void handleDiagnostic(
const llvm::SMDiagnostic &
D,
336 std::vector<Diag> *ClientDiagnostics) {
337 switch (
D.getKind()) {
338 case llvm::SourceMgr::DK_Error:
339 elog(
"config error at {0}:{1}:{2}: {3}",
D.getFilename(),
D.getLineNo(),
340 D.getColumnNo(),
D.getMessage());
342 case llvm::SourceMgr::DK_Warning:
343 log(
"config warning at {0}:{1}:{2}: {3}",
D.getFilename(),
344 D.getLineNo(),
D.getColumnNo(),
D.getMessage());
346 case llvm::SourceMgr::DK_Note:
347 case llvm::SourceMgr::DK_Remark:
348 vlog(
"config note at {0}:{1}:{2}: {3}",
D.getFilename(),
D.getLineNo(),
349 D.getColumnNo(),
D.getMessage());
350 ClientDiagnostics =
nullptr;
353 if (ClientDiagnostics)
359 return [I(std::make_shared<Impl>(Provider, Publish))](llvm::StringRef
Path) {
366 WorkScheduler->remove(File);
373 auto CodeCompleteOpts = Opts;
374 if (!CodeCompleteOpts.Index)
375 CodeCompleteOpts.Index = Index;
377 auto Task = [
Pos, CodeCompleteOpts, File = File.str(), CB = std::move(CB),
378 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
380 return CB(IP.takeError());
382 return CB(llvm::make_error<CancelledError>(Reason));
384 llvm::Optional<SpeculativeFuzzyFind> SpecFuzzyFind;
388 vlog(
"Build for file {0} is not ready. Enter fallback mode.", File);
389 }
else if (CodeCompleteOpts.Index) {
390 SpecFuzzyFind.emplace();
392 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
393 SpecFuzzyFind->CachedReq = CachedCompletionFuzzyFindRequestByFile[File];
399 if (!IP->Contents.endswith(
"\n"))
403 CodeCompleteOpts.MainFileSignals = IP->Signals;
409 SpecFuzzyFind ? SpecFuzzyFind.getPointer() :
nullptr);
412 CB(std::move(Result));
414 if (SpecFuzzyFind && SpecFuzzyFind->NewReq.hasValue()) {
415 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
416 CachedCompletionFuzzyFindRequestByFile[File] =
417 SpecFuzzyFind->NewReq.getValue();
426 WorkScheduler->runWithPreamble(
427 "CodeComplete", File,
438 auto Action = [
Pos, File = File.str(), CB = std::move(CB),
440 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
442 return CB(IP.takeError());
446 return CB(
error(
"Failed to parse includes"));
451 if (!IP->Contents.endswith(
"\n"))
455 DocumentationFormat));
467 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
473 return CB(Begin.takeError());
476 return CB(End.takeError());
484 Ranges = std::vector<tooling::Range>{RequestedRange},
485 CB = std::move(CB),
this]()
mutable {
487 tooling::Replacements IncludeReplaces =
488 format::sortIncludes(Style,
Code, Ranges, File);
489 auto Changed = tooling::applyAllReplacements(
Code, IncludeReplaces);
491 return CB(
Changed.takeError());
493 CB(IncludeReplaces.merge(format::reformat(
495 tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
498 WorkScheduler->runQuick(
"Format", File, std::move(
Action));
502 StringRef TriggerText,
503 Callback<std::vector<TextEdit>> CB) {
506 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
510 return CB(CursorPos.takeError());
512 TriggerText = TriggerText.str(), CursorPos = *CursorPos,
513 CB = std::move(CB),
this]()
mutable {
514 auto Style = format::getStyle(format::DefaultFormatStyle, File,
515 format::DefaultFallbackStyle,
Code,
516 TFS.
view(llvm::None).get());
518 return CB(Style.takeError());
520 std::vector<TextEdit> Result;
521 for (
const tooling::Replacement &R :
526 WorkScheduler->runQuick(
"FormatOnType", File, std::move(
Action));
530 llvm::Optional<std::string> NewName,
533 auto Action = [
Pos, File = File.str(), CB = std::move(CB),
534 NewName = std::move(NewName),
535 RenameOpts](llvm::Expected<InputsAndAST> InpAST)
mutable {
537 return CB(InpAST.takeError());
542 InpAST->AST, File,
nullptr,
543 nullptr, RenameOpts});
548 return CB(
Results.takeError());
552 WorkScheduler->runWithAST(
"PrepareRename", File, std::move(
Action));
558 auto Action = [File = File.str(), NewName = NewName.str(),
Pos, Opts,
560 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
565 return CB(InpAST.takeError());
567 DirtyFS->view(llvm::None), Index, Opts});
569 return CB(R.takeError());
571 if (Opts.WantFormat) {
573 *InpAST->Inputs.TFS);
574 llvm::Error Err = llvm::Error::success();
575 for (
auto &
E : R->GlobalChanges)
577 llvm::joinErrors(
reformatEdit(
E.getValue(), Style), std::move(Err));
580 return CB(std::move(Err));
582 RenameFiles.record(R->GlobalChanges.size());
585 WorkScheduler->runWithAST(
"Rename", File, std::move(
Action));
590 static llvm::Expected<std::vector<std::unique_ptr<Tweak::Selection>>>
592 llvm::vfs::FileSystem *FS) {
595 return Begin.takeError();
598 return End.takeError();
599 std::vector<std::unique_ptr<Tweak::Selection>> Result;
603 Result.push_back(std::make_unique<Tweak::Selection>(
604 AST.Inputs.Index, AST.AST, *Begin, *End, std::move(T), FS));
607 assert(!Result.empty() &&
"Expected at least one SelectionTree");
608 return std::move(Result);
613 Callback<std::vector<TweakRef>> CB) {
617 auto Action = [Sel, CB = std::move(CB), Filter = std::move(Filter),
618 FeatureModules(this->FeatureModules)](
619 Expected<InputsAndAST> InpAST)
mutable {
621 return CB(InpAST.takeError());
624 return CB(Selections.takeError());
625 std::vector<TweakRef> Res;
627 llvm::DenseSet<llvm::StringRef> PreparedTweaks;
628 auto DeduplicatingFilter = [&](
const Tweak &T) {
629 return Filter(T) && !PreparedTweaks.count(T.id());
631 for (
const auto &Sel : *Selections) {
632 for (
auto &T :
prepareTweaks(*Sel, DeduplicatingFilter, FeatureModules)) {
633 Res.push_back({T->id(), T->title(), T->kind()});
634 PreparedTweaks.insert(T->id());
635 TweakAvailable.record(1, T->id());
642 WorkScheduler->runWithAST(
"EnumerateTweaks", File, std::move(
Action),
654 TweakAttempt.record(1, TweakID);
655 auto Action = [File = File.str(), Sel, TweakID = TweakID.str(),
657 this](Expected<InputsAndAST> InpAST)
mutable {
659 return CB(InpAST.takeError());
660 auto FS = DirtyFS->view(llvm::None);
663 return CB(Selections.takeError());
664 llvm::Optional<llvm::Expected<Tweak::Effect>> Effect;
667 for (
const auto &Selection : *Selections) {
668 auto T =
prepareTweak(TweakID, *Selection, FeatureModules);
670 Effect = (*T)->apply(*Selection);
673 Effect = T.takeError();
675 assert(Effect &&
"Expected at least one selection");
676 if (*Effect && (*Effect)->FormatEdits) {
678 for (
auto &It : (*Effect)->ApplyEdits) {
683 elog(
"Failed to format {0}: {1}", It.first(), std::move(Err));
686 TweakFailed.record(1, TweakID);
688 return CB(std::move(*Effect));
690 WorkScheduler->runWithAST(
"ApplyTweak", File, std::move(
Action));
694 Callback<std::vector<LocatedSymbol>> CB) {
696 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
698 return CB(InpAST.takeError());
702 WorkScheduler->runWithAST(
"Definitions", File, std::move(
Action));
713 if (
auto CorrespondingFile =
715 return CB(std::move(CorrespondingFile));
717 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
719 return CB(InpAST.takeError());
722 WorkScheduler->runWithAST(
"SwitchHeaderSource",
Path, std::move(
Action));
728 [
Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
730 return CB(InpAST.takeError());
734 WorkScheduler->runWithAST(
"Highlights", File, std::move(
Action), Transient);
738 Callback<llvm::Optional<HoverInfo>> CB) {
739 auto Action = [File = File.str(),
Pos, CB = std::move(CB),
740 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
742 return CB(InpAST.takeError());
744 File, InpAST->Inputs.Contents, *InpAST->Inputs.TFS);
748 WorkScheduler->runWithAST(
"Hover", File, std::move(
Action), Transient);
753 Callback<Optional<TypeHierarchyItem>> CB) {
754 auto Action = [File = File.str(),
Pos, Resolve, Direction, CB = std::move(CB),
755 this](Expected<InputsAndAST> InpAST)
mutable {
757 return CB(InpAST.takeError());
762 WorkScheduler->runWithAST(
"TypeHierarchy", File, std::move(
Action));
767 Callback<llvm::Optional<TypeHierarchyItem>> CB) {
769 "Resolve Type Hierarchy",
"", [=, CB = std::move(CB)]()
mutable {
778 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
780 return CB(InpAST.takeError());
783 WorkScheduler->runWithAST(
"CallHierarchy", File, std::move(
Action));
788 Callback<std::vector<CallHierarchyIncomingCall>> CB) {
789 WorkScheduler->run(
"Incoming Calls",
"",
790 [CB = std::move(CB), Item,
this]()
mutable {
796 Callback<std::vector<InlayHint>> CB) {
797 auto Action = [RestrictRange(std::move(RestrictRange)),
798 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
800 return CB(InpAST.takeError());
803 WorkScheduler->runWithAST(
"InlayHints", File, std::move(
Action), Transient);
812 llvm::StringRef Query,
int Limit,
813 Callback<std::vector<SymbolInformation>> CB) {
815 "getWorkspaceSymbols",
"",
816 [Query = Query.str(), Limit, CB = std::move(CB),
this]()
mutable {
817 CB(clangd::getWorkspaceSymbols(Query, Limit, Index,
818 WorkspaceRoot.value_or(
"")));
823 Callback<std::vector<DocumentSymbol>> CB) {
825 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
827 return CB(InpAST.takeError());
830 WorkScheduler->runWithAST(
"DocumentSymbols", File, std::move(
Action),
835 Callback<std::vector<FoldingRange>> CB) {
837 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
839 return CB(InpAST.takeError());
842 WorkScheduler->runWithAST(
"FoldingRanges", File, std::move(
Action),
847 Callback<std::vector<LocatedSymbol>> CB) {
849 [
Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
851 return CB(InpAST.takeError());
854 WorkScheduler->runWithAST(
"FindType", File, std::move(
Action));
860 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
862 return CB(InpAST.takeError());
866 WorkScheduler->runWithAST(
"Implementations", File, std::move(
Action));
871 auto Action = [
Pos, Limit, CB = std::move(CB),
872 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
874 return CB(InpAST.takeError());
878 WorkScheduler->runWithAST(
"References", File, std::move(
Action));
882 Callback<std::vector<SymbolDetails>> CB) {
884 [
Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
886 return CB(InpAST.takeError());
890 WorkScheduler->runWithAST(
"SymbolInfo", File, std::move(
Action));
894 const std::vector<Position> &Positions,
895 Callback<std::vector<SelectionRange>> CB) {
896 auto Action = [Positions, CB = std::move(CB)](
897 llvm::Expected<InputsAndAST> InpAST)
mutable {
899 return CB(InpAST.takeError());
900 std::vector<SelectionRange> Result;
901 for (
const auto &
Pos : Positions) {
903 Result.push_back(std::move(*
Range));
905 return CB(
Range.takeError());
907 CB(std::move(Result));
909 WorkScheduler->runWithAST(
"SemanticRanges", File, std::move(
Action));
913 Callback<std::vector<DocumentLink>> CB) {
915 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
917 return CB(InpAST.takeError());
920 WorkScheduler->runWithAST(
"DocumentLinks", File, std::move(
Action),
927 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
929 return CB(InpAST.takeError());
932 WorkScheduler->runWithAST(
"SemanticHighlights", File, std::move(
Action),
937 Callback<llvm::Optional<ASTNode>> CB) {
939 [R, CB(std::move(CB))](llvm::Expected<InputsAndAST>
Inputs)
mutable {
941 return CB(
Inputs.takeError());
945 auto Node = DynTypedNode::create(
946 *
Inputs->AST.getASTContext().getTranslationUnitDecl());
948 Inputs->AST.getASTContext()));
954 return CB(
Offset.takeError());
958 return CB(
Offset.takeError());
960 Inputs->AST.getASTContext(),
Inputs->AST.getTokens(), Start, End,
962 if (const SelectionTree::Node *N = T.commonAncestor()) {
963 CB(dumpAST(N->ASTNode, Inputs->AST.getTokens(),
964 Inputs->AST.getASTContext()));
972 WorkScheduler->runWithAST(
"GetAST", File, std::move(
Action));
975 void ClangdServer::customAction(
PathRef File, llvm::StringRef
Name,
977 WorkScheduler->runWithAST(
Name, File, std::move(
Action));
982 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
984 return CB(InpAST.takeError());
985 if (
auto Diags = InpAST->AST.getDiagnostics())
988 return CB(llvm::make_error<LSPError>(
"server is busy parsing includes",
989 ErrorCode::InternalError));
992 WorkScheduler->runWithAST(
"Diagnostics", File, std::move(
Action));
995 llvm::StringMap<TUScheduler::FileStats> ClangdServer::fileStats()
const {
996 return WorkScheduler->fileStats();
1000 ClangdServer::blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds) {
1006 if (!WorkScheduler->blockUntilIdle(
timeoutSeconds(TimeoutSeconds)))
1009 if (IndexTasks && !IndexTasks->wait(
timeoutSeconds(TimeoutSeconds)))
1021 for (llvm::Optional<double> Timeout :
1022 {TimeoutSeconds, TimeoutSeconds, llvm::Optional<double>(0)}) {
1025 if (BackgroundIdx && !BackgroundIdx->blockUntilIdleForTest(Timeout))
1033 assert(WorkScheduler->blockUntilIdle(Deadline::zero()) &&
1034 "Something scheduled work while we're blocking the main thread!");
1040 DynamicIdx->profile(MT.
child(
"dynamic_index"));
1042 BackgroundIdx->profile(MT.
child(
"background_index"));
1043 WorkScheduler->profile(MT.
child(
"tuscheduler"));