26#include "clang-include-cleaner/Record.h"
38#include "clang/Basic/Stack.h"
39#include "clang/Format/Format.h"
40#include "clang/Lex/Preprocessor.h"
41#include "clang/Tooling/CompilationDatabase.h"
42#include "clang/Tooling/Core/Replacement.h"
43#include "llvm/ADT/ArrayRef.h"
44#include "llvm/ADT/STLExtras.h"
45#include "llvm/ADT/StringRef.h"
46#include "llvm/Support/Error.h"
47#include "llvm/Support/Path.h"
48#include "llvm/Support/raw_ostream.h"
70 UpdateIndexCallbacks(FileIndex *FIndex,
71 ClangdServer::Callbacks *ServerCallbacks,
72 const ThreadsafeFS &TFS, AsyncTaskRunner *Tasks,
73 bool CollectInactiveRegions)
74 : FIndex(FIndex), ServerCallbacks(ServerCallbacks), TFS(TFS),
75 Stdlib{std::make_shared<StdLibSet>()}, Tasks(Tasks),
76 CollectInactiveRegions(CollectInactiveRegions) {}
79 PathRef Path, llvm::StringRef Version, CapturedASTCtx ASTCtx,
80 std::shared_ptr<const include_cleaner::PragmaIncludes> PI)
override {
85 auto &PP = ASTCtx.getPreprocessor();
86 auto &CI = ASTCtx.getCompilerInvocation();
87 if (
auto Loc = Stdlib->add(CI.getLangOpts(), PP.getHeaderSearchInfo()))
88 indexStdlib(CI, std::move(*Loc));
91 auto Task = [FIndex(FIndex),
Path(
Path.str()), Version(Version.str()),
92 ASTCtx(std::move(ASTCtx)), PI(std::move(PI))]()
mutable {
93 trace::Span Tracer(
"PreambleIndexing");
94 FIndex->updatePreamble(
Path, Version, ASTCtx.getASTContext(),
95 ASTCtx.getPreprocessor(), *PI);
99 Tasks->runAsync(
"Preamble indexing for:" +
Path + Version,
105 void indexStdlib(
const CompilerInvocation &CI, StdLibLocation Loc) {
109 auto Task = [LO(CI.getLangOpts()), Loc(std::move(Loc)),
110 CI(std::make_unique<CompilerInvocation>(CI)),
121 WithContext
C(std::move(Ctx));
122 clang::noteBottomOfStack();
125 if (Stdlib->isBest(LO))
126 FIndex->updatePreamble(std::move(IF));
130 Tasks->runAsync(
"IndexStdlib", std::move(Task));
135 void onMainAST(
PathRef Path, ParsedAST &
AST, PublishFn Publish)
override {
141 ServerCallbacks->onDiagnosticsReady(
Path,
AST.version(),
142 AST.getDiagnostics());
143 if (CollectInactiveRegions) {
144 ServerCallbacks->onInactiveRegionsReady(
Path,
150 void onFailedAST(
PathRef Path, llvm::StringRef Version,
151 std::vector<Diag> Diags, PublishFn Publish)
override {
154 [&]() { ServerCallbacks->onDiagnosticsReady(
Path, Version, Diags); });
157 void onFileUpdated(
PathRef File,
const TUStatus &Status)
override {
159 ServerCallbacks->onFileUpdated(
File, Status);
164 ServerCallbacks->onSemanticsMaybeChanged(
File);
169 ClangdServer::Callbacks *ServerCallbacks;
170 const ThreadsafeFS &TFS;
171 std::shared_ptr<StdLibSet> Stdlib;
172 AsyncTaskRunner *Tasks;
173 bool CollectInactiveRegions;
178 DraftStoreFS(
const ThreadsafeFS &Base,
const DraftStore &Drafts)
179 : Base(Base), DirtyFiles(Drafts) {}
182 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
183 auto OFS = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(
184 Base.view(std::nullopt));
185 OFS->pushOverlay(DirtyFiles.asVFS());
189 const ThreadsafeFS &Base;
190 const DraftStore &DirtyFiles;
217 : FeatureModules(Opts.FeatureModules), CDB(CDB), TFS(TFS),
218 DynamicIdx(Opts.BuildDynamicSymbolIndex
219 ? new
FileIndex(Opts.EnableOutgoingCalls)
221 ModulesManager(Opts.ModulesManager),
222 UseDirtyHeaders(Opts.UseDirtyHeaders),
223 LineFoldingOnly(Opts.LineFoldingOnly),
224 PreambleParseForwardingFunctions(Opts.PreambleParseForwardingFunctions),
225 SkipPreambleBuild(Opts.SkipPreambleBuild),
226 ImportInsertions(Opts.ImportInsertions),
227 PublishInactiveRegions(Opts.PublishInactiveRegions),
228 WorkspaceRoot(Opts.WorkspaceRoot),
229 Transient(Opts.ImplicitCancellation ?
TUScheduler::InvalidateOnUpdate
231 DirtyFS(std::make_unique<DraftStoreFS>(TFS, DraftMgr)),
232 ContextProvider(Opts.ContextProvider) {
234 IndexTasks.emplace();
239 std::make_unique<UpdateIndexCallbacks>(
241 IndexTasks ? &*IndexTasks :
nullptr,
242 PublishInactiveRegions));
245 if (this->Index != nullptr) {
246 MergedIdx.push_back(std::make_unique<MergedIndex>(Idx, this->Index));
247 this->Index = MergedIdx.back().get();
252 if (Opts.StaticIndex)
253 AddIndex(Opts.StaticIndex);
254 if (Opts.BackgroundIndex) {
255 BackgroundIndex::Options BGOpts;
256 BGOpts.ThreadPoolSize = std::max(Opts.AsyncThreadsCount, 1u);
257 BGOpts.OnProgress = [Callbacks](BackgroundQueue::Stats S) {
259 Callbacks->onBackgroundIndexProgress(S);
261 BGOpts.ContextProvider = Opts.ContextProvider;
262 BGOpts.SupportContainedRefs = Opts.EnableOutgoingCalls;
263 BackgroundIdx = std::make_unique<BackgroundIndex>(
266 [&CDB](llvm::StringRef
File) { return CDB.getProjectInfo(File); }),
268 AddIndex(BackgroundIdx.get());
271 AddIndex(DynamicIdx.get());
273 if (Opts.FeatureModules) {
274 FeatureModule::Facilities F{
275 *this->WorkScheduler,
279 for (
auto &Mod : *Opts.FeatureModules)
288 WorkScheduler.reset();
290 if (FeatureModules) {
291 for (
auto &Mod : *FeatureModules)
293 for (
auto &Mod : *FeatureModules)
299 llvm::StringRef Version,
301 bool NewModule = ModulesManager && ModulesManager->observeSourcePath(
File);
303 std::string ActualVersion = DraftMgr.addDraft(
File, Version, Contents);
310 Inputs.
TFS = &getHeaderFS();
311 Inputs.
Contents = std::string(Contents);
312 Inputs.
Version = std::move(ActualVersion);
314 Inputs.
Opts = std::move(Opts);
315 Inputs.
Index = Index;
318 adjustParseInputs(Inputs,
File);
319 bool NewFile = WorkScheduler->update(
File, Inputs, WantDiags);
321 if (NewFile && BackgroundIdx)
322 BackgroundIdx->boostRelated(
File);
329 llvm::function_ref<
bool(llvm::StringRef
File)> Filter) {
331 for (
const Path &FilePath : DraftMgr.getActiveFiles())
332 if (Filter(FilePath))
333 if (
auto Draft = DraftMgr.getDraft(FilePath))
334 addDocument(FilePath, *Draft->Contents, Draft->Version,
339 auto Draft = DraftMgr.getDraft(
File);
342 return std::move(Draft->Contents);
354 std::mutex PublishMu;
357 : Provider(Provider), Publish(Publish) {}
364 std::chrono::steady_clock::now() - std::chrono::seconds(5);
365 llvm::SmallString<256> PosixPath;
367 assert(llvm::sys::path::is_absolute(
File));
368 llvm::sys::path::native(
File, PosixPath, llvm::sys::path::Style::posix);
369 Params.
Path = PosixPath.str();
372 llvm::StringMap<std::vector<Diag>> ReportableDiagnostics;
373 Config C = Provider->
getConfig(Params, [&](
const llvm::SMDiagnostic &D) {
377 handleDiagnostic(D, !Publish || D.getFilename().empty()
379 : &ReportableDiagnostics[D.getFilename()]);
384 if (!ReportableDiagnostics.empty()) {
385 std::lock_guard<std::mutex> Lock(PublishMu);
386 for (
auto &
Entry : ReportableDiagnostics)
393 void handleDiagnostic(
const llvm::SMDiagnostic &D,
394 std::vector<Diag> *ClientDiagnostics) {
395 switch (D.getKind()) {
396 case llvm::SourceMgr::DK_Error:
397 elog(
"config error at {0}:{1}:{2}: {3}", D.getFilename(), D.getLineNo(),
398 D.getColumnNo(), D.getMessage());
400 case llvm::SourceMgr::DK_Warning:
401 log(
"config warning at {0}:{1}:{2}: {3}", D.getFilename(),
402 D.getLineNo(), D.getColumnNo(), D.getMessage());
404 case llvm::SourceMgr::DK_Note:
405 case llvm::SourceMgr::DK_Remark:
406 vlog(
"config note at {0}:{1}:{2}: {3}", D.getFilename(), D.getLineNo(),
407 D.getColumnNo(), D.getMessage());
408 ClientDiagnostics =
nullptr;
411 if (ClientDiagnostics)
417 return [I(std::make_shared<Impl>(Provider, Publish))](llvm::StringRef
Path) {
423 DraftMgr.removeDraft(
File);
424 WorkScheduler->remove(
File);
431 auto CodeCompleteOpts = Opts;
432 if (!CodeCompleteOpts.Index)
433 CodeCompleteOpts.Index = Index;
435 auto Task = [Pos, CodeCompleteOpts,
File =
File.str(), CB = std::move(CB),
436 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
438 return CB(IP.takeError());
440 return CB(llvm::make_error<CancelledError>(Reason));
442 std::optional<SpeculativeFuzzyFind> SpecFuzzyFind;
446 vlog(
"Build for file {0} is not ready. Enter fallback mode.",
File);
447 }
else if (CodeCompleteOpts.Index) {
448 SpecFuzzyFind.emplace();
450 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
451 SpecFuzzyFind->CachedReq = CachedCompletionFuzzyFindRequestByFile[
File];
454 ParseInputs ParseInput{IP->Command, &getHeaderFS(), IP->Contents.str()};
457 if (!IP->Contents.ends_with(
"\n"))
459 ParseInput.
Index = Index;
461 CodeCompleteOpts.MainFileSignals = IP->Signals;
463 CodeCompleteOpts.ArgumentLists =
Config::current().Completion.ArgumentLists;
464 CodeCompleteOpts.InsertIncludes =
466 CodeCompleteOpts.CodePatterns =
Config::current().Completion.CodePatterns;
467 CodeCompleteOpts.MacroFilter =
Config::current().Completion.MacroFilter;
468 adjustParseInputs(ParseInput,
File);
472 File, Pos, IP->Preamble, ParseInput, CodeCompleteOpts,
473 SpecFuzzyFind ? &*SpecFuzzyFind :
nullptr);
479 CB(std::move(Result));
483 if (SpecFuzzyFind->NewReq) {
484 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
485 CachedCompletionFuzzyFindRequestByFile[
File] = *SpecFuzzyFind->NewReq;
490 if (SpecFuzzyFind->Result.valid())
491 SpecFuzzyFind->Result.wait();
495 WorkScheduler->runWithPreamble(
496 "CodeComplete",
File,
497 (Opts.RunParser == CodeCompleteOptions::AlwaysParse)
507 auto Action = [Pos,
File =
File.str(), CB = std::move(CB),
509 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
511 return CB(IP.takeError());
515 return CB(
error(
"Failed to parse includes"));
517 ParseInputs ParseInput{IP->Command, &getHeaderFS(), IP->Contents.str()};
520 if (!IP->Contents.ends_with(
"\n"))
522 ParseInput.
Index = Index;
524 DocumentationFormat));
536 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
538 std::vector<tooling::Range> RequestedRanges;
540 RequestedRanges.reserve(Rngs.size());
541 for (
const auto &Rng : Rngs) {
544 return CB(Begin.takeError());
547 return CB(End.takeError());
548 RequestedRanges.emplace_back(*Begin, *End - *Begin);
551 RequestedRanges = {tooling::Range(0, Code->size())};
555 auto Action = [
File =
File.str(), Code = std::move(*Code),
556 Ranges = std::move(RequestedRanges), CB = std::move(CB),
559 tooling::Replacements IncludeReplaces =
560 format::sortIncludes(Style, Code, Ranges,
File);
561 auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces);
563 return CB(
Changed.takeError());
565 CB(IncludeReplaces.merge(format::reformat(
567 tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
570 WorkScheduler->runQuick(
"Format",
File, std::move(Action));
574 StringRef TriggerText,
575 Callback<std::vector<TextEdit>> CB) {
578 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
582 return CB(CursorPos.takeError());
583 auto Action = [
File =
File.str(), Code = std::move(*Code),
584 TriggerText = TriggerText.str(), CursorPos = *CursorPos,
585 CB = std::move(CB),
this]()
mutable {
587 std::vector<TextEdit> Result;
588 for (
const tooling::Replacement &R :
593 WorkScheduler->runQuick(
"FormatOnType",
File, std::move(Action));
597 std::optional<std::string> NewName,
600 auto Action = [Pos,
File =
File.str(), CB = std::move(CB),
601 NewName = std::move(NewName),
602 RenameOpts](llvm::Expected<InputsAndAST> InpAST)
mutable {
604 return CB(InpAST.takeError());
608 clangd::rename({Pos, NewName.value_or(
"__clangd_rename_placeholder"),
609 InpAST->AST,
File,
nullptr,
610 nullptr, RenameOpts});
615 return CB(Results.takeError());
619 WorkScheduler->runWithAST(
"PrepareRename",
File, std::move(Action));
625 auto Action = [
File =
File.str(), NewName = NewName.str(), Pos, Opts,
627 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
632 return CB(InpAST.takeError());
634 DirtyFS->view(std::nullopt), Index, Opts});
636 return CB(R.takeError());
640 *InpAST->Inputs.TFS,
false);
641 llvm::Error Err = llvm::Error::success();
642 for (
auto &E : R->GlobalChanges)
644 llvm::joinErrors(
reformatEdit(E.getValue(), Style), std::move(Err));
647 return CB(std::move(Err));
649 RenameFiles.
record(R->GlobalChanges.size());
652 WorkScheduler->runWithAST(
"Rename",
File, std::move(Action));
658llvm::Expected<std::vector<std::unique_ptr<Tweak::Selection>>>
660 llvm::vfs::FileSystem *FS) {
663 return Begin.takeError();
666 return End.takeError();
667 std::vector<std::unique_ptr<Tweak::Selection>> Result;
669 AST.AST.getASTContext(),
AST.AST.getTokens(), *Begin, *End,
671 Result.push_back(std::make_unique<Tweak::Selection>(
672 AST.Inputs.Index, AST.AST, *Begin, *End, std::move(T), FS));
675 assert(!Result.empty() &&
"Expected at least one SelectionTree");
676 return std::move(Result);
682std::optional<ClangdServer::CodeActionResult::Rename>
683tryConvertToRename(
const Diag *Diag,
const Fix &
Fix) {
684 bool IsClangTidyRename = Diag->Source == Diag::ClangTidy &&
685 Diag->Name ==
"readability-identifier-naming" &&
687 if (IsClangTidyRename && Diag->InsideMainFile) {
688 ClangdServer::CodeActionResult::Rename R;
689 R.NewName =
Fix.Edits.front().newText;
690 R.FixMessage =
Fix.Message;
691 R.Diag = {Diag->Range, Diag->Message};
702 auto Action = [Params, CB = std::move(CB),
703 FeatureModules(this->FeatureModules)](
704 Expected<InputsAndAST> InpAST)
mutable {
706 return CB(InpAST.takeError());
711 return llvm::any_of(Only, [&](llvm::StringRef Base) {
712 return Kind.consume_front(Base) &&
713 (Kind.empty() || Kind.starts_with(
"."));
718 Result.
Version = InpAST->AST.version().str();
720 auto FindMatchedDiag = [&InpAST](
const DiagRef &DR) ->
const Diag * {
721 for (
const auto &
Diag : InpAST->AST.getDiagnostics())
729 if (
auto Rename = tryConvertToRename(
Diag,
Fix)) {
730 Result.
Renames.emplace_back(std::move(*Rename));
739 auto Selections = tweakSelection(Params.
Selection, *InpAST,
nullptr);
741 return CB(Selections.takeError());
743 llvm::DenseSet<llvm::StringRef> PreparedTweaks;
744 auto DeduplicatingFilter = [&](
const Tweak &T) {
745 return KindAllowed(T.kind()) && Params.
TweakFilter(T) &&
746 !PreparedTweaks.count(T.id());
748 for (
const auto &Sel : *Selections) {
749 for (
auto &T :
prepareTweaks(*Sel, DeduplicatingFilter, FeatureModules)) {
751 PreparedTweaks.insert(T->id());
752 TweakAvailable.record(1, T->id());
755 CB(std::move(Result));
758 WorkScheduler->runWithAST(
"codeAction", Params.
File, std::move(Action),
770 TweakAttempt.
record(1, TweakID);
771 auto Action = [
File =
File.str(), Sel, TweakID = TweakID.str(),
773 this](Expected<InputsAndAST> InpAST)
mutable {
775 return CB(InpAST.takeError());
776 auto FS = DirtyFS->view(std::nullopt);
777 auto Selections = tweakSelection(Sel, *InpAST, FS.get());
779 return CB(Selections.takeError());
780 std::optional<llvm::Expected<Tweak::Effect>> Effect;
783 for (
const auto &Selection : *Selections) {
784 auto T =
prepareTweak(TweakID, *Selection, FeatureModules);
786 Effect = (*T)->apply(*Selection);
789 Effect = T.takeError();
791 assert(Effect &&
"Expected at least one selection");
792 if (*Effect && (*Effect)->FormatEdits) {
794 for (
auto &It : (*Effect)->ApplyEdits) {
796 format::FormatStyle Style =
799 elog(
"Failed to format {0}: {1}", It.first(), std::move(Err));
802 TweakFailed.
record(1, TweakID);
804 return CB(std::move(*Effect));
806 WorkScheduler->runWithAST(
"ApplyTweak",
File, std::move(Action));
810 Callback<std::vector<LocatedSymbol>> CB) {
811 auto Action = [Pos, CB = std::move(CB),
812 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
814 return CB(InpAST.takeError());
818 WorkScheduler->runWithAST(
"Definitions",
File, std::move(Action));
829 if (
auto CorrespondingFile =
831 return CB(std::move(CorrespondingFile));
832 auto Action = [
Path =
Path.str(), CB = std::move(CB),
833 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
835 return CB(InpAST.takeError());
838 WorkScheduler->runWithAST(
"SwitchHeaderSource",
Path, std::move(Action));
844 [Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
846 return CB(InpAST.takeError());
850 WorkScheduler->runWithAST(
"Highlights",
File, std::move(Action), Transient);
854 Callback<std::optional<HoverInfo>> CB) {
855 auto Action = [
File =
File.str(), Pos, CB = std::move(CB),
856 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
858 return CB(InpAST.takeError());
860 File, InpAST->Inputs.Contents, *InpAST->Inputs.TFS,
false);
864 WorkScheduler->runWithAST(
"Hover",
File, std::move(Action), Transient);
869 Callback<std::vector<TypeHierarchyItem>> CB) {
870 auto Action = [
File =
File.str(), Pos, Resolve, Direction, CB = std::move(CB),
871 this](Expected<InputsAndAST> InpAST)
mutable {
873 return CB(InpAST.takeError());
878 WorkScheduler->runWithAST(
"TypeHierarchy",
File, std::move(Action));
883 Callback<std::optional<std::vector<TypeHierarchyItem>>> CB) {
884 WorkScheduler->run(
"typeHierarchy/superTypes",
"",
885 [=, CB = std::move(CB)]()
mutable {
891 Callback<std::vector<TypeHierarchyItem>> CB) {
893 "typeHierarchy/subTypes",
"",
899 Callback<std::optional<TypeHierarchyItem>> CB) {
901 "Resolve Type Hierarchy",
"", [=, CB = std::move(CB)]()
mutable {
909 auto Action = [
File =
File.str(), Pos,
910 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
912 return CB(InpAST.takeError());
915 WorkScheduler->runWithAST(
"CallHierarchy",
File, std::move(Action));
920 Callback<std::vector<CallHierarchyIncomingCall>> CB) {
921 WorkScheduler->run(
"Incoming Calls",
"",
922 [CB = std::move(CB), Item,
this]()
mutable {
928 Callback<std::vector<InlayHint>> CB) {
929 auto Action = [RestrictRange(std::move(RestrictRange)),
930 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
932 return CB(InpAST.takeError());
935 WorkScheduler->runWithAST(
"InlayHints",
File, std::move(Action), Transient);
940 Callback<std::vector<CallHierarchyOutgoingCall>> CB) {
941 WorkScheduler->run(
"Outgoing Calls",
"",
942 [CB = std::move(CB), Item,
this]()
mutable {
950 bool ModulesChanged =
false;
951 for (
const auto &Change : Params.
changes)
952 ModulesChanged |= ModulesManager->onFileEvent(Change);
958 llvm::StringRef Query,
int Limit,
959 Callback<std::vector<SymbolInformation>> CB) {
961 "getWorkspaceSymbols",
"",
962 [Query = Query.str(), Limit, CB = std::move(CB),
this]()
mutable {
963 CB(clangd::getWorkspaceSymbols(Query, Limit, Index,
964 WorkspaceRoot.value_or(
"")));
969 Callback<std::vector<DocumentSymbol>> CB) {
971 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
973 return CB(InpAST.takeError());
976 WorkScheduler->runWithAST(
"DocumentSymbols",
File, std::move(Action),
981 Callback<std::vector<FoldingRange>> CB) {
984 return CB(llvm::make_error<LSPError>(
985 "trying to compute folding ranges for non-added document",
987 auto Action = [LineFoldingOnly = LineFoldingOnly, CB = std::move(CB),
988 Code = std::move(*Code)]()
mutable {
993 WorkScheduler->runQuick(
"FoldingRanges",
File, std::move(Action));
997 Callback<std::vector<LocatedSymbol>> CB) {
998 auto Action = [Pos, CB = std::move(CB),
999 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
1001 return CB(InpAST.takeError());
1004 WorkScheduler->runWithAST(
"FindType",
File, std::move(Action));
1009 auto Action = [Pos, CB = std::move(CB),
1010 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
1012 return CB(InpAST.takeError());
1016 WorkScheduler->runWithAST(
"Implementations",
File, std::move(Action));
1022 auto Action = [Pos, Limit, AddContainer, CB = std::move(CB),
1023 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
1025 return CB(InpAST.takeError());
1029 WorkScheduler->runWithAST(
"References",
File, std::move(Action));
1033 Callback<std::vector<SymbolDetails>> CB) {
1035 [Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1037 return CB(InpAST.takeError());
1041 WorkScheduler->runWithAST(
"SymbolInfo",
File, std::move(Action));
1045 const std::vector<Position> &Positions,
1046 Callback<std::vector<SelectionRange>> CB) {
1047 auto Action = [Positions, CB = std::move(CB)](
1048 llvm::Expected<InputsAndAST> InpAST)
mutable {
1050 return CB(InpAST.takeError());
1051 std::vector<SelectionRange> Result;
1052 for (
const auto &Pos : Positions) {
1054 Result.push_back(std::move(*
Range));
1056 return CB(
Range.takeError());
1058 CB(std::move(Result));
1060 WorkScheduler->runWithAST(
"SemanticRanges",
File, std::move(Action));
1064 Callback<std::vector<DocumentLink>> CB) {
1066 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1068 return CB(InpAST.takeError());
1071 WorkScheduler->runWithAST(
"DocumentLinks",
File, std::move(Action),
1078 auto Action = [CB = std::move(CB),
1079 PublishInactiveRegions = PublishInactiveRegions](
1080 llvm::Expected<InputsAndAST> InpAST)
mutable {
1082 return CB(InpAST.takeError());
1088 WorkScheduler->runWithAST(
"SemanticHighlights",
File, std::move(Action),
1093 Callback<std::optional<ASTNode>> CB) {
1095 [R, CB(std::move(CB))](llvm::Expected<InputsAndAST> Inputs)
mutable {
1097 return CB(Inputs.takeError());
1101 auto Node = DynTypedNode::create(
1102 *Inputs->AST.getASTContext().getTranslationUnitDecl());
1103 return CB(
dumpAST(Node, Inputs->AST.getTokens(),
1104 Inputs->AST.getASTContext()));
1106 unsigned Start, End;
1110 return CB(Offset.takeError());
1114 return CB(Offset.takeError());
1116 Inputs->AST.getASTContext(), Inputs->AST.getTokens(), Start, End,
1118 if (const SelectionTree::Node *N = T.commonAncestor()) {
1119 CB(dumpAST(N->ASTNode, Inputs->AST.getTokens(),
1120 Inputs->AST.getASTContext()));
1128 WorkScheduler->runWithAST(
"GetAST",
File, std::move(Action));
1133 WorkScheduler->runWithAST(Name,
File, std::move(Action));
1138 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1140 return CB(InpAST.takeError());
1141 return CB(InpAST->AST.getDiagnostics());
1144 WorkScheduler->runWithAST(
"Diagnostics",
File, std::move(Action));
1148 return WorkScheduler->fileStats();
1156#if defined(__has_feature) && \
1157 (__has_feature(address_sanitizer) || __has_feature(hwaddress_sanitizer) || \
1158 __has_feature(memory_sanitizer) || __has_feature(thread_sanitizer) || \
1159 __has_feature(undefined_behavior_sanitizer))
1160 if (TimeoutSeconds.has_value())
1161 (*TimeoutSeconds) *= 10;
1166 if (!WorkScheduler->blockUntilIdle(
timeoutSeconds(TimeoutSeconds)))
1169 if (IndexTasks && !IndexTasks->wait(
timeoutSeconds(TimeoutSeconds)))
1181 for (std::optional<double> Timeout :
1182 {TimeoutSeconds, TimeoutSeconds, std::optional<double>(0)}) {
1185 if (BackgroundIdx && !BackgroundIdx->blockUntilIdleForTest(Timeout))
1187 if (FeatureModules && llvm::any_of(*FeatureModules, [&](
FeatureModule &M) {
1194 "Something scheduled work while we're blocking the main thread!");
1200 DynamicIdx->profile(MT.
child(
"dynamic_index"));
1202 BackgroundIdx->profile(MT.
child(
"background_index"));
1203 WorkScheduler->profile(MT.
child(
"tuscheduler"));
1211 auto HasRequiredModules = [
this,
File]() {
1212 if (!ModulesManager)
1220 return ModulesManager->hasRequiredModules(
File);
1224 switch (SkipPreambleBuild) {
1225 case SkipPreambleBuildPolicy::Never:
1227 case SkipPreambleBuildPolicy::Modules:
1228 return HasRequiredModules();
1229 case SkipPreambleBuildPolicy::Always:
1232 llvm_unreachable(
"fully covered switch");
static cl::opt< bool > Fix("fix", desc(R"(
Apply suggested fixes. Without -fix-errors
clang-tidy will bail out if any compilation
errors were found.
)"), cl::init(false), cl::cat(ClangTidyCategory))
void elog(const char *Fmt, Ts &&... Vals)
static Factory createDiskBackedStorageFactory(std::function< std::optional< ProjectInfo >(PathRef)> GetProjectInfo)
Interface with hooks for users of ClangdServer to be notified of events.
virtual void onDiagnosticsReady(PathRef File, llvm::StringRef Version, llvm::ArrayRef< Diag > Diagnostics)
Called by ClangdServer when Diagnostics for File are ready.
llvm::StringMap< TUScheduler::FileStats > fileStats() const
Returns estimated memory usage and other statistics for each of the currently open files.
ClangdServer(const GlobalCompilationDatabase &CDB, const ThreadsafeFS &TFS, const Options &Opts, Callbacks *Callbacks=nullptr)
Creates a new ClangdServer instance.
void prepareRename(PathRef File, Position Pos, std::optional< std::string > NewName, const RenameOptions &RenameOpts, Callback< RenameResult > CB)
Test the validity of a rename operation.
void prepareCallHierarchy(PathRef File, Position Pos, Callback< std::vector< CallHierarchyItem > > CB)
Get information about call hierarchy for a given position.
void resolveTypeHierarchy(TypeHierarchyItem Item, int Resolve, TypeHierarchyDirection Direction, Callback< std::optional< TypeHierarchyItem > > CB)
Resolve type hierarchy item in the given direction.
void documentSymbols(StringRef File, Callback< std::vector< DocumentSymbol > > CB)
Retrieve the symbols within the specified file.
void workspaceSymbols(StringRef Query, int Limit, Callback< std::vector< SymbolInformation > > CB)
Retrieve the top symbols from the workspace matching a query.
void diagnostics(PathRef File, Callback< std::vector< Diag > > CB)
Fetches diagnostics for current version of the File.
void typeHierarchy(PathRef File, Position Pos, int Resolve, TypeHierarchyDirection Direction, Callback< std::vector< TypeHierarchyItem > > CB)
Get information about type hierarchy for a given position.
void removeDocument(PathRef File)
Remove File from list of tracked files, schedule a request to free resources associated with it.
void outgoingCalls(const CallHierarchyItem &Item, Callback< std::vector< CallHierarchyOutgoingCall > >)
Resolve outgoing calls for a given call hierarchy item.
void addDocument(PathRef File, StringRef Contents, llvm::StringRef Version="null", WantDiagnostics WD=WantDiagnostics::Auto, bool ForceRebuild=false)
Add a File to the list of tracked C++ files or update the contents if File is already tracked.
void findDocumentHighlights(PathRef File, Position Pos, Callback< std::vector< DocumentHighlight > > CB)
Get document highlights for a given position.
static std::function< Context(PathRef)> createConfiguredContextProvider(const config::Provider *Provider, ClangdServer::Callbacks *)
Creates a context provider that loads and installs config.
void signatureHelp(PathRef File, Position Pos, MarkupKind DocumentationFormat, Callback< SignatureHelp > CB)
Provide signature help for File at Pos.
void findReferences(PathRef File, Position Pos, uint32_t Limit, bool AddContainer, Callback< ReferencesResult > CB)
Retrieve locations for symbol references.
void switchSourceHeader(PathRef Path, Callback< std::optional< clangd::Path > > CB)
Switch to a corresponding source file when given a header file, and vice versa.
void findType(PathRef File, Position Pos, Callback< std::vector< LocatedSymbol > > CB)
Retrieve symbols for types referenced at Pos.
void findImplementations(PathRef File, Position Pos, Callback< std::vector< LocatedSymbol > > CB)
Retrieve implementations for virtual method.
static Options optsForTest()
void subTypes(const TypeHierarchyItem &Item, Callback< std::vector< TypeHierarchyItem > > CB)
Get direct children of a type hierarchy item.
void semanticRanges(PathRef File, const std::vector< Position > &Pos, Callback< std::vector< SelectionRange > > CB)
Get semantic ranges around a specified position in a file.
void formatFile(PathRef File, const std::vector< Range > &Rngs, Callback< tooling::Replacements > CB)
Run formatting for the File with content Code.
void applyTweak(PathRef File, Range Sel, StringRef ID, Callback< Tweak::Effect > CB)
Apply the code tweak with a specified ID.
void semanticHighlights(PathRef File, Callback< std::vector< HighlightingToken > >)
void getAST(PathRef File, std::optional< Range > R, Callback< std::optional< ASTNode > > CB)
Describe the AST subtree for a piece of code.
void symbolInfo(PathRef File, Position Pos, Callback< std::vector< SymbolDetails > > CB)
Get symbol info for given position.
void onFileEvent(const DidChangeWatchedFilesParams &Params)
Called when an event occurs for a watched file in the workspace.
void superTypes(const TypeHierarchyItem &Item, Callback< std::optional< std::vector< TypeHierarchyItem > > > CB)
Get direct parents of a type hierarchy item.
void profile(MemoryTree &MT) const
Builds a nested representation of memory used by components.
void findHover(PathRef File, Position Pos, Callback< std::optional< HoverInfo > > CB)
Get code hover for a given position.
void formatOnType(PathRef File, Position Pos, StringRef TriggerText, Callback< std::vector< TextEdit > > CB)
Run formatting after TriggerText was typed at Pos in File with content Code.
void rename(PathRef File, Position Pos, llvm::StringRef NewName, const RenameOptions &Opts, Callback< RenameResult > CB)
Rename all occurrences of the symbol at the Pos in File to NewName.
void customAction(PathRef File, llvm::StringRef Name, Callback< InputsAndAST > Action)
Runs an arbitrary action that has access to the AST of the specified file.
void codeAction(const CodeActionInputs &Inputs, Callback< CodeActionResult > CB)
Surface code actions (quick-fixes for diagnostics, or available code tweaks) for a given range in a f...
void locateSymbolAt(PathRef File, Position Pos, Callback< std::vector< LocatedSymbol > > CB)
Find declaration/definition locations of symbol at a specified position.
void incomingCalls(const CallHierarchyItem &Item, Callback< std::vector< CallHierarchyIncomingCall > >)
Resolve incoming calls for a given call hierarchy item.
bool blockUntilIdleForTest(std::optional< double > TimeoutSeconds=10)
void inlayHints(PathRef File, std::optional< Range > RestrictRange, Callback< std::vector< InlayHint > >)
Resolve inlay hints for a given document.
void codeComplete(PathRef File, Position Pos, const clangd::CodeCompleteOptions &Opts, Callback< CodeCompleteResult > CB)
Run code completion for File at Pos.
void reparseOpenFilesIfNeeded(llvm::function_ref< bool(llvm::StringRef File)> Filter)
Requests a reparse of currently opened files using their latest source.
void foldingRanges(StringRef File, Callback< std::vector< FoldingRange > > CB)
Retrieve ranges that can be used to fold code within the specified file.
void documentLinks(PathRef File, Callback< std::vector< DocumentLink > > CB)
Get all document links in a file.
std::shared_ptr< const std::string > getDraft(PathRef File) const
Gets the contents of a currently tracked file.
A context is an immutable container for per-request data that must be propagated through layers that ...
static const Context & current()
Returns the context for the current thread, creating it if needed.
static Deadline infinity()
A FeatureModule contributes a vertical feature to clangd.
virtual bool blockUntilIdle(Deadline)
Waits until the module is idle (no background work) or a deadline expires.
This manages symbols from files and an in-memory index on all symbols.
Provides compilation arguments used for parsing C and C++ files.
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Handles running tasks for ClangdServer and managing the resources (e.g., preambles and ASTs) for open...
@ StaleOrAbsent
Besides accepting stale preamble, this also allow preamble to be absent (not ready or failed to build...
@ Stale
The preamble may be generated from an older version of the file.
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
An interface base for small context-sensitive refactoring actions.
WithContext replaces Context::current() with a provided scope.
A source of configuration fragments.
Config getConfig(const Params &, DiagnosticCallback) const
Build a config based on this provider.
Records an event whose duration is the lifetime of the Span object.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
@ Changed
The file got changed.
std::vector< TypeHierarchyItem > subTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct children of a TypeHierarchyItem.
std::optional< std::vector< TypeHierarchyItem > > superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct parents of a TypeHierarchyItem using SymbolIDs stored inside the item.
std::vector< CallHierarchyIncomingCall > incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
std::vector< HighlightingToken > getSemanticHighlightings(ParsedAST &AST, bool IncludeInactiveRegionTokens)
bool pathEqual(PathRef A, PathRef B)
llvm::Expected< std::unique_ptr< Tweak > > prepareTweak(StringRef ID, const Tweak::Selection &S, const FeatureModuleSet *Modules)
ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens, const ASTContext &Ctx)
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
void vlog(const char *Fmt, Ts &&... Vals)
llvm::Error reformatEdit(Edit &E, const format::FormatStyle &Style)
Formats the edits and code around it according to Style.
std::vector< LocatedSymbol > findType(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns symbols for types referenced at Pos.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
llvm::Expected< std::vector< FoldingRange > > getFoldingRanges(const std::string &Code, bool LineFoldingOnly)
Returns a list of ranges whose contents might be collapsible in an editor.
llvm::Expected< RenameResult > rename(const RenameInputs &RInputs)
Renames all occurrences of the symbol.
std::vector< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index, bool AddContext)
Returns references of the symbol at a specified Pos.
std::optional< HoverInfo > getHover(ParsedAST &AST, Position Pos, const format::FormatStyle &Style, const SymbolIndex *Index)
Get the hover information when hovering at Pos.
std::vector< tooling::Replacement > formatIncremental(llvm::StringRef OriginalCode, unsigned OriginalCursor, llvm::StringRef InsertedText, format::FormatStyle Style)
Applies limited formatting around new InsertedText.
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
llvm::Expected< SelectionRange > getSemanticRanges(ParsedAST &AST, Position Pos)
Returns the list of all interesting ranges around the Position Pos.
void log(const char *Fmt, Ts &&... Vals)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
llvm::Expected< std::vector< DocumentSymbol > > getDocumentSymbols(ParsedAST &AST)
Retrieves the symbols contained in the "main file" section of an AST in the same order that they appe...
std::optional< Path > getCorrespondingHeaderOrSource(PathRef OriginalFile, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS)
Given a header file, returns the best matching source file, and vice visa.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Diag toDiag(const llvm::SMDiagnostic &D, Diag::DiagSource Source)
std::vector< std::unique_ptr< Tweak > > prepareTweaks(const Tweak::Selection &S, llvm::function_ref< bool(const Tweak &)> Filter, const FeatureModuleSet *Modules)
Calls prepare() on all tweaks that satisfy the filter, returning those that can run on the selection.
WantDiagnostics
Determines whether diagnostics should be generated for a file snapshot.
@ Auto
Diagnostics must not be generated for this snapshot.
std::vector< LocatedSymbol > findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns implementations at a specified Pos:
std::string Path
A typedef to represent a file path.
int isCancelled(const Context &Ctx)
If the current context is within a cancelled task, returns the reason.
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
std::vector< Range > getInactiveRegions(ParsedAST &AST)
Deadline timeoutSeconds(std::optional< double > Seconds)
Makes a deadline from a timeout in seconds. std::nullopt means wait forever.
CodeCompleteResult codeComplete(PathRef FileName, Position Pos, const PreambleData *Preamble, const ParseInputs &ParseInput, CodeCompleteOptions Opts, SpeculativeFuzzyFind *SpecFuzzyFind)
Gets code completions at a specified Pos in FileName.
std::vector< CallHierarchyOutgoingCall > outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
SignatureHelp signatureHelp(PathRef FileName, Position Pos, const PreambleData &Preamble, const ParseInputs &ParseInput, MarkupKind DocumentationFormat)
Get signature help at a specified Pos in FileName.
std::vector< InlayHint > inlayHints(ParsedAST &AST, std::optional< Range > RestrictRange, InlayHintOptions HintOptions)
Compute and return inlay hints for a file.
TextEdit replacementToEdit(llvm::StringRef Code, const tooling::Replacement &R)
SymbolSlab indexStandardLibrary(llvm::StringRef HeaderSources, std::unique_ptr< CompilerInvocation > CI, const StdLibLocation &Loc, const ThreadsafeFS &TFS)
std::vector< CallHierarchyItem > prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath)
Get call hierarchy information at Pos.
format::FormatStyle getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content, const ThreadsafeFS &TFS, bool FormatFile)
Choose the clang-format style we should apply to a certain file.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Represents programming constructs like functions or constructors in the context of call hierarchy.
std::vector< TweakRef > TweakRefs
std::vector< Rename > Renames
std::vector< QuickFix > QuickFixes
std::function< Context(PathRef)> ContextProvider
If set, queried to derive a processing context for some work.
clangd::PreambleThrottler * PreambleThrottler
This throttler controls which preambles may be built at a given time.
bool StorePreamblesInMemory
Cached preambles are potentially large. If false, store them on disk.
ASTRetentionPolicy RetentionPolicy
AST caching policy. The default is to keep up to 3 ASTs in memory.
unsigned AsyncThreadsCount
To process requests asynchronously, ClangdServer spawns worker threads.
DebouncePolicy UpdateDebounce
Time to wait after a new file version before computing diagnostics.
static const llvm::StringLiteral QUICKFIX_KIND
Settings that express user/project preferences and control clangd behavior.
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
static DebouncePolicy fixed(clock::duration)
A policy that always returns the same duration, useful for tests.
A top-level diagnostic that may have Notes and Fixes.
std::vector< Fix > Fixes
Alternative fixes for this diagnostic, one should be chosen.
std::vector< FileEvent > changes
The actual file events.
A set of edits generated for a single file.
Represents a single fix-it that editor can apply to fix the error.
A tree that can be used to represent memory usage of nested components while preserving the hierarchy...
MemoryTree & child(llvm::StringLiteral Name)
No copy of the Name.
bool PreambleParseForwardingFunctions
The parsed preamble and associated data.
PrecompiledPreamble Preamble
Position start
The range's start position.
Position end
The range's end position.
bool WantFormat
If true, format the rename edits, only meaningful in ClangdServer layer.
ASTRetentionPolicy RetentionPolicy
Determines when to keep idle ASTs in memory for future use.
DebouncePolicy UpdateDebounce
Time to wait after an update to see if another one comes along.
std::function< Context(PathRef)> ContextProvider
Used to create a context that wraps each single operation.
bool StorePreamblesInMemory
Cache (large) preamble data in RAM rather than temporary files on disk.
unsigned AsyncThreadsCount
Number of concurrent actions.
clangd::PreambleThrottler * PreambleThrottler
This throttler controls which preambles may be built at a given time.
Describes the context used to evaluate configuration fragments.
std::chrono::steady_clock::time_point FreshTime
Hint that stale data is OK to improve performance (e.g.
llvm::StringRef Path
Absolute path to a source file we're applying the config to.
Represents measurements of clangd events, e.g.
@ Counter
An aggregate number whose rate of change over time is meaningful.
@ Distribution
A distribution of values with a meaningful mean and count.
void record(double Value, llvm::StringRef Label="") const
Records a measurement for this metric to active tracer.