26#include "clang-include-cleaner/Record.h"
37#include "clang/Basic/Stack.h"
38#include "clang/Format/Format.h"
39#include "clang/Lex/Preprocessor.h"
40#include "clang/Tooling/CompilationDatabase.h"
41#include "clang/Tooling/Core/Replacement.h"
42#include "llvm/ADT/ArrayRef.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"
64static constexpr trace::Metric TweakAvailable(
68struct UpdateIndexCallbacks :
public ParsingCallbacks {
69 UpdateIndexCallbacks(FileIndex *FIndex,
70 ClangdServer::Callbacks *ServerCallbacks,
71 const ThreadsafeFS &TFS, AsyncTaskRunner *Tasks,
72 bool CollectInactiveRegions)
73 : FIndex(FIndex), ServerCallbacks(ServerCallbacks), TFS(TFS),
74 Stdlib{std::make_shared<StdLibSet>()}, Tasks(Tasks),
75 CollectInactiveRegions(CollectInactiveRegions) {}
78 PathRef Path, llvm::StringRef Version, CapturedASTCtx ASTCtx,
79 std::shared_ptr<const include_cleaner::PragmaIncludes> PI)
override {
84 auto &PP = ASTCtx.getPreprocessor();
85 auto &
CI = ASTCtx.getCompilerInvocation();
86 if (
auto Loc = Stdlib->add(
CI.getLangOpts(), PP.getHeaderSearchInfo()))
87 indexStdlib(
CI, std::move(*
Loc));
90 auto Task = [FIndex(FIndex),
Path(
Path.str()), Version(Version.str()),
91 ASTCtx(std::move(ASTCtx)), PI(std::move(PI))]()
mutable {
92 trace::Span Tracer(
"PreambleIndexing");
93 FIndex->updatePreamble(
Path, Version, ASTCtx.getASTContext(),
94 ASTCtx.getPreprocessor(), *PI);
98 Tasks->runAsync(
"Preamble indexing for:" +
Path + Version,
104 void indexStdlib(
const CompilerInvocation &
CI, StdLibLocation
Loc) {
108 auto Task = [LO(
CI.getLangOpts()),
Loc(std::move(
Loc)),
109 CI(std::make_unique<CompilerInvocation>(
CI)),
115 Stdlib(Stdlib)]()
mutable {
116 clang::noteBottomOfStack();
119 if (Stdlib->isBest(LO))
120 FIndex->updatePreamble(std::move(IF));
124 Tasks->runAsync(
"IndexStdlib", std::move(Task));
129 void onMainAST(
PathRef Path, ParsedAST &
AST, PublishFn Publish)
override {
135 ServerCallbacks->onDiagnosticsReady(
Path,
AST.version(),
136 AST.getDiagnostics());
137 if (CollectInactiveRegions) {
138 ServerCallbacks->onInactiveRegionsReady(
Path,
144 void onFailedAST(
PathRef Path, llvm::StringRef Version,
145 std::vector<Diag> Diags, PublishFn Publish)
override {
148 [&]() { ServerCallbacks->onDiagnosticsReady(
Path, Version, Diags); });
151 void onFileUpdated(
PathRef File,
const TUStatus &Status)
override {
153 ServerCallbacks->onFileUpdated(
File, Status);
158 ServerCallbacks->onSemanticsMaybeChanged(
File);
163 ClangdServer::Callbacks *ServerCallbacks;
164 const ThreadsafeFS &TFS;
165 std::shared_ptr<StdLibSet> Stdlib;
166 AsyncTaskRunner *Tasks;
167 bool CollectInactiveRegions;
170class DraftStoreFS :
public ThreadsafeFS {
172 DraftStoreFS(
const ThreadsafeFS &Base,
const DraftStore &Drafts)
173 : Base(Base), DirtyFiles(Drafts) {}
176 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
177 auto OFS = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(
178 Base.view(std::nullopt));
179 OFS->pushOverlay(DirtyFiles.asVFS());
183 const ThreadsafeFS &Base;
184 const DraftStore &DirtyFiles;
192 Opts.StorePreamblesInMemory =
true;
193 Opts.AsyncThreadsCount = 4;
199 Opts.AsyncThreadsCount = AsyncThreadsCount;
200 Opts.RetentionPolicy = RetentionPolicy;
201 Opts.StorePreamblesInMemory = StorePreamblesInMemory;
202 Opts.UpdateDebounce = UpdateDebounce;
203 Opts.ContextProvider = ContextProvider;
212 DynamicIdx(Opts.BuildDynamicSymbolIndex ? new
FileIndex() : nullptr),
213 ClangTidyProvider(Opts.ClangTidyProvider),
214 UseDirtyHeaders(Opts.UseDirtyHeaders),
215 LineFoldingOnly(Opts.LineFoldingOnly),
216 PreambleParseForwardingFunctions(Opts.PreambleParseForwardingFunctions),
217 ImportInsertions(Opts.ImportInsertions),
218 PublishInactiveRegions(Opts.PublishInactiveRegions),
219 WorkspaceRoot(Opts.WorkspaceRoot),
220 Transient(Opts.ImplicitCancellation ?
TUScheduler::InvalidateOnUpdate
222 DirtyFS(std::make_unique<DraftStoreFS>(TFS, DraftMgr)) {
223 if (Opts.AsyncThreadsCount != 0)
224 IndexTasks.emplace();
229 std::make_unique<UpdateIndexCallbacks>(
231 IndexTasks ? &*IndexTasks :
nullptr,
232 PublishInactiveRegions));
235 if (this->Index !=
nullptr) {
236 MergedIdx.push_back(std::make_unique<MergedIndex>(Idx, this->Index));
237 this->Index = MergedIdx.back().get();
242 if (Opts.StaticIndex)
243 AddIndex(Opts.StaticIndex);
244 if (Opts.BackgroundIndex) {
252 BackgroundIdx = std::make_unique<BackgroundIndex>(
255 [&CDB](llvm::StringRef
File) {
return CDB.getProjectInfo(
File); }),
257 AddIndex(BackgroundIdx.get());
260 AddIndex(DynamicIdx.get());
262 if (Opts.FeatureModules) {
264 *this->WorkScheduler,
268 for (
auto &Mod : *Opts.FeatureModules)
277 WorkScheduler.reset();
279 if (FeatureModules) {
280 for (
auto &Mod : *FeatureModules)
288 llvm::StringRef Version,
290 std::string ActualVersion = DraftMgr.
addDraft(
File, Version, Contents);
292 Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions;
293 Opts.ImportInsertions = ImportInsertions;
297 Inputs.TFS = &getHeaderFS();
298 Inputs.Contents = std::string(Contents);
299 Inputs.Version = std::move(ActualVersion);
300 Inputs.ForceRebuild = ForceRebuild;
301 Inputs.Opts = std::move(Opts);
302 Inputs.Index = Index;
303 Inputs.ClangTidyProvider = ClangTidyProvider;
304 Inputs.FeatureModules = FeatureModules;
305 bool NewFile = WorkScheduler->update(
File, Inputs,
WantDiags);
307 if (NewFile && BackgroundIdx)
308 BackgroundIdx->boostRelated(
File);
312 llvm::function_ref<
bool(llvm::StringRef
File)> Filter) {
315 if (Filter(FilePath))
316 if (
auto Draft = DraftMgr.
getDraft(FilePath))
317 addDocument(FilePath, *Draft->Contents, Draft->Version,
325 return std::move(Draft->Contents);
337 std::mutex PublishMu;
340 : Provider(Provider), Publish(Publish) {}
342 Context operator()(llvm::StringRef File) {
347 std::chrono::steady_clock::now() - std::chrono::seconds(5);
348 llvm::SmallString<256> PosixPath;
350 assert(llvm::sys::path::is_absolute(File));
351 llvm::sys::path::native(File, PosixPath, llvm::sys::path::Style::posix);
352 Params.
Path = PosixPath.str();
355 llvm::StringMap<std::vector<Diag>> ReportableDiagnostics;
360 handleDiagnostic(D, !Publish || D.getFilename().empty()
362 : &ReportableDiagnostics[D.getFilename()]);
367 if (!ReportableDiagnostics.empty()) {
368 std::lock_guard<std::mutex> Lock(PublishMu);
369 for (
auto &
Entry : ReportableDiagnostics)
373 return Context::current().derive(Config::Key, std::move(
C));
376 void handleDiagnostic(
const llvm::SMDiagnostic &D,
377 std::vector<Diag> *ClientDiagnostics) {
378 switch (D.getKind()) {
379 case llvm::SourceMgr::DK_Error:
380 elog(
"config error at {0}:{1}:{2}: {3}", D.getFilename(), D.getLineNo(),
381 D.getColumnNo(), D.getMessage());
383 case llvm::SourceMgr::DK_Warning:
384 log(
"config warning at {0}:{1}:{2}: {3}", D.getFilename(),
385 D.getLineNo(), D.getColumnNo(), D.getMessage());
387 case llvm::SourceMgr::DK_Note:
388 case llvm::SourceMgr::DK_Remark:
389 vlog(
"config note at {0}:{1}:{2}: {3}", D.getFilename(), D.getLineNo(),
390 D.getColumnNo(), D.getMessage());
391 ClientDiagnostics =
nullptr;
394 if (ClientDiagnostics)
395 ClientDiagnostics->push_back(
toDiag(D, Diag::ClangdConfig));
400 return [I(std::make_shared<Impl>(Provider, Publish))](llvm::StringRef
Path) {
407 WorkScheduler->remove(
File);
414 auto CodeCompleteOpts = Opts;
415 if (!CodeCompleteOpts.Index)
416 CodeCompleteOpts.Index = Index;
418 auto Task = [
Pos, CodeCompleteOpts,
File =
File.str(), CB = std::move(CB),
419 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
421 return CB(IP.takeError());
423 return CB(llvm::make_error<CancelledError>(Reason));
425 std::optional<SpeculativeFuzzyFind> SpecFuzzyFind;
429 vlog(
"Build for file {0} is not ready. Enter fallback mode.",
File);
430 }
else if (CodeCompleteOpts.Index) {
431 SpecFuzzyFind.emplace();
433 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
434 SpecFuzzyFind->CachedReq = CachedCompletionFuzzyFindRequestByFile[
File];
440 if (!IP->Contents.ends_with(
"\n"))
444 CodeCompleteOpts.MainFileSignals = IP->Signals;
450 SpecFuzzyFind ? &*SpecFuzzyFind :
nullptr);
453 CB(std::move(Result));
455 if (SpecFuzzyFind && SpecFuzzyFind->NewReq) {
456 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
457 CachedCompletionFuzzyFindRequestByFile[
File] = *SpecFuzzyFind->NewReq;
466 WorkScheduler->runWithPreamble(
467 "CodeComplete",
File,
480 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
482 return CB(IP.takeError());
486 return CB(
error(
"Failed to parse includes"));
491 if (!IP->Contents.ends_with(
"\n"))
495 DocumentationFormat));
507 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
509 tooling::Range RequestedRange;
513 return CB(Begin.takeError());
516 return CB(End.takeError());
517 RequestedRange = tooling::Range(*Begin, *End - *Begin);
519 RequestedRange = tooling::Range(0,
Code->size());
524 Ranges = std::vector<tooling::Range>{RequestedRange},
525 CB = std::move(CB),
this]()
mutable {
527 tooling::Replacements IncludeReplaces =
528 format::sortIncludes(Style,
Code, Ranges,
File);
529 auto Changed = tooling::applyAllReplacements(
Code, IncludeReplaces);
531 return CB(
Changed.takeError());
533 CB(IncludeReplaces.merge(format::reformat(
535 tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
538 WorkScheduler->runQuick(
"Format",
File, std::move(
Action));
542 StringRef TriggerText,
543 Callback<std::vector<TextEdit>> CB) {
546 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
550 return CB(CursorPos.takeError());
552 TriggerText = TriggerText.str(), CursorPos = *CursorPos,
553 CB = std::move(CB),
this]()
mutable {
555 std::vector<TextEdit> Result;
556 for (
const tooling::Replacement &R :
561 WorkScheduler->runQuick(
"FormatOnType",
File, std::move(
Action));
565 std::optional<std::string> NewName,
569 NewName = std::move(NewName),
570 RenameOpts](llvm::Expected<InputsAndAST> InpAST)
mutable {
572 return CB(InpAST.takeError());
577 InpAST->AST,
File,
nullptr,
578 nullptr, RenameOpts});
583 return CB(
Results.takeError());
587 WorkScheduler->runWithAST(
"PrepareRename",
File, std::move(
Action));
595 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
600 return CB(InpAST.takeError());
602 DirtyFS->view(std::nullopt), Index, Opts});
604 return CB(R.takeError());
606 if (Opts.WantFormat) {
608 *InpAST->Inputs.TFS,
false);
609 llvm::Error Err = llvm::Error::success();
610 for (
auto &
E : R->GlobalChanges)
612 llvm::joinErrors(
reformatEdit(
E.getValue(), Style), std::move(Err));
615 return CB(std::move(Err));
617 RenameFiles.
record(R->GlobalChanges.size());
620 WorkScheduler->runWithAST(
"Rename",
File, std::move(
Action));
626llvm::Expected<std::vector<std::unique_ptr<Tweak::Selection>>>
628 llvm::vfs::FileSystem *FS) {
631 return Begin.takeError();
634 return End.takeError();
635 std::vector<std::unique_ptr<Tweak::Selection>> Result;
637 AST.AST.getASTContext(),
AST.AST.getTokens(), *Begin, *End,
639 Result.push_back(std::make_unique<Tweak::Selection>(
640 AST.Inputs.Index, AST.AST, *Begin, *End, std::move(T), FS));
643 assert(!Result.empty() &&
"Expected at least one SelectionTree");
644 return std::move(Result);
650std::optional<ClangdServer::CodeActionResult::Rename>
651tryConvertToRename(
const Diag *Diag,
const Fix &Fix) {
653 Diag->Name ==
"readability-identifier-naming" &&
655 if (IsClangTidyRename && Diag->InsideMainFile) {
656 ClangdServer::CodeActionResult::Rename R;
657 R.NewName = Fix.Edits.front().newText;
658 R.FixMessage = Fix.Message;
659 R.Diag = {Diag->Range, Diag->Message};
670 auto Action = [Params, CB = std::move(CB),
671 FeatureModules(this->FeatureModules)](
672 Expected<InputsAndAST> InpAST)
mutable {
674 return CB(InpAST.takeError());
679 return llvm::any_of(Only, [&](llvm::StringRef Base) {
680 return Kind.consume_front(Base) &&
681 (
Kind.empty() ||
Kind.starts_with(
"."));
686 Result.Version = InpAST->AST.version().str();
688 auto FindMatchedDiag = [&InpAST](
const DiagRef &DR) ->
const Diag * {
689 for (
const auto &
Diag : InpAST->AST.getDiagnostics())
697 if (
auto Rename = tryConvertToRename(
Diag,
Fix)) {
698 Result.Renames.emplace_back(std::move(*Rename));
707 auto Selections = tweakSelection(Params.
Selection, *InpAST,
nullptr);
709 return CB(Selections.takeError());
711 llvm::DenseSet<llvm::StringRef> PreparedTweaks;
712 auto DeduplicatingFilter = [&](
const Tweak &T) {
713 return KindAllowed(T.kind()) && Params.
TweakFilter(T) &&
714 !PreparedTweaks.count(T.id());
716 for (
const auto &Sel : *Selections) {
717 for (
auto &T :
prepareTweaks(*Sel, DeduplicatingFilter, FeatureModules)) {
718 Result.TweakRefs.push_back(
TweakRef{T->id(), T->title(), T->kind()});
719 PreparedTweaks.insert(T->id());
720 TweakAvailable.record(1, T->id());
723 CB(std::move(Result));
726 WorkScheduler->runWithAST(
"codeAction", Params.
File, std::move(
Action),
738 TweakAttempt.
record(1, TweakID);
741 this](Expected<InputsAndAST> InpAST)
mutable {
743 return CB(InpAST.takeError());
744 auto FS = DirtyFS->view(std::nullopt);
745 auto Selections = tweakSelection(Sel, *InpAST, FS.get());
747 return CB(Selections.takeError());
748 std::optional<llvm::Expected<Tweak::Effect>> Effect;
751 for (
const auto &Selection : *Selections) {
752 auto T =
prepareTweak(TweakID, *Selection, FeatureModules);
754 Effect = (*T)->apply(*Selection);
757 Effect = T.takeError();
759 assert(Effect &&
"Expected at least one selection");
760 if (*Effect && (*Effect)->FormatEdits) {
762 for (
auto &It : (*Effect)->ApplyEdits) {
764 format::FormatStyle Style =
767 elog(
"Failed to format {0}: {1}", It.first(), std::move(Err));
770 TweakFailed.
record(1, TweakID);
772 return CB(std::move(*Effect));
774 WorkScheduler->runWithAST(
"ApplyTweak",
File, std::move(
Action));
778 Callback<std::vector<LocatedSymbol>> CB) {
780 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
782 return CB(InpAST.takeError());
786 WorkScheduler->runWithAST(
"Definitions",
File, std::move(
Action));
797 if (
auto CorrespondingFile =
799 return CB(std::move(CorrespondingFile));
801 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
803 return CB(InpAST.takeError());
806 WorkScheduler->runWithAST(
"SwitchHeaderSource",
Path, std::move(
Action));
812 [
Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
814 return CB(InpAST.takeError());
818 WorkScheduler->runWithAST(
"Highlights",
File, std::move(
Action), Transient);
822 Callback<std::optional<HoverInfo>> CB) {
824 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
826 return CB(InpAST.takeError());
828 File, InpAST->Inputs.Contents, *InpAST->Inputs.TFS,
false);
832 WorkScheduler->runWithAST(
"Hover",
File, std::move(
Action), Transient);
837 Callback<std::vector<TypeHierarchyItem>> CB) {
839 this](Expected<InputsAndAST> InpAST)
mutable {
841 return CB(InpAST.takeError());
846 WorkScheduler->runWithAST(
"TypeHierarchy",
File, std::move(
Action));
851 Callback<std::optional<std::vector<TypeHierarchyItem>>> CB) {
852 WorkScheduler->run(
"typeHierarchy/superTypes",
"",
853 [=, CB = std::move(CB)]()
mutable {
859 Callback<std::vector<TypeHierarchyItem>> CB) {
861 "typeHierarchy/subTypes",
"",
867 Callback<std::optional<TypeHierarchyItem>> CB) {
869 "Resolve Type Hierarchy",
"", [=, CB = std::move(CB)]()
mutable {
878 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
880 return CB(InpAST.takeError());
883 WorkScheduler->runWithAST(
"CallHierarchy",
File, std::move(
Action));
888 Callback<std::vector<CallHierarchyIncomingCall>> CB) {
889 WorkScheduler->run(
"Incoming Calls",
"",
890 [CB = std::move(CB), Item,
this]()
mutable {
896 Callback<std::vector<InlayHint>> CB) {
897 auto Action = [RestrictRange(std::move(RestrictRange)),
898 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
900 return CB(InpAST.takeError());
903 WorkScheduler->runWithAST(
"InlayHints",
File, std::move(
Action), Transient);
912 llvm::StringRef Query,
int Limit,
913 Callback<std::vector<SymbolInformation>> CB) {
915 "getWorkspaceSymbols",
"",
916 [Query = Query.str(), Limit, CB = std::move(CB),
this]()
mutable {
917 CB(clangd::getWorkspaceSymbols(Query, Limit, Index,
918 WorkspaceRoot.value_or(
"")));
923 Callback<std::vector<DocumentSymbol>> CB) {
925 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
927 return CB(InpAST.takeError());
930 WorkScheduler->runWithAST(
"DocumentSymbols",
File, std::move(
Action),
935 Callback<std::vector<FoldingRange>> CB) {
938 return CB(llvm::make_error<LSPError>(
939 "trying to compute folding ranges for non-added document",
941 auto Action = [LineFoldingOnly = LineFoldingOnly, CB = std::move(CB),
942 Code = std::move(*
Code)]()
mutable {
947 WorkScheduler->runQuick(
"FoldingRanges",
File, std::move(
Action));
951 Callback<std::vector<LocatedSymbol>> CB) {
953 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
955 return CB(InpAST.takeError());
958 WorkScheduler->runWithAST(
"FindType",
File, std::move(
Action));
964 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
966 return CB(InpAST.takeError());
970 WorkScheduler->runWithAST(
"Implementations",
File, std::move(
Action));
976 auto Action = [
Pos, Limit, AddContainer, CB = std::move(CB),
977 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
979 return CB(InpAST.takeError());
983 WorkScheduler->runWithAST(
"References",
File, std::move(
Action));
987 Callback<std::vector<SymbolDetails>> CB) {
989 [
Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
991 return CB(InpAST.takeError());
995 WorkScheduler->runWithAST(
"SymbolInfo",
File, std::move(
Action));
999 const std::vector<Position> &Positions,
1000 Callback<std::vector<SelectionRange>> CB) {
1001 auto Action = [Positions, CB = std::move(CB)](
1002 llvm::Expected<InputsAndAST> InpAST)
mutable {
1004 return CB(InpAST.takeError());
1005 std::vector<SelectionRange> Result;
1006 for (
const auto &
Pos : Positions) {
1008 Result.push_back(std::move(*
Range));
1010 return CB(
Range.takeError());
1012 CB(std::move(Result));
1014 WorkScheduler->runWithAST(
"SemanticRanges",
File, std::move(
Action));
1018 Callback<std::vector<DocumentLink>> CB) {
1020 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1022 return CB(InpAST.takeError());
1025 WorkScheduler->runWithAST(
"DocumentLinks",
File, std::move(
Action),
1032 auto Action = [CB = std::move(CB),
1033 PublishInactiveRegions = PublishInactiveRegions](
1034 llvm::Expected<InputsAndAST> InpAST)
mutable {
1036 return CB(InpAST.takeError());
1042 WorkScheduler->runWithAST(
"SemanticHighlights",
File, std::move(
Action),
1047 Callback<std::optional<ASTNode>> CB) {
1049 [R, CB(std::move(CB))](llvm::Expected<InputsAndAST> Inputs)
mutable {
1051 return CB(Inputs.takeError());
1055 auto Node = DynTypedNode::create(
1056 *Inputs->AST.getASTContext().getTranslationUnitDecl());
1058 Inputs->AST.getASTContext()));
1060 unsigned Start, End;
1064 return CB(
Offset.takeError());
1068 return CB(
Offset.takeError());
1070 Inputs->AST.getASTContext(), Inputs->AST.getTokens(), Start, End,
1072 if (const SelectionTree::Node *N = T.commonAncestor()) {
1073 CB(dumpAST(N->ASTNode, Inputs->AST.getTokens(),
1074 Inputs->AST.getASTContext()));
1082 WorkScheduler->runWithAST(
"GetAST",
File, std::move(
Action));
1087 WorkScheduler->runWithAST(
Name, File, std::move(
Action));
1092 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1094 return CB(InpAST.takeError());
1095 return CB(InpAST->AST.getDiagnostics());
1098 WorkScheduler->runWithAST(
"Diagnostics", File, std::move(
Action));
1101llvm::StringMap<TUScheduler::FileStats> ClangdServer::fileStats()
const {
1102 return WorkScheduler->fileStats();
1106ClangdServer::blockUntilIdleForTest(std::optional<double> TimeoutSeconds) {
1110#if defined(__has_feature) && \
1111 (__has_feature(address_sanitizer) || __has_feature(hwaddress_sanitizer) || \
1112 __has_feature(memory_sanitizer) || __has_feature(thread_sanitizer))
1113 if (TimeoutSeconds.has_value())
1114 (*TimeoutSeconds) *= 10;
1119 if (!WorkScheduler->blockUntilIdle(
timeoutSeconds(TimeoutSeconds)))
1122 if (IndexTasks && !IndexTasks->wait(
timeoutSeconds(TimeoutSeconds)))
1134 for (std::optional<double> Timeout :
1135 {TimeoutSeconds, TimeoutSeconds, std::optional<double>(0)}) {
1138 if (BackgroundIdx && !BackgroundIdx->blockUntilIdleForTest(Timeout))
1146 assert(WorkScheduler->blockUntilIdle(Deadline::zero()) &&
1147 "Something scheduled work while we're blocking the main thread!");
1153 DynamicIdx->profile(MT.
child(
"dynamic_index"));
1155 BackgroundIdx->profile(MT.
child(
"background_index"));
1156 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 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.
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
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.
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.