clang-tools  15.0.0git
ClangdLSPServer.cpp
Go to the documentation of this file.
1 //===--- ClangdLSPServer.cpp - LSP server ------------------------*- 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 "ClangdLSPServer.h"
10 #include "ClangdServer.h"
11 #include "CodeComplete.h"
12 #include "CompileCommands.h"
13 #include "Diagnostics.h"
14 #include "Feature.h"
16 #include "LSPBinder.h"
17 #include "Protocol.h"
18 #include "SemanticHighlighting.h"
19 #include "SourceCode.h"
20 #include "TUScheduler.h"
21 #include "URI.h"
22 #include "refactor/Tweak.h"
23 #include "support/Cancellation.h"
24 #include "support/Context.h"
25 #include "support/MemoryTree.h"
26 #include "support/Trace.h"
27 #include "clang/Tooling/Core/Replacement.h"
28 #include "llvm/ADT/ArrayRef.h"
29 #include "llvm/ADT/Optional.h"
30 #include "llvm/ADT/ScopeExit.h"
31 #include "llvm/ADT/StringRef.h"
32 #include "llvm/ADT/Twine.h"
33 #include "llvm/Support/Allocator.h"
34 #include "llvm/Support/Error.h"
35 #include "llvm/Support/FormatVariadic.h"
36 #include "llvm/Support/JSON.h"
37 #include "llvm/Support/SHA1.h"
38 #include "llvm/Support/ScopedPrinter.h"
39 #include "llvm/Support/raw_ostream.h"
40 #include <chrono>
41 #include <cstddef>
42 #include <cstdint>
43 #include <functional>
44 #include <memory>
45 #include <mutex>
46 #include <string>
47 #include <vector>
48 
49 namespace clang {
50 namespace clangd {
51 namespace {
52 // Tracks end-to-end latency of high level lsp calls. Measurements are in
53 // seconds.
54 constexpr trace::Metric LSPLatency("lsp_latency", trace::Metric::Distribution,
55  "method_name");
56 
57 // LSP defines file versions as numbers that increase.
58 // ClangdServer treats them as opaque and therefore uses strings instead.
59 std::string encodeVersion(llvm::Optional<int64_t> LSPVersion) {
60  return LSPVersion ? llvm::to_string(*LSPVersion) : "";
61 }
62 llvm::Optional<int64_t> decodeVersion(llvm::StringRef Encoded) {
63  int64_t Result;
64  if (llvm::to_integer(Encoded, Result, 10))
65  return Result;
66  if (!Encoded.empty()) // Empty can be e.g. diagnostics on close.
67  elog("unexpected non-numeric version {0}", Encoded);
68  return llvm::None;
69 }
70 
71 const llvm::StringLiteral ApplyFixCommand = "clangd.applyFix";
72 const llvm::StringLiteral ApplyTweakCommand = "clangd.applyTweak";
73 
74 /// Transforms a tweak into a code action that would apply it if executed.
75 /// EXPECTS: T.prepare() was called and returned true.
76 CodeAction toCodeAction(const ClangdServer::TweakRef &T, const URIForFile &File,
77  Range Selection) {
78  CodeAction CA;
79  CA.title = T.Title;
80  CA.kind = T.Kind.str();
81  // This tweak may have an expensive second stage, we only run it if the user
82  // actually chooses it in the UI. We reply with a command that would run the
83  // corresponding tweak.
84  // FIXME: for some tweaks, computing the edits is cheap and we could send them
85  // directly.
86  CA.command.emplace();
87  CA.command->title = T.Title;
88  CA.command->command = std::string(ApplyTweakCommand);
89  TweakArgs Args;
90  Args.file = File;
91  Args.tweakID = T.ID;
92  Args.selection = Selection;
93  CA.command->argument = std::move(Args);
94  return CA;
95 }
96 
97 void adjustSymbolKinds(llvm::MutableArrayRef<DocumentSymbol> Syms,
98  SymbolKindBitset Kinds) {
99  for (auto &S : Syms) {
100  S.kind = adjustKindToCapability(S.kind, Kinds);
101  adjustSymbolKinds(S.children, Kinds);
102  }
103 }
104 
105 SymbolKindBitset defaultSymbolKinds() {
107  for (size_t I = SymbolKindMin; I <= static_cast<size_t>(SymbolKind::Array);
108  ++I)
109  Defaults.set(I);
110  return Defaults;
111 }
112 
113 CompletionItemKindBitset defaultCompletionItemKinds() {
115  for (size_t I = CompletionItemKindMin;
116  I <= static_cast<size_t>(CompletionItemKind::Reference); ++I)
117  Defaults.set(I);
118  return Defaults;
119 }
120 
121 // Makes sure edits in \p FE are applicable to latest file contents reported by
122 // editor. If not generates an error message containing information about files
123 // that needs to be saved.
124 llvm::Error validateEdits(const ClangdServer &Server, const FileEdits &FE) {
125  size_t InvalidFileCount = 0;
126  llvm::StringRef LastInvalidFile;
127  for (const auto &It : FE) {
128  if (auto Draft = Server.getDraft(It.first())) {
129  // If the file is open in user's editor, make sure the version we
130  // saw and current version are compatible as this is the text that
131  // will be replaced by editors.
132  if (!It.second.canApplyTo(*Draft)) {
133  ++InvalidFileCount;
134  LastInvalidFile = It.first();
135  }
136  }
137  }
138  if (!InvalidFileCount)
139  return llvm::Error::success();
140  if (InvalidFileCount == 1)
141  return error("File must be saved first: {0}", LastInvalidFile);
142  return error("Files must be saved first: {0} (and {1} others)",
143  LastInvalidFile, InvalidFileCount - 1);
144 }
145 } // namespace
146 
147 // MessageHandler dispatches incoming LSP messages.
148 // It handles cross-cutting concerns:
149 // - serializes/deserializes protocol objects to JSON
150 // - logging of inbound messages
151 // - cancellation handling
152 // - basic call tracing
153 // MessageHandler ensures that initialize() is called before any other handler.
155 public:
156  MessageHandler(ClangdLSPServer &Server) : Server(Server) {}
157 
158  bool onNotify(llvm::StringRef Method, llvm::json::Value Params) override {
159  trace::Span Tracer(Method, LSPLatency);
160  SPAN_ATTACH(Tracer, "Params", Params);
161  WithContext HandlerContext(handlerContext());
162  log("<-- {0}", Method);
163  if (Method == "exit")
164  return false;
165  auto Handler = Server.Handlers.NotificationHandlers.find(Method);
166  if (Handler != Server.Handlers.NotificationHandlers.end()) {
167  Handler->second(std::move(Params));
168  Server.maybeExportMemoryProfile();
169  Server.maybeCleanupMemory();
170  } else if (!Server.Server) {
171  elog("Notification {0} before initialization", Method);
172  } else if (Method == "$/cancelRequest") {
173  onCancel(std::move(Params));
174  } else {
175  log("unhandled notification {0}", Method);
176  }
177  return true;
178  }
179 
180  bool onCall(llvm::StringRef Method, llvm::json::Value Params,
181  llvm::json::Value ID) override {
182  WithContext HandlerContext(handlerContext());
183  // Calls can be canceled by the client. Add cancellation context.
184  WithContext WithCancel(cancelableRequestContext(ID));
185  trace::Span Tracer(Method, LSPLatency);
186  SPAN_ATTACH(Tracer, "Params", Params);
187  ReplyOnce Reply(ID, Method, &Server, Tracer.Args);
188  log("<-- {0}({1})", Method, ID);
189  auto Handler = Server.Handlers.MethodHandlers.find(Method);
190  if (Handler != Server.Handlers.MethodHandlers.end()) {
191  Handler->second(std::move(Params), std::move(Reply));
192  } else if (!Server.Server) {
193  elog("Call {0} before initialization.", Method);
194  Reply(llvm::make_error<LSPError>("server not initialized",
196  } else {
197  Reply(llvm::make_error<LSPError>("method not found",
199  }
200  return true;
201  }
202 
204  llvm::Expected<llvm::json::Value> Result) override {
205  WithContext HandlerContext(handlerContext());
206 
207  Callback<llvm::json::Value> ReplyHandler = nullptr;
208  if (auto IntID = ID.getAsInteger()) {
209  std::lock_guard<std::mutex> Mutex(CallMutex);
210  // Find a corresponding callback for the request ID;
211  for (size_t Index = 0; Index < ReplyCallbacks.size(); ++Index) {
212  if (ReplyCallbacks[Index].first == *IntID) {
213  ReplyHandler = std::move(ReplyCallbacks[Index].second);
214  ReplyCallbacks.erase(ReplyCallbacks.begin() +
215  Index); // remove the entry
216  break;
217  }
218  }
219  }
220 
221  if (!ReplyHandler) {
222  // No callback being found, use a default log callback.
223  ReplyHandler = [&ID](llvm::Expected<llvm::json::Value> Result) {
224  elog("received a reply with ID {0}, but there was no such call", ID);
225  if (!Result)
226  llvm::consumeError(Result.takeError());
227  };
228  }
229 
230  // Log and run the reply handler.
231  if (Result) {
232  log("<-- reply({0})", ID);
233  ReplyHandler(std::move(Result));
234  } else {
235  auto Err = Result.takeError();
236  log("<-- reply({0}) error: {1}", ID, Err);
237  ReplyHandler(std::move(Err));
238  }
239  return true;
240  }
241 
242  // Bind a reply callback to a request. The callback will be invoked when
243  // clangd receives the reply from the LSP client.
244  // Return a call id of the request.
246  llvm::Optional<std::pair<int, Callback<llvm::json::Value>>> OldestCB;
247  int ID;
248  {
249  std::lock_guard<std::mutex> Mutex(CallMutex);
250  ID = NextCallID++;
251  ReplyCallbacks.emplace_back(ID, std::move(Reply));
252 
253  // If the queue overflows, we assume that the client didn't reply the
254  // oldest request, and run the corresponding callback which replies an
255  // error to the client.
256  if (ReplyCallbacks.size() > MaxReplayCallbacks) {
257  elog("more than {0} outstanding LSP calls, forgetting about {1}",
258  MaxReplayCallbacks, ReplyCallbacks.front().first);
259  OldestCB = std::move(ReplyCallbacks.front());
260  ReplyCallbacks.pop_front();
261  }
262  }
263  if (OldestCB)
264  OldestCB->second(
265  error("failed to receive a client reply for request ({0})",
266  OldestCB->first));
267  return ID;
268  }
269 
270 private:
271  // Function object to reply to an LSP call.
272  // Each instance must be called exactly once, otherwise:
273  // - the bug is logged, and (in debug mode) an assert will fire
274  // - if there was no reply, an error reply is sent
275  // - if there were multiple replies, only the first is sent
276  class ReplyOnce {
277  std::atomic<bool> Replied = {false};
278  std::chrono::steady_clock::time_point Start;
280  std::string Method;
281  ClangdLSPServer *Server; // Null when moved-from.
282  llvm::json::Object *TraceArgs;
283 
284  public:
285  ReplyOnce(const llvm::json::Value &ID, llvm::StringRef Method,
286  ClangdLSPServer *Server, llvm::json::Object *TraceArgs)
287  : Start(std::chrono::steady_clock::now()), ID(ID), Method(Method),
288  Server(Server), TraceArgs(TraceArgs) {
289  assert(Server);
290  }
291  ReplyOnce(ReplyOnce &&Other)
292  : Replied(Other.Replied.load()), Start(Other.Start),
293  ID(std::move(Other.ID)), Method(std::move(Other.Method)),
294  Server(Other.Server), TraceArgs(Other.TraceArgs) {
295  Other.Server = nullptr;
296  }
297  ReplyOnce &operator=(ReplyOnce &&) = delete;
298  ReplyOnce(const ReplyOnce &) = delete;
299  ReplyOnce &operator=(const ReplyOnce &) = delete;
300 
301  ~ReplyOnce() {
302  // There's one legitimate reason to never reply to a request: clangd's
303  // request handler send a call to the client (e.g. applyEdit) and the
304  // client never replied. In this case, the ReplyOnce is owned by
305  // ClangdLSPServer's reply callback table and is destroyed along with the
306  // server. We don't attempt to send a reply in this case, there's little
307  // to be gained from doing so.
308  if (Server && !Server->IsBeingDestroyed && !Replied) {
309  elog("No reply to message {0}({1})", Method, ID);
310  assert(false && "must reply to all calls!");
311  (*this)(llvm::make_error<LSPError>("server failed to reply",
313  }
314  }
315 
316  void operator()(llvm::Expected<llvm::json::Value> Reply) {
317  assert(Server && "moved-from!");
318  if (Replied.exchange(true)) {
319  elog("Replied twice to message {0}({1})", Method, ID);
320  assert(false && "must reply to each call only once!");
321  return;
322  }
323  auto Duration = std::chrono::steady_clock::now() - Start;
324  if (Reply) {
325  log("--> reply:{0}({1}) {2:ms}", Method, ID, Duration);
326  if (TraceArgs)
327  (*TraceArgs)["Reply"] = *Reply;
328  std::lock_guard<std::mutex> Lock(Server->TranspWriter);
329  Server->Transp.reply(std::move(ID), std::move(Reply));
330  } else {
331  llvm::Error Err = Reply.takeError();
332  log("--> reply:{0}({1}) {2:ms}, error: {3}", Method, ID, Duration, Err);
333  if (TraceArgs)
334  (*TraceArgs)["Error"] = llvm::to_string(Err);
335  std::lock_guard<std::mutex> Lock(Server->TranspWriter);
336  Server->Transp.reply(std::move(ID), std::move(Err));
337  }
338  }
339  };
340 
341  // Method calls may be cancelled by ID, so keep track of their state.
342  // This needs a mutex: handlers may finish on a different thread, and that's
343  // when we clean up entries in the map.
344  mutable std::mutex RequestCancelersMutex;
345  llvm::StringMap<std::pair<Canceler, /*Cookie*/ unsigned>> RequestCancelers;
346  unsigned NextRequestCookie = 0; // To disambiguate reused IDs, see below.
347  void onCancel(const llvm::json::Value &Params) {
348  const llvm::json::Value *ID = nullptr;
349  if (auto *O = Params.getAsObject())
350  ID = O->get("id");
351  if (!ID) {
352  elog("Bad cancellation request: {0}", Params);
353  return;
354  }
355  auto StrID = llvm::to_string(*ID);
356  std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
357  auto It = RequestCancelers.find(StrID);
358  if (It != RequestCancelers.end())
359  It->second.first(); // Invoke the canceler.
360  }
361 
362  Context handlerContext() const {
363  return Context::current().derive(
365  Server.Opts.Encoding.value_or(OffsetEncoding::UTF16));
366  }
367 
368  // We run cancelable requests in a context that does two things:
369  // - allows cancellation using RequestCancelers[ID]
370  // - cleans up the entry in RequestCancelers when it's no longer needed
371  // If a client reuses an ID, the last wins and the first cannot be canceled.
372  Context cancelableRequestContext(const llvm::json::Value &ID) {
373  auto Task = cancelableTask(
374  /*Reason=*/static_cast<int>(ErrorCode::RequestCancelled));
375  auto StrID = llvm::to_string(ID); // JSON-serialize ID for map key.
376  auto Cookie = NextRequestCookie++; // No lock, only called on main thread.
377  {
378  std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
379  RequestCancelers[StrID] = {std::move(Task.second), Cookie};
380  }
381  // When the request ends, we can clean up the entry we just added.
382  // The cookie lets us check that it hasn't been overwritten due to ID
383  // reuse.
384  return Task.first.derive(llvm::make_scope_exit([this, StrID, Cookie] {
385  std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
386  auto It = RequestCancelers.find(StrID);
387  if (It != RequestCancelers.end() && It->second.second == Cookie)
388  RequestCancelers.erase(It);
389  }));
390  }
391 
392  // The maximum number of callbacks held in clangd.
393  //
394  // We bound the maximum size to the pending map to prevent memory leakage
395  // for cases where LSP clients don't reply for the request.
396  // This has to go after RequestCancellers and RequestCancellersMutex since it
397  // can contain a callback that has a cancelable context.
398  static constexpr int MaxReplayCallbacks = 100;
399  mutable std::mutex CallMutex;
400  int NextCallID = 0; /* GUARDED_BY(CallMutex) */
401  std::deque<std::pair</*RequestID*/ int,
402  /*ReplyHandler*/ Callback<llvm::json::Value>>>
403  ReplyCallbacks; /* GUARDED_BY(CallMutex) */
404 
405  ClangdLSPServer &Server;
406 };
407 constexpr int ClangdLSPServer::MessageHandler::MaxReplayCallbacks;
408 
409 // call(), notify(), and reply() wrap the Transport, adding logging and locking.
410 void ClangdLSPServer::callMethod(StringRef Method, llvm::json::Value Params,
411  Callback<llvm::json::Value> CB) {
412  auto ID = MsgHandler->bindReply(std::move(CB));
413  log("--> {0}({1})", Method, ID);
414  std::lock_guard<std::mutex> Lock(TranspWriter);
415  Transp.call(Method, std::move(Params), ID);
416 }
417 
418 void ClangdLSPServer::notify(llvm::StringRef Method, llvm::json::Value Params) {
419  log("--> {0}", Method);
420  maybeCleanupMemory();
421  std::lock_guard<std::mutex> Lock(TranspWriter);
422  Transp.notify(Method, std::move(Params));
423 }
424 
425 static std::vector<llvm::StringRef> semanticTokenTypes() {
426  std::vector<llvm::StringRef> Types;
427  for (unsigned I = 0; I <= static_cast<unsigned>(HighlightingKind::LastKind);
428  ++I)
429  Types.push_back(toSemanticTokenType(static_cast<HighlightingKind>(I)));
430  return Types;
431 }
432 
433 static std::vector<llvm::StringRef> semanticTokenModifiers() {
434  std::vector<llvm::StringRef> Modifiers;
435  for (unsigned I = 0;
436  I <= static_cast<unsigned>(HighlightingModifier::LastModifier); ++I)
437  Modifiers.push_back(
439  return Modifiers;
440 }
441 
442 void ClangdLSPServer::onInitialize(const InitializeParams &Params,
443  Callback<llvm::json::Value> Reply) {
444  // Determine character encoding first as it affects constructed ClangdServer.
445  if (Params.capabilities.offsetEncoding && !Opts.Encoding) {
446  Opts.Encoding = OffsetEncoding::UTF16; // fallback
447  for (OffsetEncoding Supported : *Params.capabilities.offsetEncoding)
448  if (Supported != OffsetEncoding::UnsupportedEncoding) {
449  Opts.Encoding = Supported;
450  break;
451  }
452  }
453 
454  if (Params.capabilities.TheiaSemanticHighlighting &&
455  !Params.capabilities.SemanticTokens) {
456  elog("Client requested legacy semanticHighlights notification, which is "
457  "no longer supported. Migrate to standard semanticTokens request");
458  }
459 
460  if (Params.rootUri && *Params.rootUri)
461  Opts.WorkspaceRoot = std::string(Params.rootUri->file());
462  else if (Params.rootPath && !Params.rootPath->empty())
463  Opts.WorkspaceRoot = *Params.rootPath;
464  if (Server)
465  return Reply(llvm::make_error<LSPError>("server already initialized",
467  if (Opts.UseDirBasedCDB) {
468  DirectoryBasedGlobalCompilationDatabase::Options CDBOpts(TFS);
469  if (const auto &Dir = Params.initializationOptions.compilationDatabasePath)
470  CDBOpts.CompileCommandsDir = Dir;
471  CDBOpts.ContextProvider = Opts.ContextProvider;
472  BaseCDB =
473  std::make_unique<DirectoryBasedGlobalCompilationDatabase>(CDBOpts);
474  BaseCDB = getQueryDriverDatabase(llvm::makeArrayRef(Opts.QueryDriverGlobs),
475  std::move(BaseCDB));
476  }
477  auto Mangler = CommandMangler::detect();
478  if (Opts.ResourceDir)
479  Mangler.ResourceDir = *Opts.ResourceDir;
480  CDB.emplace(BaseCDB.get(), Params.initializationOptions.fallbackFlags,
481  tooling::ArgumentsAdjuster(std::move(Mangler)));
482  {
483  // Switch caller's context with LSPServer's background context. Since we
484  // rather want to propagate information from LSPServer's context into the
485  // Server, CDB, etc.
486  WithContext MainContext(BackgroundContext.clone());
487  llvm::Optional<WithContextValue> WithOffsetEncoding;
488  if (Opts.Encoding)
489  WithOffsetEncoding.emplace(kCurrentOffsetEncoding, *Opts.Encoding);
490  Server.emplace(*CDB, TFS, Opts,
491  static_cast<ClangdServer::Callbacks *>(this));
492  }
493 
494  Opts.CodeComplete.EnableSnippets = Params.capabilities.CompletionSnippets;
495  Opts.CodeComplete.IncludeFixIts = Params.capabilities.CompletionFixes;
496  if (!Opts.CodeComplete.BundleOverloads)
497  Opts.CodeComplete.BundleOverloads = Params.capabilities.HasSignatureHelp;
499  Params.capabilities.CompletionDocumentationFormat;
501  Params.capabilities.SignatureHelpDocumentationFormat;
502  DiagOpts.EmbedFixesInDiagnostics = Params.capabilities.DiagnosticFixes;
503  DiagOpts.SendDiagnosticCategory = Params.capabilities.DiagnosticCategory;
504  DiagOpts.EmitRelatedLocations =
505  Params.capabilities.DiagnosticRelatedInformation;
506  if (Params.capabilities.WorkspaceSymbolKinds)
507  SupportedSymbolKinds |= *Params.capabilities.WorkspaceSymbolKinds;
508  if (Params.capabilities.CompletionItemKinds)
509  SupportedCompletionItemKinds |= *Params.capabilities.CompletionItemKinds;
510  SupportsCodeAction = Params.capabilities.CodeActionStructure;
511  SupportsHierarchicalDocumentSymbol =
512  Params.capabilities.HierarchicalDocumentSymbol;
513  SupportFileStatus = Params.initializationOptions.FileStatus;
514  HoverContentFormat = Params.capabilities.HoverContentFormat;
515  SupportsOffsetsInSignatureHelp = Params.capabilities.OffsetsInSignatureHelp;
516  if (Params.capabilities.WorkDoneProgress)
517  BackgroundIndexProgressState = BackgroundIndexProgress::Empty;
518  BackgroundIndexSkipCreate = Params.capabilities.ImplicitProgressCreation;
519  Opts.ImplicitCancellation = !Params.capabilities.CancelsStaleRequests;
520 
521  llvm::json::Object ServerCaps{
522  {"textDocumentSync",
523  llvm::json::Object{
524  {"openClose", true},
525  {"change", (int)TextDocumentSyncKind::Incremental},
526  {"save", true},
527  }},
528  {"documentFormattingProvider", true},
529  {"documentRangeFormattingProvider", true},
530  {"documentOnTypeFormattingProvider",
531  llvm::json::Object{
532  {"firstTriggerCharacter", "\n"},
533  {"moreTriggerCharacter", {}},
534  }},
535  {"completionProvider",
536  llvm::json::Object{
537  {"allCommitCharacters",
538  {" ", "\t", "(", ")", "[", "]", "{", "}", "<",
539  ">", ":", ";", ",", "+", "-", "/", "*", "%",
540  "^", "&", "#", "?", ".", "=", "\"", "'", "|"}},
541  {"resolveProvider", false},
542  // We do extra checks, e.g. that > is part of ->.
543  {"triggerCharacters", {".", "<", ">", ":", "\"", "/", "*"}},
544  }},
545  {"semanticTokensProvider",
546  llvm::json::Object{
547  {"full", llvm::json::Object{{"delta", true}}},
548  {"range", false},
549  {"legend",
550  llvm::json::Object{{"tokenTypes", semanticTokenTypes()},
551  {"tokenModifiers", semanticTokenModifiers()}}},
552  }},
553  {"signatureHelpProvider",
554  llvm::json::Object{
555  {"triggerCharacters", {"(", ")", "{", "}", "<", ">", ","}},
556  }},
557  {"declarationProvider", true},
558  {"definitionProvider", true},
559  {"implementationProvider", true},
560  {"typeDefinitionProvider", true},
561  {"documentHighlightProvider", true},
562  {"documentLinkProvider",
563  llvm::json::Object{
564  {"resolveProvider", false},
565  }},
566  {"hoverProvider", true},
567  {"selectionRangeProvider", true},
568  {"documentSymbolProvider", true},
569  {"workspaceSymbolProvider", true},
570  {"referencesProvider", true},
571  {"astProvider", true}, // clangd extension
572  {"typeHierarchyProvider", true},
573  {"memoryUsageProvider", true}, // clangd extension
574  {"compilationDatabase", // clangd extension
575  llvm::json::Object{{"automaticReload", true}}},
576  {"callHierarchyProvider", true},
577  {"clangdInlayHintsProvider", true},
578  {"inlayHintProvider", true},
579  };
580 
581  {
582  LSPBinder Binder(Handlers, *this);
583  bindMethods(Binder, Params.capabilities);
584  if (Opts.FeatureModules)
585  for (auto &Mod : *Opts.FeatureModules)
586  Mod.initializeLSP(Binder, Params.rawCapabilities, ServerCaps);
587  }
588 
589  // Per LSP, renameProvider can be either boolean or RenameOptions.
590  // RenameOptions will be specified if the client states it supports prepare.
591  ServerCaps["renameProvider"] =
592  Params.capabilities.RenamePrepareSupport
593  ? llvm::json::Object{{"prepareProvider", true}}
594  : llvm::json::Value(true);
595 
596  // Per LSP, codeActionProvider can be either boolean or CodeActionOptions.
597  // CodeActionOptions is only valid if the client supports action literal
598  // via textDocument.codeAction.codeActionLiteralSupport.
599  llvm::json::Value CodeActionProvider = true;
600  ServerCaps["codeActionProvider"] =
601  Params.capabilities.CodeActionStructure
602  ? llvm::json::Object{{"codeActionKinds",
606  : llvm::json::Value(true);
607 
608  if (Opts.FoldingRanges)
609  ServerCaps["foldingRangeProvider"] = true;
610 
611  std::vector<llvm::StringRef> Commands;
612  for (llvm::StringRef Command : Handlers.CommandHandlers.keys())
613  Commands.push_back(Command);
614  llvm::sort(Commands);
615  ServerCaps["executeCommandProvider"] =
616  llvm::json::Object{{"commands", Commands}};
617 
618  llvm::json::Object Result{
619  {{"serverInfo",
620  llvm::json::Object{
621  {"name", "clangd"},
622  {"version", llvm::formatv("{0} {1} {2}", versionString(),
623  featureString(), platformString())}}},
624  {"capabilities", std::move(ServerCaps)}}};
625  if (Opts.Encoding)
626  Result["offsetEncoding"] = *Opts.Encoding;
627  Reply(std::move(Result));
628 
629  // Apply settings after we're fully initialized.
630  // This can start background indexing and in turn trigger LSP notifications.
631  applyConfiguration(Params.initializationOptions.ConfigSettings);
632 }
633 
634 void ClangdLSPServer::onInitialized(const InitializedParams &Params) {}
635 
636 void ClangdLSPServer::onShutdown(const NoParams &,
637  Callback<std::nullptr_t> Reply) {
638  // Do essentially nothing, just say we're ready to exit.
639  ShutdownRequestReceived = true;
640  Reply(nullptr);
641 }
642 
643 // sync is a clangd extension: it blocks until all background work completes.
644 // It blocks the calling thread, so no messages are processed until it returns!
645 void ClangdLSPServer::onSync(const NoParams &, Callback<std::nullptr_t> Reply) {
646  if (Server->blockUntilIdleForTest(/*TimeoutSeconds=*/60))
647  Reply(nullptr);
648  else
649  Reply(error("Not idle after a minute"));
650 }
651 
652 void ClangdLSPServer::onDocumentDidOpen(
653  const DidOpenTextDocumentParams &Params) {
654  PathRef File = Params.textDocument.uri.file();
655 
656  const std::string &Contents = Params.textDocument.text;
657 
658  Server->addDocument(File, Contents,
659  encodeVersion(Params.textDocument.version),
661 }
662 
663 void ClangdLSPServer::onDocumentDidChange(
664  const DidChangeTextDocumentParams &Params) {
666  if (Params.wantDiagnostics)
667  WantDiags = Params.wantDiagnostics.getValue() ? WantDiagnostics::Yes
669 
670  PathRef File = Params.textDocument.uri.file();
671  auto Code = Server->getDraft(File);
672  if (!Code) {
673  log("Trying to incrementally change non-added document: {0}", File);
674  return;
675  }
676  std::string NewCode(*Code);
677  for (const auto &Change : Params.contentChanges) {
678  if (auto Err = applyChange(NewCode, Change)) {
679  // If this fails, we are most likely going to be not in sync anymore with
680  // the client. It is better to remove the draft and let further
681  // operations fail rather than giving wrong results.
682  Server->removeDocument(File);
683  elog("Failed to update {0}: {1}", File, std::move(Err));
684  return;
685  }
686  }
687  Server->addDocument(File, NewCode, encodeVersion(Params.textDocument.version),
688  WantDiags, Params.forceRebuild);
689 }
690 
691 void ClangdLSPServer::onDocumentDidSave(
692  const DidSaveTextDocumentParams &Params) {
693  Server->reparseOpenFilesIfNeeded([](llvm::StringRef) { return true; });
694 }
695 
696 void ClangdLSPServer::onFileEvent(const DidChangeWatchedFilesParams &Params) {
697  // We could also reparse all open files here. However:
698  // - this could be frequent, and revalidating all the preambles isn't free
699  // - this is useful e.g. when switching git branches, but we're likely to see
700  // fresh headers but still have the old-branch main-file content
701  Server->onFileEvent(Params);
702  // FIXME: observe config files, immediately expire time-based caches, reparse:
703  // - compile_commands.json and compile_flags.txt
704  // - .clang_format and .clang-tidy
705  // - .clangd and clangd/config.yaml
706 }
707 
708 void ClangdLSPServer::onCommand(const ExecuteCommandParams &Params,
709  Callback<llvm::json::Value> Reply) {
710  auto It = Handlers.CommandHandlers.find(Params.command);
711  if (It == Handlers.CommandHandlers.end()) {
712  return Reply(llvm::make_error<LSPError>(
713  llvm::formatv("Unsupported command \"{0}\".", Params.command).str(),
715  }
716  It->second(Params.argument, std::move(Reply));
717 }
718 
719 void ClangdLSPServer::onCommandApplyEdit(const WorkspaceEdit &WE,
720  Callback<llvm::json::Value> Reply) {
721  // The flow for "apply-fix" :
722  // 1. We publish a diagnostic, including fixits
723  // 2. The user clicks on the diagnostic, the editor asks us for code actions
724  // 3. We send code actions, with the fixit embedded as context
725  // 4. The user selects the fixit, the editor asks us to apply it
726  // 5. We unwrap the changes and send them back to the editor
727  // 6. The editor applies the changes (applyEdit), and sends us a reply
728  // 7. We unwrap the reply and send a reply to the editor.
729  applyEdit(WE, "Fix applied.", std::move(Reply));
730 }
731 
732 void ClangdLSPServer::onCommandApplyTweak(const TweakArgs &Args,
733  Callback<llvm::json::Value> Reply) {
734  auto Action = [this, Reply = std::move(Reply)](
735  llvm::Expected<Tweak::Effect> R) mutable {
736  if (!R)
737  return Reply(R.takeError());
738 
739  assert(R->ShowMessage || (!R->ApplyEdits.empty() && "tweak has no effect"));
740 
741  if (R->ShowMessage) {
742  ShowMessageParams Msg;
743  Msg.message = *R->ShowMessage;
744  Msg.type = MessageType::Info;
745  ShowMessage(Msg);
746  }
747  // When no edit is specified, make sure we Reply().
748  if (R->ApplyEdits.empty())
749  return Reply("Tweak applied.");
750 
751  if (auto Err = validateEdits(*Server, R->ApplyEdits))
752  return Reply(std::move(Err));
753 
754  WorkspaceEdit WE;
755  for (const auto &It : R->ApplyEdits) {
756  WE.changes[URI::createFile(It.first()).toString()] =
757  It.second.asTextEdits();
758  }
759  // ApplyEdit will take care of calling Reply().
760  return applyEdit(std::move(WE), "Tweak applied.", std::move(Reply));
761  };
762  Server->applyTweak(Args.file.file(), Args.selection, Args.tweakID,
763  std::move(Action));
764 }
765 
766 void ClangdLSPServer::applyEdit(WorkspaceEdit WE, llvm::json::Value Success,
767  Callback<llvm::json::Value> Reply) {
768  ApplyWorkspaceEditParams Edit;
769  Edit.edit = std::move(WE);
770  ApplyWorkspaceEdit(
771  Edit, [Reply = std::move(Reply), SuccessMessage = std::move(Success)](
772  llvm::Expected<ApplyWorkspaceEditResponse> Response) mutable {
773  if (!Response)
774  return Reply(Response.takeError());
775  if (!Response->applied) {
776  std::string Reason = Response->failureReason
777  ? *Response->failureReason
778  : "unknown reason";
779  return Reply(error("edits were not applied: {0}", Reason));
780  }
781  return Reply(SuccessMessage);
782  });
783 }
784 
785 void ClangdLSPServer::onWorkspaceSymbol(
786  const WorkspaceSymbolParams &Params,
787  Callback<std::vector<SymbolInformation>> Reply) {
788  Server->workspaceSymbols(
789  Params.query, Params.limit.value_or(Opts.CodeComplete.Limit),
790  [Reply = std::move(Reply),
791  this](llvm::Expected<std::vector<SymbolInformation>> Items) mutable {
792  if (!Items)
793  return Reply(Items.takeError());
794  for (auto &Sym : *Items)
795  Sym.kind = adjustKindToCapability(Sym.kind, SupportedSymbolKinds);
796 
797  Reply(std::move(*Items));
798  });
799 }
800 
801 void ClangdLSPServer::onPrepareRename(const TextDocumentPositionParams &Params,
802  Callback<llvm::Optional<Range>> Reply) {
803  Server->prepareRename(
804  Params.textDocument.uri.file(), Params.position, /*NewName*/ llvm::None,
805  Opts.Rename,
806  [Reply = std::move(Reply)](llvm::Expected<RenameResult> Result) mutable {
807  if (!Result)
808  return Reply(Result.takeError());
809  return Reply(std::move(Result->Target));
810  });
811 }
812 
813 void ClangdLSPServer::onRename(const RenameParams &Params,
814  Callback<WorkspaceEdit> Reply) {
815  Path File = std::string(Params.textDocument.uri.file());
816  if (!Server->getDraft(File))
817  return Reply(llvm::make_error<LSPError>(
818  "onRename called for non-added file", ErrorCode::InvalidParams));
819  Server->rename(File, Params.position, Params.newName, Opts.Rename,
820  [File, Params, Reply = std::move(Reply),
821  this](llvm::Expected<RenameResult> R) mutable {
822  if (!R)
823  return Reply(R.takeError());
824  if (auto Err = validateEdits(*Server, R->GlobalChanges))
825  return Reply(std::move(Err));
826  WorkspaceEdit Result;
827  for (const auto &Rep : R->GlobalChanges) {
828  Result.changes[URI::createFile(Rep.first()).toString()] =
829  Rep.second.asTextEdits();
830  }
831  Reply(Result);
832  });
833 }
834 
835 void ClangdLSPServer::onDocumentDidClose(
836  const DidCloseTextDocumentParams &Params) {
837  PathRef File = Params.textDocument.uri.file();
838  Server->removeDocument(File);
839 
840  {
841  std::lock_guard<std::mutex> Lock(FixItsMutex);
842  FixItsMap.erase(File);
843  }
844  {
845  std::lock_guard<std::mutex> HLock(SemanticTokensMutex);
846  LastSemanticTokens.erase(File);
847  }
848  // clangd will not send updates for this file anymore, so we empty out the
849  // list of diagnostics shown on the client (e.g. in the "Problems" pane of
850  // VSCode). Note that this cannot race with actual diagnostics responses
851  // because removeDocument() guarantees no diagnostic callbacks will be
852  // executed after it returns.
853  PublishDiagnosticsParams Notification;
854  Notification.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
855  PublishDiagnostics(Notification);
856 }
857 
858 void ClangdLSPServer::onDocumentOnTypeFormatting(
859  const DocumentOnTypeFormattingParams &Params,
860  Callback<std::vector<TextEdit>> Reply) {
861  auto File = Params.textDocument.uri.file();
862  Server->formatOnType(File, Params.position, Params.ch, std::move(Reply));
863 }
864 
865 void ClangdLSPServer::onDocumentRangeFormatting(
866  const DocumentRangeFormattingParams &Params,
867  Callback<std::vector<TextEdit>> Reply) {
868  auto File = Params.textDocument.uri.file();
869  auto Code = Server->getDraft(File);
870  Server->formatFile(File, Params.range,
871  [Code = std::move(Code), Reply = std::move(Reply)](
872  llvm::Expected<tooling::Replacements> Result) mutable {
873  if (Result)
874  Reply(replacementsToEdits(*Code, Result.get()));
875  else
876  Reply(Result.takeError());
877  });
878 }
879 
880 void ClangdLSPServer::onDocumentFormatting(
881  const DocumentFormattingParams &Params,
882  Callback<std::vector<TextEdit>> Reply) {
883  auto File = Params.textDocument.uri.file();
884  auto Code = Server->getDraft(File);
885  Server->formatFile(File,
886  /*Rng=*/llvm::None,
887  [Code = std::move(Code), Reply = std::move(Reply)](
888  llvm::Expected<tooling::Replacements> Result) mutable {
889  if (Result)
890  Reply(replacementsToEdits(*Code, Result.get()));
891  else
892  Reply(Result.takeError());
893  });
894 }
895 
896 /// The functions constructs a flattened view of the DocumentSymbol hierarchy.
897 /// Used by the clients that do not support the hierarchical view.
898 static std::vector<SymbolInformation>
899 flattenSymbolHierarchy(llvm::ArrayRef<DocumentSymbol> Symbols,
900  const URIForFile &FileURI) {
901  std::vector<SymbolInformation> Results;
902  std::function<void(const DocumentSymbol &, llvm::StringRef)> Process =
903  [&](const DocumentSymbol &S, llvm::Optional<llvm::StringRef> ParentName) {
905  SI.containerName = std::string(ParentName ? "" : *ParentName);
906  SI.name = S.name;
907  SI.kind = S.kind;
908  SI.location.range = S.range;
909  SI.location.uri = FileURI;
910 
911  Results.push_back(std::move(SI));
912  std::string FullName =
913  !ParentName ? S.name : (ParentName->str() + "::" + S.name);
914  for (auto &C : S.children)
915  Process(C, /*ParentName=*/FullName);
916  };
917  for (auto &S : Symbols)
918  Process(S, /*ParentName=*/"");
919  return Results;
920 }
921 
922 void ClangdLSPServer::onDocumentSymbol(const DocumentSymbolParams &Params,
923  Callback<llvm::json::Value> Reply) {
924  URIForFile FileURI = Params.textDocument.uri;
925  Server->documentSymbols(
926  Params.textDocument.uri.file(),
927  [this, FileURI, Reply = std::move(Reply)](
928  llvm::Expected<std::vector<DocumentSymbol>> Items) mutable {
929  if (!Items)
930  return Reply(Items.takeError());
931  adjustSymbolKinds(*Items, SupportedSymbolKinds);
932  if (SupportsHierarchicalDocumentSymbol)
933  return Reply(std::move(*Items));
934  return Reply(flattenSymbolHierarchy(*Items, FileURI));
935  });
936 }
937 
938 void ClangdLSPServer::onFoldingRange(
939  const FoldingRangeParams &Params,
940  Callback<std::vector<FoldingRange>> Reply) {
941  Server->foldingRanges(Params.textDocument.uri.file(), std::move(Reply));
942 }
943 
944 static llvm::Optional<Command> asCommand(const CodeAction &Action) {
945  Command Cmd;
946  if (Action.command && Action.edit)
947  return None; // Not representable. (We never emit these anyway).
948  if (Action.command) {
949  Cmd = *Action.command;
950  } else if (Action.edit) {
951  Cmd.command = std::string(ApplyFixCommand);
952  Cmd.argument = *Action.edit;
953  } else {
954  return None;
955  }
956  Cmd.title = Action.title;
957  if (Action.kind && *Action.kind == CodeAction::QUICKFIX_KIND)
958  Cmd.title = "Apply fix: " + Cmd.title;
959  return Cmd;
960 }
961 
962 void ClangdLSPServer::onCodeAction(const CodeActionParams &Params,
963  Callback<llvm::json::Value> Reply) {
964  URIForFile File = Params.textDocument.uri;
965  // Checks whether a particular CodeActionKind is included in the response.
966  auto KindAllowed = [Only(Params.context.only)](llvm::StringRef Kind) {
967  if (Only.empty())
968  return true;
969  return llvm::any_of(Only, [&](llvm::StringRef Base) {
970  return Kind.consume_front(Base) && (Kind.empty() || Kind.startswith("."));
971  });
972  };
973 
974  // We provide a code action for Fixes on the specified diagnostics.
975  std::vector<CodeAction> FixIts;
976  if (KindAllowed(CodeAction::QUICKFIX_KIND)) {
977  for (const Diagnostic &D : Params.context.diagnostics) {
978  for (auto &F : getFixes(File.file(), D)) {
979  FixIts.push_back(toCodeAction(F, Params.textDocument.uri));
980  FixIts.back().diagnostics = {D};
981  }
982  }
983  }
984 
985  // Now enumerate the semantic code actions.
986  auto ConsumeActions =
987  [Diags = Params.context.diagnostics, Reply = std::move(Reply), File,
988  Selection = Params.range, FixIts = std::move(FixIts), this](
989  llvm::Expected<std::vector<ClangdServer::TweakRef>> Tweaks) mutable {
990  if (!Tweaks)
991  return Reply(Tweaks.takeError());
992 
993  std::vector<CodeAction> Actions = std::move(FixIts);
994  Actions.reserve(Actions.size() + Tweaks->size());
995  for (const auto &T : *Tweaks)
996  Actions.push_back(toCodeAction(T, File, Selection));
997 
998  // If there's exactly one quick-fix, call it "preferred".
999  // We never consider refactorings etc as preferred.
1000  CodeAction *OnlyFix = nullptr;
1001  for (auto &Action : Actions) {
1002  if (Action.kind && *Action.kind == CodeAction::QUICKFIX_KIND) {
1003  if (OnlyFix) {
1004  OnlyFix = nullptr;
1005  break;
1006  }
1007  OnlyFix = &Action;
1008  }
1009  }
1010  if (OnlyFix) {
1011  OnlyFix->isPreferred = true;
1012  if (Diags.size() == 1 && Diags.front().range == Selection)
1013  OnlyFix->diagnostics = {Diags.front()};
1014  }
1015 
1016  if (SupportsCodeAction)
1017  return Reply(llvm::json::Array(Actions));
1018  std::vector<Command> Commands;
1019  for (const auto &Action : Actions) {
1020  if (auto Command = asCommand(Action))
1021  Commands.push_back(std::move(*Command));
1022  }
1023  return Reply(llvm::json::Array(Commands));
1024  };
1025  Server->enumerateTweaks(
1026  File.file(), Params.range,
1027  [this, KindAllowed(std::move(KindAllowed))](const Tweak &T) {
1028  return Opts.TweakFilter(T) && KindAllowed(T.kind());
1029  },
1030  std::move(ConsumeActions));
1031 }
1032 
1033 void ClangdLSPServer::onCompletion(const CompletionParams &Params,
1034  Callback<CompletionList> Reply) {
1035  if (!shouldRunCompletion(Params)) {
1036  // Clients sometimes auto-trigger completions in undesired places (e.g.
1037  // 'a >^ '), we return empty results in those cases.
1038  vlog("ignored auto-triggered completion, preceding char did not match");
1039  return Reply(CompletionList());
1040  }
1041  auto Opts = this->Opts.CodeComplete;
1042  if (Params.limit && *Params.limit >= 0)
1043  Opts.Limit = *Params.limit;
1044  Server->codeComplete(Params.textDocument.uri.file(), Params.position, Opts,
1045  [Reply = std::move(Reply), Opts,
1046  this](llvm::Expected<CodeCompleteResult> List) mutable {
1047  if (!List)
1048  return Reply(List.takeError());
1049  CompletionList LSPList;
1050  LSPList.isIncomplete = List->HasMore;
1051  for (const auto &R : List->Completions) {
1052  CompletionItem C = R.render(Opts);
1053  C.kind = adjustKindToCapability(
1054  C.kind, SupportedCompletionItemKinds);
1055  LSPList.items.push_back(std::move(C));
1056  }
1057  return Reply(std::move(LSPList));
1058  });
1059 }
1060 
1061 void ClangdLSPServer::onSignatureHelp(const TextDocumentPositionParams &Params,
1062  Callback<SignatureHelp> Reply) {
1063  Server->signatureHelp(Params.textDocument.uri.file(), Params.position,
1064  Opts.SignatureHelpDocumentationFormat,
1065  [Reply = std::move(Reply), this](
1066  llvm::Expected<SignatureHelp> Signature) mutable {
1067  if (!Signature)
1068  return Reply(Signature.takeError());
1069  if (SupportsOffsetsInSignatureHelp)
1070  return Reply(std::move(*Signature));
1071  // Strip out the offsets from signature help for
1072  // clients that only support string labels.
1073  for (auto &SigInfo : Signature->signatures) {
1074  for (auto &Param : SigInfo.parameters)
1075  Param.labelOffsets.reset();
1076  }
1077  return Reply(std::move(*Signature));
1078  });
1079 }
1080 
1081 // Go to definition has a toggle function: if def and decl are distinct, then
1082 // the first press gives you the def, the second gives you the matching def.
1083 // getToggle() returns the counterpart location that under the cursor.
1084 //
1085 // We return the toggled location alone (ignoring other symbols) to encourage
1086 // editors to "bounce" quickly between locations, without showing a menu.
1088  LocatedSymbol &Sym) {
1089  // Toggle only makes sense with two distinct locations.
1090  if (!Sym.Definition || *Sym.Definition == Sym.PreferredDeclaration)
1091  return nullptr;
1092  if (Sym.Definition->uri.file() == Point.textDocument.uri.file() &&
1093  Sym.Definition->range.contains(Point.position))
1094  return &Sym.PreferredDeclaration;
1095  if (Sym.PreferredDeclaration.uri.file() == Point.textDocument.uri.file() &&
1097  return &*Sym.Definition;
1098  return nullptr;
1099 }
1100 
1101 void ClangdLSPServer::onGoToDefinition(const TextDocumentPositionParams &Params,
1102  Callback<std::vector<Location>> Reply) {
1103  Server->locateSymbolAt(
1104  Params.textDocument.uri.file(), Params.position,
1105  [Params, Reply = std::move(Reply)](
1106  llvm::Expected<std::vector<LocatedSymbol>> Symbols) mutable {
1107  if (!Symbols)
1108  return Reply(Symbols.takeError());
1109  std::vector<Location> Defs;
1110  for (auto &S : *Symbols) {
1111  if (Location *Toggle = getToggle(Params, S))
1112  return Reply(std::vector<Location>{std::move(*Toggle)});
1113  Defs.push_back(S.Definition.value_or(S.PreferredDeclaration));
1114  }
1115  Reply(std::move(Defs));
1116  });
1117 }
1118 
1119 void ClangdLSPServer::onGoToDeclaration(
1120  const TextDocumentPositionParams &Params,
1121  Callback<std::vector<Location>> Reply) {
1122  Server->locateSymbolAt(
1123  Params.textDocument.uri.file(), Params.position,
1124  [Params, Reply = std::move(Reply)](
1125  llvm::Expected<std::vector<LocatedSymbol>> Symbols) mutable {
1126  if (!Symbols)
1127  return Reply(Symbols.takeError());
1128  std::vector<Location> Decls;
1129  for (auto &S : *Symbols) {
1130  if (Location *Toggle = getToggle(Params, S))
1131  return Reply(std::vector<Location>{std::move(*Toggle)});
1132  Decls.push_back(std::move(S.PreferredDeclaration));
1133  }
1134  Reply(std::move(Decls));
1135  });
1136 }
1137 
1138 void ClangdLSPServer::onSwitchSourceHeader(
1139  const TextDocumentIdentifier &Params,
1140  Callback<llvm::Optional<URIForFile>> Reply) {
1141  Server->switchSourceHeader(
1142  Params.uri.file(),
1143  [Reply = std::move(Reply),
1144  Params](llvm::Expected<llvm::Optional<clangd::Path>> Path) mutable {
1145  if (!Path)
1146  return Reply(Path.takeError());
1147  if (*Path)
1148  return Reply(URIForFile::canonicalize(**Path, Params.uri.file()));
1149  return Reply(llvm::None);
1150  });
1151 }
1152 
1153 void ClangdLSPServer::onDocumentHighlight(
1154  const TextDocumentPositionParams &Params,
1155  Callback<std::vector<DocumentHighlight>> Reply) {
1156  Server->findDocumentHighlights(Params.textDocument.uri.file(),
1157  Params.position, std::move(Reply));
1158 }
1159 
1160 void ClangdLSPServer::onHover(const TextDocumentPositionParams &Params,
1161  Callback<llvm::Optional<Hover>> Reply) {
1162  Server->findHover(Params.textDocument.uri.file(), Params.position,
1163  [Reply = std::move(Reply), this](
1164  llvm::Expected<llvm::Optional<HoverInfo>> H) mutable {
1165  if (!H)
1166  return Reply(H.takeError());
1167  if (!*H)
1168  return Reply(llvm::None);
1169 
1170  Hover R;
1171  R.contents.kind = HoverContentFormat;
1172  R.range = (*H)->SymRange;
1173  switch (HoverContentFormat) {
1174  case MarkupKind::PlainText:
1175  R.contents.value = (*H)->present().asPlainText();
1176  return Reply(std::move(R));
1177  case MarkupKind::Markdown:
1178  R.contents.value = (*H)->present().asMarkdown();
1179  return Reply(std::move(R));
1180  };
1181  llvm_unreachable("unhandled MarkupKind");
1182  });
1183 }
1184 
1185 void ClangdLSPServer::onTypeHierarchy(
1186  const TypeHierarchyParams &Params,
1187  Callback<Optional<TypeHierarchyItem>> Reply) {
1188  Server->typeHierarchy(Params.textDocument.uri.file(), Params.position,
1189  Params.resolve, Params.direction, std::move(Reply));
1190 }
1191 
1192 void ClangdLSPServer::onResolveTypeHierarchy(
1193  const ResolveTypeHierarchyItemParams &Params,
1194  Callback<Optional<TypeHierarchyItem>> Reply) {
1195  Server->resolveTypeHierarchy(Params.item, Params.resolve, Params.direction,
1196  std::move(Reply));
1197 }
1198 
1199 void ClangdLSPServer::onPrepareCallHierarchy(
1200  const CallHierarchyPrepareParams &Params,
1201  Callback<std::vector<CallHierarchyItem>> Reply) {
1202  Server->prepareCallHierarchy(Params.textDocument.uri.file(), Params.position,
1203  std::move(Reply));
1204 }
1205 
1206 void ClangdLSPServer::onCallHierarchyIncomingCalls(
1207  const CallHierarchyIncomingCallsParams &Params,
1208  Callback<std::vector<CallHierarchyIncomingCall>> Reply) {
1209  Server->incomingCalls(Params.item, std::move(Reply));
1210 }
1211 
1212 void ClangdLSPServer::onClangdInlayHints(const InlayHintsParams &Params,
1213  Callback<llvm::json::Value> Reply) {
1214  // Our extension has a different representation on the wire than the standard.
1215  // We have a "range" property and "kind" is represented as a string, not as an
1216  // enum value.
1217  // https://clangd.llvm.org/extensions#inlay-hints
1218  auto Serialize = [Reply = std::move(Reply)](
1219  llvm::Expected<std::vector<InlayHint>> Hints) mutable {
1220  if (!Hints) {
1221  Reply(Hints.takeError());
1222  return;
1223  }
1224  llvm::json::Array Result;
1225  Result.reserve(Hints->size());
1226  for (auto &Hint : *Hints) {
1227  Result.emplace_back(llvm::json::Object{
1228  {"kind", llvm::to_string(Hint.kind)},
1229  {"range", Hint.range},
1230  {"position", Hint.position},
1231  // Extension doesn't have paddingLeft/Right so adjust the label
1232  // accordingly.
1233  {"label",
1234  ((Hint.paddingLeft ? " " : "") + llvm::StringRef(Hint.label) +
1235  (Hint.paddingRight ? " " : ""))
1236  .str()},
1237  });
1238  }
1239  Reply(std::move(Result));
1240  };
1241  Server->inlayHints(Params.textDocument.uri.file(), Params.range,
1242  std::move(Serialize));
1243 }
1244 
1245 void ClangdLSPServer::onInlayHint(const InlayHintsParams &Params,
1246  Callback<std::vector<InlayHint>> Reply) {
1247  Server->inlayHints(Params.textDocument.uri.file(), Params.range,
1248  std::move(Reply));
1249 }
1250 
1251 void ClangdLSPServer::applyConfiguration(
1252  const ConfigurationSettings &Settings) {
1253  // Per-file update to the compilation database.
1254  llvm::StringSet<> ModifiedFiles;
1255  for (auto &Entry : Settings.compilationDatabaseChanges) {
1256  PathRef File = Entry.first;
1257  auto Old = CDB->getCompileCommand(File);
1258  auto New =
1259  tooling::CompileCommand(std::move(Entry.second.workingDirectory), File,
1260  std::move(Entry.second.compilationCommand),
1261  /*Output=*/"");
1262  if (Old != New) {
1263  CDB->setCompileCommand(File, std::move(New));
1264  ModifiedFiles.insert(File);
1265  }
1266  }
1267 
1268  Server->reparseOpenFilesIfNeeded(
1269  [&](llvm::StringRef File) { return ModifiedFiles.count(File) != 0; });
1270 }
1271 
1272 void ClangdLSPServer::maybeExportMemoryProfile() {
1273  if (!trace::enabled() || !ShouldProfile())
1274  return;
1275 
1276  static constexpr trace::Metric MemoryUsage(
1277  "memory_usage", trace::Metric::Value, "component_name");
1278  trace::Span Tracer("ProfileBrief");
1279  MemoryTree MT;
1280  profile(MT);
1281  record(MT, "clangd_lsp_server", MemoryUsage);
1282 }
1283 
1284 void ClangdLSPServer::maybeCleanupMemory() {
1285  if (!Opts.MemoryCleanup || !ShouldCleanupMemory())
1286  return;
1287  Opts.MemoryCleanup();
1288 }
1289 
1290 // FIXME: This function needs to be properly tested.
1291 void ClangdLSPServer::onChangeConfiguration(
1292  const DidChangeConfigurationParams &Params) {
1293  applyConfiguration(Params.settings);
1294 }
1295 
1296 void ClangdLSPServer::onReference(const ReferenceParams &Params,
1297  Callback<std::vector<Location>> Reply) {
1298  Server->findReferences(
1299  Params.textDocument.uri.file(), Params.position, Opts.ReferencesLimit,
1300  [Reply = std::move(Reply),
1301  IncludeDecl(Params.context.includeDeclaration)](
1302  llvm::Expected<ReferencesResult> Refs) mutable {
1303  if (!Refs)
1304  return Reply(Refs.takeError());
1305  // Filter out declarations if the client asked.
1306  std::vector<Location> Result;
1307  Result.reserve(Refs->References.size());
1308  for (auto &Ref : Refs->References) {
1309  bool IsDecl = Ref.Attributes & ReferencesResult::Declaration;
1310  if (IncludeDecl || !IsDecl)
1311  Result.push_back(std::move(Ref.Loc));
1312  }
1313  return Reply(std::move(Result));
1314  });
1315 }
1316 
1317 void ClangdLSPServer::onGoToType(const TextDocumentPositionParams &Params,
1318  Callback<std::vector<Location>> Reply) {
1319  Server->findType(
1320  Params.textDocument.uri.file(), Params.position,
1321  [Reply = std::move(Reply)](
1322  llvm::Expected<std::vector<LocatedSymbol>> Types) mutable {
1323  if (!Types)
1324  return Reply(Types.takeError());
1325  std::vector<Location> Response;
1326  for (const LocatedSymbol &Sym : *Types)
1327  Response.push_back(Sym.PreferredDeclaration);
1328  return Reply(std::move(Response));
1329  });
1330 }
1331 
1332 void ClangdLSPServer::onGoToImplementation(
1333  const TextDocumentPositionParams &Params,
1334  Callback<std::vector<Location>> Reply) {
1335  Server->findImplementations(
1336  Params.textDocument.uri.file(), Params.position,
1337  [Reply = std::move(Reply)](
1338  llvm::Expected<std::vector<LocatedSymbol>> Overrides) mutable {
1339  if (!Overrides)
1340  return Reply(Overrides.takeError());
1341  std::vector<Location> Impls;
1342  for (const LocatedSymbol &Sym : *Overrides)
1343  Impls.push_back(Sym.PreferredDeclaration);
1344  return Reply(std::move(Impls));
1345  });
1346 }
1347 
1348 void ClangdLSPServer::onSymbolInfo(const TextDocumentPositionParams &Params,
1349  Callback<std::vector<SymbolDetails>> Reply) {
1350  Server->symbolInfo(Params.textDocument.uri.file(), Params.position,
1351  std::move(Reply));
1352 }
1353 
1354 void ClangdLSPServer::onSelectionRange(
1355  const SelectionRangeParams &Params,
1356  Callback<std::vector<SelectionRange>> Reply) {
1357  Server->semanticRanges(
1358  Params.textDocument.uri.file(), Params.positions,
1359  [Reply = std::move(Reply)](
1360  llvm::Expected<std::vector<SelectionRange>> Ranges) mutable {
1361  if (!Ranges)
1362  return Reply(Ranges.takeError());
1363  return Reply(std::move(*Ranges));
1364  });
1365 }
1366 
1367 void ClangdLSPServer::onDocumentLink(
1368  const DocumentLinkParams &Params,
1369  Callback<std::vector<DocumentLink>> Reply) {
1370 
1371  // TODO(forster): This currently resolves all targets eagerly. This is slow,
1372  // because it blocks on the preamble/AST being built. We could respond to the
1373  // request faster by using string matching or the lexer to find the includes
1374  // and resolving the targets lazily.
1375  Server->documentLinks(
1376  Params.textDocument.uri.file(),
1377  [Reply = std::move(Reply)](
1378  llvm::Expected<std::vector<DocumentLink>> Links) mutable {
1379  if (!Links) {
1380  return Reply(Links.takeError());
1381  }
1382  return Reply(std::move(Links));
1383  });
1384 }
1385 
1386 // Increment a numeric string: "" -> 1 -> 2 -> ... -> 9 -> 10 -> 11 ...
1387 static void increment(std::string &S) {
1388  for (char &C : llvm::reverse(S)) {
1389  if (C != '9') {
1390  ++C;
1391  return;
1392  }
1393  C = '0';
1394  }
1395  S.insert(S.begin(), '1');
1396 }
1397 
1398 void ClangdLSPServer::onSemanticTokens(const SemanticTokensParams &Params,
1399  Callback<SemanticTokens> CB) {
1400  auto File = Params.textDocument.uri.file();
1401  Server->semanticHighlights(
1402  Params.textDocument.uri.file(),
1403  [this, File(File.str()), CB(std::move(CB)), Code(Server->getDraft(File))](
1404  llvm::Expected<std::vector<HighlightingToken>> HT) mutable {
1405  if (!HT)
1406  return CB(HT.takeError());
1407  SemanticTokens Result;
1408  Result.tokens = toSemanticTokens(*HT, *Code);
1409  {
1410  std::lock_guard<std::mutex> Lock(SemanticTokensMutex);
1411  auto &Last = LastSemanticTokens[File];
1412 
1413  Last.tokens = Result.tokens;
1414  increment(Last.resultId);
1415  Result.resultId = Last.resultId;
1416  }
1417  CB(std::move(Result));
1418  });
1419 }
1420 
1421 void ClangdLSPServer::onSemanticTokensDelta(
1422  const SemanticTokensDeltaParams &Params,
1423  Callback<SemanticTokensOrDelta> CB) {
1424  auto File = Params.textDocument.uri.file();
1425  Server->semanticHighlights(
1426  Params.textDocument.uri.file(),
1427  [this, PrevResultID(Params.previousResultId), File(File.str()),
1428  CB(std::move(CB)), Code(Server->getDraft(File))](
1429  llvm::Expected<std::vector<HighlightingToken>> HT) mutable {
1430  if (!HT)
1431  return CB(HT.takeError());
1432  std::vector<SemanticToken> Toks = toSemanticTokens(*HT, *Code);
1433 
1434  SemanticTokensOrDelta Result;
1435  {
1436  std::lock_guard<std::mutex> Lock(SemanticTokensMutex);
1437  auto &Last = LastSemanticTokens[File];
1438 
1439  if (PrevResultID == Last.resultId) {
1440  Result.edits = diffTokens(Last.tokens, Toks);
1441  } else {
1442  vlog("semanticTokens/full/delta: wanted edits vs {0} but last "
1443  "result had ID {1}. Returning full token list.",
1444  PrevResultID, Last.resultId);
1445  Result.tokens = Toks;
1446  }
1447 
1448  Last.tokens = std::move(Toks);
1449  increment(Last.resultId);
1450  Result.resultId = Last.resultId;
1451  }
1452 
1453  CB(std::move(Result));
1454  });
1455 }
1456 
1457 void ClangdLSPServer::onMemoryUsage(const NoParams &,
1458  Callback<MemoryTree> Reply) {
1459  llvm::BumpPtrAllocator DetailAlloc;
1460  MemoryTree MT(&DetailAlloc);
1461  profile(MT);
1462  Reply(std::move(MT));
1463 }
1464 
1465 void ClangdLSPServer::onAST(const ASTParams &Params,
1466  Callback<llvm::Optional<ASTNode>> CB) {
1467  Server->getAST(Params.textDocument.uri.file(), Params.range, std::move(CB));
1468 }
1469 
1470 ClangdLSPServer::ClangdLSPServer(Transport &Transp, const ThreadsafeFS &TFS,
1471  const ClangdLSPServer::Options &Opts)
1472  : ShouldProfile(/*Period=*/std::chrono::minutes(5),
1473  /*Delay=*/std::chrono::minutes(1)),
1474  ShouldCleanupMemory(/*Period=*/std::chrono::minutes(1),
1475  /*Delay=*/std::chrono::minutes(1)),
1476  BackgroundContext(Context::current().clone()), Transp(Transp),
1477  MsgHandler(new MessageHandler(*this)), TFS(TFS),
1478  SupportedSymbolKinds(defaultSymbolKinds()),
1479  SupportedCompletionItemKinds(defaultCompletionItemKinds()), Opts(Opts) {
1480  if (Opts.ConfigProvider) {
1481  assert(!Opts.ContextProvider &&
1482  "Only one of ConfigProvider and ContextProvider allowed!");
1484  Opts.ConfigProvider, this);
1485  }
1486  LSPBinder Bind(this->Handlers, *this);
1487  Bind.method("initialize", this, &ClangdLSPServer::onInitialize);
1488 }
1489 
1490 void ClangdLSPServer::bindMethods(LSPBinder &Bind,
1491  const ClientCapabilities &Caps) {
1492  // clang-format off
1493  Bind.notification("initialized", this, &ClangdLSPServer::onInitialized);
1494  Bind.method("shutdown", this, &ClangdLSPServer::onShutdown);
1495  Bind.method("sync", this, &ClangdLSPServer::onSync);
1496  Bind.method("textDocument/rangeFormatting", this, &ClangdLSPServer::onDocumentRangeFormatting);
1497  Bind.method("textDocument/onTypeFormatting", this, &ClangdLSPServer::onDocumentOnTypeFormatting);
1498  Bind.method("textDocument/formatting", this, &ClangdLSPServer::onDocumentFormatting);
1499  Bind.method("textDocument/codeAction", this, &ClangdLSPServer::onCodeAction);
1500  Bind.method("textDocument/completion", this, &ClangdLSPServer::onCompletion);
1501  Bind.method("textDocument/signatureHelp", this, &ClangdLSPServer::onSignatureHelp);
1502  Bind.method("textDocument/definition", this, &ClangdLSPServer::onGoToDefinition);
1503  Bind.method("textDocument/declaration", this, &ClangdLSPServer::onGoToDeclaration);
1504  Bind.method("textDocument/typeDefinition", this, &ClangdLSPServer::onGoToType);
1505  Bind.method("textDocument/implementation", this, &ClangdLSPServer::onGoToImplementation);
1506  Bind.method("textDocument/references", this, &ClangdLSPServer::onReference);
1507  Bind.method("textDocument/switchSourceHeader", this, &ClangdLSPServer::onSwitchSourceHeader);
1508  Bind.method("textDocument/prepareRename", this, &ClangdLSPServer::onPrepareRename);
1509  Bind.method("textDocument/rename", this, &ClangdLSPServer::onRename);
1510  Bind.method("textDocument/hover", this, &ClangdLSPServer::onHover);
1511  Bind.method("textDocument/documentSymbol", this, &ClangdLSPServer::onDocumentSymbol);
1512  Bind.method("workspace/executeCommand", this, &ClangdLSPServer::onCommand);
1513  Bind.method("textDocument/documentHighlight", this, &ClangdLSPServer::onDocumentHighlight);
1514  Bind.method("workspace/symbol", this, &ClangdLSPServer::onWorkspaceSymbol);
1515  Bind.method("textDocument/ast", this, &ClangdLSPServer::onAST);
1516  Bind.notification("textDocument/didOpen", this, &ClangdLSPServer::onDocumentDidOpen);
1517  Bind.notification("textDocument/didClose", this, &ClangdLSPServer::onDocumentDidClose);
1518  Bind.notification("textDocument/didChange", this, &ClangdLSPServer::onDocumentDidChange);
1519  Bind.notification("textDocument/didSave", this, &ClangdLSPServer::onDocumentDidSave);
1520  Bind.notification("workspace/didChangeWatchedFiles", this, &ClangdLSPServer::onFileEvent);
1521  Bind.notification("workspace/didChangeConfiguration", this, &ClangdLSPServer::onChangeConfiguration);
1522  Bind.method("textDocument/symbolInfo", this, &ClangdLSPServer::onSymbolInfo);
1523  Bind.method("textDocument/typeHierarchy", this, &ClangdLSPServer::onTypeHierarchy);
1524  Bind.method("typeHierarchy/resolve", this, &ClangdLSPServer::onResolveTypeHierarchy);
1525  Bind.method("textDocument/prepareCallHierarchy", this, &ClangdLSPServer::onPrepareCallHierarchy);
1526  Bind.method("callHierarchy/incomingCalls", this, &ClangdLSPServer::onCallHierarchyIncomingCalls);
1527  Bind.method("textDocument/selectionRange", this, &ClangdLSPServer::onSelectionRange);
1528  Bind.method("textDocument/documentLink", this, &ClangdLSPServer::onDocumentLink);
1529  Bind.method("textDocument/semanticTokens/full", this, &ClangdLSPServer::onSemanticTokens);
1530  Bind.method("textDocument/semanticTokens/full/delta", this, &ClangdLSPServer::onSemanticTokensDelta);
1531  Bind.method("clangd/inlayHints", this, &ClangdLSPServer::onClangdInlayHints);
1532  Bind.method("textDocument/inlayHint", this, &ClangdLSPServer::onInlayHint);
1533  Bind.method("$/memoryUsage", this, &ClangdLSPServer::onMemoryUsage);
1534  if (Opts.FoldingRanges)
1535  Bind.method("textDocument/foldingRange", this, &ClangdLSPServer::onFoldingRange);
1536  Bind.command(ApplyFixCommand, this, &ClangdLSPServer::onCommandApplyEdit);
1537  Bind.command(ApplyTweakCommand, this, &ClangdLSPServer::onCommandApplyTweak);
1538 
1539  ApplyWorkspaceEdit = Bind.outgoingMethod("workspace/applyEdit");
1540  PublishDiagnostics = Bind.outgoingNotification("textDocument/publishDiagnostics");
1541  ShowMessage = Bind.outgoingNotification("window/showMessage");
1542  NotifyFileStatus = Bind.outgoingNotification("textDocument/clangd.fileStatus");
1543  CreateWorkDoneProgress = Bind.outgoingMethod("window/workDoneProgress/create");
1544  BeginWorkDoneProgress = Bind.outgoingNotification("$/progress");
1545  ReportWorkDoneProgress = Bind.outgoingNotification("$/progress");
1546  EndWorkDoneProgress = Bind.outgoingNotification("$/progress");
1548  SemanticTokensRefresh = Bind.outgoingMethod("workspace/semanticTokens/refresh");
1549  // clang-format on
1550 }
1551 
1553  IsBeingDestroyed = true;
1554  // Explicitly destroy ClangdServer first, blocking on threads it owns.
1555  // This ensures they don't access any other members.
1556  Server.reset();
1557 }
1558 
1560  // Run the Language Server loop.
1561  bool CleanExit = true;
1562  if (auto Err = Transp.loop(*MsgHandler)) {
1563  elog("Transport error: {0}", std::move(Err));
1564  CleanExit = false;
1565  }
1566 
1567  return CleanExit && ShutdownRequestReceived;
1568 }
1569 
1571  if (Server)
1572  Server->profile(MT.child("clangd_server"));
1573 }
1574 
1575 std::vector<Fix> ClangdLSPServer::getFixes(llvm::StringRef File,
1576  const clangd::Diagnostic &D) {
1577  std::lock_guard<std::mutex> Lock(FixItsMutex);
1578  auto DiagToFixItsIter = FixItsMap.find(File);
1579  if (DiagToFixItsIter == FixItsMap.end())
1580  return {};
1581 
1582  const auto &DiagToFixItsMap = DiagToFixItsIter->second;
1583  auto FixItsIter = DiagToFixItsMap.find(D);
1584  if (FixItsIter == DiagToFixItsMap.end())
1585  return {};
1586 
1587  return FixItsIter->second;
1588 }
1589 
1590 // A completion request is sent when the user types '>' or ':', but we only
1591 // want to trigger on '->' and '::'. We check the preceeding text to make
1592 // sure it matches what we expected.
1593 // Running the lexer here would be more robust (e.g. we can detect comments
1594 // and avoid triggering completion there), but we choose to err on the side
1595 // of simplicity here.
1596 bool ClangdLSPServer::shouldRunCompletion(
1597  const CompletionParams &Params) const {
1598  if (Params.context.triggerKind != CompletionTriggerKind::TriggerCharacter)
1599  return true;
1600  auto Code = Server->getDraft(Params.textDocument.uri.file());
1601  if (!Code)
1602  return true; // completion code will log the error for untracked doc.
1603  auto Offset = positionToOffset(*Code, Params.position,
1604  /*AllowColumnsBeyondLineLength=*/false);
1605  if (!Offset) {
1606  vlog("could not convert position '{0}' to offset for file '{1}'",
1607  Params.position, Params.textDocument.uri.file());
1608  return true;
1609  }
1610  return allowImplicitCompletion(*Code, *Offset);
1611 }
1612 
1613 void ClangdLSPServer::onDiagnosticsReady(PathRef File, llvm::StringRef Version,
1614  std::vector<Diag> Diagnostics) {
1615  PublishDiagnosticsParams Notification;
1616  Notification.version = decodeVersion(Version);
1617  Notification.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
1618  DiagnosticToReplacementMap LocalFixIts; // Temporary storage
1619  for (auto &Diag : Diagnostics) {
1620  toLSPDiags(Diag, Notification.uri, DiagOpts,
1621  [&](clangd::Diagnostic Diag, llvm::ArrayRef<Fix> Fixes) {
1622  auto &FixItsForDiagnostic = LocalFixIts[Diag];
1623  llvm::copy(Fixes, std::back_inserter(FixItsForDiagnostic));
1624  Notification.diagnostics.push_back(std::move(Diag));
1625  });
1626  }
1627 
1628  // Cache FixIts
1629  {
1630  std::lock_guard<std::mutex> Lock(FixItsMutex);
1631  FixItsMap[File] = LocalFixIts;
1632  }
1633 
1634  // Send a notification to the LSP client.
1635  PublishDiagnostics(Notification);
1636 }
1637 
1638 void ClangdLSPServer::onBackgroundIndexProgress(
1639  const BackgroundQueue::Stats &Stats) {
1640  static const char ProgressToken[] = "backgroundIndexProgress";
1641 
1642  // The background index did some work, maybe we need to cleanup
1643  maybeCleanupMemory();
1644 
1645  std::lock_guard<std::mutex> Lock(BackgroundIndexProgressMutex);
1646 
1647  auto NotifyProgress = [this](const BackgroundQueue::Stats &Stats) {
1648  if (BackgroundIndexProgressState != BackgroundIndexProgress::Live) {
1649  WorkDoneProgressBegin Begin;
1650  Begin.percentage = true;
1651  Begin.title = "indexing";
1652  BeginWorkDoneProgress({ProgressToken, std::move(Begin)});
1653  BackgroundIndexProgressState = BackgroundIndexProgress::Live;
1654  }
1655 
1656  if (Stats.Completed < Stats.Enqueued) {
1657  assert(Stats.Enqueued > Stats.LastIdle);
1658  WorkDoneProgressReport Report;
1659  Report.percentage = 100 * (Stats.Completed - Stats.LastIdle) /
1660  (Stats.Enqueued - Stats.LastIdle);
1661  Report.message =
1662  llvm::formatv("{0}/{1}", Stats.Completed - Stats.LastIdle,
1663  Stats.Enqueued - Stats.LastIdle);
1664  ReportWorkDoneProgress({ProgressToken, std::move(Report)});
1665  } else {
1666  assert(Stats.Completed == Stats.Enqueued);
1667  EndWorkDoneProgress({ProgressToken, WorkDoneProgressEnd()});
1668  BackgroundIndexProgressState = BackgroundIndexProgress::Empty;
1669  }
1670  };
1671 
1672  switch (BackgroundIndexProgressState) {
1673  case BackgroundIndexProgress::Unsupported:
1674  return;
1675  case BackgroundIndexProgress::Creating:
1676  // Cache this update for when the progress bar is available.
1677  PendingBackgroundIndexProgress = Stats;
1678  return;
1679  case BackgroundIndexProgress::Empty: {
1680  if (BackgroundIndexSkipCreate) {
1681  NotifyProgress(Stats);
1682  break;
1683  }
1684  // Cache this update for when the progress bar is available.
1685  PendingBackgroundIndexProgress = Stats;
1686  BackgroundIndexProgressState = BackgroundIndexProgress::Creating;
1687  WorkDoneProgressCreateParams CreateRequest;
1688  CreateRequest.token = ProgressToken;
1689  CreateWorkDoneProgress(
1690  CreateRequest,
1691  [this, NotifyProgress](llvm::Expected<std::nullptr_t> E) {
1692  std::lock_guard<std::mutex> Lock(BackgroundIndexProgressMutex);
1693  if (E) {
1694  NotifyProgress(this->PendingBackgroundIndexProgress);
1695  } else {
1696  elog("Failed to create background index progress bar: {0}",
1697  E.takeError());
1698  // give up forever rather than thrashing about
1699  BackgroundIndexProgressState = BackgroundIndexProgress::Unsupported;
1700  }
1701  });
1702  break;
1703  }
1704  case BackgroundIndexProgress::Live:
1705  NotifyProgress(Stats);
1706  break;
1707  }
1708 }
1709 
1710 void ClangdLSPServer::onFileUpdated(PathRef File, const TUStatus &Status) {
1711  if (!SupportFileStatus)
1712  return;
1713  // FIXME: we don't emit "BuildingFile" and `RunningAction`, as these
1714  // two statuses are running faster in practice, which leads the UI constantly
1715  // changing, and doesn't provide much value. We may want to emit status at a
1716  // reasonable time interval (e.g. 0.5s).
1717  if (Status.PreambleActivity == PreambleAction::Idle &&
1718  (Status.ASTActivity.K == ASTAction::Building ||
1719  Status.ASTActivity.K == ASTAction::RunningAction))
1720  return;
1721  NotifyFileStatus(Status.render(File));
1722 }
1723 
1724 void ClangdLSPServer::onSemanticsMaybeChanged(PathRef File) {
1725  if (SemanticTokensRefresh) {
1726  SemanticTokensRefresh(NoParams{}, [](llvm::Expected<std::nullptr_t> E) {
1727  if (E)
1728  return;
1729  elog("Failed to refresh semantic tokens: {0}", E.takeError());
1730  });
1731  }
1732 }
1733 } // namespace clangd
1734 } // namespace clang
clang::clangd::versionString
std::string versionString()
Definition: Feature.cpp:17
clang::clangd::ClangdLSPServer::run
bool run()
Run LSP server loop, communicating with the Transport provided in the constructor.
Definition: ClangdLSPServer.cpp:1559
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
WantDiags
WantDiagnostics WantDiags
Definition: TUScheduler.cpp:494
clang::clangd::DocumentSymbol::range
Range range
The range enclosing this symbol not including leading/trailing whitespace but everything else like co...
Definition: Protocol.h:1043
Base
std::unique_ptr< GlobalCompilationDatabase > Base
Definition: GlobalCompilationDatabaseTests.cpp:85
clang::clangd::MemoryTree::child
MemoryTree & child(llvm::StringLiteral Name)
No copy of the Name.
Definition: MemoryTree.h:39
clang::clangd::cancelableTask
std::pair< Context, Canceler > cancelableTask(int Reason)
Defines a new task whose cancellation may be requested.
Definition: Cancellation.cpp:24
clang::clangd::SymbolKindMin
constexpr auto SymbolKindMin
Definition: Protocol.h:362
clang::clangd::TextDocumentIdentifier::uri
URIForFile uri
The text document's URI.
Definition: Protocol.h:130
clang::clangd::HighlightingModifier
HighlightingModifier
Definition: SemanticHighlighting.h:62
Hints
std::vector< FixItHint > Hints
Definition: RedundantStrcatCallsCheck.cpp:46
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
clang::clangd::Location::uri
URIForFile uri
The text document's URI.
Definition: Protocol.h:210
clang::clangd::HighlightingModifier::LastModifier
@ LastModifier
clang::clangd::LSPBinder::outgoingNotification
UntypedOutgoingNotification outgoingNotification(llvm::StringLiteral Method)
Bind a function object to be used for outgoing notifications.
Definition: LSPBinder.h:186
CodeComplete.h
clang::clangd::ClangdLSPServer::profile
void profile(MemoryTree &MT) const
Profiles resource-usage.
Definition: ClangdLSPServer.cpp:1570
clang::clangd::ErrorCode::ServerNotInitialized
@ ServerNotInitialized
clang::clangd::ClangdLSPServer::MessageHandler::onCall
bool onCall(llvm::StringRef Method, llvm::json::Value Params, llvm::json::Value ID) override
Definition: ClangdLSPServer.cpp:180
Refs
RefSlab Refs
Definition: SymbolCollectorTests.cpp:312
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:26
clang::clangd::semanticTokenModifiers
static std::vector< llvm::StringRef > semanticTokenModifiers()
Definition: ClangdLSPServer.cpp:433
Expected
std::vector< const char * > Expected
Definition: PrintASTTests.cpp:26
clang::clangd::toSemanticTokenModifier
llvm::StringRef toSemanticTokenModifier(HighlightingModifier Modifier)
Definition: SemanticHighlighting.cpp:1039
clang::clangd::CodeAction
A code action represents a change that can be performed in code, e.g.
Definition: Protocol.h:992
Tracer
std::unique_ptr< trace::EventTracer > Tracer
Definition: TraceTests.cpp:161
clang::clangd::error
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
Definition: Logger.h:79
clang::clangd::Transport::call
virtual void call(llvm::StringRef Method, llvm::json::Value Params, llvm::json::Value ID)=0
clang::clangd::Context::current
static const Context & current()
Returns the context for the current thread, creating it if needed.
Definition: Context.cpp:27
clang::clangd::Location
Definition: Protocol.h:208
clang::clangd::WantDiagnostics::Yes
@ Yes
clang::clangd::ClangdServer::Options::FeatureModules
FeatureModuleSet * FeatureModules
Definition: ClangdServer.h:164
clang::clangd::Context::clone
Context clone() const
Clone this context object.
Definition: Context.cpp:20
Diagnostics
WantDiagnostics Diagnostics
Definition: TUScheduler.cpp:602
clang::clangd::replacementsToEdits
std::vector< TextEdit > replacementsToEdits(llvm::StringRef Code, const tooling::Replacements &Repls)
Definition: SourceCode.cpp:503
clang::clangd::ClientCapabilities
Definition: Protocol.h:402
clang::clangd::WantDiagnostics::Auto
@ Auto
Diagnostics must not be generated for this snapshot.
clang::clangd::SymbolInformation
Represents information about programming constructs like variables, classes, interfaces etc.
Definition: Protocol.h:1057
clang::clangd::LSPBinder::notification
void notification(llvm::StringLiteral Method, ThisT *This, void(ThisT::*Handler)(const Param &))
Bind a handler for an LSP notification.
Definition: LSPBinder.h:146
Kind
BindArgumentKind Kind
Definition: AvoidBindCheck.cpp:59
clang::clangd::CompletionItemKind::Reference
@ Reference
clang::clangd::HighlightingKind
HighlightingKind
Definition: SemanticHighlighting.h:31
clang::clangd::InitializedParams
NoParams InitializedParams
Definition: Protocol.h:274
Feature.h
clang::clangd::ClangdServer::Options::ResourceDir
llvm::Optional< std::string > ResourceDir
The resource directory is used to find internal headers, overriding defaults and -resource-dir compil...
Definition: ClangdServer.h:142
clang::clangd::SymbolInformation::name
std::string name
The name of this symbol.
Definition: Protocol.h:1059
Trace.h
clang::clangd::ErrorCode::InternalError
@ InternalError
clang::clangd::LSPBinder::method
void method(llvm::StringLiteral Method, ThisT *This, void(ThisT::*Handler)(const Param &, Callback< Result >))
Bind a handler for an LSP method.
Definition: LSPBinder.h:133
clang::clangd::Location::range
Range range
Definition: Protocol.h:211
clang::clangd::ClangdLSPServer::Options::CodeComplete
clangd::CodeCompleteOptions CodeComplete
Per-feature options.
Definition: ClangdLSPServer.h:52
clang::clangd::ClangdServer::Options::QueryDriverGlobs
std::vector< std::string > QueryDriverGlobs
Clangd will execute compiler drivers matching one of these globs to fetch system include path.
Definition: ClangdServer.h:159
clang::clangd::HighlightingKind::LastKind
@ LastKind
clang::clangd::increment
static void increment(std::string &S)
Definition: ClangdLSPServer.cpp:1387
clang::clangd::ClangdLSPServer::MessageHandler::MessageHandler
MessageHandler(ClangdLSPServer &Server)
Definition: ClangdLSPServer.cpp:156
clang::clangd::ClangdLSPServer::MessageHandler::onReply
bool onReply(llvm::json::Value ID, llvm::Expected< llvm::json::Value > Result) override
Definition: ClangdLSPServer.cpp:203
clang::clangd::featureString
std::string featureString()
Definition: Feature.cpp:32
clang::clangd::ClangdServer::Options::ImplicitCancellation
bool ImplicitCancellation
Cancel certain requests if the file changes before they begin running.
Definition: ClangdServer.h:155
clang::clangd::DocumentSymbol::children
std::vector< DocumentSymbol > children
Children of this symbol, e.g. properties of a class.
Definition: Protocol.h:1050
clang::clangd::SymbolKindBitset
std::bitset< SymbolKindMax+1 > SymbolKindBitset
Definition: Protocol.h:364
LSPBinder.h
Cancellation.h
clang::clangd::CompletionItemKindBitset
std::bitset< CompletionItemKindMax+1 > CompletionItemKindBitset
Definition: Protocol.h:325
clang::clangd::ClangdLSPServer::MessageHandler::bindReply
llvm::json::Value bindReply(Callback< llvm::json::Value > Reply)
Definition: ClangdLSPServer.cpp:245
clang::clangd::ClangdLSPServer::Options
Definition: ClangdLSPServer.h:38
clang::clangd::CodeAction::title
std::string title
A short, human-readable, title for this code action.
Definition: Protocol.h:994
clang::clangd::canonicalize
static llvm::SmallString< 128 > canonicalize(llvm::StringRef Path)
Definition: FileDistance.cpp:48
Protocol.h
clang::clangd::SymbolKind::Array
@ Array
clang::clangd::ClangdLSPServer
This class exposes ClangdServer's capabilities via Language Server Protocol.
Definition: ClangdLSPServer.h:35
clang::clangd::Diagnostic
Definition: Protocol.h:846
Offset
size_t Offset
Definition: CodeComplete.cpp:1203
Code
std::string Code
Definition: FindTargetTests.cpp:67
ns1::ns2::D
@ D
Definition: CategoricalFeature.h:3
Diagnostic
DiagnosticCallback Diagnostic
Definition: ConfigCompile.cpp:100
ClangdLSPServer.h
clang::clangd::ErrorCode::InvalidParams
@ InvalidParams
Tweak.h
clang::clangd::MemoryTree
A tree that can be used to represent memory usage of nested components while preserving the hierarchy...
Definition: MemoryTree.h:30
GlobalCompilationDatabase.h
clang::clangd::CommandMangler::detect
static CommandMangler detect()
Definition: CompileCommands.cpp:188
clang::clangd::PreambleAction::Idle
@ Idle
CompileCommands.h
clang::clangd::trace::enabled
bool enabled()
Returns true if there is an active tracer.
Definition: Trace.cpp:283
Args
llvm::json::Object Args
Definition: Trace.cpp:138
clang::clangd::OffsetEncoding::UTF16
@ UTF16
clang::clangd::positionToOffset
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
clang::tidy::readability::Defaults
static constexpr DefaultHeuristicConfiguration Defaults[]
Definition: SuspiciousCallArgumentCheck.cpp:51
clang::clangd::platformString
std::string platformString()
Definition: Feature.cpp:19
clang::clangd::ClangdLSPServer::Options::Rename
clangd::RenameOptions Rename
Definition: ClangdLSPServer.h:54
SPAN_ATTACH
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
Definition: Trace.h:164
clang::clangd::CodeCompleteOptions::IncludeFixIts
bool IncludeFixIts
Include completions that require small corrections, e.g.
Definition: CodeComplete.h:92
clang::clangd::vlog
void vlog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:72
clang::clangd::trace::Metric::Distribution
@ Distribution
A distribution of values with a meaningful mean and count.
Definition: Trace.h:52
clang::clangd::CodeCompleteOptions::BundleOverloads
llvm::Optional< bool > BundleOverloads
Combine overloads into a single completion item where possible.
Definition: CodeComplete.h:58
Diagnostics.h
clang::clangd::TextDocumentPositionParams::position
Position position
The position inside the text document.
Definition: Protocol.h:1131
Results
std::vector< CodeCompletionResult > Results
Definition: CodeComplete.cpp:784
clang::clangd::ClangdLSPServer::Options::UseDirBasedCDB
bool UseDirBasedCDB
Look for compilation databases, rather than using compile commands set via LSP (extensions) only.
Definition: ClangdLSPServer.h:43
clang::clangd::asCommand
static llvm::Optional< Command > asCommand(const CodeAction &Action)
Definition: ClangdLSPServer.cpp:944
clang::clangd::DocumentSymbol
Represents programming constructs like variables, classes, interfaces etc.
Definition: Protocol.h:1026
clang::clangd::URIForFile
Definition: Protocol.h:81
clang::clangd::CompletionItemKind::Method
@ Method
clang::clangd::ErrorCode::InvalidRequest
@ InvalidRequest
clang::clangd::ClangdLSPServer::ClangdLSPServer
ClangdLSPServer(Transport &Transp, const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts)
Definition: ClangdLSPServer.cpp:1470
clang::clangd::ClangdServer::Options::ContextProvider
std::function< Context(PathRef)> ContextProvider
If set, queried to derive a processing context for some work.
Definition: ClangdServer.h:127
clang::clangd::WithContext
WithContext replaces Context::current() with a provided scope.
Definition: Context.h:187
clang::clangd::TextDocumentSyncKind::Incremental
@ Incremental
Documents are synced by sending the full content on open.
clang::clangd::Transport::MessageHandler
Definition: Transport.h:47
clang::clangd::ClangdLSPServer::Options::SignatureHelpDocumentationFormat
MarkupKind SignatureHelpDocumentationFormat
Definition: ClangdLSPServer.h:53
clang::clangd::ASTAction::RunningAction
@ RunningAction
Definition: TUScheduler.h:98
clang::clangd::log
void log(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:67
clang::clangd::ClangdLSPServer::MessageHandler::onNotify
bool onNotify(llvm::StringRef Method, llvm::json::Value Params) override
Definition: ClangdLSPServer.cpp:158
clang::clangd::Transport
Definition: Transport.h:35
clang::clangd::toCodeAction
CodeAction toCodeAction(const Fix &F, const URIForFile &File)
Convert from Fix to LSP CodeAction.
Definition: Diagnostics.cpp:424
clang::clangd::allowImplicitCompletion
bool allowImplicitCompletion(llvm::StringRef Content, unsigned Offset)
Definition: CodeComplete.cpp:2214
Entry
Definition: Modularize.cpp:427
SourceCode.h
Index
const SymbolIndex * Index
Definition: Dexp.cpp:98
clang::clangd::getQueryDriverDatabase
std::unique_ptr< GlobalCompilationDatabase > getQueryDriverDatabase(llvm::ArrayRef< std::string > QueryDriverGlobs, std::unique_ptr< GlobalCompilationDatabase > Base)
Extracts system include search path from drivers matching QueryDriverGlobs and adds them to the compi...
Definition: QueryDriverDatabase.cpp:375
clang::clangd::applyChange
llvm::Error applyChange(std::string &Contents, const TextDocumentContentChangeEvent &Change)
Apply an incremental update to a text document.
Definition: SourceCode.cpp:1062
clang::clangd::URI::toString
std::string toString() const
Returns a string URI with all components percent-encoded.
Definition: URI.cpp:160
clang::clangd::getToggle
static Location * getToggle(const TextDocumentPositionParams &Point, LocatedSymbol &Sym)
Definition: ClangdLSPServer.cpp:1087
clang::clangd::ClangdDiagnosticOptions::EmitRelatedLocations
bool EmitRelatedLocations
If true, Clangd uses the relatedInformation field to include other locations (in particular attached ...
Definition: Diagnostics.h:44
clang::clangd::Context::derive
Context derive(const Key< Type > &Key, typename std::decay< Type >::type Value) const &
Derives a child context It is safe to move or destroy a parent context after calling derive().
Definition: Context.h:119
clang::clangd::ClangdDiagnosticOptions::SendDiagnosticCategory
bool SendDiagnosticCategory
If true, Clangd uses an LSP extension to send the diagnostic's category to the client.
Definition: Diagnostics.h:50
clang::clangd::ClientCapabilities::SemanticTokenRefreshSupport
bool SemanticTokenRefreshSupport
Whether the client implementation supports a refresh request sent from the server to the client.
Definition: Protocol.h:495
clang::clangd::ErrorCode::RequestCancelled
@ RequestCancelled
clang::clangd::Transport::notify
virtual void notify(llvm::StringRef Method, llvm::json::Value Params)=0
clang::clangd::semanticTokenTypes
static std::vector< llvm::StringRef > semanticTokenTypes()
Definition: ClangdLSPServer.cpp:425
clang::clangd::DocumentSymbol::kind
SymbolKind kind
The kind of this symbol.
Definition: Protocol.h:1034
ID
static char ID
Definition: Logger.cpp:74
clang::clangd::LSPBinder
LSPBinder collects a table of functions that handle LSP calls.
Definition: LSPBinder.h:34
clang::clangd::PathRef
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:29
clang::clangd::ThreadsafeFS
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
Definition: ThreadsafeFS.h:27
clang::clangd::ClangdDiagnosticOptions::EmbedFixesInDiagnostics
bool EmbedFixesInDiagnostics
If true, Clangd uses an LSP extension to embed the fixes with the diagnostics that are sent to the cl...
Definition: Diagnostics.h:39
clang::clangd::kCurrentOffsetEncoding
Key< OffsetEncoding > kCurrentOffsetEncoding
Definition: SourceCode.cpp:141
clang::clangd::TextDocumentPositionParams::textDocument
TextDocumentIdentifier textDocument
The text document.
Definition: Protocol.h:1128
clang::clangd::CodeCompleteOptions::EnableSnippets
bool EnableSnippets
When true, completion items will contain expandable code snippets in completion (e....
Definition: CodeComplete.h:48
clang::clangd::Transport::loop
virtual llvm::Error loop(MessageHandler &)=0
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang::clangd::toSemanticTokenType
llvm::StringRef toSemanticTokenType(HighlightingKind Kind)
Definition: SemanticHighlighting.cpp:993
clang::clangd::URIForFile::canonicalize
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Definition: Protocol.cpp:45
clang::clangd::MessageType::Info
@ Info
An information message.
SemanticHighlighting.h
clang::clangd::LocatedSymbol
Definition: XRefs.h:40
MemoryTree.h
clang::clangd::flattenSymbolHierarchy
static std::vector< SymbolInformation > flattenSymbolHierarchy(llvm::ArrayRef< DocumentSymbol > Symbols, const URIForFile &FileURI)
The functions constructs a flattened view of the DocumentSymbol hierarchy.
Definition: ClangdLSPServer.cpp:899
if
if(CLANG_PLUGIN_SUPPORT) export_executable_symbols_for_plugins(clang-tidy) endif() install(PROGRAMS clang-tidy-diff.py DESTINATION "$
Definition: clang-tidy/tool/CMakeLists.txt:59
clang::clangd::Canceler
std::function< void()> Canceler
A canceller requests cancellation of a task, when called.
Definition: Cancellation.h:70
clang::clangd::toLSPDiags
void toLSPDiags(const Diag &D, const URIForFile &File, const ClangdDiagnosticOptions &Opts, llvm::function_ref< void(clangd::Diagnostic, llvm::ArrayRef< Fix >)> OutFn)
Conversion to LSP diagnostics.
Definition: Diagnostics.cpp:459
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::LSPBinder::outgoingMethod
UntypedOutgoingMethod outgoingMethod(llvm::StringLiteral Method)
Bind a function object to be used for outgoing method calls.
Definition: LSPBinder.h:216
ClangdServer.h
clang::clangd::CodeCompleteOptions::Limit
size_t Limit
Limit the number of results returned (0 means no limit).
Definition: CodeComplete.h:62
clang::clangd::CodeAction::REFACTOR_KIND
const static llvm::StringLiteral REFACTOR_KIND
Definition: Protocol.h:1000
clang::clangd::ClangdLSPServer::Options::Encoding
llvm::Optional< OffsetEncoding > Encoding
The offset-encoding to use, or None to negotiate it over LSP.
Definition: ClangdLSPServer.h:45
TUScheduler.h
clang::clangd::OffsetEncoding
OffsetEncoding
Definition: Protocol.h:376
clang::clangd::LSPBinder::RawHandlers::CommandHandlers
HandlerMap< void(JSON, Callback< JSON >)> CommandHandlers
Definition: LSPBinder.h:44
Diags
CapturedDiags Diags
Definition: ConfigCompileTests.cpp:39
clang::clangd::TextDocumentPositionParams
Definition: Protocol.h:1126
Symbols
SymbolSlab Symbols
Definition: SymbolCollectorTests.cpp:311
Commands
static cl::list< std::string > Commands("c", cl::desc("Specify command to run"), cl::value_desc("command"), cl::cat(ClangQueryCategory))
clang::clangd::LocatedSymbol::PreferredDeclaration
Location PreferredDeclaration
Definition: XRefs.h:44
clang::clangd::FileEdits
llvm::StringMap< Edit > FileEdits
A mapping from absolute file path (the one used for accessing the underlying VFS) to edits.
Definition: SourceCode.h:204
clang::clangd::OffsetEncoding::UnsupportedEncoding
@ UnsupportedEncoding
clang::clangd::SymbolInformation::containerName
std::string containerName
The name of the symbol containing this symbol.
Definition: Protocol.h:1068
clang::clangd::Range::contains
bool contains(Position Pos) const
Definition: Protocol.h:199
clang::clangd::ASTAction::Building
@ Building
Definition: TUScheduler.h:99
clang::clangd::record
void record(const MemoryTree &MT, std::string RootName, const trace::Metric &Out)
Records total memory usage of each node under Out.
Definition: MemoryTree.cpp:53
clang::clangd::URIForFile::file
llvm::StringRef file() const
Retrieves absolute path to the file.
Definition: Protocol.h:101
clang::clangd::DocumentSymbol::name
std::string name
The name of this symbol.
Definition: Protocol.h:1028
clang::clangd::ErrorCode::MethodNotFound
@ MethodNotFound
clang::clangd::Callback
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:28
clang::clangd::ClangdServer::Options::FoldingRanges
bool FoldingRanges
Enable preview of FoldingRanges feature.
Definition: ClangdServer.h:162
clang::clangd::LSPBinder::command
void command(llvm::StringLiteral Command, ThisT *This, void(ThisT::*Handler)(const Param &, Callback< Result >))
Bind a handler for an LSP command.
Definition: LSPBinder.h:158
URI.h
clang::clangd::WantDiagnostics::No
@ No
Diagnostics must be generated for this snapshot.
clang::clangd::CompletionTriggerKind::TriggerCharacter
@ TriggerCharacter
Completion was triggered by a trigger character specified by the triggerCharacters properties of the ...
clang::clangd::URI::createFile
static URI createFile(llvm::StringRef AbsolutePath)
This creates a file:// URI for AbsolutePath. The path must be absolute.
Definition: URI.cpp:238
clang::clangd::SymbolInformation::location
Location location
The location of this symbol.
Definition: Protocol.h:1065
clang::clangd::elog
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:61
clang::clangd::ClangdLSPServer::~ClangdLSPServer
~ClangdLSPServer()
The destructor blocks on any outstanding background tasks.
Definition: ClangdLSPServer.cpp:1552
clang::clangd::CompletionItemKindMin
constexpr auto CompletionItemKindMin
Definition: Protocol.h:321
clang::clangd::Context
A context is an immutable container for per-request data that must be propagated through layers that ...
Definition: Context.h:69
clang::clangd::CodeAction::INFO_KIND
const static llvm::StringLiteral INFO_KIND
Definition: Protocol.h:1001
clang::clangd::CodeCompleteOptions::DocumentationFormat
MarkupKind DocumentationFormat
Whether to present doc comments as plain-text or markdown.
Definition: CodeComplete.h:65
clang::clangd::SymbolInformation::kind
SymbolKind kind
The kind of this symbol.
Definition: Protocol.h:1062
clang::clangd::LocatedSymbol::Definition
llvm::Optional< Location > Definition
Definition: XRefs.h:46
clang::clangd::ClangdLSPServer::MessageHandler
Definition: ClangdLSPServer.cpp:154
Value
static constexpr bool Value
Definition: SuspiciousCallArgumentCheck.cpp:72
clang::clangd::ClangdServer::Options::WorkspaceRoot
llvm::Optional< std::string > WorkspaceRoot
Clangd's workspace root.
Definition: ClangdServer.h:136
Signature
std::string Signature
Definition: CodeComplete.cpp:451
Context.h
Path
std::vector< HeaderHandle > Path
Definition: PreprocessorTracker.cpp:525
clang::clangd::adjustKindToCapability
SymbolKind adjustKindToCapability(SymbolKind Kind, SymbolKindBitset &SupportedSymbolKinds)
Definition: Protocol.cpp:232
clang::clangd::CodeAction::QUICKFIX_KIND
const static llvm::StringLiteral QUICKFIX_KIND
Definition: Protocol.h:999
clang::clangd::ClangdServer::createConfiguredContextProvider
static std::function< Context(PathRef)> createConfiguredContextProvider(const config::Provider *Provider, ClangdServer::Callbacks *)
Creates a context provider that loads and installs config.
Definition: ClangdServer.cpp:288
Action
FieldAction Action
Definition: MemberwiseConstructor.cpp:261
clang::clangd::trace::Span
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:143