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"
65static constexpr trace::Metric TweakAvailable(
69struct UpdateIndexCallbacks :
public ParsingCallbacks {
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;
176class DraftStoreFS :
public ThreadsafeFS {
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;
198 Opts.StorePreamblesInMemory =
true;
199 Opts.AsyncThreadsCount = 4;
205 Opts.AsyncThreadsCount = AsyncThreadsCount;
206 Opts.RetentionPolicy = RetentionPolicy;
207 Opts.StorePreamblesInMemory = StorePreamblesInMemory;
208 Opts.UpdateDebounce = UpdateDebounce;
209 Opts.ContextProvider = ContextProvider;
218 DynamicIdx(Opts.BuildDynamicSymbolIndex
219 ? new
FileIndex(Opts.EnableOutgoingCalls)
221 ModulesManager(Opts.ModulesManager),
222 ClangTidyProvider(Opts.ClangTidyProvider),
223 UseDirtyHeaders(Opts.UseDirtyHeaders),
224 LineFoldingOnly(Opts.LineFoldingOnly),
225 PreambleParseForwardingFunctions(Opts.PreambleParseForwardingFunctions),
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 if (Opts.AsyncThreadsCount != 0)
233 IndexTasks.emplace();
238 std::make_unique<UpdateIndexCallbacks>(
240 IndexTasks ? &*IndexTasks :
nullptr,
241 PublishInactiveRegions));
244 if (this->Index !=
nullptr) {
245 MergedIdx.push_back(std::make_unique<MergedIndex>(Idx, this->Index));
246 this->Index = MergedIdx.back().get();
251 if (Opts.StaticIndex)
252 AddIndex(Opts.StaticIndex);
253 if (Opts.BackgroundIndex) {
262 BackgroundIdx = std::make_unique<BackgroundIndex>(
265 [&CDB](llvm::StringRef
File) {
return CDB.getProjectInfo(
File); }),
267 AddIndex(BackgroundIdx.get());
270 AddIndex(DynamicIdx.get());
272 if (Opts.FeatureModules) {
274 *this->WorkScheduler,
278 for (
auto &Mod : *Opts.FeatureModules)
287 WorkScheduler.reset();
289 if (FeatureModules) {
290 for (
auto &Mod : *FeatureModules)
298 llvm::StringRef Version,
300 std::string ActualVersion = DraftMgr.
addDraft(
File, Version, Contents);
302 Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions;
303 Opts.ImportInsertions = ImportInsertions;
307 Inputs.TFS = &getHeaderFS();
308 Inputs.Contents = std::string(Contents);
309 Inputs.Version = std::move(ActualVersion);
310 Inputs.ForceRebuild = ForceRebuild;
311 Inputs.Opts = std::move(Opts);
312 Inputs.Index = Index;
313 Inputs.ClangTidyProvider = ClangTidyProvider;
314 Inputs.FeatureModules = FeatureModules;
315 Inputs.ModulesManager = ModulesManager;
316 bool NewFile = WorkScheduler->update(
File, Inputs,
WantDiags);
318 if (NewFile && BackgroundIdx)
319 BackgroundIdx->boostRelated(
File);
323 llvm::function_ref<
bool(llvm::StringRef
File)> Filter) {
326 if (Filter(FilePath))
327 if (
auto Draft = DraftMgr.
getDraft(FilePath))
328 addDocument(FilePath, *Draft->Contents, Draft->Version,
336 return std::move(Draft->Contents);
348 std::mutex PublishMu;
351 : Provider(Provider), Publish(Publish) {}
353 Context operator()(llvm::StringRef File) {
358 std::chrono::steady_clock::now() - std::chrono::seconds(5);
359 llvm::SmallString<256> PosixPath;
361 assert(llvm::sys::path::is_absolute(File));
362 llvm::sys::path::native(File, PosixPath, llvm::sys::path::Style::posix);
363 Params.
Path = PosixPath.str();
366 llvm::StringMap<std::vector<Diag>> ReportableDiagnostics;
371 handleDiagnostic(D, !Publish || D.getFilename().empty()
373 : &ReportableDiagnostics[D.getFilename()]);
378 if (!ReportableDiagnostics.empty()) {
379 std::lock_guard<std::mutex> Lock(PublishMu);
380 for (
auto &
Entry : ReportableDiagnostics)
384 return Context::current().derive(Config::Key, std::move(
C));
387 void handleDiagnostic(
const llvm::SMDiagnostic &D,
388 std::vector<Diag> *ClientDiagnostics) {
389 switch (D.getKind()) {
390 case llvm::SourceMgr::DK_Error:
391 elog(
"config error at {0}:{1}:{2}: {3}", D.getFilename(), D.getLineNo(),
392 D.getColumnNo(), D.getMessage());
394 case llvm::SourceMgr::DK_Warning:
395 log(
"config warning at {0}:{1}:{2}: {3}", D.getFilename(),
396 D.getLineNo(), D.getColumnNo(), D.getMessage());
398 case llvm::SourceMgr::DK_Note:
399 case llvm::SourceMgr::DK_Remark:
400 vlog(
"config note at {0}:{1}:{2}: {3}", D.getFilename(), D.getLineNo(),
401 D.getColumnNo(), D.getMessage());
402 ClientDiagnostics =
nullptr;
405 if (ClientDiagnostics)
406 ClientDiagnostics->push_back(
toDiag(D, Diag::ClangdConfig));
411 return [I(std::make_shared<Impl>(Provider, Publish))](llvm::StringRef
Path) {
418 WorkScheduler->remove(
File);
425 auto CodeCompleteOpts = Opts;
426 if (!CodeCompleteOpts.Index)
427 CodeCompleteOpts.Index = Index;
429 auto Task = [
Pos, CodeCompleteOpts,
File =
File.str(), CB = std::move(CB),
430 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
432 return CB(IP.takeError());
434 return CB(llvm::make_error<CancelledError>(Reason));
436 std::optional<SpeculativeFuzzyFind> SpecFuzzyFind;
440 vlog(
"Build for file {0} is not ready. Enter fallback mode.",
File);
441 }
else if (CodeCompleteOpts.Index) {
442 SpecFuzzyFind.emplace();
444 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
445 SpecFuzzyFind->CachedReq = CachedCompletionFuzzyFindRequestByFile[
File];
451 if (!IP->Contents.ends_with(
"\n"))
455 CodeCompleteOpts.MainFileSignals = IP->Signals;
462 SpecFuzzyFind ? &*SpecFuzzyFind :
nullptr);
465 CB(std::move(Result));
467 if (SpecFuzzyFind && SpecFuzzyFind->NewReq) {
468 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
469 CachedCompletionFuzzyFindRequestByFile[
File] = *SpecFuzzyFind->NewReq;
478 WorkScheduler->runWithPreamble(
479 "CodeComplete",
File,
492 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
494 return CB(IP.takeError());
498 return CB(
error(
"Failed to parse includes"));
503 if (!IP->Contents.ends_with(
"\n"))
507 DocumentationFormat));
519 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
521 tooling::Range RequestedRange;
525 return CB(Begin.takeError());
528 return CB(End.takeError());
529 RequestedRange = tooling::Range(*Begin, *End - *Begin);
531 RequestedRange = tooling::Range(0, Code->size());
536 Ranges = std::vector<tooling::Range>{RequestedRange},
537 CB = std::move(CB),
this]()
mutable {
539 tooling::Replacements IncludeReplaces =
540 format::sortIncludes(Style, Code, Ranges,
File);
541 auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces);
543 return CB(
Changed.takeError());
545 CB(IncludeReplaces.merge(format::reformat(
547 tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
550 WorkScheduler->runQuick(
"Format",
File, std::move(
Action));
554 StringRef TriggerText,
555 Callback<std::vector<TextEdit>> CB) {
558 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
562 return CB(CursorPos.takeError());
564 TriggerText = TriggerText.str(), CursorPos = *CursorPos,
565 CB = std::move(CB),
this]()
mutable {
567 std::vector<TextEdit> Result;
568 for (
const tooling::Replacement &R :
573 WorkScheduler->runQuick(
"FormatOnType",
File, std::move(
Action));
577 std::optional<std::string> NewName,
581 NewName = std::move(NewName),
582 RenameOpts](llvm::Expected<InputsAndAST> InpAST)
mutable {
584 return CB(InpAST.takeError());
589 InpAST->AST,
File,
nullptr,
590 nullptr, RenameOpts});
595 return CB(
Results.takeError());
599 WorkScheduler->runWithAST(
"PrepareRename",
File, std::move(
Action));
607 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
612 return CB(InpAST.takeError());
614 DirtyFS->view(std::nullopt), Index, Opts});
616 return CB(R.takeError());
618 if (Opts.WantFormat) {
620 *InpAST->Inputs.TFS,
false);
621 llvm::Error Err = llvm::Error::success();
622 for (
auto &
E : R->GlobalChanges)
624 llvm::joinErrors(
reformatEdit(
E.getValue(), Style), std::move(Err));
627 return CB(std::move(Err));
629 RenameFiles.
record(R->GlobalChanges.size());
632 WorkScheduler->runWithAST(
"Rename",
File, std::move(
Action));
638llvm::Expected<std::vector<std::unique_ptr<Tweak::Selection>>>
640 llvm::vfs::FileSystem *FS) {
643 return Begin.takeError();
646 return End.takeError();
647 std::vector<std::unique_ptr<Tweak::Selection>> Result;
649 AST.AST.getASTContext(),
AST.AST.getTokens(), *Begin, *End,
651 Result.push_back(std::make_unique<Tweak::Selection>(
652 AST.Inputs.Index, AST.AST, *Begin, *End, std::move(T), FS));
655 assert(!Result.empty() &&
"Expected at least one SelectionTree");
656 return std::move(Result);
662std::optional<ClangdServer::CodeActionResult::Rename>
663tryConvertToRename(
const Diag *Diag,
const Fix &Fix) {
665 Diag->Name ==
"readability-identifier-naming" &&
667 if (IsClangTidyRename && Diag->InsideMainFile) {
668 ClangdServer::CodeActionResult::Rename R;
669 R.NewName = Fix.Edits.front().newText;
670 R.FixMessage = Fix.Message;
671 R.Diag = {Diag->Range, Diag->Message};
682 auto Action = [Params, CB = std::move(CB),
683 FeatureModules(this->FeatureModules)](
684 Expected<InputsAndAST> InpAST)
mutable {
686 return CB(InpAST.takeError());
691 return llvm::any_of(Only, [&](llvm::StringRef Base) {
692 return Kind.consume_front(Base) &&
693 (
Kind.empty() ||
Kind.starts_with(
"."));
698 Result.Version = InpAST->AST.version().str();
700 auto FindMatchedDiag = [&InpAST](
const DiagRef &DR) ->
const Diag * {
701 for (
const auto &
Diag : InpAST->AST.getDiagnostics())
709 if (
auto Rename = tryConvertToRename(
Diag,
Fix)) {
710 Result.Renames.emplace_back(std::move(*Rename));
719 auto Selections = tweakSelection(Params.
Selection, *InpAST,
nullptr);
721 return CB(Selections.takeError());
723 llvm::DenseSet<llvm::StringRef> PreparedTweaks;
724 auto DeduplicatingFilter = [&](
const Tweak &T) {
725 return KindAllowed(T.kind()) && Params.
TweakFilter(T) &&
726 !PreparedTweaks.count(T.id());
728 for (
const auto &Sel : *Selections) {
729 for (
auto &T :
prepareTweaks(*Sel, DeduplicatingFilter, FeatureModules)) {
730 Result.TweakRefs.push_back(
TweakRef{T->id(), T->title(), T->kind()});
731 PreparedTweaks.insert(T->id());
732 TweakAvailable.record(1, T->id());
735 CB(std::move(Result));
738 WorkScheduler->runWithAST(
"codeAction", Params.
File, std::move(
Action),
750 TweakAttempt.
record(1, TweakID);
753 this](Expected<InputsAndAST> InpAST)
mutable {
755 return CB(InpAST.takeError());
756 auto FS = DirtyFS->view(std::nullopt);
757 auto Selections = tweakSelection(Sel, *InpAST, FS.get());
759 return CB(Selections.takeError());
760 std::optional<llvm::Expected<Tweak::Effect>> Effect;
763 for (
const auto &Selection : *Selections) {
764 auto T =
prepareTweak(TweakID, *Selection, FeatureModules);
766 Effect = (*T)->apply(*Selection);
769 Effect = T.takeError();
771 assert(Effect &&
"Expected at least one selection");
772 if (*Effect && (*Effect)->FormatEdits) {
774 for (
auto &It : (*Effect)->ApplyEdits) {
776 format::FormatStyle Style =
779 elog(
"Failed to format {0}: {1}", It.first(), std::move(Err));
782 TweakFailed.
record(1, TweakID);
784 return CB(std::move(*Effect));
786 WorkScheduler->runWithAST(
"ApplyTweak",
File, std::move(
Action));
790 Callback<std::vector<LocatedSymbol>> CB) {
792 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
794 return CB(InpAST.takeError());
798 WorkScheduler->runWithAST(
"Definitions",
File, std::move(
Action));
809 if (
auto CorrespondingFile =
811 return CB(std::move(CorrespondingFile));
813 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
815 return CB(InpAST.takeError());
818 WorkScheduler->runWithAST(
"SwitchHeaderSource",
Path, std::move(
Action));
824 [
Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
826 return CB(InpAST.takeError());
830 WorkScheduler->runWithAST(
"Highlights",
File, std::move(
Action), Transient);
834 Callback<std::optional<HoverInfo>> CB) {
836 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
838 return CB(InpAST.takeError());
840 File, InpAST->Inputs.Contents, *InpAST->Inputs.TFS,
false);
844 WorkScheduler->runWithAST(
"Hover",
File, std::move(
Action), Transient);
849 Callback<std::vector<TypeHierarchyItem>> CB) {
851 this](Expected<InputsAndAST> InpAST)
mutable {
853 return CB(InpAST.takeError());
858 WorkScheduler->runWithAST(
"TypeHierarchy",
File, std::move(
Action));
863 Callback<std::optional<std::vector<TypeHierarchyItem>>> CB) {
864 WorkScheduler->run(
"typeHierarchy/superTypes",
"",
865 [=, CB = std::move(CB)]()
mutable {
871 Callback<std::vector<TypeHierarchyItem>> CB) {
873 "typeHierarchy/subTypes",
"",
879 Callback<std::optional<TypeHierarchyItem>> CB) {
881 "Resolve Type Hierarchy",
"", [=, CB = std::move(CB)]()
mutable {
890 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
892 return CB(InpAST.takeError());
895 WorkScheduler->runWithAST(
"CallHierarchy",
File, std::move(
Action));
900 Callback<std::vector<CallHierarchyIncomingCall>> CB) {
901 WorkScheduler->run(
"Incoming Calls",
"",
902 [CB = std::move(CB), Item,
this]()
mutable {
908 Callback<std::vector<InlayHint>> CB) {
909 auto Action = [RestrictRange(std::move(RestrictRange)),
910 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
912 return CB(InpAST.takeError());
915 WorkScheduler->runWithAST(
"InlayHints",
File, std::move(
Action), Transient);
920 Callback<std::vector<CallHierarchyOutgoingCall>> CB) {
921 WorkScheduler->run(
"Outgoing Calls",
"",
922 [CB = std::move(CB), Item,
this]()
mutable {
933 llvm::StringRef Query,
int Limit,
934 Callback<std::vector<SymbolInformation>> CB) {
936 "getWorkspaceSymbols",
"",
937 [Query = Query.str(), Limit, CB = std::move(CB),
this]()
mutable {
938 CB(clangd::getWorkspaceSymbols(Query, Limit, Index,
939 WorkspaceRoot.value_or(
"")));
944 Callback<std::vector<DocumentSymbol>> CB) {
946 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
948 return CB(InpAST.takeError());
951 WorkScheduler->runWithAST(
"DocumentSymbols",
File, std::move(
Action),
956 Callback<std::vector<FoldingRange>> CB) {
959 return CB(llvm::make_error<LSPError>(
960 "trying to compute folding ranges for non-added document",
962 auto Action = [LineFoldingOnly = LineFoldingOnly, CB = std::move(CB),
963 Code = std::move(*Code)]()
mutable {
968 WorkScheduler->runQuick(
"FoldingRanges",
File, std::move(
Action));
972 Callback<std::vector<LocatedSymbol>> CB) {
974 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
976 return CB(InpAST.takeError());
979 WorkScheduler->runWithAST(
"FindType",
File, std::move(
Action));
985 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
987 return CB(InpAST.takeError());
991 WorkScheduler->runWithAST(
"Implementations",
File, std::move(
Action));
997 auto Action = [
Pos, Limit, AddContainer, CB = std::move(CB),
998 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
1000 return CB(InpAST.takeError());
1004 WorkScheduler->runWithAST(
"References",
File, std::move(
Action));
1008 Callback<std::vector<SymbolDetails>> CB) {
1010 [
Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1012 return CB(InpAST.takeError());
1016 WorkScheduler->runWithAST(
"SymbolInfo",
File, std::move(
Action));
1020 const std::vector<Position> &Positions,
1021 Callback<std::vector<SelectionRange>> CB) {
1022 auto Action = [Positions, CB = std::move(CB)](
1023 llvm::Expected<InputsAndAST> InpAST)
mutable {
1025 return CB(InpAST.takeError());
1026 std::vector<SelectionRange> Result;
1027 for (
const auto &
Pos : Positions) {
1029 Result.push_back(std::move(*
Range));
1031 return CB(
Range.takeError());
1033 CB(std::move(Result));
1035 WorkScheduler->runWithAST(
"SemanticRanges",
File, std::move(
Action));
1039 Callback<std::vector<DocumentLink>> CB) {
1041 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1043 return CB(InpAST.takeError());
1046 WorkScheduler->runWithAST(
"DocumentLinks",
File, std::move(
Action),
1053 auto Action = [CB = std::move(CB),
1054 PublishInactiveRegions = PublishInactiveRegions](
1055 llvm::Expected<InputsAndAST> InpAST)
mutable {
1057 return CB(InpAST.takeError());
1063 WorkScheduler->runWithAST(
"SemanticHighlights",
File, std::move(
Action),
1068 Callback<std::optional<ASTNode>> CB) {
1070 [R, CB(std::move(CB))](llvm::Expected<InputsAndAST> Inputs)
mutable {
1072 return CB(Inputs.takeError());
1076 auto Node = DynTypedNode::create(
1077 *Inputs->AST.getASTContext().getTranslationUnitDecl());
1079 Inputs->AST.getASTContext()));
1081 unsigned Start, End;
1085 return CB(
Offset.takeError());
1089 return CB(
Offset.takeError());
1091 Inputs->AST.getASTContext(), Inputs->AST.getTokens(), Start, End,
1093 if (const SelectionTree::Node *N = T.commonAncestor()) {
1094 CB(dumpAST(N->ASTNode, Inputs->AST.getTokens(),
1095 Inputs->AST.getASTContext()));
1103 WorkScheduler->runWithAST(
"GetAST",
File, std::move(
Action));
1108 WorkScheduler->runWithAST(
Name, File, std::move(
Action));
1113 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1115 return CB(InpAST.takeError());
1116 return CB(InpAST->AST.getDiagnostics());
1119 WorkScheduler->runWithAST(
"Diagnostics", File, std::move(
Action));
1122llvm::StringMap<TUScheduler::FileStats> ClangdServer::fileStats()
const {
1123 return WorkScheduler->fileStats();
1127ClangdServer::blockUntilIdleForTest(std::optional<double> TimeoutSeconds) {
1131#if defined(__has_feature) && \
1132 (__has_feature(address_sanitizer) || __has_feature(hwaddress_sanitizer) || \
1133 __has_feature(memory_sanitizer) || __has_feature(thread_sanitizer))
1134 if (TimeoutSeconds.has_value())
1135 (*TimeoutSeconds) *= 10;
1140 if (!WorkScheduler->blockUntilIdle(
timeoutSeconds(TimeoutSeconds)))
1143 if (IndexTasks && !IndexTasks->wait(
timeoutSeconds(TimeoutSeconds)))
1155 for (std::optional<double> Timeout :
1156 {TimeoutSeconds, TimeoutSeconds, std::optional<double>(0)}) {
1159 if (BackgroundIdx && !BackgroundIdx->blockUntilIdleForTest(Timeout))
1167 assert(WorkScheduler->blockUntilIdle(Deadline::zero()) &&
1168 "Something scheduled work while we're blocking the main thread!");
1174 DynamicIdx->profile(MT.
child(
"dynamic_index"));
1176 BackgroundIdx->profile(MT.
child(
"background_index"));
1177 WorkScheduler->profile(MT.
child(
"tuscheduler"));
llvm::SmallString< 256U > Name
FeatureModuleSet FeatureModules
const ParseInputs & ParseInput
std::vector< CodeCompletionResult > Results
::clang::DynTypedNode Node
const google::protobuf::Message & M
std::unique_ptr< CompilerInvocation > CI
WantDiagnostics WantDiags
static Factory createDiskBackedStorageFactory(std::function< std::optional< ProjectInfo >(PathRef)> GetProjectInfo)
Interface with hooks for users of ClangdServer to be notified of events.
virtual void onBackgroundIndexProgress(const BackgroundQueue::Stats &Stats)
Called when background indexing tasks are enqueued/started/completed.
virtual void onDiagnosticsReady(PathRef File, llvm::StringRef Version, llvm::ArrayRef< Diag > Diagnostics)
Called by ClangdServer when Diagnostics for File are ready.
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 typeHierarchy(PathRef File, Position Pos, int Resolve, TypeHierarchyDirection Direction, Callback< std::vector< TypeHierarchyItem > > CB)
Get information about type hierarchy for a given position.
void formatFile(PathRef File, std::optional< Range > Rng, Callback< tooling::Replacements > CB)
Run formatting for the File with content Code.
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 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 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 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.
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 ...
Context clone() const
Clone this context object.
static const Context & current()
Returns the context for the current thread, creating it if needed.
static Deadline infinity()
std::vector< Path > getActiveFiles() const
std::optional< Draft > getDraft(PathRef File) const
void removeDraft(PathRef File)
Remove the draft from the store.
std::string addDraft(PathRef File, llvm::StringRef Version, StringRef Contents)
Replace contents of the draft for File with Contents.
A FeatureModule contributes a vertical feature to clangd.
This manages symbols from files and an in-memory index on all symbols.
Provides compilation arguments used for parsing C and C++ files.
PreambleThrottler controls which preambles can build at any given time.
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.
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > view(std::nullopt_t CWD) const
Obtain a vfs::FileSystem with an arbitrary initial working directory.
An interface base for small context-sensitive refactoring actions.
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.
@ 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)
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::string Path
A typedef to represent a file path.
llvm::Expected< std::vector< FoldingRange > > getFoldingRanges(ParsedAST &AST)
Returns a list of ranges whose contents might be collapsible in an editor.
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::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.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
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.
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.
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::vector< InlayHint > inlayHints(ParsedAST &AST, std::optional< Range > RestrictRange)
Compute and return inlay hints for a file.
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)
llvm::StringRef PathRef
A typedef to represent a ref to file path.
SignatureHelp signatureHelp(PathRef FileName, Position Pos, const PreambleData &Preamble, const ParseInputs &ParseInput, MarkupKind DocumentationFormat)
Get signature help at a specified Pos in FileName.
void elog(const char *Fmt, Ts &&... Vals)
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++ -*-===//
std::function< Context(PathRef)> ContextProvider
std::function< void(BackgroundQueue::Stats)> OnProgress
bool SupportContainedRefs
Represents programming constructs like functions or constructors in the context of call hierarchy.
static const llvm::StringLiteral QUICKFIX_KIND
@ AlwaysParse
Block until we can run the parser (e.g.
Settings that express user/project preferences and control clangd behavior.
bool AllScopes
Whether code completion includes results that are not visible in current scopes.
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
ArgumentListsPolicy ArgumentLists
controls the completion options for argument lists.
struct clang::clangd::Config::@6 Completion
Configures code completion feature.
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.
A set of edits generated for a single file.
Shared server facilities needed by the module to get its work done.
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.
The parsed preamble and associated data.
PrecompiledPreamble Preamble
Position start
The range's start position.
Position end
The range's end position.
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.