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