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