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