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