26#include "clang-include-cleaner/Record.h"
38#include "clang/Basic/Stack.h"
39#include "clang/Format/Format.h"
40#include "clang/Lex/Preprocessor.h"
41#include "clang/Tooling/CompilationDatabase.h"
42#include "clang/Tooling/Core/Replacement.h"
43#include "llvm/ADT/ArrayRef.h"
44#include "llvm/ADT/STLExtras.h"
45#include "llvm/ADT/StringRef.h"
46#include "llvm/Support/Error.h"
47#include "llvm/Support/Path.h"
48#include "llvm/Support/raw_ostream.h"
70 UpdateIndexCallbacks(FileIndex *FIndex,
71 ClangdServer::Callbacks *ServerCallbacks,
72 const ThreadsafeFS &TFS, AsyncTaskRunner *Tasks,
73 bool CollectInactiveRegions)
74 : FIndex(FIndex), ServerCallbacks(ServerCallbacks), TFS(TFS),
75 Stdlib{std::make_shared<StdLibSet>()}, Tasks(Tasks),
76 CollectInactiveRegions(CollectInactiveRegions) {}
79 PathRef Path, llvm::StringRef Version, CapturedASTCtx ASTCtx,
80 std::shared_ptr<const include_cleaner::PragmaIncludes> PI)
override {
85 auto &PP = ASTCtx.getPreprocessor();
86 auto &CI = ASTCtx.getCompilerInvocation();
87 if (
auto Loc = Stdlib->add(CI.getLangOpts(), PP.getHeaderSearchInfo()))
88 indexStdlib(CI, std::move(*Loc));
91 auto Task = [FIndex(FIndex),
Path(
Path.str()), Version(Version.str()),
92 ASTCtx(std::move(ASTCtx)), PI(std::move(PI))]()
mutable {
93 trace::Span Tracer(
"PreambleIndexing");
94 FIndex->updatePreamble(
Path, Version, ASTCtx.getASTContext(),
95 ASTCtx.getPreprocessor(), *PI);
99 Tasks->runAsync(
"Preamble indexing for:" +
Path + Version,
105 void indexStdlib(
const CompilerInvocation &CI, StdLibLocation Loc) {
109 auto Task = [LO(CI.getLangOpts()), Loc(std::move(Loc)),
110 CI(std::make_unique<CompilerInvocation>(CI)),
121 WithContext
C(std::move(Ctx));
122 clang::noteBottomOfStack();
125 if (Stdlib->isBest(LO))
126 FIndex->updatePreamble(std::move(IF));
130 Tasks->runAsync(
"IndexStdlib", std::move(Task));
135 void onMainAST(
PathRef Path, ParsedAST &
AST, PublishFn Publish)
override {
141 ServerCallbacks->onDiagnosticsReady(
Path,
AST.version(),
142 AST.getDiagnostics());
143 if (CollectInactiveRegions) {
144 ServerCallbacks->onInactiveRegionsReady(
Path,
150 void onFailedAST(
PathRef Path, llvm::StringRef Version,
151 std::vector<Diag> Diags, PublishFn Publish)
override {
154 [&]() { ServerCallbacks->onDiagnosticsReady(
Path, Version, Diags); });
157 void onFileUpdated(
PathRef File,
const TUStatus &Status)
override {
159 ServerCallbacks->onFileUpdated(
File, Status);
164 ServerCallbacks->onSemanticsMaybeChanged(
File);
169 ClangdServer::Callbacks *ServerCallbacks;
170 const ThreadsafeFS &TFS;
171 std::shared_ptr<StdLibSet> Stdlib;
172 AsyncTaskRunner *Tasks;
173 bool CollectInactiveRegions;
178 DraftStoreFS(
const ThreadsafeFS &Base,
const DraftStore &Drafts)
179 : Base(Base), DirtyFiles(Drafts) {}
182 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
183 auto OFS = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(
184 Base.view(std::nullopt));
185 OFS->pushOverlay(DirtyFiles.asVFS());
189 const ThreadsafeFS &Base;
190 const DraftStore &DirtyFiles;
217 : FeatureModules(Opts.FeatureModules), CDB(CDB), TFS(TFS),
218 DynamicIdx(Opts.BuildDynamicSymbolIndex
219 ? new
FileIndex(Opts.EnableOutgoingCalls)
221 ModulesManager(Opts.ModulesManager),
222 ClangTidyProvider(Opts.ClangTidyProvider),
223 UseDirtyHeaders(Opts.UseDirtyHeaders),
224 LineFoldingOnly(Opts.LineFoldingOnly),
225 PreambleParseForwardingFunctions(Opts.PreambleParseForwardingFunctions),
226 SkipPreambleBuild(Opts.SkipPreambleBuild),
227 ImportInsertions(Opts.ImportInsertions),
228 PublishInactiveRegions(Opts.PublishInactiveRegions),
229 WorkspaceRoot(Opts.WorkspaceRoot),
230 Transient(Opts.ImplicitCancellation ?
TUScheduler::InvalidateOnUpdate
232 DirtyFS(std::make_unique<DraftStoreFS>(TFS, DraftMgr)),
233 ContextProvider(Opts.ContextProvider) {
235 IndexTasks.emplace();
240 std::make_unique<UpdateIndexCallbacks>(
242 IndexTasks ? &*IndexTasks :
nullptr,
243 PublishInactiveRegions));
246 if (this->Index != nullptr) {
247 MergedIdx.push_back(std::make_unique<MergedIndex>(Idx, this->Index));
248 this->Index = MergedIdx.back().get();
253 if (Opts.StaticIndex)
254 AddIndex(Opts.StaticIndex);
255 if (Opts.BackgroundIndex) {
256 BackgroundIndex::Options BGOpts;
257 BGOpts.ThreadPoolSize = std::max(Opts.AsyncThreadsCount, 1u);
258 BGOpts.OnProgress = [Callbacks](BackgroundQueue::Stats S) {
260 Callbacks->onBackgroundIndexProgress(S);
262 BGOpts.ContextProvider = Opts.ContextProvider;
263 BGOpts.SupportContainedRefs = Opts.EnableOutgoingCalls;
264 BackgroundIdx = std::make_unique<BackgroundIndex>(
267 [&CDB](llvm::StringRef
File) { return CDB.getProjectInfo(File); }),
269 AddIndex(BackgroundIdx.get());
272 AddIndex(DynamicIdx.get());
274 if (Opts.FeatureModules) {
275 FeatureModule::Facilities F{
276 *this->WorkScheduler,
280 for (
auto &Mod : *Opts.FeatureModules)
289 WorkScheduler.reset();
291 if (FeatureModules) {
292 for (
auto &Mod : *FeatureModules)
294 for (
auto &Mod : *FeatureModules)
300 llvm::StringRef Version,
302 bool NewModule = ModulesManager && ModulesManager->observeSourcePath(
File);
304 std::string ActualVersion = DraftMgr.addDraft(
File, Version, Contents);
311 Inputs.
TFS = &getHeaderFS();
312 Inputs.
Contents = std::string(Contents);
313 Inputs.
Version = std::move(ActualVersion);
315 Inputs.
Opts = std::move(Opts);
316 Inputs.
Index = Index;
320 adjustParseInputs(Inputs,
File);
321 bool NewFile = WorkScheduler->update(
File, Inputs, WantDiags);
323 if (NewFile && BackgroundIdx)
324 BackgroundIdx->boostRelated(
File);
331 llvm::function_ref<
bool(llvm::StringRef
File)> Filter) {
333 for (
const Path &FilePath : DraftMgr.getActiveFiles())
334 if (Filter(FilePath))
335 if (
auto Draft = DraftMgr.getDraft(FilePath))
336 addDocument(FilePath, *Draft->Contents, Draft->Version,
341 auto Draft = DraftMgr.getDraft(
File);
344 return std::move(Draft->Contents);
356 std::mutex PublishMu;
359 : Provider(Provider), Publish(Publish) {}
366 std::chrono::steady_clock::now() - std::chrono::seconds(5);
367 llvm::SmallString<256> PosixPath;
369 assert(llvm::sys::path::is_absolute(
File));
370 llvm::sys::path::native(
File, PosixPath, llvm::sys::path::Style::posix);
371 Params.
Path = PosixPath.str();
374 llvm::StringMap<std::vector<Diag>> ReportableDiagnostics;
375 Config C = Provider->
getConfig(Params, [&](
const llvm::SMDiagnostic &D) {
379 handleDiagnostic(D, !Publish || D.getFilename().empty()
381 : &ReportableDiagnostics[D.getFilename()]);
386 if (!ReportableDiagnostics.empty()) {
387 std::lock_guard<std::mutex> Lock(PublishMu);
388 for (
auto &
Entry : ReportableDiagnostics)
395 void handleDiagnostic(
const llvm::SMDiagnostic &D,
396 std::vector<Diag> *ClientDiagnostics) {
397 switch (D.getKind()) {
398 case llvm::SourceMgr::DK_Error:
399 elog(
"config error at {0}:{1}:{2}: {3}", D.getFilename(), D.getLineNo(),
400 D.getColumnNo(), D.getMessage());
402 case llvm::SourceMgr::DK_Warning:
403 log(
"config warning at {0}:{1}:{2}: {3}", D.getFilename(),
404 D.getLineNo(), D.getColumnNo(), D.getMessage());
406 case llvm::SourceMgr::DK_Note:
407 case llvm::SourceMgr::DK_Remark:
408 vlog(
"config note at {0}:{1}:{2}: {3}", D.getFilename(), D.getLineNo(),
409 D.getColumnNo(), D.getMessage());
410 ClientDiagnostics =
nullptr;
413 if (ClientDiagnostics)
419 return [I(std::make_shared<Impl>(Provider, Publish))](llvm::StringRef
Path) {
425 DraftMgr.removeDraft(
File);
426 WorkScheduler->remove(
File);
433 auto CodeCompleteOpts = Opts;
434 if (!CodeCompleteOpts.Index)
435 CodeCompleteOpts.Index = Index;
437 auto Task = [Pos, CodeCompleteOpts,
File =
File.str(), CB = std::move(CB),
438 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
440 return CB(IP.takeError());
442 return CB(llvm::make_error<CancelledError>(Reason));
444 std::optional<SpeculativeFuzzyFind> SpecFuzzyFind;
448 vlog(
"Build for file {0} is not ready. Enter fallback mode.",
File);
449 }
else if (CodeCompleteOpts.Index) {
450 SpecFuzzyFind.emplace();
452 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
453 SpecFuzzyFind->CachedReq = CachedCompletionFuzzyFindRequestByFile[
File];
456 ParseInputs ParseInput{IP->Command, &getHeaderFS(), IP->Contents.str()};
459 if (!IP->Contents.ends_with(
"\n"))
461 ParseInput.
Index = Index;
463 CodeCompleteOpts.MainFileSignals = IP->Signals;
465 CodeCompleteOpts.ArgumentLists =
Config::current().Completion.ArgumentLists;
466 CodeCompleteOpts.InsertIncludes =
468 CodeCompleteOpts.CodePatterns =
Config::current().Completion.CodePatterns;
469 CodeCompleteOpts.MacroFilter =
Config::current().Completion.MacroFilter;
470 adjustParseInputs(ParseInput,
File);
474 File, Pos, IP->Preamble, ParseInput, CodeCompleteOpts,
475 SpecFuzzyFind ? &*SpecFuzzyFind :
nullptr);
481 CB(std::move(Result));
485 if (SpecFuzzyFind->NewReq) {
486 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
487 CachedCompletionFuzzyFindRequestByFile[
File] = *SpecFuzzyFind->NewReq;
492 if (SpecFuzzyFind->Result.valid())
493 SpecFuzzyFind->Result.wait();
497 WorkScheduler->runWithPreamble(
498 "CodeComplete",
File,
499 (Opts.RunParser == CodeCompleteOptions::AlwaysParse)
509 auto Action = [Pos,
File =
File.str(), CB = std::move(CB),
511 this](llvm::Expected<InputsAndPreamble> IP)
mutable {
513 return CB(IP.takeError());
517 return CB(
error(
"Failed to parse includes"));
519 ParseInputs ParseInput{IP->Command, &getHeaderFS(), IP->Contents.str()};
522 if (!IP->Contents.ends_with(
"\n"))
524 ParseInput.
Index = Index;
526 DocumentationFormat));
538 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
540 std::vector<tooling::Range> RequestedRanges;
542 RequestedRanges.reserve(Rngs.size());
543 for (
const auto &Rng : Rngs) {
546 return CB(Begin.takeError());
549 return CB(End.takeError());
550 RequestedRanges.emplace_back(*Begin, *End - *Begin);
553 RequestedRanges = {tooling::Range(0, Code->size())};
557 auto Action = [
File =
File.str(), Code = std::move(*Code),
558 Ranges = std::move(RequestedRanges), CB = std::move(CB),
561 tooling::Replacements IncludeReplaces =
562 format::sortIncludes(Style, Code, Ranges,
File);
563 auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces);
565 return CB(
Changed.takeError());
567 CB(IncludeReplaces.merge(format::reformat(
569 tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
572 WorkScheduler->runQuick(
"Format",
File, std::move(Action));
576 StringRef TriggerText,
577 Callback<std::vector<TextEdit>> CB) {
580 return CB(llvm::make_error<LSPError>(
"trying to format non-added document",
584 return CB(CursorPos.takeError());
585 auto Action = [
File =
File.str(), Code = std::move(*Code),
586 TriggerText = TriggerText.str(), CursorPos = *CursorPos,
587 CB = std::move(CB),
this]()
mutable {
589 std::vector<TextEdit> Result;
590 for (
const tooling::Replacement &R :
595 WorkScheduler->runQuick(
"FormatOnType",
File, std::move(Action));
599 std::optional<std::string> NewName,
602 auto Action = [Pos,
File =
File.str(), CB = std::move(CB),
603 NewName = std::move(NewName),
604 RenameOpts](llvm::Expected<InputsAndAST> InpAST)
mutable {
606 return CB(InpAST.takeError());
610 clangd::rename({Pos, NewName.value_or(
"__clangd_rename_placeholder"),
611 InpAST->AST,
File,
nullptr,
612 nullptr, RenameOpts});
617 return CB(Results.takeError());
621 WorkScheduler->runWithAST(
"PrepareRename",
File, std::move(Action));
627 auto Action = [
File =
File.str(), NewName = NewName.str(), Pos, Opts,
629 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
634 return CB(InpAST.takeError());
636 DirtyFS->view(std::nullopt), Index, Opts});
638 return CB(R.takeError());
642 *InpAST->Inputs.TFS,
false);
643 llvm::Error Err = llvm::Error::success();
644 for (
auto &E : R->GlobalChanges)
646 llvm::joinErrors(
reformatEdit(E.getValue(), Style), std::move(Err));
649 return CB(std::move(Err));
651 RenameFiles.
record(R->GlobalChanges.size());
654 WorkScheduler->runWithAST(
"Rename",
File, std::move(Action));
660llvm::Expected<std::vector<std::unique_ptr<Tweak::Selection>>>
662 llvm::vfs::FileSystem *FS) {
665 return Begin.takeError();
668 return End.takeError();
669 std::vector<std::unique_ptr<Tweak::Selection>> Result;
671 AST.AST.getASTContext(),
AST.AST.getTokens(), *Begin, *End,
673 Result.push_back(std::make_unique<Tweak::Selection>(
674 AST.Inputs.Index, AST.AST, *Begin, *End, std::move(T), FS));
677 assert(!Result.empty() &&
"Expected at least one SelectionTree");
678 return std::move(Result);
684std::optional<ClangdServer::CodeActionResult::Rename>
685tryConvertToRename(
const Diag *Diag,
const Fix &
Fix) {
686 bool IsClangTidyRename = Diag->Source == Diag::ClangTidy &&
687 Diag->Name ==
"readability-identifier-naming" &&
689 if (IsClangTidyRename && Diag->InsideMainFile) {
690 ClangdServer::CodeActionResult::Rename R;
691 R.NewName =
Fix.Edits.front().newText;
692 R.FixMessage =
Fix.Message;
693 R.Diag = {Diag->Range, Diag->Message};
704 auto Action = [Params, CB = std::move(CB),
705 FeatureModules(this->FeatureModules)](
706 Expected<InputsAndAST> InpAST)
mutable {
708 return CB(InpAST.takeError());
713 return llvm::any_of(Only, [&](llvm::StringRef Base) {
714 return Kind.consume_front(Base) &&
715 (Kind.empty() || Kind.starts_with(
"."));
720 Result.
Version = InpAST->AST.version().str();
722 auto FindMatchedDiag = [&InpAST](
const DiagRef &DR) ->
const Diag * {
723 for (
const auto &
Diag : InpAST->AST.getDiagnostics())
731 if (
auto Rename = tryConvertToRename(
Diag,
Fix)) {
732 Result.
Renames.emplace_back(std::move(*Rename));
741 auto Selections = tweakSelection(Params.
Selection, *InpAST,
nullptr);
743 return CB(Selections.takeError());
745 llvm::DenseSet<llvm::StringRef> PreparedTweaks;
746 auto DeduplicatingFilter = [&](
const Tweak &T) {
747 return KindAllowed(T.kind()) && Params.
TweakFilter(T) &&
748 !PreparedTweaks.count(T.id());
750 for (
const auto &Sel : *Selections) {
751 for (
auto &T :
prepareTweaks(*Sel, DeduplicatingFilter, FeatureModules)) {
753 PreparedTweaks.insert(T->id());
754 TweakAvailable.record(1, T->id());
757 CB(std::move(Result));
760 WorkScheduler->runWithAST(
"codeAction", Params.
File, std::move(Action),
772 TweakAttempt.
record(1, TweakID);
773 auto Action = [
File =
File.str(), Sel, TweakID = TweakID.str(),
775 this](Expected<InputsAndAST> InpAST)
mutable {
777 return CB(InpAST.takeError());
778 auto FS = DirtyFS->view(std::nullopt);
779 auto Selections = tweakSelection(Sel, *InpAST, FS.get());
781 return CB(Selections.takeError());
782 std::optional<llvm::Expected<Tweak::Effect>> Effect;
785 for (
const auto &Selection : *Selections) {
786 auto T =
prepareTweak(TweakID, *Selection, FeatureModules);
788 Effect = (*T)->apply(*Selection);
791 Effect = T.takeError();
793 assert(Effect &&
"Expected at least one selection");
794 if (*Effect && (*Effect)->FormatEdits) {
796 for (
auto &It : (*Effect)->ApplyEdits) {
798 format::FormatStyle Style =
801 elog(
"Failed to format {0}: {1}", It.first(), std::move(Err));
804 TweakFailed.
record(1, TweakID);
806 return CB(std::move(*Effect));
808 WorkScheduler->runWithAST(
"ApplyTweak",
File, std::move(Action));
812 Callback<std::vector<LocatedSymbol>> CB) {
813 auto Action = [Pos, CB = std::move(CB),
814 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
816 return CB(InpAST.takeError());
820 WorkScheduler->runWithAST(
"Definitions",
File, std::move(Action));
831 if (
auto CorrespondingFile =
833 return CB(std::move(CorrespondingFile));
834 auto Action = [
Path =
Path.str(), CB = std::move(CB),
835 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
837 return CB(InpAST.takeError());
840 WorkScheduler->runWithAST(
"SwitchHeaderSource",
Path, std::move(Action));
846 [Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
848 return CB(InpAST.takeError());
852 WorkScheduler->runWithAST(
"Highlights",
File, std::move(Action), Transient);
856 Callback<std::optional<HoverInfo>> CB) {
857 auto Action = [
File =
File.str(), Pos, CB = std::move(CB),
858 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
860 return CB(InpAST.takeError());
862 File, InpAST->Inputs.Contents, *InpAST->Inputs.TFS,
false);
866 WorkScheduler->runWithAST(
"Hover",
File, std::move(Action), Transient);
871 Callback<std::vector<TypeHierarchyItem>> CB) {
872 auto Action = [
File =
File.str(), Pos, Resolve, Direction, CB = std::move(CB),
873 this](Expected<InputsAndAST> InpAST)
mutable {
875 return CB(InpAST.takeError());
880 WorkScheduler->runWithAST(
"TypeHierarchy",
File, std::move(Action));
885 Callback<std::optional<std::vector<TypeHierarchyItem>>> CB) {
886 WorkScheduler->run(
"typeHierarchy/superTypes",
"",
887 [=, CB = std::move(CB)]()
mutable {
893 Callback<std::vector<TypeHierarchyItem>> CB) {
895 "typeHierarchy/subTypes",
"",
901 Callback<std::optional<TypeHierarchyItem>> CB) {
903 "Resolve Type Hierarchy",
"", [=, CB = std::move(CB)]()
mutable {
911 auto Action = [
File =
File.str(), Pos,
912 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
914 return CB(InpAST.takeError());
917 WorkScheduler->runWithAST(
"CallHierarchy",
File, std::move(Action));
922 Callback<std::vector<CallHierarchyIncomingCall>> CB) {
923 WorkScheduler->run(
"Incoming Calls",
"",
924 [CB = std::move(CB), Item,
this]()
mutable {
930 Callback<std::vector<InlayHint>> CB) {
931 auto Action = [RestrictRange(std::move(RestrictRange)),
932 CB = std::move(CB)](Expected<InputsAndAST> InpAST)
mutable {
934 return CB(InpAST.takeError());
937 WorkScheduler->runWithAST(
"InlayHints",
File, std::move(Action), Transient);
942 Callback<std::vector<CallHierarchyOutgoingCall>> CB) {
943 WorkScheduler->run(
"Outgoing Calls",
"",
944 [CB = std::move(CB), Item,
this]()
mutable {
952 bool ModulesChanged =
false;
953 for (
const auto &Change : Params.
changes)
954 ModulesChanged |= ModulesManager->onFileEvent(Change);
960 llvm::StringRef Query,
int Limit,
961 Callback<std::vector<SymbolInformation>> CB) {
963 "getWorkspaceSymbols",
"",
964 [Query = Query.str(), Limit, CB = std::move(CB),
this]()
mutable {
965 CB(clangd::getWorkspaceSymbols(Query, Limit, Index,
966 WorkspaceRoot.value_or(
"")));
971 Callback<std::vector<DocumentSymbol>> CB) {
973 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
975 return CB(InpAST.takeError());
978 WorkScheduler->runWithAST(
"DocumentSymbols",
File, std::move(Action),
983 Callback<std::vector<FoldingRange>> CB) {
986 return CB(llvm::make_error<LSPError>(
987 "trying to compute folding ranges for non-added document",
989 auto Action = [LineFoldingOnly = LineFoldingOnly, CB = std::move(CB),
990 Code = std::move(*Code)]()
mutable {
995 WorkScheduler->runQuick(
"FoldingRanges",
File, std::move(Action));
999 Callback<std::vector<LocatedSymbol>> CB) {
1000 auto Action = [Pos, CB = std::move(CB),
1001 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
1003 return CB(InpAST.takeError());
1006 WorkScheduler->runWithAST(
"FindType",
File, std::move(Action));
1011 auto Action = [Pos, CB = std::move(CB),
1012 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
1014 return CB(InpAST.takeError());
1018 WorkScheduler->runWithAST(
"Implementations",
File, std::move(Action));
1024 auto Action = [Pos, Limit, AddContainer, CB = std::move(CB),
1025 this](llvm::Expected<InputsAndAST> InpAST)
mutable {
1027 return CB(InpAST.takeError());
1031 WorkScheduler->runWithAST(
"References",
File, std::move(Action));
1035 Callback<std::vector<SymbolDetails>> CB) {
1037 [Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1039 return CB(InpAST.takeError());
1043 WorkScheduler->runWithAST(
"SymbolInfo",
File, std::move(Action));
1047 const std::vector<Position> &Positions,
1048 Callback<std::vector<SelectionRange>> CB) {
1049 auto Action = [Positions, CB = std::move(CB)](
1050 llvm::Expected<InputsAndAST> InpAST)
mutable {
1052 return CB(InpAST.takeError());
1053 std::vector<SelectionRange> Result;
1054 for (
const auto &Pos : Positions) {
1056 Result.push_back(std::move(*
Range));
1058 return CB(
Range.takeError());
1060 CB(std::move(Result));
1062 WorkScheduler->runWithAST(
"SemanticRanges",
File, std::move(Action));
1066 Callback<std::vector<DocumentLink>> CB) {
1068 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1070 return CB(InpAST.takeError());
1073 WorkScheduler->runWithAST(
"DocumentLinks",
File, std::move(Action),
1080 auto Action = [CB = std::move(CB),
1081 PublishInactiveRegions = PublishInactiveRegions](
1082 llvm::Expected<InputsAndAST> InpAST)
mutable {
1084 return CB(InpAST.takeError());
1090 WorkScheduler->runWithAST(
"SemanticHighlights",
File, std::move(Action),
1095 Callback<std::optional<ASTNode>> CB) {
1097 [R, CB(std::move(CB))](llvm::Expected<InputsAndAST> Inputs)
mutable {
1099 return CB(Inputs.takeError());
1103 auto Node = DynTypedNode::create(
1104 *Inputs->AST.getASTContext().getTranslationUnitDecl());
1105 return CB(
dumpAST(Node, Inputs->AST.getTokens(),
1106 Inputs->AST.getASTContext()));
1108 unsigned Start, End;
1112 return CB(Offset.takeError());
1116 return CB(Offset.takeError());
1118 Inputs->AST.getASTContext(), Inputs->AST.getTokens(), Start, End,
1120 if (const SelectionTree::Node *N = T.commonAncestor()) {
1121 CB(dumpAST(N->ASTNode, Inputs->AST.getTokens(),
1122 Inputs->AST.getASTContext()));
1130 WorkScheduler->runWithAST(
"GetAST",
File, std::move(Action));
1135 WorkScheduler->runWithAST(Name,
File, std::move(Action));
1140 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST)
mutable {
1142 return CB(InpAST.takeError());
1143 return CB(InpAST->AST.getDiagnostics());
1146 WorkScheduler->runWithAST(
"Diagnostics",
File, std::move(Action));
1150 return WorkScheduler->fileStats();
1158#if defined(__has_feature) && \
1159 (__has_feature(address_sanitizer) || __has_feature(hwaddress_sanitizer) || \
1160 __has_feature(memory_sanitizer) || __has_feature(thread_sanitizer))
1161 if (TimeoutSeconds.has_value())
1162 (*TimeoutSeconds) *= 10;
1167 if (!WorkScheduler->blockUntilIdle(
timeoutSeconds(TimeoutSeconds)))
1170 if (IndexTasks && !IndexTasks->wait(
timeoutSeconds(TimeoutSeconds)))
1182 for (std::optional<double> Timeout :
1183 {TimeoutSeconds, TimeoutSeconds, std::optional<double>(0)}) {
1186 if (BackgroundIdx && !BackgroundIdx->blockUntilIdleForTest(Timeout))
1188 if (FeatureModules && llvm::any_of(*FeatureModules, [&](
FeatureModule &M) {
1195 "Something scheduled work while we're blocking the main thread!");
1201 DynamicIdx->profile(MT.
child(
"dynamic_index"));
1203 BackgroundIdx->profile(MT.
child(
"background_index"));
1204 WorkScheduler->profile(MT.
child(
"tuscheduler"));
1212 auto HasRequiredModules = [
this,
File]() {
1213 if (!ModulesManager)
1221 return ModulesManager->hasRequiredModules(
File);
static cl::opt< bool > Fix("fix", desc(R"(
Apply suggested fixes. Without -fix-errors
clang-tidy will bail out if any compilation
errors were found.
)"), cl::init(false), cl::cat(ClangTidyCategory))
void elog(const char *Fmt, Ts &&... Vals)
static Factory createDiskBackedStorageFactory(std::function< std::optional< ProjectInfo >(PathRef)> GetProjectInfo)
Interface with hooks for users of ClangdServer to be notified of events.
virtual void onDiagnosticsReady(PathRef File, llvm::StringRef Version, llvm::ArrayRef< Diag > Diagnostics)
Called by ClangdServer when Diagnostics for File are ready.
llvm::StringMap< TUScheduler::FileStats > fileStats() const
Returns estimated memory usage and other statistics for each of the currently open files.
ClangdServer(const GlobalCompilationDatabase &CDB, const ThreadsafeFS &TFS, const Options &Opts, Callbacks *Callbacks=nullptr)
Creates a new ClangdServer instance.
void prepareRename(PathRef File, Position Pos, std::optional< std::string > NewName, const RenameOptions &RenameOpts, Callback< RenameResult > CB)
Test the validity of a rename operation.
void prepareCallHierarchy(PathRef File, Position Pos, Callback< std::vector< CallHierarchyItem > > CB)
Get information about call hierarchy for a given position.
void resolveTypeHierarchy(TypeHierarchyItem Item, int Resolve, TypeHierarchyDirection Direction, Callback< std::optional< TypeHierarchyItem > > CB)
Resolve type hierarchy item in the given direction.
void documentSymbols(StringRef File, Callback< std::vector< DocumentSymbol > > CB)
Retrieve the symbols within the specified file.
void workspaceSymbols(StringRef Query, int Limit, Callback< std::vector< SymbolInformation > > CB)
Retrieve the top symbols from the workspace matching a query.
void diagnostics(PathRef File, Callback< std::vector< Diag > > CB)
Fetches diagnostics for current version of the File.
void typeHierarchy(PathRef File, Position Pos, int Resolve, TypeHierarchyDirection Direction, Callback< std::vector< TypeHierarchyItem > > CB)
Get information about type hierarchy for a given position.
void removeDocument(PathRef File)
Remove File from list of tracked files, schedule a request to free resources associated with it.
void outgoingCalls(const CallHierarchyItem &Item, Callback< std::vector< CallHierarchyOutgoingCall > >)
Resolve outgoing calls for a given call hierarchy item.
void addDocument(PathRef File, StringRef Contents, llvm::StringRef Version="null", WantDiagnostics WD=WantDiagnostics::Auto, bool ForceRebuild=false)
Add a File to the list of tracked C++ files or update the contents if File is already tracked.
void findDocumentHighlights(PathRef File, Position Pos, Callback< std::vector< DocumentHighlight > > CB)
Get document highlights for a given position.
static std::function< Context(PathRef)> createConfiguredContextProvider(const config::Provider *Provider, ClangdServer::Callbacks *)
Creates a context provider that loads and installs config.
void signatureHelp(PathRef File, Position Pos, MarkupKind DocumentationFormat, Callback< SignatureHelp > CB)
Provide signature help for File at Pos.
void findReferences(PathRef File, Position Pos, uint32_t Limit, bool AddContainer, Callback< ReferencesResult > CB)
Retrieve locations for symbol references.
void switchSourceHeader(PathRef Path, Callback< std::optional< clangd::Path > > CB)
Switch to a corresponding source file when given a header file, and vice versa.
void findType(PathRef File, Position Pos, Callback< std::vector< LocatedSymbol > > CB)
Retrieve symbols for types referenced at Pos.
void findImplementations(PathRef File, Position Pos, Callback< std::vector< LocatedSymbol > > CB)
Retrieve implementations for virtual method.
static Options optsForTest()
void subTypes(const TypeHierarchyItem &Item, Callback< std::vector< TypeHierarchyItem > > CB)
Get direct children of a type hierarchy item.
void semanticRanges(PathRef File, const std::vector< Position > &Pos, Callback< std::vector< SelectionRange > > CB)
Get semantic ranges around a specified position in a file.
void formatFile(PathRef File, const std::vector< Range > &Rngs, Callback< tooling::Replacements > CB)
Run formatting for the File with content Code.
void applyTweak(PathRef File, Range Sel, StringRef ID, Callback< Tweak::Effect > CB)
Apply the code tweak with a specified ID.
void semanticHighlights(PathRef File, Callback< std::vector< HighlightingToken > >)
void getAST(PathRef File, std::optional< Range > R, Callback< std::optional< ASTNode > > CB)
Describe the AST subtree for a piece of code.
void symbolInfo(PathRef File, Position Pos, Callback< std::vector< SymbolDetails > > CB)
Get symbol info for given position.
void onFileEvent(const DidChangeWatchedFilesParams &Params)
Called when an event occurs for a watched file in the workspace.
void superTypes(const TypeHierarchyItem &Item, Callback< std::optional< std::vector< TypeHierarchyItem > > > CB)
Get direct parents of a type hierarchy item.
void profile(MemoryTree &MT) const
Builds a nested representation of memory used by components.
void findHover(PathRef File, Position Pos, Callback< std::optional< HoverInfo > > CB)
Get code hover for a given position.
void formatOnType(PathRef File, Position Pos, StringRef TriggerText, Callback< std::vector< TextEdit > > CB)
Run formatting after TriggerText was typed at Pos in File with content Code.
void rename(PathRef File, Position Pos, llvm::StringRef NewName, const RenameOptions &Opts, Callback< RenameResult > CB)
Rename all occurrences of the symbol at the Pos in File to NewName.
void customAction(PathRef File, llvm::StringRef Name, Callback< InputsAndAST > Action)
Runs an arbitrary action that has access to the AST of the specified file.
void codeAction(const CodeActionInputs &Inputs, Callback< CodeActionResult > CB)
Surface code actions (quick-fixes for diagnostics, or available code tweaks) for a given range in a f...
void locateSymbolAt(PathRef File, Position Pos, Callback< std::vector< LocatedSymbol > > CB)
Find declaration/definition locations of symbol at a specified position.
void incomingCalls(const CallHierarchyItem &Item, Callback< std::vector< CallHierarchyIncomingCall > >)
Resolve incoming calls for a given call hierarchy item.
bool blockUntilIdleForTest(std::optional< double > TimeoutSeconds=10)
void inlayHints(PathRef File, std::optional< Range > RestrictRange, Callback< std::vector< InlayHint > >)
Resolve inlay hints for a given document.
void codeComplete(PathRef File, Position Pos, const clangd::CodeCompleteOptions &Opts, Callback< CodeCompleteResult > CB)
Run code completion for File at Pos.
void reparseOpenFilesIfNeeded(llvm::function_ref< bool(llvm::StringRef File)> Filter)
Requests a reparse of currently opened files using their latest source.
void foldingRanges(StringRef File, Callback< std::vector< FoldingRange > > CB)
Retrieve ranges that can be used to fold code within the specified file.
void documentLinks(PathRef File, Callback< std::vector< DocumentLink > > CB)
Get all document links in a file.
std::shared_ptr< const std::string > getDraft(PathRef File) const
Gets the contents of a currently tracked file.
A context is an immutable container for per-request data that must be propagated through layers that ...
static const Context & current()
Returns the context for the current thread, creating it if needed.
static Deadline infinity()
A FeatureModule contributes a vertical feature to clangd.
virtual bool blockUntilIdle(Deadline)
Waits until the module is idle (no background work) or a deadline expires.
This manages symbols from files and an in-memory index on all symbols.
Provides compilation arguments used for parsing C and C++ files.
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Handles running tasks for ClangdServer and managing the resources (e.g., preambles and ASTs) for open...
@ StaleOrAbsent
Besides accepting stale preamble, this also allow preamble to be absent (not ready or failed to build...
@ Stale
The preamble may be generated from an older version of the file.
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
An interface base for small context-sensitive refactoring actions.
WithContext replaces Context::current() with a provided scope.
A source of configuration fragments.
Config getConfig(const Params &, DiagnosticCallback) const
Build a config based on this provider.
Records an event whose duration is the lifetime of the Span object.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
@ Changed
The file got changed.
std::vector< TypeHierarchyItem > subTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct children of a TypeHierarchyItem.
std::optional< std::vector< TypeHierarchyItem > > superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct parents of a TypeHierarchyItem using SymbolIDs stored inside the item.
std::vector< CallHierarchyIncomingCall > incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
std::vector< HighlightingToken > getSemanticHighlightings(ParsedAST &AST, bool IncludeInactiveRegionTokens)
bool pathEqual(PathRef A, PathRef B)
llvm::Expected< std::unique_ptr< Tweak > > prepareTweak(StringRef ID, const Tweak::Selection &S, const FeatureModuleSet *Modules)
ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens, const ASTContext &Ctx)
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
std::vector< DocumentLink > getDocumentLinks(ParsedAST &AST)
Get all document links.
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
void vlog(const char *Fmt, Ts &&... Vals)
llvm::Error reformatEdit(Edit &E, const format::FormatStyle &Style)
Formats the edits and code around it according to Style.
std::vector< LocatedSymbol > findType(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns symbols for types referenced at Pos.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
llvm::Expected< std::vector< FoldingRange > > getFoldingRanges(const std::string &Code, bool LineFoldingOnly)
Returns a list of ranges whose contents might be collapsible in an editor.
llvm::Expected< RenameResult > rename(const RenameInputs &RInputs)
Renames all occurrences of the symbol.
std::vector< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index, bool AddContext)
Returns references of the symbol at a specified Pos.
std::optional< HoverInfo > getHover(ParsedAST &AST, Position Pos, const format::FormatStyle &Style, const SymbolIndex *Index)
Get the hover information when hovering at Pos.
std::vector< tooling::Replacement > formatIncremental(llvm::StringRef OriginalCode, unsigned OriginalCursor, llvm::StringRef InsertedText, format::FormatStyle Style)
Applies limited formatting around new InsertedText.
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
llvm::Expected< SelectionRange > getSemanticRanges(ParsedAST &AST, Position Pos)
Returns the list of all interesting ranges around the Position Pos.
void log(const char *Fmt, Ts &&... Vals)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
llvm::Expected< std::vector< DocumentSymbol > > getDocumentSymbols(ParsedAST &AST)
Retrieves the symbols contained in the "main file" section of an AST in the same order that they appe...
std::optional< Path > getCorrespondingHeaderOrSource(PathRef OriginalFile, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS)
Given a header file, returns the best matching source file, and vice visa.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Diag toDiag(const llvm::SMDiagnostic &D, Diag::DiagSource Source)
std::vector< std::unique_ptr< Tweak > > prepareTweaks(const Tweak::Selection &S, llvm::function_ref< bool(const Tweak &)> Filter, const FeatureModuleSet *Modules)
Calls prepare() on all tweaks that satisfy the filter, returning those that can run on the selection.
WantDiagnostics
Determines whether diagnostics should be generated for a file snapshot.
@ Auto
Diagnostics must not be generated for this snapshot.
std::vector< LocatedSymbol > findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Returns implementations at a specified Pos:
std::string Path
A typedef to represent a file path.
int isCancelled(const Context &Ctx)
If the current context is within a cancelled task, returns the reason.
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
std::vector< Range > getInactiveRegions(ParsedAST &AST)
Deadline timeoutSeconds(std::optional< double > Seconds)
Makes a deadline from a timeout in seconds. std::nullopt means wait forever.
CodeCompleteResult codeComplete(PathRef FileName, Position Pos, const PreambleData *Preamble, const ParseInputs &ParseInput, CodeCompleteOptions Opts, SpeculativeFuzzyFind *SpecFuzzyFind)
Gets code completions at a specified Pos in FileName.
std::vector< CallHierarchyOutgoingCall > outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
SignatureHelp signatureHelp(PathRef FileName, Position Pos, const PreambleData &Preamble, const ParseInputs &ParseInput, MarkupKind DocumentationFormat)
Get signature help at a specified Pos in FileName.
std::vector< InlayHint > inlayHints(ParsedAST &AST, std::optional< Range > RestrictRange, InlayHintOptions HintOptions)
Compute and return inlay hints for a file.
TextEdit replacementToEdit(llvm::StringRef Code, const tooling::Replacement &R)
SymbolSlab indexStandardLibrary(llvm::StringRef HeaderSources, std::unique_ptr< CompilerInvocation > CI, const StdLibLocation &Loc, const ThreadsafeFS &TFS)
std::vector< CallHierarchyItem > prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath)
Get call hierarchy information at Pos.
format::FormatStyle getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content, const ThreadsafeFS &TFS, bool FormatFile)
Choose the clang-format style we should apply to a certain file.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Represents programming constructs like functions or constructors in the context of call hierarchy.
std::vector< TweakRef > TweakRefs
std::vector< Rename > Renames
std::vector< QuickFix > QuickFixes
std::function< Context(PathRef)> ContextProvider
If set, queried to derive a processing context for some work.
clangd::PreambleThrottler * PreambleThrottler
This throttler controls which preambles may be built at a given time.
bool StorePreamblesInMemory
Cached preambles are potentially large. If false, store them on disk.
ASTRetentionPolicy RetentionPolicy
AST caching policy. The default is to keep up to 3 ASTs in memory.
unsigned AsyncThreadsCount
To process requests asynchronously, ClangdServer spawns worker threads.
DebouncePolicy UpdateDebounce
Time to wait after a new file version before computing diagnostics.
static const llvm::StringLiteral QUICKFIX_KIND
Settings that express user/project preferences and control clangd behavior.
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
static DebouncePolicy fixed(clock::duration)
A policy that always returns the same duration, useful for tests.
A top-level diagnostic that may have Notes and Fixes.
std::vector< Fix > Fixes
Alternative fixes for this diagnostic, one should be chosen.
std::vector< FileEvent > changes
The actual file events.
A set of edits generated for a single file.
Represents a single fix-it that editor can apply to fix the error.
A tree that can be used to represent memory usage of nested components while preserving the hierarchy...
MemoryTree & child(llvm::StringLiteral Name)
No copy of the Name.
bool PreambleParseForwardingFunctions
The parsed preamble and associated data.
PrecompiledPreamble Preamble
Position start
The range's start position.
Position end
The range's end position.
bool WantFormat
If true, format the rename edits, only meaningful in ClangdServer layer.
ASTRetentionPolicy RetentionPolicy
Determines when to keep idle ASTs in memory for future use.
DebouncePolicy UpdateDebounce
Time to wait after an update to see if another one comes along.
std::function< Context(PathRef)> ContextProvider
Used to create a context that wraps each single operation.
bool StorePreamblesInMemory
Cache (large) preamble data in RAM rather than temporary files on disk.
unsigned AsyncThreadsCount
Number of concurrent actions.
clangd::PreambleThrottler * PreambleThrottler
This throttler controls which preambles may be built at a given time.
Describes the context used to evaluate configuration fragments.
std::chrono::steady_clock::time_point FreshTime
Hint that stale data is OK to improve performance (e.g.
llvm::StringRef Path
Absolute path to a source file we're applying the config to.
Represents measurements of clangd events, e.g.
@ Counter
An aggregate number whose rate of change over time is meaningful.
@ Distribution
A distribution of values with a meaningful mean and count.
void record(double Value, llvm::StringRef Label="") const
Records a measurement for this metric to active tracer.