clang-tools 17.0.0git
ClangdServer.cpp
Go to the documentation of this file.
1//===--- ClangdServer.cpp - Main clangd server code --------------*- C++-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===-------------------------------------------------------------------===//
8
9#include "ClangdServer.h"
10#include "CodeComplete.h"
11#include "Config.h"
12#include "Diagnostics.h"
13#include "DumpAST.h"
14#include "FindSymbols.h"
15#include "Format.h"
16#include "HeaderSourceSwitch.h"
17#include "InlayHints.h"
18#include "ParsedAST.h"
19#include "Preamble.h"
20#include "Protocol.h"
22#include "SemanticSelection.h"
23#include "SourceCode.h"
24#include "TUScheduler.h"
25#include "XRefs.h"
27#include "index/FileIndex.h"
28#include "index/Merge.h"
29#include "index/StdLib.h"
30#include "refactor/Rename.h"
31#include "refactor/Tweak.h"
33#include "support/Logger.h"
34#include "support/MemoryTree.h"
36#include "support/Trace.h"
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"
47#include <algorithm>
48#include <chrono>
49#include <future>
50#include <memory>
51#include <mutex>
52#include <optional>
53#include <string>
54#include <type_traits>
55
56namespace clang {
57namespace clangd {
58namespace {
59
60// Update the FileIndex with new ASTs and plumb the diagnostics responses.
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) {}
67
68 void onPreambleAST(PathRef Path, llvm::StringRef Version,
69 const CompilerInvocation &CI, ASTContext &Ctx,
70 Preprocessor &PP,
71 const CanonicalIncludes &CanonIncludes) override {
72 // If this preamble uses a standard library we haven't seen yet, index it.
73 if (FIndex)
74 if (auto Loc = Stdlib->add(*CI.getLangOpts(), PP.getHeaderSearchInfo()))
75 indexStdlib(CI, std::move(*Loc));
76
77 if (FIndex)
78 FIndex->updatePreamble(Path, Version, Ctx, PP, CanonIncludes);
79 }
80
81 void indexStdlib(const CompilerInvocation &CI, StdLibLocation Loc) {
82 // This task is owned by Tasks, which outlives the TUScheduler and
83 // therefore the UpdateIndexCallbacks.
84 // We must be careful that the references we capture outlive TUScheduler.
85 auto Task = [LO(*CI.getLangOpts()), Loc(std::move(Loc)),
86 CI(std::make_unique<CompilerInvocation>(CI)),
87 // External values that outlive ClangdServer
88 TFS(&TFS),
89 // Index outlives TUScheduler (declared first)
90 FIndex(FIndex),
91 // shared_ptr extends lifetime
92 Stdlib(Stdlib)]() mutable {
93 IndexFileIn IF;
94 IF.Symbols = indexStandardLibrary(std::move(CI), Loc, *TFS);
95 if (Stdlib->isBest(LO))
96 FIndex->updatePreamble(std::move(IF));
97 };
98 if (Tasks)
99 // This doesn't have a semaphore to enforce -j, but it's rare.
100 Tasks->runAsync("IndexStdlib", std::move(Task));
101 else
102 Task();
103 }
104
105 void onMainAST(PathRef Path, ParsedAST &AST, PublishFn Publish) override {
106 if (FIndex)
107 FIndex->updateMain(Path, AST);
108
109 assert(AST.getDiagnostics() &&
110 "We issue callback only with fresh preambles");
111 std::vector<Diag> Diagnostics = *AST.getDiagnostics();
112 if (ServerCallbacks)
113 Publish([&]() {
114 ServerCallbacks->onDiagnosticsReady(Path, AST.version(),
115 std::move(Diagnostics));
116 });
117 }
118
119 void onFailedAST(PathRef Path, llvm::StringRef Version,
120 std::vector<Diag> Diags, PublishFn Publish) override {
121 if (ServerCallbacks)
122 Publish(
123 [&]() { ServerCallbacks->onDiagnosticsReady(Path, Version, Diags); });
124 }
125
126 void onFileUpdated(PathRef File, const TUStatus &Status) override {
127 if (ServerCallbacks)
128 ServerCallbacks->onFileUpdated(File, Status);
129 }
130
131 void onPreamblePublished(PathRef File) override {
132 if (ServerCallbacks)
133 ServerCallbacks->onSemanticsMaybeChanged(File);
134 }
135
136private:
137 FileIndex *FIndex;
138 ClangdServer::Callbacks *ServerCallbacks;
139 const ThreadsafeFS &TFS;
140 std::shared_ptr<StdLibSet> Stdlib;
141 AsyncTaskRunner *Tasks;
142};
143
144class DraftStoreFS : public ThreadsafeFS {
145public:
146 DraftStoreFS(const ThreadsafeFS &Base, const DraftStore &Drafts)
147 : Base(Base), DirtyFiles(Drafts) {}
148
149private:
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());
154 return OFS;
155 }
156
157 const ThreadsafeFS &Base;
158 const DraftStore &DirtyFiles;
159};
160
161} // namespace
162
165 Opts.UpdateDebounce = DebouncePolicy::fixed(/*zero*/ {});
166 Opts.StorePreamblesInMemory = true;
167 Opts.AsyncThreadsCount = 4; // Consistent!
168 return Opts;
169}
170
171ClangdServer::Options::operator TUScheduler::Options() const {
173 Opts.AsyncThreadsCount = AsyncThreadsCount;
174 Opts.RetentionPolicy = RetentionPolicy;
175 Opts.StorePreamblesInMemory = StorePreamblesInMemory;
176 Opts.UpdateDebounce = UpdateDebounce;
177 Opts.ContextProvider = ContextProvider;
178 Opts.PreambleThrottler = PreambleThrottler;
179 return Opts;
180}
181
183 const ThreadsafeFS &TFS, const Options &Opts,
185 : FeatureModules(Opts.FeatureModules), CDB(CDB), TFS(TFS),
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
194 : TUScheduler::NoInvalidation),
195 DirtyFS(std::make_unique<DraftStoreFS>(TFS, DraftMgr)) {
196 if (Opts.AsyncThreadsCount != 0)
197 IndexTasks.emplace();
198 // Pass a callback into `WorkScheduler` to extract symbols from a newly
199 // parsed file and rebuild the file index synchronously each time an AST
200 // is parsed.
201 WorkScheduler.emplace(CDB, TUScheduler::Options(Opts),
202 std::make_unique<UpdateIndexCallbacks>(
203 DynamicIdx.get(), Callbacks, TFS,
204 IndexTasks ? &*IndexTasks : nullptr));
205 // Adds an index to the stack, at higher priority than existing indexes.
206 auto AddIndex = [&](SymbolIndex *Idx) {
207 if (this->Index != nullptr) {
208 MergedIdx.push_back(std::make_unique<MergedIndex>(Idx, this->Index));
209 this->Index = MergedIdx.back().get();
210 } else {
211 this->Index = Idx;
212 }
213 };
214 if (Opts.StaticIndex)
215 AddIndex(Opts.StaticIndex);
216 if (Opts.BackgroundIndex) {
218 BGOpts.ThreadPoolSize = std::max(Opts.AsyncThreadsCount, 1u);
220 if (Callbacks)
222 };
223 BGOpts.ContextProvider = Opts.ContextProvider;
224 BackgroundIdx = std::make_unique<BackgroundIndex>(
225 TFS, CDB,
227 [&CDB](llvm::StringRef File) { return CDB.getProjectInfo(File); }),
228 std::move(BGOpts));
229 AddIndex(BackgroundIdx.get());
230 }
231 if (DynamicIdx)
232 AddIndex(DynamicIdx.get());
233
234 if (Opts.FeatureModules) {
236 *this->WorkScheduler,
237 this->Index,
238 this->TFS,
239 };
240 for (auto &Mod : *Opts.FeatureModules)
241 Mod.initialize(F);
242 }
243}
244
246 // Destroying TUScheduler first shuts down request threads that might
247 // otherwise access members concurrently.
248 // (Nobody can be using TUScheduler because we're on the main thread).
249 WorkScheduler.reset();
250 // Now requests have stopped, we can shut down feature modules.
251 if (FeatureModules) {
252 for (auto &Mod : *FeatureModules)
253 Mod.stop();
254 for (auto &Mod : *FeatureModules)
255 Mod.blockUntilIdle(Deadline::infinity());
256 }
257}
258
259void ClangdServer::addDocument(PathRef File, llvm::StringRef Contents,
260 llvm::StringRef Version,
261 WantDiagnostics WantDiags, bool ForceRebuild) {
262 std::string ActualVersion = DraftMgr.addDraft(File, Version, Contents);
263 ParseOptions Opts;
264 Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions;
265 Opts.ImportInsertions = ImportInsertions;
266
267 // Compile command is set asynchronously during update, as it can be slow.
268 ParseInputs Inputs;
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);
278 // If we loaded Foo.h, we want to make sure Foo.cpp is indexed.
279 if (NewFile && BackgroundIdx)
280 BackgroundIdx->boostRelated(File);
281}
282
284 llvm::function_ref<bool(llvm::StringRef File)> Filter) {
285 // Reparse only opened files that were modified.
286 for (const Path &FilePath : DraftMgr.getActiveFiles())
287 if (Filter(FilePath))
288 if (auto Draft = DraftMgr.getDraft(FilePath)) // else disappeared in race?
289 addDocument(FilePath, *Draft->Contents, Draft->Version,
291}
292
293std::shared_ptr<const std::string> ClangdServer::getDraft(PathRef File) const {
294 auto Draft = DraftMgr.getDraft(File);
295 if (!Draft)
296 return nullptr;
297 return std::move(Draft->Contents);
298}
299
300std::function<Context(PathRef)>
302 Callbacks *Publish) {
303 if (!Provider)
304 return [](llvm::StringRef) { return Context::current().clone(); };
305
306 struct Impl {
307 const config::Provider *Provider;
309 std::mutex PublishMu;
310
311 Impl(const config::Provider *Provider, ClangdServer::Callbacks *Publish)
312 : Provider(Provider), Publish(Publish) {}
313
314 Context operator()(llvm::StringRef File) {
315 config::Params Params;
316 // Don't reread config files excessively often.
317 // FIXME: when we see a config file change event, use the event timestamp?
318 Params.FreshTime =
319 std::chrono::steady_clock::now() - std::chrono::seconds(5);
320 llvm::SmallString<256> PosixPath;
321 if (!File.empty()) {
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();
325 }
326
327 llvm::StringMap<std::vector<Diag>> ReportableDiagnostics;
328 Config C = Provider->getConfig(Params, [&](const llvm::SMDiagnostic &D) {
329 // Create the map entry even for note diagnostics we don't report.
330 // This means that when the file is parsed with no warnings, we
331 // publish an empty set of diagnostics, clearing any the client has.
332 handleDiagnostic(D, !Publish || D.getFilename().empty()
333 ? nullptr
334 : &ReportableDiagnostics[D.getFilename()]);
335 });
336 // Blindly publish diagnostics for the (unopened) parsed config files.
337 // We must avoid reporting diagnostics for *the same file* concurrently.
338 // Source diags are published elsewhere, but those are different files.
339 if (!ReportableDiagnostics.empty()) {
340 std::lock_guard<std::mutex> Lock(PublishMu);
341 for (auto &Entry : ReportableDiagnostics)
342 Publish->onDiagnosticsReady(Entry.first(), /*Version=*/"",
343 std::move(Entry.second));
344 }
345 return Context::current().derive(Config::Key, std::move(C));
346 }
347
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());
354 break;
355 case llvm::SourceMgr::DK_Warning:
356 log("config warning at {0}:{1}:{2}: {3}", D.getFilename(),
357 D.getLineNo(), D.getColumnNo(), D.getMessage());
358 break;
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; // Don't emit notes as LSP diagnostics.
364 break;
365 }
366 if (ClientDiagnostics)
367 ClientDiagnostics->push_back(toDiag(D, Diag::ClangdConfig));
368 }
369 };
370
371 // Copyable wrapper.
372 return [I(std::make_shared<Impl>(Provider, Publish))](llvm::StringRef Path) {
373 return (*I)(Path);
374 };
375}
376
378 DraftMgr.removeDraft(File);
379 WorkScheduler->remove(File);
380}
381
383 const clangd::CodeCompleteOptions &Opts,
385 // Copy completion options for passing them to async task handler.
386 auto CodeCompleteOpts = Opts;
387 if (!CodeCompleteOpts.Index) // Respect overridden index.
388 CodeCompleteOpts.Index = Index;
389
390 auto Task = [Pos, CodeCompleteOpts, File = File.str(), CB = std::move(CB),
391 this](llvm::Expected<InputsAndPreamble> IP) mutable {
392 if (!IP)
393 return CB(IP.takeError());
394 if (auto Reason = isCancelled())
395 return CB(llvm::make_error<CancelledError>(Reason));
396
397 std::optional<SpeculativeFuzzyFind> SpecFuzzyFind;
398 if (!IP->Preamble) {
399 // No speculation in Fallback mode, as it's supposed to be much faster
400 // without compiling.
401 vlog("Build for file {0} is not ready. Enter fallback mode.", File);
402 } else if (CodeCompleteOpts.Index) {
403 SpecFuzzyFind.emplace();
404 {
405 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
406 SpecFuzzyFind->CachedReq = CachedCompletionFuzzyFindRequestByFile[File];
407 }
408 }
409 ParseInputs ParseInput{IP->Command, &getHeaderFS(), IP->Contents.str()};
410 // FIXME: Add traling new line if there is none at eof, workaround a crash,
411 // see https://github.com/clangd/clangd/issues/332
412 if (!IP->Contents.endswith("\n"))
413 ParseInput.Contents.append("\n");
414 ParseInput.Index = Index;
415
416 CodeCompleteOpts.MainFileSignals = IP->Signals;
417 CodeCompleteOpts.AllScopes = Config::current().Completion.AllScopes;
418 // FIXME(ibiryukov): even if Preamble is non-null, we may want to check
419 // both the old and the new version in case only one of them matches.
421 File, Pos, IP->Preamble, ParseInput, CodeCompleteOpts,
422 SpecFuzzyFind ? &*SpecFuzzyFind : nullptr);
423 {
424 clang::clangd::trace::Span Tracer("Completion results callback");
425 CB(std::move(Result));
426 }
427 if (SpecFuzzyFind && SpecFuzzyFind->NewReq) {
428 std::lock_guard<std::mutex> Lock(CachedCompletionFuzzyFindRequestMutex);
429 CachedCompletionFuzzyFindRequestByFile[File] = *SpecFuzzyFind->NewReq;
430 }
431 // SpecFuzzyFind is only destroyed after speculative fuzzy find finishes.
432 // We don't want `codeComplete` to wait for the async call if it doesn't use
433 // the result (e.g. non-index completion, speculation fails), so that `CB`
434 // is called as soon as results are available.
435 };
436
437 // We use a potentially-stale preamble because latency is critical here.
438 WorkScheduler->runWithPreamble(
439 "CodeComplete", File,
440 (Opts.RunParser == CodeCompleteOptions::AlwaysParse)
443 std::move(Task));
444}
445
447 MarkupKind DocumentationFormat,
449
450 auto Action = [Pos, File = File.str(), CB = std::move(CB),
451 DocumentationFormat,
452 this](llvm::Expected<InputsAndPreamble> IP) mutable {
453 if (!IP)
454 return CB(IP.takeError());
455
456 const auto *PreambleData = IP->Preamble;
457 if (!PreambleData)
458 return CB(error("Failed to parse includes"));
459
460 ParseInputs ParseInput{IP->Command, &getHeaderFS(), IP->Contents.str()};
461 // FIXME: Add traling new line if there is none at eof, workaround a crash,
462 // see https://github.com/clangd/clangd/issues/332
463 if (!IP->Contents.endswith("\n"))
464 ParseInput.Contents.append("\n");
465 ParseInput.Index = Index;
467 DocumentationFormat));
468 };
469
470 // Unlike code completion, we wait for a preamble here.
471 WorkScheduler->runWithPreamble("SignatureHelp", File, TUScheduler::Stale,
472 std::move(Action));
473}
474
475void ClangdServer::formatFile(PathRef File, std::optional<Range> Rng,
477 auto Code = getDraft(File);
478 if (!Code)
479 return CB(llvm::make_error<LSPError>("trying to format non-added document",
481 tooling::Range RequestedRange;
482 if (Rng) {
483 llvm::Expected<size_t> Begin = positionToOffset(*Code, Rng->start);
484 if (!Begin)
485 return CB(Begin.takeError());
486 llvm::Expected<size_t> End = positionToOffset(*Code, Rng->end);
487 if (!End)
488 return CB(End.takeError());
489 RequestedRange = tooling::Range(*Begin, *End - *Begin);
490 } else {
491 RequestedRange = tooling::Range(0, Code->size());
492 }
493
494 // Call clang-format.
495 auto Action = [File = File.str(), Code = std::move(*Code),
496 Ranges = std::vector<tooling::Range>{RequestedRange},
497 CB = std::move(CB), this]() mutable {
498 format::FormatStyle Style = getFormatStyleForFile(File, Code, TFS);
499 tooling::Replacements IncludeReplaces =
500 format::sortIncludes(Style, Code, Ranges, File);
501 auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces);
502 if (!Changed)
503 return CB(Changed.takeError());
504
505 CB(IncludeReplaces.merge(format::reformat(
506 Style, *Changed,
507 tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
508 File)));
509 };
510 WorkScheduler->runQuick("Format", File, std::move(Action));
511}
512
514 StringRef TriggerText,
515 Callback<std::vector<TextEdit>> CB) {
516 auto Code = getDraft(File);
517 if (!Code)
518 return CB(llvm::make_error<LSPError>("trying to format non-added document",
520 llvm::Expected<size_t> CursorPos = positionToOffset(*Code, Pos);
521 if (!CursorPos)
522 return CB(CursorPos.takeError());
523 auto Action = [File = File.str(), Code = std::move(*Code),
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(/*CWD=*/std::nullopt).get());
529 if (!Style)
530 return CB(Style.takeError());
531
532 std::vector<TextEdit> Result;
533 for (const tooling::Replacement &R :
534 formatIncremental(Code, CursorPos, TriggerText, *Style))
535 Result.push_back(replacementToEdit(Code, R));
536 return CB(Result);
537 };
538 WorkScheduler->runQuick("FormatOnType", File, std::move(Action));
539}
540
542 std::optional<std::string> NewName,
543 const RenameOptions &RenameOpts,
545 auto Action = [Pos, File = File.str(), CB = std::move(CB),
546 NewName = std::move(NewName),
547 RenameOpts](llvm::Expected<InputsAndAST> InpAST) mutable {
548 if (!InpAST)
549 return CB(InpAST.takeError());
550 // prepareRename is latency-sensitive: we don't query the index, as we
551 // only need main-file references
552 auto Results =
553 clangd::rename({Pos, NewName.value_or("__clangd_rename_placeholder"),
554 InpAST->AST, File, /*FS=*/nullptr,
555 /*Index=*/nullptr, RenameOpts});
556 if (!Results) {
557 // LSP says to return null on failure, but that will result in a generic
558 // failure message. If we send an LSP error response, clients can surface
559 // the message to users (VSCode does).
560 return CB(Results.takeError());
561 }
562 return CB(*Results);
563 };
564 WorkScheduler->runWithAST("PrepareRename", File, std::move(Action));
565}
566
567void ClangdServer::rename(PathRef File, Position Pos, llvm::StringRef NewName,
568 const RenameOptions &Opts,
570 auto Action = [File = File.str(), NewName = NewName.str(), Pos, Opts,
571 CB = std::move(CB),
572 this](llvm::Expected<InputsAndAST> InpAST) mutable {
573 // Tracks number of files edited per invocation.
574 static constexpr trace::Metric RenameFiles("rename_files",
576 if (!InpAST)
577 return CB(InpAST.takeError());
578 auto R = clangd::rename({Pos, NewName, InpAST->AST, File,
579 DirtyFS->view(std::nullopt), Index, Opts});
580 if (!R)
581 return CB(R.takeError());
582
583 if (Opts.WantFormat) {
584 auto Style = getFormatStyleForFile(File, InpAST->Inputs.Contents,
585 *InpAST->Inputs.TFS);
586 llvm::Error Err = llvm::Error::success();
587 for (auto &E : R->GlobalChanges)
588 Err =
589 llvm::joinErrors(reformatEdit(E.getValue(), Style), std::move(Err));
590
591 if (Err)
592 return CB(std::move(Err));
593 }
594 RenameFiles.record(R->GlobalChanges.size());
595 return CB(*R);
596 };
597 WorkScheduler->runWithAST("Rename", File, std::move(Action));
598}
599
600// May generate several candidate selections, due to SelectionTree ambiguity.
601// vector of pointers because GCC doesn't like non-copyable Selection.
602static llvm::Expected<std::vector<std::unique_ptr<Tweak::Selection>>>
604 llvm::vfs::FileSystem *FS) {
605 auto Begin = positionToOffset(AST.Inputs.Contents, Sel.start);
606 if (!Begin)
607 return Begin.takeError();
608 auto End = positionToOffset(AST.Inputs.Contents, Sel.end);
609 if (!End)
610 return End.takeError();
611 std::vector<std::unique_ptr<Tweak::Selection>> Result;
613 AST.AST.getASTContext(), AST.AST.getTokens(), *Begin, *End,
614 [&](SelectionTree T) {
615 Result.push_back(std::make_unique<Tweak::Selection>(
616 AST.Inputs.Index, AST.AST, *Begin, *End, std::move(T), FS));
617 return false;
618 });
619 assert(!Result.empty() && "Expected at least one SelectionTree");
620 return std::move(Result);
621}
622
624 PathRef File, Range Sel, llvm::unique_function<bool(const Tweak &)> Filter,
625 Callback<std::vector<TweakRef>> CB) {
626 // Tracks number of times a tweak has been offered.
627 static constexpr trace::Metric TweakAvailable(
628 "tweak_available", trace::Metric::Counter, "tweak_id");
629 auto Action = [Sel, CB = std::move(CB), Filter = std::move(Filter),
630 FeatureModules(this->FeatureModules)](
631 Expected<InputsAndAST> InpAST) mutable {
632 if (!InpAST)
633 return CB(InpAST.takeError());
634 auto Selections = tweakSelection(Sel, *InpAST, /*FS=*/nullptr);
635 if (!Selections)
636 return CB(Selections.takeError());
637 std::vector<TweakRef> Res;
638 // Don't allow a tweak to fire more than once across ambiguous selections.
639 llvm::DenseSet<llvm::StringRef> PreparedTweaks;
640 auto DeduplicatingFilter = [&](const Tweak &T) {
641 return Filter(T) && !PreparedTweaks.count(T.id());
642 };
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());
648 }
649 }
650
651 CB(std::move(Res));
652 };
653
654 WorkScheduler->runWithAST("EnumerateTweaks", File, std::move(Action),
655 Transient);
656}
657
658void ClangdServer::applyTweak(PathRef File, Range Sel, StringRef TweakID,
660 // Tracks number of times a tweak has been attempted.
661 static constexpr trace::Metric TweakAttempt(
662 "tweak_attempt", trace::Metric::Counter, "tweak_id");
663 // Tracks number of times a tweak has failed to produce edits.
664 static constexpr trace::Metric TweakFailed(
665 "tweak_failed", trace::Metric::Counter, "tweak_id");
666 TweakAttempt.record(1, TweakID);
667 auto Action = [File = File.str(), Sel, TweakID = TweakID.str(),
668 CB = std::move(CB),
669 this](Expected<InputsAndAST> InpAST) mutable {
670 if (!InpAST)
671 return CB(InpAST.takeError());
672 auto FS = DirtyFS->view(std::nullopt);
673 auto Selections = tweakSelection(Sel, *InpAST, FS.get());
674 if (!Selections)
675 return CB(Selections.takeError());
676 std::optional<llvm::Expected<Tweak::Effect>> Effect;
677 // Try each selection, take the first one that prepare()s.
678 // If they all fail, Effect will hold get the last error.
679 for (const auto &Selection : *Selections) {
680 auto T = prepareTweak(TweakID, *Selection, FeatureModules);
681 if (T) {
682 Effect = (*T)->apply(*Selection);
683 break;
684 }
685 Effect = T.takeError();
686 }
687 assert(Effect && "Expected at least one selection");
688 if (*Effect && (*Effect)->FormatEdits) {
689 // Format tweaks that require it centrally here.
690 for (auto &It : (*Effect)->ApplyEdits) {
691 Edit &E = It.second;
692 format::FormatStyle Style =
693 getFormatStyleForFile(File, E.InitialCode, TFS);
694 if (llvm::Error Err = reformatEdit(E, Style))
695 elog("Failed to format {0}: {1}", It.first(), std::move(Err));
696 }
697 } else {
698 TweakFailed.record(1, TweakID);
699 }
700 return CB(std::move(*Effect));
701 };
702 WorkScheduler->runWithAST("ApplyTweak", File, std::move(Action));
703}
704
706 Callback<std::vector<LocatedSymbol>> CB) {
707 auto Action = [Pos, CB = std::move(CB),
708 this](llvm::Expected<InputsAndAST> InpAST) mutable {
709 if (!InpAST)
710 return CB(InpAST.takeError());
711 CB(clangd::locateSymbolAt(InpAST->AST, Pos, Index));
712 };
713
714 WorkScheduler->runWithAST("Definitions", File, std::move(Action));
715}
716
718 PathRef Path, Callback<std::optional<clangd::Path>> CB) {
719 // We want to return the result as fast as possible, strategy is:
720 // 1) use the file-only heuristic, it requires some IO but it is much
721 // faster than building AST, but it only works when .h/.cc files are in
722 // the same directory.
723 // 2) if 1) fails, we use the AST&Index approach, it is slower but supports
724 // different code layout.
725 if (auto CorrespondingFile =
726 getCorrespondingHeaderOrSource(Path, TFS.view(std::nullopt)))
727 return CB(std::move(CorrespondingFile));
728 auto Action = [Path = Path.str(), CB = std::move(CB),
729 this](llvm::Expected<InputsAndAST> InpAST) mutable {
730 if (!InpAST)
731 return CB(InpAST.takeError());
732 CB(getCorrespondingHeaderOrSource(Path, InpAST->AST, Index));
733 };
734 WorkScheduler->runWithAST("SwitchHeaderSource", Path, std::move(Action));
735}
736
738 PathRef File, Position Pos, Callback<std::vector<DocumentHighlight>> CB) {
739 auto Action =
740 [Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST) mutable {
741 if (!InpAST)
742 return CB(InpAST.takeError());
743 CB(clangd::findDocumentHighlights(InpAST->AST, Pos));
744 };
745
746 WorkScheduler->runWithAST("Highlights", File, std::move(Action), Transient);
747}
748
750 Callback<std::optional<HoverInfo>> CB) {
751 auto Action = [File = File.str(), Pos, CB = std::move(CB),
752 this](llvm::Expected<InputsAndAST> InpAST) mutable {
753 if (!InpAST)
754 return CB(InpAST.takeError());
755 format::FormatStyle Style = getFormatStyleForFile(
756 File, InpAST->Inputs.Contents, *InpAST->Inputs.TFS);
757 CB(clangd::getHover(InpAST->AST, Pos, std::move(Style), Index));
758 };
759
760 WorkScheduler->runWithAST("Hover", File, std::move(Action), Transient);
761}
762
764 TypeHierarchyDirection Direction,
765 Callback<std::vector<TypeHierarchyItem>> CB) {
766 auto Action = [File = File.str(), Pos, Resolve, Direction, CB = std::move(CB),
767 this](Expected<InputsAndAST> InpAST) mutable {
768 if (!InpAST)
769 return CB(InpAST.takeError());
770 CB(clangd::getTypeHierarchy(InpAST->AST, Pos, Resolve, Direction, Index,
771 File));
772 };
773
774 WorkScheduler->runWithAST("TypeHierarchy", File, std::move(Action));
775}
776
778 const TypeHierarchyItem &Item,
779 Callback<std::optional<std::vector<TypeHierarchyItem>>> CB) {
780 WorkScheduler->run("typeHierarchy/superTypes", /*Path=*/"",
781 [=, CB = std::move(CB)]() mutable {
782 CB(clangd::superTypes(Item, Index));
783 });
784}
785
787 Callback<std::vector<TypeHierarchyItem>> CB) {
788 WorkScheduler->run(
789 "typeHierarchy/subTypes", /*Path=*/"",
790 [=, CB = std::move(CB)]() mutable { CB(clangd::subTypes(Item, Index)); });
791}
792
794 TypeHierarchyItem Item, int Resolve, TypeHierarchyDirection Direction,
795 Callback<std::optional<TypeHierarchyItem>> CB) {
796 WorkScheduler->run(
797 "Resolve Type Hierarchy", "", [=, CB = std::move(CB)]() mutable {
798 clangd::resolveTypeHierarchy(Item, Resolve, Direction, Index);
799 CB(Item);
800 });
801}
802
804 PathRef File, Position Pos, Callback<std::vector<CallHierarchyItem>> CB) {
805 auto Action = [File = File.str(), Pos,
806 CB = std::move(CB)](Expected<InputsAndAST> InpAST) mutable {
807 if (!InpAST)
808 return CB(InpAST.takeError());
809 CB(clangd::prepareCallHierarchy(InpAST->AST, Pos, File));
810 };
811 WorkScheduler->runWithAST("CallHierarchy", File, std::move(Action));
812}
813
815 const CallHierarchyItem &Item,
816 Callback<std::vector<CallHierarchyIncomingCall>> CB) {
817 WorkScheduler->run("Incoming Calls", "",
818 [CB = std::move(CB), Item, this]() mutable {
819 CB(clangd::incomingCalls(Item, Index));
820 });
821}
822
823void ClangdServer::inlayHints(PathRef File, std::optional<Range> RestrictRange,
824 Callback<std::vector<InlayHint>> CB) {
825 auto Action = [RestrictRange(std::move(RestrictRange)),
826 CB = std::move(CB)](Expected<InputsAndAST> InpAST) mutable {
827 if (!InpAST)
828 return CB(InpAST.takeError());
829 CB(clangd::inlayHints(InpAST->AST, std::move(RestrictRange)));
830 };
831 WorkScheduler->runWithAST("InlayHints", File, std::move(Action), Transient);
832}
833
835 // FIXME: Do nothing for now. This will be used for indexing and potentially
836 // invalidating other caches.
837}
838
840 llvm::StringRef Query, int Limit,
841 Callback<std::vector<SymbolInformation>> CB) {
842 WorkScheduler->run(
843 "getWorkspaceSymbols", /*Path=*/"",
844 [Query = Query.str(), Limit, CB = std::move(CB), this]() mutable {
845 CB(clangd::getWorkspaceSymbols(Query, Limit, Index,
846 WorkspaceRoot.value_or("")));
847 });
848}
849
851 Callback<std::vector<DocumentSymbol>> CB) {
852 auto Action =
853 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST) mutable {
854 if (!InpAST)
855 return CB(InpAST.takeError());
856 CB(clangd::getDocumentSymbols(InpAST->AST));
857 };
858 WorkScheduler->runWithAST("DocumentSymbols", File, std::move(Action),
859 Transient);
860}
861
863 Callback<std::vector<FoldingRange>> CB) {
864 auto Code = getDraft(File);
865 if (!Code)
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 {
871 CB(clangd::getFoldingRanges(Code, LineFoldingOnly));
872 };
873 // We want to make sure folding ranges are always available for all the open
874 // files, hence prefer runQuick to not wait for operations on other files.
875 WorkScheduler->runQuick("FoldingRanges", File, std::move(Action));
876}
877
879 Callback<std::vector<LocatedSymbol>> CB) {
880 auto Action =
881 [Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST) mutable {
882 if (!InpAST)
883 return CB(InpAST.takeError());
884 CB(clangd::findType(InpAST->AST, Pos));
885 };
886 WorkScheduler->runWithAST("FindType", File, std::move(Action));
887}
888
890 PathRef File, Position Pos, Callback<std::vector<LocatedSymbol>> CB) {
891 auto Action = [Pos, CB = std::move(CB),
892 this](llvm::Expected<InputsAndAST> InpAST) mutable {
893 if (!InpAST)
894 return CB(InpAST.takeError());
895 CB(clangd::findImplementations(InpAST->AST, Pos, Index));
896 };
897
898 WorkScheduler->runWithAST("Implementations", File, std::move(Action));
899}
900
902 bool AddContainer,
904 auto Action = [Pos, Limit, AddContainer, CB = std::move(CB),
905 this](llvm::Expected<InputsAndAST> InpAST) mutable {
906 if (!InpAST)
907 return CB(InpAST.takeError());
908 CB(clangd::findReferences(InpAST->AST, Pos, Limit, Index, AddContainer));
909 };
910
911 WorkScheduler->runWithAST("References", File, std::move(Action));
912}
913
915 Callback<std::vector<SymbolDetails>> CB) {
916 auto Action =
917 [Pos, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST) mutable {
918 if (!InpAST)
919 return CB(InpAST.takeError());
920 CB(clangd::getSymbolInfo(InpAST->AST, Pos));
921 };
922
923 WorkScheduler->runWithAST("SymbolInfo", File, std::move(Action));
924}
925
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 {
931 if (!InpAST)
932 return CB(InpAST.takeError());
933 std::vector<SelectionRange> Result;
934 for (const auto &Pos : Positions) {
935 if (auto Range = clangd::getSemanticRanges(InpAST->AST, Pos))
936 Result.push_back(std::move(*Range));
937 else
938 return CB(Range.takeError());
939 }
940 CB(std::move(Result));
941 };
942 WorkScheduler->runWithAST("SemanticRanges", File, std::move(Action));
943}
944
946 Callback<std::vector<DocumentLink>> CB) {
947 auto Action =
948 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST) mutable {
949 if (!InpAST)
950 return CB(InpAST.takeError());
951 CB(clangd::getDocumentLinks(InpAST->AST));
952 };
953 WorkScheduler->runWithAST("DocumentLinks", File, std::move(Action),
954 Transient);
955}
956
958 PathRef File, Callback<std::vector<HighlightingToken>> CB) {
959 auto Action =
960 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST) mutable {
961 if (!InpAST)
962 return CB(InpAST.takeError());
963 CB(clangd::getSemanticHighlightings(InpAST->AST));
964 };
965 WorkScheduler->runWithAST("SemanticHighlights", File, std::move(Action),
966 Transient);
967}
968
969void ClangdServer::getAST(PathRef File, std::optional<Range> R,
970 Callback<std::optional<ASTNode>> CB) {
971 auto Action =
972 [R, CB(std::move(CB))](llvm::Expected<InputsAndAST> Inputs) mutable {
973 if (!Inputs)
974 return CB(Inputs.takeError());
975 if (!R) {
976 // It's safe to pass in the TU, as dumpAST() does not
977 // deserialize the preamble.
978 auto Node = DynTypedNode::create(
979 *Inputs->AST.getASTContext().getTranslationUnitDecl());
980 return CB(dumpAST(Node, Inputs->AST.getTokens(),
981 Inputs->AST.getASTContext()));
982 }
983 unsigned Start, End;
984 if (auto Offset = positionToOffset(Inputs->Inputs.Contents, R->start))
985 Start = *Offset;
986 else
987 return CB(Offset.takeError());
988 if (auto Offset = positionToOffset(Inputs->Inputs.Contents, R->end))
989 End = *Offset;
990 else
991 return CB(Offset.takeError());
992 bool Success = SelectionTree::createEach(
993 Inputs->AST.getASTContext(), Inputs->AST.getTokens(), Start, End,
994 [&](SelectionTree T) {
995 if (const SelectionTree::Node *N = T.commonAncestor()) {
996 CB(dumpAST(N->ASTNode, Inputs->AST.getTokens(),
997 Inputs->AST.getASTContext()));
998 return true;
999 }
1000 return false;
1001 });
1002 if (!Success)
1003 CB(std::nullopt);
1004 };
1005 WorkScheduler->runWithAST("GetAST", File, std::move(Action));
1006}
1007
1008void ClangdServer::customAction(PathRef File, llvm::StringRef Name,
1010 WorkScheduler->runWithAST(Name, File, std::move(Action));
1011}
1012
1013void ClangdServer::diagnostics(PathRef File, Callback<std::vector<Diag>> CB) {
1014 auto Action =
1015 [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST) mutable {
1016 if (!InpAST)
1017 return CB(InpAST.takeError());
1018 if (auto Diags = InpAST->AST.getDiagnostics())
1019 return CB(*Diags);
1020 // FIXME: Use ServerCancelled error once it is settled in LSP-3.17.
1021 return CB(llvm::make_error<LSPError>("server is busy parsing includes",
1022 ErrorCode::InternalError));
1023 };
1024
1025 WorkScheduler->runWithAST("Diagnostics", File, std::move(Action));
1026}
1027
1028llvm::StringMap<TUScheduler::FileStats> ClangdServer::fileStats() const {
1029 return WorkScheduler->fileStats();
1030}
1031
1032[[nodiscard]] bool
1033ClangdServer::blockUntilIdleForTest(std::optional<double> TimeoutSeconds) {
1034 // Order is important here: we don't want to block on A and then B,
1035 // if B might schedule work on A.
1036
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;
1041#endif
1042
1043 // Nothing else can schedule work on TUScheduler, because it's not threadsafe
1044 // and we're blocking the main thread.
1045 if (!WorkScheduler->blockUntilIdle(timeoutSeconds(TimeoutSeconds)))
1046 return false;
1047 // TUScheduler is the only thing that starts background indexing work.
1048 if (IndexTasks && !IndexTasks->wait(timeoutSeconds(TimeoutSeconds)))
1049 return false;
1050
1051 // Unfortunately we don't have strict topological order between the rest of
1052 // the components. E.g. CDB broadcast triggers backrgound indexing.
1053 // This queries the CDB which may discover new work if disk has changed.
1054 //
1055 // So try each one a few times in a loop.
1056 // If there are no tricky interactions then all after the first are no-ops.
1057 // Then on the last iteration, verify they're idle without waiting.
1058 //
1059 // There's a small chance they're juggling work and we didn't catch them :-(
1060 for (std::optional<double> Timeout :
1061 {TimeoutSeconds, TimeoutSeconds, std::optional<double>(0)}) {
1062 if (!CDB.blockUntilIdle(timeoutSeconds(Timeout)))
1063 return false;
1064 if (BackgroundIdx && !BackgroundIdx->blockUntilIdleForTest(Timeout))
1065 return false;
1066 if (FeatureModules && llvm::any_of(*FeatureModules, [&](FeatureModule &M) {
1067 return !M.blockUntilIdle(timeoutSeconds(Timeout));
1068 }))
1069 return false;
1070 }
1071
1072 assert(WorkScheduler->blockUntilIdle(Deadline::zero()) &&
1073 "Something scheduled work while we're blocking the main thread!");
1074 return true;
1075}
1076
1077void ClangdServer::profile(MemoryTree &MT) const {
1078 if (DynamicIdx)
1079 DynamicIdx->profile(MT.child("dynamic_index"));
1080 if (BackgroundIdx)
1081 BackgroundIdx->profile(MT.child("background_index"));
1082 WorkScheduler->profile(MT.child("tuscheduler"));
1083}
1084} // namespace clangd
1085} // namespace clang
const Expr * E
FeatureModuleSet FeatureModules
const ParseInputs & ParseInput
size_t Offset
std::vector< CodeCompletionResult > Results
std::string Code
const Criteria C
SourceLocation Loc
Token Name
FieldAction Action
size_t Pos
const google::protobuf::Message & M
Definition: Server.cpp:309
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.
Definition: ClangdServer.h:61
virtual void onDiagnosticsReady(PathRef File, llvm::StringRef Version, std::vector< Diag > Diagnostics)
Called by ClangdServer when Diagnostics for File are ready.
Definition: ClangdServer.h:69
virtual void onBackgroundIndexProgress(const BackgroundQueue::Stats &Stats)
Called when background indexing tasks are enqueued/started/completed.
Definition: ClangdServer.h:78
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 ...
Definition: Context.h:69
Context clone() const
Clone this context object.
Definition: Context.cpp:20
static const Context & current()
Returns the context for the current thread, creating it if needed.
Definition: Context.cpp:27
static Deadline infinity()
Definition: Threading.h:51
std::vector< Path > getActiveFiles() const
Definition: DraftStore.cpp:29
std::optional< Draft > getDraft(PathRef File) const
Definition: DraftStore.cpp:19
void removeDraft(PathRef File)
Remove the draft from the store.
Definition: DraftStore.cpp:86
std::string addDraft(PathRef File, llvm::StringRef Version, StringRef Contents)
Replace contents of the draft for File with Contents.
Definition: DraftStore.cpp:75
A FeatureModule contributes a vertical feature to clangd.
Definition: FeatureModule.h:56
This manages symbols from files and an in-memory index on all symbols.
Definition: FileIndex.h:109
Provides compilation arguments used for parsing C and C++ files.
PreambleThrottler controls which preambles can build at any given time.
Definition: TUScheduler.h:97
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
Definition: Selection.cpp:1048
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:113
Handles running tasks for ClangdServer and managing the resources (e.g., preambles and ASTs) for open...
Definition: TUScheduler.h:213
@ StaleOrAbsent
Besides accepting stale preamble, this also allow preamble to be absent (not ready or failed to build...
Definition: TUScheduler.h:321
@ Stale
The preamble may be generated from an older version of the file.
Definition: TUScheduler.h:318
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
Definition: ThreadsafeFS.h:26
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > view(std::nullopt_t CWD) const
Obtain a vfs::FileSystem with an arbitrary initial working directory.
Definition: ThreadsafeFS.h:32
An interface base for small context-sensitive refactoring actions.
Definition: Tweak.h:46
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.
Definition: Trace.h:143
@ Changed
The file got changed.
std::vector< TypeHierarchyItem > subTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct children of a TypeHierarchyItem.
Definition: XRefs.cpp:2133
std::optional< std::vector< TypeHierarchyItem > > superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct parents of a TypeHierarchyItem using SymbolIDs stored inside the item.
Definition: XRefs.cpp:2112
std::vector< LocatedSymbol > findType(ParsedAST &AST, Position Pos)
Returns symbols for types referenced at Pos.
Definition: XRefs.cpp:1995
std::vector< CallHierarchyIncomingCall > incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index)
Definition: XRefs.cpp:2179
llvm::Expected< std::unique_ptr< Tweak > > prepareTweak(StringRef ID, const Tweak::Selection &S, const FeatureModuleSet *Modules)
Definition: Tweak.cpp:91
ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens, const ASTContext &Ctx)
Definition: DumpAST.cpp:402
std::vector< DocumentHighlight > findDocumentHighlights(ParsedAST &AST, Position Pos)
Returns highlights for all usages of a symbol at Pos.
Definition: XRefs.cpp:1218
std::string Path
A typedef to represent a file path.
Definition: Path.h:26
format::FormatStyle getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content, const ThreadsafeFS &TFS)
Choose the clang-format style we should apply to a certain file.
Definition: SourceCode.cpp:581
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.
Definition: XRefs.cpp:826
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
Definition: XRefs.cpp:1527
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)
Definition: Logger.h:72
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.
Definition: Rename.cpp:733
std::vector< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
Definition: XRefs.cpp:2068
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
Definition: Logger.h:79
ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index, bool AddContext)
Returns references of the symbol at a specified Pos.
Definition: XRefs.cpp:1315
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:28
std::optional< HoverInfo > getHover(ParsedAST &AST, Position Pos, const format::FormatStyle &Style, const SymbolIndex *Index)
Get the hover information when hovering at Pos.
Definition: Hover.cpp:1139
std::vector< tooling::Replacement > formatIncremental(llvm::StringRef OriginalCode, unsigned OriginalCursor, llvm::StringRef InsertedText, format::FormatStyle Style)
Applies limited formatting around new InsertedText.
Definition: Format.cpp:277
std::vector< LocatedSymbol > locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index)
Get definition of symbol at a specified Pos.
Definition: XRefs.cpp:747
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.
Definition: SourceCode.cpp:172
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.
Definition: Tweak.cpp:72
WantDiagnostics
Determines whether diagnostics should be generated for a file snapshot.
Definition: TUScheduler.h:52
@ 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:
Definition: XRefs.cpp:1259
std::vector< InlayHint > inlayHints(ParsedAST &AST, std::optional< Range > RestrictRange)
Compute and return inlay hints for a file.
Definition: InlayHints.cpp:723
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)
Definition: XRefs.cpp:2142
Deadline timeoutSeconds(std::optional< double > Seconds)
Makes a deadline from a timeout in seconds. None means wait forever.
Definition: Threading.cpp:113
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.
Definition: Path.h:29
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)
Definition: Logger.h:61
std::vector< HighlightingToken > getSemanticHighlightings(ParsedAST &AST)
TextEdit replacementToEdit(llvm::StringRef Code, const tooling::Replacement &R)
Definition: SourceCode.cpp:499
SymbolSlab indexStandardLibrary(llvm::StringRef HeaderSources, std::unique_ptr< CompilerInvocation > CI, const StdLibLocation &Loc, const ThreadsafeFS &TFS)
Definition: StdLib.cpp:198
std::vector< CallHierarchyItem > prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath)
Get call hierarchy information at Pos.
Definition: XRefs.cpp:2157
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::function< Context(PathRef)> ContextProvider
Definition: Background.h:147
std::function< void(BackgroundQueue::Stats)> OnProgress
Definition: Background.h:143
Represents programming constructs like functions or constructors in the context of call hierarchy.
Definition: Protocol.h:1491
@ AlwaysParse
Block until we can run the parser (e.g.
Definition: CodeComplete.h:115
Settings that express user/project preferences and control clangd behavior.
Definition: Config.h:44
bool AllScopes
Whether code completion includes results that are not visible in current scopes.
Definition: Config.h:133
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
Definition: Config.cpp:17
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.
Definition: SourceCode.h:185
Shared server facilities needed by the module to get its work done.
Definition: FeatureModule.h:76
A tree that can be used to represent memory usage of nested components while preserving the hierarchy...
Definition: MemoryTree.h:30
MemoryTree & child(llvm::StringLiteral Name)
No copy of the Name.
Definition: MemoryTree.h:39
Information required to run clang, e.g. to parse AST or do code completion.
Definition: Compiler.h:48
The parsed preamble and associated data.
Definition: Preamble.h:51
PrecompiledPreamble Preamble
Definition: Preamble.h:57
Position start
The range's start position.
Definition: Protocol.h:187
Position end
The range's end position.
Definition: Protocol.h:190
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.
Definition: Trace.h:38
@ Counter
An aggregate number whose rate of change over time is meaningful.
Definition: Trace.h:46
@ Distribution
A distribution of values with a meaningful mean and count.
Definition: Trace.h:52
void record(double Value, llvm::StringRef Label="") const
Records a measurement for this metric to active tracer.
Definition: Trace.cpp:329