brintos

brintos / llvm-project-archived public Read only

0
0
Text · 57.2 KiB · 560b8e0 Raw
1769 lines · cpp
1//===--- Protocol.cpp - Language Server Protocol Implementation -----------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains the serialization code for the LSP structs.10//11//===----------------------------------------------------------------------===//12 13#include "Protocol.h"14#include "URI.h"15#include "support/Logger.h"16#include "clang/Basic/LLVM.h"17#include "clang/Index/IndexSymbol.h"18#include "llvm/ADT/StringExtras.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/ADT/StringSwitch.h"21#include "llvm/Support/ErrorHandling.h"22#include "llvm/Support/JSON.h"23#include "llvm/Support/Path.h"24#include "llvm/Support/raw_ostream.h"25 26namespace clang {27namespace clangd {28namespace {29 30// Helper that doesn't treat `null` and absent fields as failures.31template <typename T>32bool mapOptOrNull(const llvm::json::Value &Params, llvm::StringLiteral Prop,33                  T &Out, llvm::json::Path P) {34  auto *O = Params.getAsObject();35  assert(O);36  auto *V = O->get(Prop);37  // Field is missing or null.38  if (!V || V->getAsNull())39    return true;40  return fromJSON(*V, Out, P.field(Prop));41}42} // namespace43 44char LSPError::ID;45 46URIForFile URIForFile::canonicalize(llvm::StringRef AbsPath,47                                    llvm::StringRef TUPath) {48  assert(llvm::sys::path::is_absolute(AbsPath) && "the path is relative");49  auto Resolved = URI::resolvePath(AbsPath, TUPath);50  if (!Resolved) {51    elog("URIForFile: failed to resolve path {0} with TU path {1}: "52         "{2}.\nUsing unresolved path.",53         AbsPath, TUPath, Resolved.takeError());54    return URIForFile(std::string(AbsPath));55  }56  return URIForFile(std::move(*Resolved));57}58 59llvm::Expected<URIForFile> URIForFile::fromURI(const URI &U,60                                               llvm::StringRef HintPath) {61  auto Resolved = URI::resolve(U, HintPath);62  if (!Resolved)63    return Resolved.takeError();64  return URIForFile(std::move(*Resolved));65}66 67bool fromJSON(const llvm::json::Value &E, URIForFile &R, llvm::json::Path P) {68  if (auto S = E.getAsString()) {69    auto Parsed = URI::parse(*S);70    if (!Parsed) {71      consumeError(Parsed.takeError());72      P.report("failed to parse URI");73      return false;74    }75    if (Parsed->scheme() != "file" && Parsed->scheme() != "test") {76      P.report("clangd only supports 'file' URI scheme for workspace files");77      return false;78    }79    // "file" and "test" schemes do not require hint path.80    auto U = URIForFile::fromURI(*Parsed, /*HintPath=*/"");81    if (!U) {82      P.report("unresolvable URI");83      consumeError(U.takeError());84      return false;85    }86    R = std::move(*U);87    return true;88  }89  return false;90}91 92llvm::json::Value toJSON(const URIForFile &U) { return U.uri(); }93 94llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const URIForFile &U) {95  return OS << U.uri();96}97 98llvm::json::Value toJSON(const TextDocumentIdentifier &R) {99  return llvm::json::Object{{"uri", R.uri}};100}101 102bool fromJSON(const llvm::json::Value &Params, TextDocumentIdentifier &R,103              llvm::json::Path P) {104  llvm::json::ObjectMapper O(Params, P);105  return O && O.map("uri", R.uri);106}107 108llvm::json::Value toJSON(const VersionedTextDocumentIdentifier &R) {109  auto Result = toJSON(static_cast<const TextDocumentIdentifier &>(R));110  Result.getAsObject()->try_emplace("version", R.version);111  return Result;112}113 114bool fromJSON(const llvm::json::Value &Params,115              VersionedTextDocumentIdentifier &R, llvm::json::Path P) {116  llvm::json::ObjectMapper O(Params, P);117  return fromJSON(Params, static_cast<TextDocumentIdentifier &>(R), P) && O &&118         O.map("version", R.version);119}120 121bool fromJSON(const llvm::json::Value &Params, Position &R,122              llvm::json::Path P) {123  llvm::json::ObjectMapper O(Params, P);124  return O && O.map("line", R.line) && O.map("character", R.character);125}126 127llvm::json::Value toJSON(const Position &P) {128  return llvm::json::Object{129      {"line", P.line},130      {"character", P.character},131  };132}133 134llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &P) {135  return OS << P.line << ':' << P.character;136}137 138bool fromJSON(const llvm::json::Value &Params, Range &R, llvm::json::Path P) {139  llvm::json::ObjectMapper O(Params, P);140  return O && O.map("start", R.start) && O.map("end", R.end);141}142 143llvm::json::Value toJSON(const Range &P) {144  return llvm::json::Object{145      {"start", P.start},146      {"end", P.end},147  };148}149 150llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Range &R) {151  return OS << R.start << '-' << R.end;152}153 154llvm::json::Value toJSON(const Location &P) {155  return llvm::json::Object{156      {"uri", P.uri},157      {"range", P.range},158  };159}160 161llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Location &L) {162  return OS << L.range << '@' << L.uri;163}164 165llvm::json::Value toJSON(const ReferenceLocation &P) {166  llvm::json::Object Result{167      {"uri", P.uri},168      {"range", P.range},169  };170  if (P.containerName)171    Result.insert({"containerName", P.containerName});172  return Result;173}174 175llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,176                              const ReferenceLocation &L) {177  return OS << L.range << '@' << L.uri << " (container: " << L.containerName178            << ")";179}180 181bool fromJSON(const llvm::json::Value &Params, TextDocumentItem &R,182              llvm::json::Path P) {183  llvm::json::ObjectMapper O(Params, P);184  return O && O.map("uri", R.uri) && O.map("languageId", R.languageId) &&185         O.map("version", R.version) && O.map("text", R.text);186}187 188bool fromJSON(const llvm::json::Value &Params, TextEdit &R,189              llvm::json::Path P) {190  llvm::json::ObjectMapper O(Params, P);191  return O && O.map("range", R.range) && O.map("newText", R.newText) &&192         O.mapOptional("annotationId", R.annotationId);193}194 195llvm::json::Value toJSON(const TextEdit &P) {196  llvm::json::Object Result{197      {"range", P.range},198      {"newText", P.newText},199  };200  if (!P.annotationId.empty())201    Result["annotationId"] = P.annotationId;202  return Result;203}204 205bool fromJSON(const llvm::json::Value &Params, ChangeAnnotation &R,206              llvm::json::Path P) {207  llvm::json::ObjectMapper O(Params, P);208  return O && O.map("label", R.label) &&209         O.map("needsConfirmation", R.needsConfirmation) &&210         O.mapOptional("description", R.description);211}212llvm::json::Value toJSON(const ChangeAnnotation & CA) {213  llvm::json::Object Result{{"label", CA.label}};214  if (CA.needsConfirmation)215    Result["needsConfirmation"] = *CA.needsConfirmation;216  if (!CA.description.empty())217    Result["description"] = CA.description;218  return Result;219}220 221bool fromJSON(const llvm::json::Value &Params, TextDocumentEdit &R,222              llvm::json::Path P) {223  llvm::json::ObjectMapper O(Params, P);224  return O && O.map("textDocument", R.textDocument) && O.map("edits", R.edits);225}226llvm::json::Value toJSON(const TextDocumentEdit &P) {227  llvm::json::Object Result{{"textDocument", P.textDocument},228                            {"edits", P.edits}};229  return Result;230}231 232llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) {233  OS << TE.range << " => \"";234  llvm::printEscapedString(TE.newText, OS);235  return OS << '"';236}237 238bool fromJSON(const llvm::json::Value &E, TraceLevel &Out, llvm::json::Path P) {239  if (auto S = E.getAsString()) {240    if (*S == "off") {241      Out = TraceLevel::Off;242      return true;243    }244    if (*S == "messages") {245      Out = TraceLevel::Messages;246      return true;247    }248    if (*S == "verbose") {249      Out = TraceLevel::Verbose;250      return true;251    }252  }253  return false;254}255 256bool fromJSON(const llvm::json::Value &E, SymbolKind &Out, llvm::json::Path P) {257  if (auto T = E.getAsInteger()) {258    if (*T < static_cast<int>(SymbolKind::File) ||259        *T > static_cast<int>(SymbolKind::TypeParameter))260      return false;261    Out = static_cast<SymbolKind>(*T);262    return true;263  }264  return false;265}266 267bool fromJSON(const llvm::json::Value &E, SymbolKindBitset &Out,268              llvm::json::Path P) {269  if (auto *A = E.getAsArray()) {270    for (size_t I = 0; I < A->size(); ++I) {271      SymbolKind KindOut;272      if (fromJSON((*A)[I], KindOut, P.index(I)))273        Out.set(size_t(KindOut));274    }275    return true;276  }277  return false;278}279 280SymbolKind adjustKindToCapability(SymbolKind Kind,281                                  SymbolKindBitset &SupportedSymbolKinds) {282  auto KindVal = static_cast<size_t>(Kind);283  if (KindVal >= SymbolKindMin && KindVal <= SupportedSymbolKinds.size() &&284      SupportedSymbolKinds[KindVal])285    return Kind;286 287  switch (Kind) {288  // Provide some fall backs for common kinds that are close enough.289  case SymbolKind::Struct:290    return SymbolKind::Class;291  case SymbolKind::EnumMember:292    return SymbolKind::Enum;293  default:294    return SymbolKind::String;295  }296}297 298SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind) {299  switch (Kind) {300  // FIXME: for backwards compatibility, the include directive kind is treated301  // the same as Unknown302  case index::SymbolKind::IncludeDirective:303  case index::SymbolKind::Unknown:304    return SymbolKind::Variable;305  case index::SymbolKind::Module:306    return SymbolKind::Module;307  case index::SymbolKind::Namespace:308    return SymbolKind::Namespace;309  case index::SymbolKind::NamespaceAlias:310    return SymbolKind::Namespace;311  case index::SymbolKind::Macro:312    return SymbolKind::String;313  case index::SymbolKind::Enum:314    return SymbolKind::Enum;315  case index::SymbolKind::Struct:316    return SymbolKind::Struct;317  case index::SymbolKind::Class:318    return SymbolKind::Class;319  case index::SymbolKind::Protocol:320    return SymbolKind::Interface;321  case index::SymbolKind::Extension:322    return SymbolKind::Interface;323  case index::SymbolKind::Union:324    return SymbolKind::Class;325  case index::SymbolKind::TypeAlias:326    return SymbolKind::Class;327  case index::SymbolKind::Function:328    return SymbolKind::Function;329  case index::SymbolKind::Variable:330    return SymbolKind::Variable;331  case index::SymbolKind::Field:332    return SymbolKind::Field;333  case index::SymbolKind::EnumConstant:334    return SymbolKind::EnumMember;335  case index::SymbolKind::InstanceMethod:336  case index::SymbolKind::ClassMethod:337  case index::SymbolKind::StaticMethod:338    return SymbolKind::Method;339  case index::SymbolKind::InstanceProperty:340  case index::SymbolKind::ClassProperty:341  case index::SymbolKind::StaticProperty:342    return SymbolKind::Property;343  case index::SymbolKind::Constructor:344  case index::SymbolKind::Destructor:345    return SymbolKind::Constructor;346  case index::SymbolKind::ConversionFunction:347    return SymbolKind::Function;348  case index::SymbolKind::Parameter:349  case index::SymbolKind::NonTypeTemplateParm:350    return SymbolKind::Variable;351  case index::SymbolKind::Using:352    return SymbolKind::Namespace;353  case index::SymbolKind::TemplateTemplateParm:354  case index::SymbolKind::TemplateTypeParm:355    return SymbolKind::TypeParameter;356  case index::SymbolKind::Concept:357    return SymbolKind::Interface;358  }359  llvm_unreachable("invalid symbol kind");360}361 362bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R,363              llvm::json::Path P) {364  const llvm::json::Object *O = Params.getAsObject();365  if (!O) {366    P.report("expected object");367    return false;368  }369  if (auto *TextDocument = O->getObject("textDocument")) {370    if (auto *SemanticHighlighting =371            TextDocument->getObject("semanticHighlightingCapabilities")) {372      if (auto SemanticHighlightingSupport =373              SemanticHighlighting->getBoolean("semanticHighlighting"))374        R.TheiaSemanticHighlighting = *SemanticHighlightingSupport;375    }376    if (auto *InactiveRegions =377            TextDocument->getObject("inactiveRegionsCapabilities")) {378      if (auto InactiveRegionsSupport =379              InactiveRegions->getBoolean("inactiveRegions")) {380        R.InactiveRegions = *InactiveRegionsSupport;381      }382    }383    if (TextDocument->getObject("semanticTokens"))384      R.SemanticTokens = true;385    if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) {386      if (auto CategorySupport = Diagnostics->getBoolean("categorySupport"))387        R.DiagnosticCategory = *CategorySupport;388      if (auto CodeActions = Diagnostics->getBoolean("codeActionsInline"))389        R.DiagnosticFixes = *CodeActions;390      if (auto RelatedInfo = Diagnostics->getBoolean("relatedInformation"))391        R.DiagnosticRelatedInformation = *RelatedInfo;392    }393    if (auto *References = TextDocument->getObject("references"))394      if (auto ContainerSupport = References->getBoolean("container"))395        R.ReferenceContainer = *ContainerSupport;396    if (auto *Completion = TextDocument->getObject("completion")) {397      if (auto *Item = Completion->getObject("completionItem")) {398        if (auto SnippetSupport = Item->getBoolean("snippetSupport"))399          R.CompletionSnippets = *SnippetSupport;400        if (auto LabelDetailsSupport = Item->getBoolean("labelDetailsSupport"))401          R.CompletionLabelDetail = *LabelDetailsSupport;402        if (const auto *DocumentationFormat =403                Item->getArray("documentationFormat")) {404          for (const auto &Format : *DocumentationFormat) {405            if (fromJSON(Format, R.CompletionDocumentationFormat, P))406              break;407          }408        }409      }410      if (auto *ItemKind = Completion->getObject("completionItemKind")) {411        if (auto *ValueSet = ItemKind->get("valueSet")) {412          R.CompletionItemKinds.emplace();413          if (!fromJSON(*ValueSet, *R.CompletionItemKinds,414                        P.field("textDocument")415                            .field("completion")416                            .field("completionItemKind")417                            .field("valueSet")))418            return false;419        }420      }421      if (auto EditsNearCursor = Completion->getBoolean("editsNearCursor"))422        R.CompletionFixes = *EditsNearCursor;423    }424    if (auto *CodeAction = TextDocument->getObject("codeAction")) {425      if (CodeAction->getObject("codeActionLiteralSupport"))426        R.CodeActionStructure = true;427    }428    if (auto *DocumentSymbol = TextDocument->getObject("documentSymbol")) {429      if (auto HierarchicalSupport =430              DocumentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))431        R.HierarchicalDocumentSymbol = *HierarchicalSupport;432    }433    if (auto *Hover = TextDocument->getObject("hover")) {434      if (auto *ContentFormat = Hover->getArray("contentFormat")) {435        for (const auto &Format : *ContentFormat) {436          if (fromJSON(Format, R.HoverContentFormat, P))437            break;438        }439      }440    }441    if (auto *Help = TextDocument->getObject("signatureHelp")) {442      R.HasSignatureHelp = true;443      if (auto *Info = Help->getObject("signatureInformation")) {444        if (auto *Parameter = Info->getObject("parameterInformation")) {445          if (auto OffsetSupport = Parameter->getBoolean("labelOffsetSupport"))446            R.OffsetsInSignatureHelp = *OffsetSupport;447        }448        if (const auto *DocumentationFormat =449                Info->getArray("documentationFormat")) {450          for (const auto &Format : *DocumentationFormat) {451            if (fromJSON(Format, R.SignatureHelpDocumentationFormat, P))452              break;453          }454        }455      }456    }457    if (auto *Folding = TextDocument->getObject("foldingRange")) {458      if (auto LineFolding = Folding->getBoolean("lineFoldingOnly"))459        R.LineFoldingOnly = *LineFolding;460    }461    if (auto *Rename = TextDocument->getObject("rename")) {462      if (auto RenameSupport = Rename->getBoolean("prepareSupport"))463        R.RenamePrepareSupport = *RenameSupport;464    }465  }466  if (auto *Workspace = O->getObject("workspace")) {467    if (auto *Symbol = Workspace->getObject("symbol")) {468      if (auto *SymbolKind = Symbol->getObject("symbolKind")) {469        if (auto *ValueSet = SymbolKind->get("valueSet")) {470          R.WorkspaceSymbolKinds.emplace();471          if (!fromJSON(*ValueSet, *R.WorkspaceSymbolKinds,472                        P.field("workspace")473                            .field("symbol")474                            .field("symbolKind")475                            .field("valueSet")))476            return false;477        }478      }479    }480    if (auto *SemanticTokens = Workspace->getObject("semanticTokens")) {481      if (auto RefreshSupport = SemanticTokens->getBoolean("refreshSupport"))482        R.SemanticTokenRefreshSupport = *RefreshSupport;483    }484    if (auto *WorkspaceEdit = Workspace->getObject("workspaceEdit")) {485      if (auto DocumentChanges = WorkspaceEdit->getBoolean("documentChanges"))486        R.DocumentChanges = *DocumentChanges;487      if (WorkspaceEdit->getObject("changeAnnotationSupport")) {488        R.ChangeAnnotation = true;489      }490    }491  }492  if (auto *Window = O->getObject("window")) {493    if (auto WorkDoneProgress = Window->getBoolean("workDoneProgress"))494      R.WorkDoneProgress = *WorkDoneProgress;495    if (auto Implicit = Window->getBoolean("implicitWorkDoneProgressCreate"))496      R.ImplicitProgressCreation = *Implicit;497  }498  if (auto *General = O->getObject("general")) {499    if (auto *StaleRequestSupport = General->getObject("staleRequestSupport")) {500      if (auto Cancel = StaleRequestSupport->getBoolean("cancel"))501        R.CancelsStaleRequests = *Cancel;502    }503    if (auto *PositionEncodings = General->get("positionEncodings")) {504      R.PositionEncodings.emplace();505      if (!fromJSON(*PositionEncodings, *R.PositionEncodings,506                    P.field("general").field("positionEncodings")))507        return false;508    }509  }510  if (auto *OffsetEncoding = O->get("offsetEncoding")) {511    R.PositionEncodings.emplace();512    elog("offsetEncoding capability is a deprecated clangd extension that'll "513         "go away with clangd 23. Migrate to standard positionEncodings "514         "capability introduced by LSP 3.17");515    if (!fromJSON(*OffsetEncoding, *R.PositionEncodings,516                  P.field("offsetEncoding")))517      return false;518  }519 520  if (auto *Experimental = O->getObject("experimental")) {521    if (auto *TextDocument = Experimental->getObject("textDocument")) {522      if (auto *Completion = TextDocument->getObject("completion")) {523        if (auto EditsNearCursor = Completion->getBoolean("editsNearCursor"))524          R.CompletionFixes |= *EditsNearCursor;525      }526      if (auto *References = TextDocument->getObject("references")) {527        if (auto ContainerSupport = References->getBoolean("container")) {528          R.ReferenceContainer |= *ContainerSupport;529        }530      }531      if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) {532        if (auto CodeActions = Diagnostics->getBoolean("codeActionsInline")) {533          R.DiagnosticFixes |= *CodeActions;534        }535      }536      if (auto *InactiveRegions =537              TextDocument->getObject("inactiveRegionsCapabilities")) {538        if (auto InactiveRegionsSupport =539                InactiveRegions->getBoolean("inactiveRegions")) {540          R.InactiveRegions |= *InactiveRegionsSupport;541        }542      }543    }544    if (auto *Window = Experimental->getObject("window")) {545      if (auto Implicit =546              Window->getBoolean("implicitWorkDoneProgressCreate")) {547        R.ImplicitProgressCreation |= *Implicit;548      }549    }550    if (auto *OffsetEncoding = Experimental->get("offsetEncoding")) {551      R.PositionEncodings.emplace();552      elog("offsetEncoding capability is a deprecated clangd extension that'll "553           "go away with clangd 23. Migrate to standard positionEncodings "554           "capability introduced by LSP 3.17");555      if (!fromJSON(*OffsetEncoding, *R.PositionEncodings,556                    P.field("offsetEncoding")))557        return false;558    }559  }560 561  return true;562}563 564bool fromJSON(const llvm::json::Value &Params, InitializeParams &R,565              llvm::json::Path P) {566  llvm::json::ObjectMapper O(Params, P);567  if (!O)568    return false;569  // We deliberately don't fail if we can't parse individual fields.570  // Failing to handle a slightly malformed initialize would be a disaster.571  O.map("processId", R.processId);572  O.map("rootUri", R.rootUri);573  O.map("rootPath", R.rootPath);574  O.map("capabilities", R.capabilities);575  if (auto *RawCaps = Params.getAsObject()->getObject("capabilities"))576    R.rawCapabilities = *RawCaps;577  O.map("trace", R.trace);578  O.map("initializationOptions", R.initializationOptions);579  return true;580}581 582llvm::json::Value toJSON(const WorkDoneProgressCreateParams &P) {583  return llvm::json::Object{{"token", P.token}};584}585 586llvm::json::Value toJSON(const WorkDoneProgressBegin &P) {587  llvm::json::Object Result{588      {"kind", "begin"},589      {"title", P.title},590  };591  if (P.cancellable)592    Result["cancellable"] = true;593  if (P.percentage)594    Result["percentage"] = 0;595 596  // FIXME: workaround for older gcc/clang597  return std::move(Result);598}599 600llvm::json::Value toJSON(const WorkDoneProgressReport &P) {601  llvm::json::Object Result{{"kind", "report"}};602  if (P.cancellable)603    Result["cancellable"] = *P.cancellable;604  if (P.message)605    Result["message"] = *P.message;606  if (P.percentage)607    Result["percentage"] = *P.percentage;608  // FIXME: workaround for older gcc/clang609  return std::move(Result);610}611 612llvm::json::Value toJSON(const WorkDoneProgressEnd &P) {613  llvm::json::Object Result{{"kind", "end"}};614  if (P.message)615    Result["message"] = *P.message;616  // FIXME: workaround for older gcc/clang617  return std::move(Result);618}619 620llvm::json::Value toJSON(const MessageType &R) {621  return static_cast<int64_t>(R);622}623 624llvm::json::Value toJSON(const ShowMessageParams &R) {625  return llvm::json::Object{{"type", R.type}, {"message", R.message}};626}627 628bool fromJSON(const llvm::json::Value &Params, DidOpenTextDocumentParams &R,629              llvm::json::Path P) {630  llvm::json::ObjectMapper O(Params, P);631  return O && O.map("textDocument", R.textDocument);632}633 634bool fromJSON(const llvm::json::Value &Params, DidCloseTextDocumentParams &R,635              llvm::json::Path P) {636  llvm::json::ObjectMapper O(Params, P);637  return O && O.map("textDocument", R.textDocument);638}639 640bool fromJSON(const llvm::json::Value &Params, DidSaveTextDocumentParams &R,641              llvm::json::Path P) {642  llvm::json::ObjectMapper O(Params, P);643  return O && O.map("textDocument", R.textDocument);644}645 646bool fromJSON(const llvm::json::Value &Params, DidChangeTextDocumentParams &R,647              llvm::json::Path P) {648  llvm::json::ObjectMapper O(Params, P);649  return O && O.map("textDocument", R.textDocument) &&650         O.map("contentChanges", R.contentChanges) &&651         O.map("wantDiagnostics", R.wantDiagnostics) &&652         mapOptOrNull(Params, "forceRebuild", R.forceRebuild, P);653}654 655bool fromJSON(const llvm::json::Value &E, FileChangeType &Out,656              llvm::json::Path P) {657  if (auto T = E.getAsInteger()) {658    if (*T < static_cast<int>(FileChangeType::Created) ||659        *T > static_cast<int>(FileChangeType::Deleted))660      return false;661    Out = static_cast<FileChangeType>(*T);662    return true;663  }664  return false;665}666 667bool fromJSON(const llvm::json::Value &Params, FileEvent &R,668              llvm::json::Path P) {669  llvm::json::ObjectMapper O(Params, P);670  return O && O.map("uri", R.uri) && O.map("type", R.type);671}672 673bool fromJSON(const llvm::json::Value &Params, DidChangeWatchedFilesParams &R,674              llvm::json::Path P) {675  llvm::json::ObjectMapper O(Params, P);676  return O && O.map("changes", R.changes);677}678 679bool fromJSON(const llvm::json::Value &Params,680              TextDocumentContentChangeEvent &R, llvm::json::Path P) {681  llvm::json::ObjectMapper O(Params, P);682  return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&683         O.map("text", R.text);684}685 686bool fromJSON(const llvm::json::Value &Params, DocumentRangeFormattingParams &R,687              llvm::json::Path P) {688  llvm::json::ObjectMapper O(Params, P);689  return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);690  ;691}692 693bool fromJSON(const llvm::json::Value &Params,694              DocumentRangesFormattingParams &R, llvm::json::Path P) {695  llvm::json::ObjectMapper O(Params, P);696  return O && O.map("textDocument", R.textDocument) &&697         O.map("ranges", R.ranges);698  ;699}700 701bool fromJSON(const llvm::json::Value &Params,702              DocumentOnTypeFormattingParams &R, llvm::json::Path P) {703  llvm::json::ObjectMapper O(Params, P);704  return O && O.map("textDocument", R.textDocument) &&705         O.map("position", R.position) && O.map("ch", R.ch);706}707 708bool fromJSON(const llvm::json::Value &Params, DocumentFormattingParams &R,709              llvm::json::Path P) {710  llvm::json::ObjectMapper O(Params, P);711  return O && O.map("textDocument", R.textDocument);712}713 714bool fromJSON(const llvm::json::Value &Params, DocumentSymbolParams &R,715              llvm::json::Path P) {716  llvm::json::ObjectMapper O(Params, P);717  return O && O.map("textDocument", R.textDocument);718}719 720llvm::json::Value toJSON(const DiagnosticRelatedInformation &DRI) {721  return llvm::json::Object{722      {"location", DRI.location},723      {"message", DRI.message},724  };725}726 727llvm::json::Value toJSON(DiagnosticTag Tag) { return static_cast<int>(Tag); }728 729llvm::json::Value toJSON(const CodeDescription &D) {730  return llvm::json::Object{{"href", D.href}};731}732 733llvm::json::Value toJSON(const Diagnostic &D) {734  llvm::json::Object Diag{735      {"range", D.range},736      {"severity", D.severity},737      {"message", D.message},738  };739  if (D.category)740    Diag["category"] = *D.category;741  if (D.codeActions)742    Diag["codeActions"] = D.codeActions;743  if (!D.code.empty())744    Diag["code"] = D.code;745  if (D.codeDescription)746    Diag["codeDescription"] = *D.codeDescription;747  if (!D.source.empty())748    Diag["source"] = D.source;749  if (D.relatedInformation)750    Diag["relatedInformation"] = *D.relatedInformation;751  if (!D.data.empty())752    Diag["data"] = llvm::json::Object(D.data);753  if (!D.tags.empty())754    Diag["tags"] = llvm::json::Array{D.tags};755  // FIXME: workaround for older gcc/clang756  return std::move(Diag);757}758 759bool fromJSON(const llvm::json::Value &Params, Diagnostic &R,760              llvm::json::Path P) {761  llvm::json::ObjectMapper O(Params, P);762  if (!O)763    return false;764  if (auto *Data = Params.getAsObject()->getObject("data"))765    R.data = *Data;766  return O.map("range", R.range) && O.map("message", R.message) &&767         mapOptOrNull(Params, "severity", R.severity, P) &&768         mapOptOrNull(Params, "category", R.category, P) &&769         mapOptOrNull(Params, "code", R.code, P) &&770         mapOptOrNull(Params, "source", R.source, P);771}772 773llvm::json::Value toJSON(const PublishDiagnosticsParams &PDP) {774  llvm::json::Object Result{775      {"uri", PDP.uri},776      {"diagnostics", PDP.diagnostics},777  };778  if (PDP.version)779    Result["version"] = PDP.version;780  return std::move(Result);781}782 783bool fromJSON(const llvm::json::Value &Params, CodeActionContext &R,784              llvm::json::Path P) {785  llvm::json::ObjectMapper O(Params, P);786  if (!O || !O.map("diagnostics", R.diagnostics))787    return false;788  O.map("only", R.only);789  return true;790}791 792llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) {793  OS << D.range << " [";794  switch (D.severity) {795  case 1:796    OS << "error";797    break;798  case 2:799    OS << "warning";800    break;801  case 3:802    OS << "note";803    break;804  case 4:805    OS << "remark";806    break;807  default:808    OS << "diagnostic";809    break;810  }811  return OS << '(' << D.severity << "): " << D.message << "]";812}813 814bool fromJSON(const llvm::json::Value &Params, CodeActionParams &R,815              llvm::json::Path P) {816  llvm::json::ObjectMapper O(Params, P);817  return O && O.map("textDocument", R.textDocument) &&818         O.map("range", R.range) && O.map("context", R.context);819}820 821bool fromJSON(const llvm::json::Value &Params, WorkspaceEdit &R,822              llvm::json::Path P) {823  llvm::json::ObjectMapper O(Params, P);824  return O && O.map("changes", R.changes) &&825         O.map("documentChanges", R.documentChanges) &&826         O.mapOptional("changeAnnotations", R.changeAnnotations);827}828 829bool fromJSON(const llvm::json::Value &Params, ExecuteCommandParams &R,830              llvm::json::Path P) {831  llvm::json::ObjectMapper O(Params, P);832  if (!O || !O.map("command", R.command))833    return false;834 835  const auto *Args = Params.getAsObject()->get("arguments");836  if (!Args)837    return true; // Missing args is ok, argument is null.838  const auto *ArgsArray = Args->getAsArray();839  if (!ArgsArray) {840    P.field("arguments").report("expected array");841    return false;842  }843  if (ArgsArray->size() > 1) {844    P.field("arguments").report("Command should have 0 or 1 argument");845    return false;846  }847  if (ArgsArray->size() == 1) {848    R.argument = ArgsArray->front();849  }850  return true;851}852 853llvm::json::Value toJSON(const SymbolInformation &P) {854  llvm::json::Object O{855      {"name", P.name},856      {"kind", static_cast<int>(P.kind)},857      {"location", P.location},858      {"containerName", P.containerName},859  };860  if (P.score)861    O["score"] = *P.score;862  return std::move(O);863}864 865llvm::raw_ostream &operator<<(llvm::raw_ostream &O,866                              const SymbolInformation &SI) {867  O << SI.containerName << "::" << SI.name << " - " << toJSON(SI);868  return O;869}870 871bool operator==(const SymbolDetails &LHS, const SymbolDetails &RHS) {872  return LHS.name == RHS.name && LHS.containerName == RHS.containerName &&873         LHS.USR == RHS.USR && LHS.ID == RHS.ID &&874         LHS.declarationRange == RHS.declarationRange &&875         LHS.definitionRange == RHS.definitionRange;876}877 878llvm::json::Value toJSON(const SymbolDetails &P) {879  llvm::json::Object Result{{"name", llvm::json::Value(nullptr)},880                            {"containerName", llvm::json::Value(nullptr)},881                            {"usr", llvm::json::Value(nullptr)},882                            {"id", llvm::json::Value(nullptr)}};883 884  if (!P.name.empty())885    Result["name"] = P.name;886 887  if (!P.containerName.empty())888    Result["containerName"] = P.containerName;889 890  if (!P.USR.empty())891    Result["usr"] = P.USR;892 893  if (P.ID)894    Result["id"] = P.ID.str();895 896  if (P.declarationRange)897    Result["declarationRange"] = *P.declarationRange;898 899  if (P.definitionRange)900    Result["definitionRange"] = *P.definitionRange;901 902  // FIXME: workaround for older gcc/clang903  return std::move(Result);904}905 906llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const SymbolDetails &S) {907  if (!S.containerName.empty()) {908    O << S.containerName;909    llvm::StringRef ContNameRef;910    if (!ContNameRef.ends_with("::")) {911      O << " ";912    }913  }914  O << S.name << " - " << toJSON(S);915  return O;916}917 918bool fromJSON(const llvm::json::Value &Params, WorkspaceSymbolParams &R,919              llvm::json::Path P) {920  llvm::json::ObjectMapper O(Params, P);921  return O && O.map("query", R.query) &&922         mapOptOrNull(Params, "limit", R.limit, P);923}924 925llvm::json::Value toJSON(const Command &C) {926  auto Cmd = llvm::json::Object{{"title", C.title}, {"command", C.command}};927  if (!C.argument.getAsNull())928    Cmd["arguments"] = llvm::json::Array{C.argument};929  return std::move(Cmd);930}931 932const llvm::StringLiteral CodeAction::QUICKFIX_KIND = "quickfix";933const llvm::StringLiteral CodeAction::REFACTOR_KIND = "refactor";934const llvm::StringLiteral CodeAction::INFO_KIND = "info";935 936llvm::json::Value toJSON(const CodeAction &CA) {937  auto CodeAction = llvm::json::Object{{"title", CA.title}};938  if (CA.kind)939    CodeAction["kind"] = *CA.kind;940  if (CA.diagnostics)941    CodeAction["diagnostics"] = llvm::json::Array(*CA.diagnostics);942  if (CA.isPreferred)943    CodeAction["isPreferred"] = true;944  if (CA.edit)945    CodeAction["edit"] = *CA.edit;946  if (CA.command)947    CodeAction["command"] = *CA.command;948  return std::move(CodeAction);949}950 951llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const DocumentSymbol &S) {952  return O << S.name << " - " << toJSON(S);953}954 955llvm::json::Value toJSON(const DocumentSymbol &S) {956  llvm::json::Object Result{{"name", S.name},957                            {"kind", static_cast<int>(S.kind)},958                            {"range", S.range},959                            {"selectionRange", S.selectionRange}};960 961  if (!S.detail.empty())962    Result["detail"] = S.detail;963  if (!S.children.empty())964    Result["children"] = S.children;965  if (S.deprecated)966    Result["deprecated"] = true;967  // FIXME: workaround for older gcc/clang968  return std::move(Result);969}970 971llvm::json::Value toJSON(const WorkspaceEdit &WE) {972  llvm::json::Object Result;973  if (WE.changes) {974    llvm::json::Object FileChanges;975    for (auto &Change : *WE.changes)976      FileChanges[Change.first] = llvm::json::Array(Change.second);977    Result["changes"] = std::move(FileChanges);978  }979  if (WE.documentChanges)980    Result["documentChanges"] = *WE.documentChanges;981  if (!WE.changeAnnotations.empty()) {982    llvm::json::Object ChangeAnnotations;983    for (auto &Annotation : WE.changeAnnotations)984      ChangeAnnotations[Annotation.first] = Annotation.second;985    Result["changeAnnotations"] = std::move(ChangeAnnotations);986  }987  return Result;988}989 990bool fromJSON(const llvm::json::Value &Params, TweakArgs &A,991              llvm::json::Path P) {992  llvm::json::ObjectMapper O(Params, P);993  return O && O.map("file", A.file) && O.map("selection", A.selection) &&994         O.map("tweakID", A.tweakID);995}996 997llvm::json::Value toJSON(const TweakArgs &A) {998  return llvm::json::Object{999      {"tweakID", A.tweakID}, {"selection", A.selection}, {"file", A.file}};1000}1001 1002llvm::json::Value toJSON(const ApplyWorkspaceEditParams &Params) {1003  return llvm::json::Object{{"edit", Params.edit}};1004}1005 1006bool fromJSON(const llvm::json::Value &Response, ApplyWorkspaceEditResponse &R,1007              llvm::json::Path P) {1008  llvm::json::ObjectMapper O(Response, P);1009  return O && O.map("applied", R.applied) &&1010         O.map("failureReason", R.failureReason);1011}1012 1013bool fromJSON(const llvm::json::Value &Params, TextDocumentPositionParams &R,1014              llvm::json::Path P) {1015  llvm::json::ObjectMapper O(Params, P);1016  return O && O.map("textDocument", R.textDocument) &&1017         O.map("position", R.position);1018}1019 1020bool fromJSON(const llvm::json::Value &Params, CompletionContext &R,1021              llvm::json::Path P) {1022  llvm::json::ObjectMapper O(Params, P);1023  int TriggerKind;1024  if (!O || !O.map("triggerKind", TriggerKind) ||1025      !mapOptOrNull(Params, "triggerCharacter", R.triggerCharacter, P))1026    return false;1027  R.triggerKind = static_cast<CompletionTriggerKind>(TriggerKind);1028  return true;1029}1030 1031bool fromJSON(const llvm::json::Value &Params, CompletionParams &R,1032              llvm::json::Path P) {1033  if (!fromJSON(Params, static_cast<TextDocumentPositionParams &>(R), P) ||1034      !mapOptOrNull(Params, "limit", R.limit, P))1035    return false;1036  if (auto *Context = Params.getAsObject()->get("context"))1037    return fromJSON(*Context, R.context, P.field("context"));1038  return true;1039}1040 1041static llvm::StringRef toTextKind(MarkupKind Kind) {1042  switch (Kind) {1043  case MarkupKind::PlainText:1044    return "plaintext";1045  case MarkupKind::Markdown:1046    return "markdown";1047  }1048  llvm_unreachable("Invalid MarkupKind");1049}1050 1051bool fromJSON(const llvm::json::Value &V, MarkupKind &K, llvm::json::Path P) {1052  auto Str = V.getAsString();1053  if (!Str) {1054    P.report("expected string");1055    return false;1056  }1057  if (*Str == "plaintext")1058    K = MarkupKind::PlainText;1059  else if (*Str == "markdown")1060    K = MarkupKind::Markdown;1061  else {1062    P.report("unknown markup kind");1063    return false;1064  }1065  return true;1066}1067 1068llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind K) {1069  return OS << toTextKind(K);1070}1071 1072llvm::json::Value toJSON(const MarkupContent &MC) {1073  if (MC.value.empty())1074    return nullptr;1075 1076  return llvm::json::Object{1077      {"kind", toTextKind(MC.kind)},1078      {"value", MC.value},1079  };1080}1081 1082llvm::json::Value toJSON(const Hover &H) {1083  llvm::json::Object Result{{"contents", toJSON(H.contents)}};1084 1085  if (H.range)1086    Result["range"] = toJSON(*H.range);1087 1088  return std::move(Result);1089}1090 1091bool fromJSON(const llvm::json::Value &E, CompletionItemKind &Out,1092              llvm::json::Path P) {1093  if (auto T = E.getAsInteger()) {1094    if (*T < static_cast<int>(CompletionItemKind::Text) ||1095        *T > static_cast<int>(CompletionItemKind::TypeParameter))1096      return false;1097    Out = static_cast<CompletionItemKind>(*T);1098    return true;1099  }1100  return false;1101}1102 1103CompletionItemKind1104adjustKindToCapability(CompletionItemKind Kind,1105                       CompletionItemKindBitset &SupportedCompletionItemKinds) {1106  auto KindVal = static_cast<size_t>(Kind);1107  if (KindVal >= CompletionItemKindMin &&1108      KindVal <= SupportedCompletionItemKinds.size() &&1109      SupportedCompletionItemKinds[KindVal])1110    return Kind;1111 1112  switch (Kind) {1113  // Provide some fall backs for common kinds that are close enough.1114  case CompletionItemKind::Folder:1115    return CompletionItemKind::File;1116  case CompletionItemKind::EnumMember:1117    return CompletionItemKind::Enum;1118  case CompletionItemKind::Struct:1119    return CompletionItemKind::Class;1120  default:1121    return CompletionItemKind::Text;1122  }1123}1124 1125bool fromJSON(const llvm::json::Value &E, CompletionItemKindBitset &Out,1126              llvm::json::Path P) {1127  if (auto *A = E.getAsArray()) {1128    for (size_t I = 0; I < A->size(); ++I) {1129      CompletionItemKind KindOut;1130      if (fromJSON((*A)[I], KindOut, P.index(I)))1131        Out.set(size_t(KindOut));1132    }1133    return true;1134  }1135  return false;1136}1137 1138llvm::json::Value toJSON(const CompletionItemLabelDetails &CD) {1139  llvm::json::Object Result;1140  if (!CD.detail.empty())1141    Result["detail"] = CD.detail;1142  if (!CD.description.empty())1143    Result["description"] = CD.description;1144  return Result;1145}1146 1147void removeCompletionLabelDetails(CompletionItem &C) {1148  if (!C.labelDetails)1149    return;1150  if (!C.labelDetails->detail.empty())1151    C.label += C.labelDetails->detail;1152  if (!C.labelDetails->description.empty())1153    C.label = C.labelDetails->description + C.label;1154  C.labelDetails.reset();1155}1156 1157llvm::json::Value toJSON(const CompletionItem &CI) {1158  assert(!CI.label.empty() && "completion item label is required");1159  llvm::json::Object Result{{"label", CI.label}};1160  if (CI.kind != CompletionItemKind::Missing)1161    Result["kind"] = static_cast<int>(CI.kind);1162  if (!CI.detail.empty())1163    Result["detail"] = CI.detail;1164  if (CI.labelDetails)1165    Result["labelDetails"] = *CI.labelDetails;1166  if (CI.documentation)1167    Result["documentation"] = CI.documentation;1168  if (!CI.sortText.empty())1169    Result["sortText"] = CI.sortText;1170  if (!CI.filterText.empty())1171    Result["filterText"] = CI.filterText;1172  if (!CI.insertText.empty())1173    Result["insertText"] = CI.insertText;1174  if (CI.insertTextFormat != InsertTextFormat::Missing)1175    Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);1176  if (CI.textEdit)1177    Result["textEdit"] = *CI.textEdit;1178  if (!CI.additionalTextEdits.empty())1179    Result["additionalTextEdits"] = llvm::json::Array(CI.additionalTextEdits);1180  if (CI.deprecated)1181    Result["deprecated"] = CI.deprecated;1182  Result["score"] = CI.score;1183  return std::move(Result);1184}1185 1186llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) {1187  O << I.label << " - " << toJSON(I);1188  return O;1189}1190 1191bool operator<(const CompletionItem &L, const CompletionItem &R) {1192  return (L.sortText.empty() ? L.label : L.sortText) <1193         (R.sortText.empty() ? R.label : R.sortText);1194}1195 1196llvm::json::Value toJSON(const CompletionList &L) {1197  return llvm::json::Object{1198      {"isIncomplete", L.isIncomplete},1199      {"items", llvm::json::Array(L.items)},1200  };1201}1202 1203llvm::json::Value toJSON(const ParameterInformation &PI) {1204  assert((PI.labelOffsets || !PI.labelString.empty()) &&1205         "parameter information label is required");1206  llvm::json::Object Result;1207  if (PI.labelOffsets)1208    Result["label"] =1209        llvm::json::Array({PI.labelOffsets->first, PI.labelOffsets->second});1210  else1211    Result["label"] = PI.labelString;1212  if (!PI.documentation.empty())1213    Result["documentation"] = PI.documentation;1214  return std::move(Result);1215}1216 1217llvm::json::Value toJSON(const SignatureInformation &SI) {1218  assert(!SI.label.empty() && "signature information label is required");1219  llvm::json::Object Result{1220      {"label", SI.label},1221      {"parameters", llvm::json::Array(SI.parameters)},1222  };1223  if (!SI.documentation.value.empty())1224    Result["documentation"] = SI.documentation;1225  return std::move(Result);1226}1227 1228llvm::raw_ostream &operator<<(llvm::raw_ostream &O,1229                              const SignatureInformation &I) {1230  O << I.label << " - " << toJSON(I);1231  return O;1232}1233 1234llvm::json::Value toJSON(const SignatureHelp &SH) {1235  assert(SH.activeSignature >= 0 &&1236         "Unexpected negative value for number of active signatures.");1237  assert(SH.activeParameter >= 0 &&1238         "Unexpected negative value for active parameter index");1239  return llvm::json::Object{1240      {"activeSignature", SH.activeSignature},1241      {"activeParameter", SH.activeParameter},1242      {"signatures", llvm::json::Array(SH.signatures)},1243  };1244}1245 1246bool fromJSON(const llvm::json::Value &Params, RenameParams &R,1247              llvm::json::Path P) {1248  llvm::json::ObjectMapper O(Params, P);1249  return O && O.map("textDocument", R.textDocument) &&1250         O.map("position", R.position) && O.map("newName", R.newName);1251}1252 1253llvm::json::Value toJSON(const RenameParams &R) {1254  return llvm::json::Object{1255      {"textDocument", R.textDocument},1256      {"position", R.position},1257      {"newName", R.newName},1258  };1259}1260 1261llvm::json::Value toJSON(const PrepareRenameResult &PRR) {1262  if (PRR.placeholder.empty())1263    return toJSON(PRR.range);1264  return llvm::json::Object{1265      {"range", toJSON(PRR.range)},1266      {"placeholder", PRR.placeholder},1267  };1268}1269 1270llvm::json::Value toJSON(const DocumentHighlight &DH) {1271  return llvm::json::Object{1272      {"range", toJSON(DH.range)},1273      {"kind", static_cast<int>(DH.kind)},1274  };1275}1276 1277llvm::json::Value toJSON(const FileStatus &FStatus) {1278  return llvm::json::Object{1279      {"uri", FStatus.uri},1280      {"state", FStatus.state},1281  };1282}1283 1284constexpr unsigned SemanticTokenEncodingSize = 5;1285static llvm::json::Value encodeTokens(llvm::ArrayRef<SemanticToken> Toks) {1286  llvm::json::Array Result;1287  Result.reserve(SemanticTokenEncodingSize * Toks.size());1288  for (const auto &Tok : Toks) {1289    Result.push_back(Tok.deltaLine);1290    Result.push_back(Tok.deltaStart);1291    Result.push_back(Tok.length);1292    Result.push_back(Tok.tokenType);1293    Result.push_back(Tok.tokenModifiers);1294  }1295  assert(Result.size() == SemanticTokenEncodingSize * Toks.size());1296  return std::move(Result);1297}1298 1299bool operator==(const SemanticToken &L, const SemanticToken &R) {1300  return std::tie(L.deltaLine, L.deltaStart, L.length, L.tokenType,1301                  L.tokenModifiers) == std::tie(R.deltaLine, R.deltaStart,1302                                                R.length, R.tokenType,1303                                                R.tokenModifiers);1304}1305 1306llvm::json::Value toJSON(const SemanticTokens &Tokens) {1307  return llvm::json::Object{{"resultId", Tokens.resultId},1308                            {"data", encodeTokens(Tokens.tokens)}};1309}1310 1311llvm::json::Value toJSON(const SemanticTokensEdit &Edit) {1312  return llvm::json::Object{1313      {"start", SemanticTokenEncodingSize * Edit.startToken},1314      {"deleteCount", SemanticTokenEncodingSize * Edit.deleteTokens},1315      {"data", encodeTokens(Edit.tokens)}};1316}1317 1318llvm::json::Value toJSON(const SemanticTokensOrDelta &TE) {1319  llvm::json::Object Result{{"resultId", TE.resultId}};1320  if (TE.edits)1321    Result["edits"] = *TE.edits;1322  if (TE.tokens)1323    Result["data"] = encodeTokens(*TE.tokens);1324  return std::move(Result);1325}1326 1327bool fromJSON(const llvm::json::Value &Params, SemanticTokensParams &R,1328              llvm::json::Path P) {1329  llvm::json::ObjectMapper O(Params, P);1330  return O && O.map("textDocument", R.textDocument);1331}1332 1333bool fromJSON(const llvm::json::Value &Params, SemanticTokensDeltaParams &R,1334              llvm::json::Path P) {1335  llvm::json::ObjectMapper O(Params, P);1336  return O && O.map("textDocument", R.textDocument) &&1337         O.map("previousResultId", R.previousResultId);1338}1339 1340llvm::json::Value toJSON(const InactiveRegionsParams &InactiveRegions) {1341  return llvm::json::Object{1342      {"textDocument", InactiveRegions.TextDocument},1343      {"regions", std::move(InactiveRegions.InactiveRegions)}};1344}1345 1346llvm::raw_ostream &operator<<(llvm::raw_ostream &O,1347                              const DocumentHighlight &V) {1348  O << V.range;1349  if (V.kind == DocumentHighlightKind::Read)1350    O << "(r)";1351  if (V.kind == DocumentHighlightKind::Write)1352    O << "(w)";1353  return O;1354}1355 1356bool fromJSON(const llvm::json::Value &Params,1357              DidChangeConfigurationParams &CCP, llvm::json::Path P) {1358  llvm::json::ObjectMapper O(Params, P);1359  return O && O.map("settings", CCP.settings);1360}1361 1362bool fromJSON(const llvm::json::Value &Params, ClangdCompileCommand &CDbUpdate,1363              llvm::json::Path P) {1364  llvm::json::ObjectMapper O(Params, P);1365  return O && O.map("workingDirectory", CDbUpdate.workingDirectory) &&1366         O.map("compilationCommand", CDbUpdate.compilationCommand);1367}1368 1369bool fromJSON(const llvm::json::Value &Params, ConfigurationSettings &S,1370              llvm::json::Path P) {1371  llvm::json::ObjectMapper O(Params, P);1372  if (!O)1373    return true; // 'any' type in LSP.1374  return mapOptOrNull(Params, "compilationDatabaseChanges",1375                      S.compilationDatabaseChanges, P);1376}1377 1378bool fromJSON(const llvm::json::Value &Params, InitializationOptions &Opts,1379              llvm::json::Path P) {1380  llvm::json::ObjectMapper O(Params, P);1381  if (!O)1382    return true; // 'any' type in LSP.1383 1384  return fromJSON(Params, Opts.ConfigSettings, P) &&1385         O.map("compilationDatabasePath", Opts.compilationDatabasePath) &&1386         mapOptOrNull(Params, "fallbackFlags", Opts.fallbackFlags, P) &&1387         mapOptOrNull(Params, "clangdFileStatus", Opts.FileStatus, P);1388}1389 1390bool fromJSON(const llvm::json::Value &E, TypeHierarchyDirection &Out,1391              llvm::json::Path P) {1392  auto T = E.getAsInteger();1393  if (!T)1394    return false;1395  if (*T < static_cast<int>(TypeHierarchyDirection::Children) ||1396      *T > static_cast<int>(TypeHierarchyDirection::Both))1397    return false;1398  Out = static_cast<TypeHierarchyDirection>(*T);1399  return true;1400}1401 1402bool fromJSON(const llvm::json::Value &Params, TypeHierarchyPrepareParams &R,1403              llvm::json::Path P) {1404  llvm::json::ObjectMapper O(Params, P);1405  return O && O.map("textDocument", R.textDocument) &&1406         O.map("position", R.position) &&1407         mapOptOrNull(Params, "resolve", R.resolve, P) &&1408         mapOptOrNull(Params, "direction", R.direction, P);1409}1410 1411llvm::raw_ostream &operator<<(llvm::raw_ostream &O,1412                              const TypeHierarchyItem &I) {1413  return O << I.name << " - " << toJSON(I);1414}1415 1416llvm::json::Value toJSON(const TypeHierarchyItem::ResolveParams &RP) {1417  llvm::json::Object Result{{"symbolID", RP.symbolID}};1418  if (RP.parents)1419    Result["parents"] = RP.parents;1420  return std::move(Result);1421}1422bool fromJSON(const llvm::json::Value &Params,1423              TypeHierarchyItem::ResolveParams &RP, llvm::json::Path P) {1424  llvm::json::ObjectMapper O(Params, P);1425  return O && O.map("symbolID", RP.symbolID) &&1426         mapOptOrNull(Params, "parents", RP.parents, P);1427}1428 1429llvm::json::Value toJSON(const TypeHierarchyItem &I) {1430  llvm::json::Object Result{1431      {"name", I.name},   {"kind", static_cast<int>(I.kind)},1432      {"range", I.range}, {"selectionRange", I.selectionRange},1433      {"uri", I.uri},     {"data", I.data},1434  };1435 1436  if (I.detail)1437    Result["detail"] = I.detail;1438  return std::move(Result);1439}1440 1441bool fromJSON(const llvm::json::Value &Params, TypeHierarchyItem &I,1442              llvm::json::Path P) {1443  llvm::json::ObjectMapper O(Params, P);1444 1445  // Required fields.1446  return O && O.map("name", I.name) && O.map("kind", I.kind) &&1447         O.map("uri", I.uri) && O.map("range", I.range) &&1448         O.map("selectionRange", I.selectionRange) &&1449         mapOptOrNull(Params, "detail", I.detail, P) &&1450         mapOptOrNull(Params, "deprecated", I.deprecated, P) &&1451         mapOptOrNull(Params, "parents", I.parents, P) &&1452         mapOptOrNull(Params, "children", I.children, P) &&1453         mapOptOrNull(Params, "data", I.data, P);1454}1455 1456bool fromJSON(const llvm::json::Value &Params,1457              ResolveTypeHierarchyItemParams &R, llvm::json::Path P) {1458  llvm::json::ObjectMapper O(Params, P);1459  return O && O.map("item", R.item) &&1460         mapOptOrNull(Params, "resolve", R.resolve, P) &&1461         mapOptOrNull(Params, "direction", R.direction, P);1462}1463 1464bool fromJSON(const llvm::json::Value &Params, ReferenceContext &R,1465              llvm::json::Path P) {1466  llvm::json::ObjectMapper O(Params, P);1467  return O && O.mapOptional("includeDeclaration", R.includeDeclaration);1468}1469 1470bool fromJSON(const llvm::json::Value &Params, ReferenceParams &R,1471              llvm::json::Path P) {1472  TextDocumentPositionParams &Base = R;1473  llvm::json::ObjectMapper O(Params, P);1474  return fromJSON(Params, Base, P) && O && O.mapOptional("context", R.context);1475}1476 1477llvm::json::Value toJSON(SymbolTag Tag) {1478  return llvm::json::Value(static_cast<int>(Tag));1479}1480 1481llvm::json::Value toJSON(const CallHierarchyItem &I) {1482  llvm::json::Object Result{{"name", I.name},1483                            {"kind", static_cast<int>(I.kind)},1484                            {"range", I.range},1485                            {"selectionRange", I.selectionRange},1486                            {"uri", I.uri}};1487  if (!I.tags.empty())1488    Result["tags"] = I.tags;1489  if (!I.detail.empty())1490    Result["detail"] = I.detail;1491  if (!I.data.empty())1492    Result["data"] = I.data;1493  return std::move(Result);1494}1495 1496bool fromJSON(const llvm::json::Value &Params, CallHierarchyItem &I,1497              llvm::json::Path P) {1498  llvm::json::ObjectMapper O(Params, P);1499 1500  // Populate the required fields only. We don't care about the1501  // optional fields `Tags` and `Detail` for the purpose of1502  // client --> server communication.1503  return O && O.map("name", I.name) && O.map("kind", I.kind) &&1504         O.map("uri", I.uri) && O.map("range", I.range) &&1505         O.map("selectionRange", I.selectionRange) &&1506         mapOptOrNull(Params, "data", I.data, P);1507}1508 1509bool fromJSON(const llvm::json::Value &Params,1510              CallHierarchyIncomingCallsParams &C, llvm::json::Path P) {1511  llvm::json::ObjectMapper O(Params, P);1512  return O.map("item", C.item);1513}1514 1515llvm::json::Value toJSON(const CallHierarchyIncomingCall &C) {1516  return llvm::json::Object{{"from", C.from}, {"fromRanges", C.fromRanges}};1517}1518 1519bool fromJSON(const llvm::json::Value &Params,1520              CallHierarchyOutgoingCallsParams &C, llvm::json::Path P) {1521  llvm::json::ObjectMapper O(Params, P);1522  return O.map("item", C.item);1523}1524 1525llvm::json::Value toJSON(const CallHierarchyOutgoingCall &C) {1526  return llvm::json::Object{{"to", C.to}, {"fromRanges", C.fromRanges}};1527}1528 1529bool fromJSON(const llvm::json::Value &Params, InlayHintsParams &R,1530              llvm::json::Path P) {1531  llvm::json::ObjectMapper O(Params, P);1532  return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);1533}1534 1535llvm::json::Value toJSON(const InlayHintKind &Kind) {1536  switch (Kind) {1537  case InlayHintKind::Type:1538    return 1;1539  case InlayHintKind::Parameter:1540    return 2;1541  case InlayHintKind::Designator:1542  case InlayHintKind::BlockEnd:1543  case InlayHintKind::DefaultArgument:1544    // This is an extension, don't serialize.1545    return nullptr;1546  }1547  llvm_unreachable("Unknown clang.clangd.InlayHintKind");1548}1549 1550llvm::json::Value toJSON(const InlayHint &H) {1551  llvm::json::Object Result{{"position", H.position},1552                            {"label", H.label},1553                            {"paddingLeft", H.paddingLeft},1554                            {"paddingRight", H.paddingRight}};1555  auto K = toJSON(H.kind);1556  if (!K.getAsNull())1557    Result["kind"] = std::move(K);1558  return std::move(Result);1559}1560bool operator==(const InlayHint &A, const InlayHint &B) {1561  return std::tie(A.position, A.range, A.kind, A.label) ==1562         std::tie(B.position, B.range, B.kind, B.label);1563}1564bool operator<(const InlayHint &A, const InlayHint &B) {1565  return std::tie(A.position, A.range, A.kind, A.label) <1566         std::tie(B.position, B.range, B.kind, B.label);1567}1568std::string InlayHint::joinLabels() const {1569  return llvm::join(llvm::map_range(label, [](auto &L) { return L.value; }),1570                    "");1571}1572 1573llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) {1574  auto ToString = [](InlayHintKind K) {1575    switch (K) {1576    case InlayHintKind::Parameter:1577      return "parameter";1578    case InlayHintKind::Type:1579      return "type";1580    case InlayHintKind::Designator:1581      return "designator";1582    case InlayHintKind::BlockEnd:1583      return "block-end";1584    case InlayHintKind::DefaultArgument:1585      return "default-argument";1586    }1587    llvm_unreachable("Unknown clang.clangd.InlayHintKind");1588  };1589  return OS << ToString(Kind);1590}1591 1592llvm::json::Value toJSON(const InlayHintLabelPart &L) {1593  llvm::json::Object Result{{"value", L.value}};1594  if (L.tooltip)1595    Result["tooltip"] = *L.tooltip;1596  if (L.location)1597    Result["location"] = *L.location;1598  if (L.command)1599    Result["command"] = *L.command;1600  return Result;1601}1602 1603bool operator==(const InlayHintLabelPart &LHS, const InlayHintLabelPart &RHS) {1604  return std::tie(LHS.value, LHS.location) == std::tie(RHS.value, RHS.location);1605}1606 1607bool operator<(const InlayHintLabelPart &LHS, const InlayHintLabelPart &RHS) {1608  return std::tie(LHS.value, LHS.location) < std::tie(RHS.value, RHS.location);1609}1610 1611llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,1612                              const InlayHintLabelPart &L) {1613  OS << L.value;1614  if (L.location)1615    OS << " (" << L.location << ")";1616  return OS;1617}1618 1619static const char *toString(OffsetEncoding OE) {1620  switch (OE) {1621  case OffsetEncoding::UTF8:1622    return "utf-8";1623  case OffsetEncoding::UTF16:1624    return "utf-16";1625  case OffsetEncoding::UTF32:1626    return "utf-32";1627  case OffsetEncoding::UnsupportedEncoding:1628    return "unknown";1629  }1630  llvm_unreachable("Unknown clang.clangd.OffsetEncoding");1631}1632llvm::json::Value toJSON(const OffsetEncoding &OE) { return toString(OE); }1633bool fromJSON(const llvm::json::Value &V, OffsetEncoding &OE,1634              llvm::json::Path P) {1635  auto Str = V.getAsString();1636  if (!Str)1637    return false;1638  OE = llvm::StringSwitch<OffsetEncoding>(*Str)1639           .Case("utf-8", OffsetEncoding::UTF8)1640           .Case("utf-16", OffsetEncoding::UTF16)1641           .Case("utf-32", OffsetEncoding::UTF32)1642           .Default(OffsetEncoding::UnsupportedEncoding);1643  return true;1644}1645llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OffsetEncoding Enc) {1646  return OS << toString(Enc);1647}1648 1649bool fromJSON(const llvm::json::Value &Params, SelectionRangeParams &S,1650              llvm::json::Path P) {1651  llvm::json::ObjectMapper O(Params, P);1652  return O && O.map("textDocument", S.textDocument) &&1653         O.map("positions", S.positions);1654}1655 1656llvm::json::Value toJSON(const SelectionRange &Out) {1657  if (Out.parent) {1658    return llvm::json::Object{{"range", Out.range},1659                              {"parent", toJSON(*Out.parent)}};1660  }1661  return llvm::json::Object{{"range", Out.range}};1662}1663 1664bool fromJSON(const llvm::json::Value &Params, DocumentLinkParams &R,1665              llvm::json::Path P) {1666  llvm::json::ObjectMapper O(Params, P);1667  return O && O.map("textDocument", R.textDocument);1668}1669 1670llvm::json::Value toJSON(const DocumentLink &DocumentLink) {1671  return llvm::json::Object{1672      {"range", DocumentLink.range},1673      {"target", DocumentLink.target},1674  };1675}1676 1677bool fromJSON(const llvm::json::Value &Params, FoldingRangeParams &R,1678              llvm::json::Path P) {1679  llvm::json::ObjectMapper O(Params, P);1680  return O && O.map("textDocument", R.textDocument);1681}1682 1683const llvm::StringLiteral FoldingRange::REGION_KIND = "region";1684const llvm::StringLiteral FoldingRange::COMMENT_KIND = "comment";1685const llvm::StringLiteral FoldingRange::IMPORT_KIND = "import";1686 1687llvm::json::Value toJSON(const FoldingRange &Range) {1688  llvm::json::Object Result{1689      {"startLine", Range.startLine},1690      {"endLine", Range.endLine},1691  };1692  if (Range.startCharacter)1693    Result["startCharacter"] = Range.startCharacter;1694  if (Range.endCharacter)1695    Result["endCharacter"] = Range.endCharacter;1696  if (!Range.kind.empty())1697    Result["kind"] = Range.kind;1698  return Result;1699}1700 1701llvm::json::Value toJSON(const MemoryTree &MT) {1702  llvm::json::Object Out;1703  int64_t Total = MT.self();1704  Out["_self"] = Total;1705  for (const auto &Entry : MT.children()) {1706    auto Child = toJSON(Entry.getSecond());1707    Total += *Child.getAsObject()->getInteger("_total");1708    Out[Entry.first] = std::move(Child);1709  }1710  Out["_total"] = Total;1711  return Out;1712}1713 1714bool fromJSON(const llvm::json::Value &Params, ASTParams &R,1715              llvm::json::Path P) {1716  llvm::json::ObjectMapper O(Params, P);1717  return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);1718}1719 1720llvm::json::Value toJSON(const ASTNode &N) {1721  llvm::json::Object Result{1722      {"role", N.role},1723      {"kind", N.kind},1724  };1725  if (!N.children.empty())1726    Result["children"] = N.children;1727  if (!N.detail.empty())1728    Result["detail"] = N.detail;1729  if (!N.arcana.empty())1730    Result["arcana"] = N.arcana;1731  if (N.range)1732    Result["range"] = *N.range;1733  return Result;1734}1735 1736llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const ASTNode &Root) {1737  std::function<void(const ASTNode &, unsigned)> Print = [&](const ASTNode &N,1738                                                             unsigned Level) {1739    OS.indent(2 * Level) << N.role << ": " << N.kind;1740    if (!N.detail.empty())1741      OS << " - " << N.detail;1742    OS << "\n";1743    for (const ASTNode &C : N.children)1744      Print(C, Level + 1);1745  };1746  Print(Root, 0);1747  return OS;1748}1749 1750bool fromJSON(const llvm::json::Value &E, SymbolID &S, llvm::json::Path P) {1751  auto Str = E.getAsString();1752  if (!Str) {1753    P.report("expected a string");1754    return false;1755  }1756  auto ID = SymbolID::fromStr(*Str);1757  if (!ID) {1758    elog("Malformed symbolid: {0}", ID.takeError());1759    P.report("malformed symbolid");1760    return false;1761  }1762  S = *ID;1763  return true;1764}1765llvm::json::Value toJSON(const SymbolID &S) { return S.str(); }1766 1767} // namespace clangd1768} // namespace clang1769