37#include "clang/Format/Format.h"
38#include "clang/Lex/Preprocessor.h"
39#include "clang/Tooling/CompilationDatabase.h"
40#include "clang/Tooling/Core/Replacement.h"
41#include "llvm/ADT/ArrayRef.h"
42#include "llvm/ADT/STLExtras.h"
43#include "llvm/ADT/StringRef.h"
44#include "llvm/Support/Error.h"
45#include "llvm/Support/Path.h"
46#include "llvm/Support/raw_ostream.h"
61struct UpdateIndexCallbacks :
public ParsingCallbacks {
62 UpdateIndexCallbacks(FileIndex *FIndex,
63 ClangdServer::Callbacks *ServerCallbacks,
64 const ThreadsafeFS &TFS, AsyncTaskRunner *Tasks)
65 : FIndex(FIndex), ServerCallbacks(ServerCallbacks), TFS(TFS),
66 Stdlib{std::make_shared<StdLibSet>()}, Tasks(Tasks) {}
68 void onPreambleAST(
PathRef Path, llvm::StringRef Version,
69 const CompilerInvocation &
CI, ASTContext &Ctx,
71 const CanonicalIncludes &CanonIncludes)
override {
74 if (
auto Loc = Stdlib->add(*
CI.getLangOpts(), PP.getHeaderSearchInfo()))
75 indexStdlib(
CI, std::move(*
Loc));
78 FIndex->updatePreamble(
Path, Version, Ctx, PP, CanonIncludes);
81 void indexStdlib(
const CompilerInvocation &
CI, StdLibLocation
Loc) {
85 auto Task = [LO(*
CI.getLangOpts()),
Loc(std::move(
Loc)),
86 CI(std::make_unique<CompilerInvocation>(
CI)),
92 Stdlib(Stdlib)]()
mutable {
95 if (Stdlib->isBest(LO))
96 FIndex->updatePreamble(std::move(IF));
100 Tasks->runAsync(
"IndexStdlib", std::move(Task));
105 void onMainAST(
PathRef Path, ParsedAST &
AST, PublishFn Publish)
override {
109 assert(
AST.getDiagnostics() &&
110 "We issue callback only with fresh preambles");
114 ServerCallbacks->onDiagnosticsReady(
Path,
AST.version(),
119 void onFailedAST(
PathRef Path, llvm::StringRef Version,
120 std::vector<Diag> Diags, PublishFn Publish)
override {
123 [&]() { ServerCallbacks->onDiagnosticsReady(
Path, Version, Diags); });
126 void onFileUpdated(
PathRef File,
const TUStatus &Status)
override {
128 ServerCallbacks->onFileUpdated(
File, Status);
133 ServerCallbacks->onSemanticsMaybeChanged(
File);
138 ClangdServer::Callbacks *ServerCallbacks;
139 const ThreadsafeFS &TFS;
140 std::shared_ptr<StdLibSet> Stdlib;
141 AsyncTaskRunner *Tasks;
144class DraftStoreFS :
public ThreadsafeFS {
146 DraftStoreFS(
const ThreadsafeFS &Base,
const DraftStore &Drafts)
147 : Base(Base), DirtyFiles(Drafts) {}
150 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
151 auto OFS = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(
152 Base.view(std::nullopt));
153 OFS->pushOverlay(DirtyFiles.asVFS());
157 const ThreadsafeFS &Base;
158 const DraftStore &DirtyFiles;
166 Opts.StorePreamblesInMemory =
true;
167 Opts.AsyncThreadsCount = 4;
173 Opts.AsyncThreadsCount = AsyncThreadsCount;
174 Opts.RetentionPolicy = RetentionPolicy;
175 Opts.StorePreamblesInMemory = StorePreamblesInMemory;
176 Opts.UpdateDebounce = UpdateDebounce;
177 Opts.ContextProvider = ContextProvider;
186 DynamicIdx(Opts.BuildDynamicSymbolIndex ? new
FileIndex() : nullptr),
187 ClangTidyProvider(Opts.ClangTidyProvider),
188 UseDirtyHeaders(Opts.UseDirtyHeaders),
189 LineFoldingOnly(Opts.LineFoldingOnly),
190 PreambleParseForwardingFunctions(Opts.PreambleParseForwardingFunctions),
191 ImportInsertions(Opts.ImportInsertions),
192 WorkspaceRoot(Opts.WorkspaceRoot),
193 Transient(Opts.ImplicitCancellation ?
TUScheduler::InvalidateOnUpdate
195 DirtyFS(std::make_unique<DraftStoreFS>(TFS, DraftMgr)) {
196 if (Opts.AsyncThreadsCount != 0)
197 IndexTasks.emplace();
202 std::make_unique<UpdateIndexCallbacks>(
204 IndexTasks ? &*IndexTasks :
nullptr));
207 if (this->Index !=
nullptr) {
208 MergedIdx.push_back(std::make_unique<MergedIndex>(Idx, this->Index));
209 this->Index = MergedIdx.back().get();
214 if (Opts.StaticIndex)
215 AddIndex(Opts.StaticIndex);
216 if (Opts.BackgroundIndex) {
224 BackgroundIdx = std::make_unique<BackgroundIndex>(
227 [&CDB](llvm::StringRef
File) {
return CDB.getProjectInfo(
File); }),
229 AddIndex(BackgroundIdx.get());
232 AddIndex(DynamicIdx.get());
234 if (Opts.FeatureModules) {
236 *this->WorkScheduler,
240 for (
auto &Mod : *Opts.FeatureModules)
249 WorkScheduler.reset();
251 if (FeatureModules) {
252 for (
auto &Mod : *FeatureModules)
260 llvm::StringRef Version,
262 std::string ActualVersion = DraftMgr.
addDraft(
File, Version, Contents);
264 Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions;
265 Opts.ImportInsertions = ImportInsertions;
269 Inputs.TFS = &getHeaderFS();
270 Inputs.Contents = std::string(Contents);
271 Inputs.Version = std::move(ActualVersion);
272 Inputs.ForceRebuild = ForceRebuild;
273 Inputs.Opts = std::move(Opts);
274 Inputs.Index = Index;
275 Inputs.ClangTidyProvider = ClangTidyProvider;
276 Inputs.FeatureModules = FeatureModules;
277 bool NewFile = WorkScheduler->update(
File, Inputs,
WantDiags);
279 if (NewFile && BackgroundIdx)
280 BackgroundIdx->boostRelated(
File);
284 llvm::function_ref<
bool(llvm::StringRef
File)> Filter) {
287 if (Filter(FilePath))
288 if (
auto Draft = DraftMgr.
getDraft(FilePath))
289 addDocument(FilePath, *Draft->Contents, Draft->Version,
297 return std::move(Draft->Contents);
309 std::mutex PublishMu;
312 : Provider(Provider), Publish(Publish) {}
314 Context operator()(llvm::StringRef File) {
319 std::chrono::steady_clock::now() - std::chrono::seconds(5);
320 llvm::SmallString<256> PosixPath;
322 assert(llvm::sys::path::is_absolute(File));
323 llvm::sys::path::native(File, PosixPath, llvm::sys::path::Style::posix);
324 Params.
Path = PosixPath.str();
327 llvm::StringMap<std::vector<Diag>> ReportableDiagnostics;
332 handleDiagnostic(D, !Publish || D.getFilename().empty()
334 : &ReportableDiagnostics[D.getFilename()]);
339 if (!ReportableDiagnostics.empty()) {
340 std::lock_guard<std::mutex> Lock(PublishMu);
341 for (
auto &
Entry : ReportableDiagnostics)
343 std::move(
Entry.second));
345 return Context::current().derive(Config::Key, std::move(
C));
348 void handleDiagnostic(
const llvm::SMDiagnostic &D,
349 std::vector<Diag> *ClientDiagnostics) {
350 switch (D.getKind()) {
351 case llvm::SourceMgr::DK_Error:
352 elog(
"config error at {0}:{1}:{2}: {3}", D.getFilename(), D.getLineNo(),
353 D.getColumnNo(), D.getMessage());
355 case llvm::SourceMgr::DK_Warning:
356 log(
"config warning at {0}:{1}:{2}: {3}", D.getFilename(),
357 D.getLineNo(), D.getColumnNo(), D.getMessage());
359 case llvm::SourceMgr::DK_Note:
360 case llvm::SourceMgr::DK_Remark:
361 vlog(
"config note at {0}:{1}:{2}: {3}", D.getFilename(), D.getLineNo(),
362 D.getColumnNo(), D.getMessage());
363 ClientDiagnostics =
nullptr;
366 if (ClientDiagnostics)
367 ClientDiagnostics->push_back(
toDiag(D, Diag::ClangdConfig));
372 return [I(std::make_shared<Impl>(Provider, Publish))](llvm::StringRef
Path) {
379 WorkScheduler->remove(
File);
386 auto CodeCompleteOpts = Opts;
387 if (!CodeCompleteOpts.Index)
388 CodeCompleteOpts.Index = Index;
390 auto Task = [
Pos, CodeCompleteOpts,
File =
File.str(), CB = std::move(CB),
391 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
393 return CB(IP.takeError());
395 return CB(llvm::make_error<CancelledError>(Reason));
397 std::optional<SpeculativeFuzzyFind> SpecFuzzyFind;
401 vlog(
"Build for file {0} is not ready. Enter fallback mode.",
File);
402 }
else if (CodeCompleteOpts.Index) {
403 SpecFuzzyFind.emplace();
405 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
406 SpecFuzzyFind->CachedReq = CachedCompletionFuzzyFindRequestByFile[
File];
412 if (!IP->Contents.endswith(
"\n"))
416 CodeCompleteOpts.MainFileSignals = IP->Signals;
422 SpecFuzzyFind ? &*SpecFuzzyFind :
nullptr);
425 CB(std::move(Result));
427 if (SpecFuzzyFind && SpecFuzzyFind->NewReq) {
428 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
429 CachedCompletionFuzzyFindRequestByFile[
File] = *SpecFuzzyFind->NewReq;
438 WorkScheduler->runWithPreamble(
439 "CodeComplete",
File,
452 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
454 return CB(IP.takeError());
458 return CB(
error(
"Failed to parse includes"));
463 if (!IP->Contents.endswith(
"\n"))
467 DocumentationFormat));
479 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
481 tooling::Range RequestedRange;
485 return CB(Begin.takeError());
488 return CB(End.takeError());
489 RequestedRange = tooling::Range(*Begin, *End - *Begin);
491 RequestedRange = tooling::Range(0,
Code->size());
496 Ranges = std::vector<tooling::Range>{RequestedRange},
497 CB = std::move(CB),
this]()
mutable {
499 tooling::Replacements IncludeReplaces =
500 format::sortIncludes(Style,
Code, Ranges,
File);
501 auto Changed = tooling::applyAllReplacements(
Code, IncludeReplaces);
503 return CB(
Changed.takeError());
505 CB(IncludeReplaces.merge(format::reformat(
507 tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
510 WorkScheduler->runQuick(
"Format",
File, std::move(
Action));
514 StringRef TriggerText,
515 Callback<std::vector<TextEdit>> CB) {
518 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
522 return CB(CursorPos.takeError());
524 TriggerText = TriggerText.str(), CursorPos = *CursorPos,
525 CB = std::move(CB),
this]()
mutable {
526 auto Style = format::getStyle(format::DefaultFormatStyle,
File,
527 format::DefaultFallbackStyle,
Code,
528 TFS.
view(std::nullopt).get());
530 return CB(Style.takeError());
532 std::vector<TextEdit> Result;
533 for (
const tooling::Replacement &R :
538 WorkScheduler->runQuick(
"FormatOnType",
File, std::move(
Action));
542 std::optional<std::string> NewName,
546 NewName = std::move(NewName),
547 RenameOpts](llvm::Expected<InputsAndAST> InpAST)
mutable {
549 return CB(InpAST.takeError());
554 InpAST->AST,
File,
nullptr,
555 nullptr, RenameOpts});
560 return CB(
Results.takeError());
564 WorkScheduler->runWithAST(
"PrepareRename",
File, std::move(
Action));
572 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
577 return CB(InpAST.takeError());
579 DirtyFS->view(std::nullopt), Index, Opts});
581 return CB(R.takeError());
583 if (Opts.WantFormat) {
585 *InpAST->Inputs.TFS);
586 llvm::Error Err = llvm::Error::success();
587 for (
auto &
E : R->GlobalChanges)
589 llvm::joinErrors(
reformatEdit(
E.getValue(), Style), std::move(Err));
592 return CB(std::move(Err));
594 RenameFiles.
record(R->GlobalChanges.size());
597 WorkScheduler->runWithAST(
"Rename",
File, std::move(
Action));
602static llvm::Expected<std::vector<std::unique_ptr<Tweak::Selection>>>
604 llvm::vfs::FileSystem *FS) {
607 return Begin.takeError();
610 return End.takeError();
611 std::vector<std::unique_ptr<Tweak::Selection>> Result;
613 AST.AST.getASTContext(),
AST.AST.getTokens(), *Begin, *End,
615 Result.push_back(std::make_unique<Tweak::Selection>(
616 AST.Inputs.Index, AST.AST, *Begin, *End, std::move(T), FS));
619 assert(!Result.empty() &&
"Expected at least one SelectionTree");
620 return std::move(Result);
625 Callback<std::vector<TweakRef>> CB) {
629 auto Action = [Sel, CB = std::move(CB), Filter = std::move(Filter),
630 FeatureModules(this->FeatureModules)](
631 Expected<InputsAndAST> InpAST)
mutable {
633 return CB(InpAST.takeError());
636 return CB(Selections.takeError());
637 std::vector<TweakRef> Res;
639 llvm::DenseSet<llvm::StringRef> PreparedTweaks;
640 auto DeduplicatingFilter = [&](
const Tweak &T) {
641 return Filter(T) && !PreparedTweaks.count(T.id());
643 for (
const auto &Sel : *Selections) {
644 for (
auto &T :
prepareTweaks(*Sel, DeduplicatingFilter, FeatureModules)) {
645 Res.push_back({T->id(), T->title(), T->kind()});
646 PreparedTweaks.insert(T->id());
647 TweakAvailable.
record(1, T->id());
654 WorkScheduler->runWithAST(
"EnumerateTweaks",
File, std::move(
Action),
666 TweakAttempt.
record(1, TweakID);
669 this](Expected<InputsAndAST> InpAST)
mutable {
671 return CB(InpAST.takeError());
672 auto FS = DirtyFS->view(std::nullopt);
675 return CB(Selections.takeError());
676 std::optional<llvm::Expected<Tweak::Effect>> Effect;
679 for (
const auto &Selection : *Selections) {
680 auto T =
prepareTweak(TweakID, *Selection, FeatureModules);
682 Effect = (*T)->apply(*Selection);
685 Effect = T.takeError();
687 assert(Effect &&
"Expected at least one selection");
688 if (*Effect && (*Effect)->FormatEdits) {
690 for (
auto &It : (*Effect)->ApplyEdits) {
692 format::FormatStyle Style =
695 elog(
"Failed to format {0}: {1}", It.first(), std::move(Err));
698 TweakFailed.
record(1, TweakID);
700 return CB(std::move(*Effect));
702 WorkScheduler->runWithAST(
"ApplyTweak",
File, std::move(
Action));
706 Callback<std::vector<LocatedSymbol>> CB) {
708 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
710 return CB(InpAST.takeError());
714 WorkScheduler->runWithAST(
"Definitions",
File, std::move(
Action));
725 if (
auto CorrespondingFile =
727 return CB(std::move(CorrespondingFile));
729 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
731 return CB(InpAST.takeError());
734 WorkScheduler->runWithAST(
"SwitchHeaderSource",
Path, std::move(
Action));
740 [
Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
742 return CB(InpAST.takeError());
746 WorkScheduler->runWithAST(
"Highlights",
File, std::move(
Action), Transient);
750 Callback<std::optional<HoverInfo>> CB) {
752 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
754 return CB(InpAST.takeError());
756 File, InpAST->Inputs.Contents, *InpAST->Inputs.TFS);
760 WorkScheduler->runWithAST(
"Hover",
File, std::move(
Action), Transient);
765 Callback<std::vector<TypeHierarchyItem>> CB) {
767 this](Expected<InputsAndAST> InpAST)
mutable {
769 return CB(InpAST.takeError());
774 WorkScheduler->runWithAST(
"TypeHierarchy",
File, std::move(
Action));
779 Callback<std::optional<std::vector<TypeHierarchyItem>>> CB) {
780 WorkScheduler->run(
"typeHierarchy/superTypes",
"",
781 [=, CB = std::move(CB)]()
mutable {
787 Callback<std::vector<TypeHierarchyItem>> CB) {
789 "typeHierarchy/subTypes",
"",
795 Callback<std::optional<TypeHierarchyItem>> CB) {
797 "Resolve Type Hierarchy",
"", [=, CB = std::move(CB)]()
mutable {
806 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
808 return CB(InpAST.takeError());
811 WorkScheduler->runWithAST(
"CallHierarchy",
File, std::move(
Action));
816 Callback<std::vector<CallHierarchyIncomingCall>> CB) {
817 WorkScheduler->run(
"Incoming Calls",
"",
818 [CB = std::move(CB), Item,
this]()
mutable {
824 Callback<std::vector<InlayHint>> CB) {
825 auto Action = [RestrictRange(std::move(RestrictRange)),
826 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
828 return CB(InpAST.takeError());
831 WorkScheduler->runWithAST(
"InlayHints",
File, std::move(
Action), Transient);
840 llvm::StringRef Query,
int Limit,
841 Callback<std::vector<SymbolInformation>> CB) {
843 "getWorkspaceSymbols",
"",
844 [Query = Query.str(), Limit, CB = std::move(CB),
this]()
mutable {
845 CB(clangd::getWorkspaceSymbols(Query, Limit, Index,
846 WorkspaceRoot.value_or(
"")));
851 Callback<std::vector<DocumentSymbol>> CB) {
853 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
855 return CB(InpAST.takeError());
858 WorkScheduler->runWithAST(
"DocumentSymbols",
File, std::move(
Action),
863 Callback<std::vector<FoldingRange>> CB) {
866 return CB(llvm::make_error<LSPError>(
867 "trying to compute folding ranges for non-added document",
869 auto Action = [LineFoldingOnly = LineFoldingOnly, CB = std::move(CB),
870 Code = std::move(*
Code)]()
mutable {
875 WorkScheduler->runQuick(
"FoldingRanges",
File, std::move(
Action));
879 Callback<std::vector<LocatedSymbol>> CB) {
881 [
Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
883 return CB(InpAST.takeError());
886 WorkScheduler->runWithAST(
"FindType",
File, std::move(
Action));
892 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
894 return CB(InpAST.takeError());
898 WorkScheduler->runWithAST(
"Implementations",
File, std::move(
Action));
904 auto Action = [
Pos, Limit, AddContainer, CB = std::move(CB),
905 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
907 return CB(InpAST.takeError());
911 WorkScheduler->runWithAST(
"References",
File, std::move(
Action));
915 Callback<std::vector<SymbolDetails>> CB) {
917 [
Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
919 return CB(InpAST.takeError());
923 WorkScheduler->runWithAST(
"SymbolInfo",
File, std::move(
Action));
927 const std::vector<Position> &Positions,
928 Callback<std::vector<SelectionRange>> CB) {
929 auto Action = [Positions, CB = std::move(CB)](
930 llvm::Expected<InputsAndAST> InpAST)
mutable {
932 return CB(InpAST.takeError());
933 std::vector<SelectionRange> Result;
934 for (
const auto &
Pos : Positions) {
936 Result.push_back(std::move(*
Range));
938 return CB(
Range.takeError());
940 CB(std::move(Result));
942 WorkScheduler->runWithAST(
"SemanticRanges",
File, std::move(
Action));
946 Callback<std::vector<DocumentLink>> CB) {
948 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
950 return CB(InpAST.takeError());
953 WorkScheduler->runWithAST(
"DocumentLinks",
File, std::move(
Action),
960 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
962 return CB(InpAST.takeError());
965 WorkScheduler->runWithAST(
"SemanticHighlights",
File, std::move(
Action),
970 Callback<std::optional<ASTNode>> CB) {
972 [R, CB(std::move(CB))](llvm::Expected<InputsAndAST> Inputs)
mutable {
974 return CB(Inputs.takeError());
978 auto Node = DynTypedNode::create(
979 *Inputs->AST.getASTContext().getTranslationUnitDecl());
980 return CB(
dumpAST(Node, Inputs->AST.getTokens(),
981 Inputs->AST.getASTContext()));
987 return CB(
Offset.takeError());
991 return CB(
Offset.takeError());
993 Inputs->AST.getASTContext(), Inputs->AST.getTokens(), Start, End,
995 if (const SelectionTree::Node *N = T.commonAncestor()) {
996 CB(dumpAST(N->ASTNode, Inputs->AST.getTokens(),
997 Inputs->AST.getASTContext()));
1005 WorkScheduler->runWithAST(
"GetAST",
File, std::move(
Action));
1010 WorkScheduler->runWithAST(
Name, File, std::move(
Action));
1015 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1017 return CB(InpAST.takeError());
1018 if (
auto Diags = InpAST->AST.getDiagnostics())
1021 return CB(llvm::make_error<LSPError>(
"server is busy parsing includes",
1022 ErrorCode::InternalError));
1025 WorkScheduler->runWithAST(
"Diagnostics", File, std::move(
Action));
1028llvm::StringMap<TUScheduler::FileStats> ClangdServer::fileStats()
const {
1029 return WorkScheduler->fileStats();
1033ClangdServer::blockUntilIdleForTest(std::optional<double> TimeoutSeconds) {
1037#if defined(__has_feature) && \
1038 (__has_feature(address_sanitizer) || __has_feature(hwaddress_sanitizer) || \
1039 __has_feature(memory_sanitizer) || __has_feature(thread_sanitizer))
1040 (*TimeoutSeconds) *= 10;
1045 if (!WorkScheduler->blockUntilIdle(
timeoutSeconds(TimeoutSeconds)))
1048 if (IndexTasks && !IndexTasks->wait(
timeoutSeconds(TimeoutSeconds)))
1060 for (std::optional<double> Timeout :
1061 {TimeoutSeconds, TimeoutSeconds, std::optional<double>(0)}) {
1064 if (BackgroundIdx && !BackgroundIdx->blockUntilIdleForTest(Timeout))
1072 assert(WorkScheduler->blockUntilIdle(Deadline::zero()) &&
1073 "Something scheduled work while we're blocking the main thread!");
1079 DynamicIdx->profile(MT.
child(
"dynamic_index"));
1081 BackgroundIdx->profile(MT.
child(
"background_index"));
1082 WorkScheduler->profile(MT.
child(
"tuscheduler"));
FeatureModuleSet FeatureModules
const ParseInputs & ParseInput
std::vector< CodeCompletionResult > Results
const google::protobuf::Message & M
std::unique_ptr< CompilerInvocation > CI
WantDiagnostics Diagnostics
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 onDiagnosticsReady(PathRef File, llvm::StringRef Version, std::vector< Diag > Diagnostics)
Called by ClangdServer when Diagnostics for File are ready.
virtual void onBackgroundIndexProgress(const BackgroundQueue::Stats &Stats)
Called when background indexing tasks are enqueued/started/completed.
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 enumerateTweaks(PathRef File, Range Sel, llvm::unique_function< bool(const Tweak &)> Filter, Callback< std::vector< TweakRef > > CB)
Enumerate the code tweaks available to the user at a specified point.
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 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< LocatedSymbol > findType(ParsedAST &AST, Position Pos)
Returns symbols for types referenced at Pos.
std::vector< CallHierarchyIncomingCall > incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
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.
format::FormatStyle getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content, const ThreadsafeFS &TFS)
Choose the clang-format style we should apply to a certain file.
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.
static llvm::Expected< std::vector< std::unique_ptr< Tweak::Selection > > > tweakSelection(const Range &Sel, const InputsAndAST &AST, llvm::vfs::FileSystem *FS)
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.
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)
Deadline timeoutSeconds(std::optional< double > Seconds)
Makes a deadline from a timeout in seconds. None 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)
std::vector< HighlightingToken > getSemanticHighlightings(ParsedAST &AST)
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.
===– 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.
@ 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 set of edits generated for a single file.
Shared server facilities needed by the module to get its work done.
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.