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 "Logger.h" 15 #include "URI.h" 16 #include "clang/Basic/LLVM.h" 17 #include "llvm/ADT/Hashing.h" 18 #include "llvm/ADT/SmallString.h" 19 #include "llvm/ADT/StringSwitch.h" 20 #include "llvm/Support/ErrorHandling.h" 21 #include "llvm/Support/Format.h" 22 #include "llvm/Support/FormatVariadic.h" 23 #include "llvm/Support/JSON.h" 24 #include "llvm/Support/Path.h" 25 #include "llvm/Support/raw_ostream.h" 26 27 namespace clang { 28 namespace clangd { 29 30 char LSPError::ID; 31 32 URIForFile URIForFile::canonicalize(llvm::StringRef AbsPath, 33 llvm::StringRef TUPath) { 34 assert(llvm::sys::path::is_absolute(AbsPath) && "the path is relative"); 35 auto Resolved = URI::resolvePath(AbsPath, TUPath); 36 if (!Resolved) { 37 elog("URIForFile: failed to resolve path {0} with TU path {1}: " 38 "{2}.\nUsing unresolved path.", 39 AbsPath, TUPath, Resolved.takeError()); 40 return URIForFile(AbsPath); 41 } 42 return URIForFile(std::move(*Resolved)); 43 } 44 45 llvm::Expected<URIForFile> URIForFile::fromURI(const URI &U, 46 llvm::StringRef HintPath) { 47 auto Resolved = URI::resolve(U, HintPath); 48 if (!Resolved) 49 return Resolved.takeError(); 50 return URIForFile(std::move(*Resolved)); 51 } 52 53 bool fromJSON(const llvm::json::Value &E, URIForFile &R) { 54 if (auto S = E.getAsString()) { 55 auto Parsed = URI::parse(*S); 56 if (!Parsed) { 57 elog("Failed to parse URI {0}: {1}", *S, Parsed.takeError()); 58 return false; 59 } 60 if (Parsed->scheme() != "file" && Parsed->scheme() != "test") { 61 elog("Clangd only supports 'file' URI scheme for workspace files: {0}", 62 *S); 63 return false; 64 } 65 // "file" and "test" schemes do not require hint path. 66 auto U = URIForFile::fromURI(*Parsed, /*HintPath=*/""); 67 if (!U) { 68 elog("{0}", U.takeError()); 69 return false; 70 } 71 R = std::move(*U); 72 return true; 73 } 74 return false; 75 } 76 77 llvm::json::Value toJSON(const URIForFile &U) { return U.uri(); } 78 79 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const URIForFile &U) { 80 return OS << U.uri(); 81 } 82 83 llvm::json::Value toJSON(const TextDocumentIdentifier &R) { 84 return llvm::json::Object{{"uri", R.uri}}; 85 } 86 87 bool fromJSON(const llvm::json::Value &Params, TextDocumentIdentifier &R) { 88 llvm::json::ObjectMapper O(Params); 89 return O && O.map("uri", R.uri); 90 } 91 92 bool fromJSON(const llvm::json::Value &Params, Position &R) { 93 llvm::json::ObjectMapper O(Params); 94 return O && O.map("line", R.line) && O.map("character", R.character); 95 } 96 97 llvm::json::Value toJSON(const Position &P) { 98 return llvm::json::Object{ 99 {"line", P.line}, 100 {"character", P.character}, 101 }; 102 } 103 104 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &P) { 105 return OS << P.line << ':' << P.character; 106 } 107 108 bool fromJSON(const llvm::json::Value &Params, Range &R) { 109 llvm::json::ObjectMapper O(Params); 110 return O && O.map("start", R.start) && O.map("end", R.end); 111 } 112 113 llvm::json::Value toJSON(const Range &P) { 114 return llvm::json::Object{ 115 {"start", P.start}, 116 {"end", P.end}, 117 }; 118 } 119 120 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Range &R) { 121 return OS << R.start << '-' << R.end; 122 } 123 124 llvm::json::Value toJSON(const Location &P) { 125 return llvm::json::Object{ 126 {"uri", P.uri}, 127 {"range", P.range}, 128 }; 129 } 130 131 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Location &L) { 132 return OS << L.range << '@' << L.uri; 133 } 134 135 bool fromJSON(const llvm::json::Value &Params, TextDocumentItem &R) { 136 llvm::json::ObjectMapper O(Params); 137 return O && O.map("uri", R.uri) && O.map("languageId", R.languageId) && 138 O.map("version", R.version) && O.map("text", R.text); 139 } 140 141 bool fromJSON(const llvm::json::Value &Params, TextEdit &R) { 142 llvm::json::ObjectMapper O(Params); 143 return O && O.map("range", R.range) && O.map("newText", R.newText); 144 } 145 146 llvm::json::Value toJSON(const TextEdit &P) { 147 return llvm::json::Object{ 148 {"range", P.range}, 149 {"newText", P.newText}, 150 }; 151 } 152 153 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) { 154 OS << TE.range << " => \""; 155 llvm::printEscapedString(TE.newText, OS); 156 return OS << '"'; 157 } 158 159 bool fromJSON(const llvm::json::Value &E, TraceLevel &Out) { 160 if (auto S = E.getAsString()) { 161 if (*S == "off") { 162 Out = TraceLevel::Off; 163 return true; 164 } else if (*S == "messages") { 165 Out = TraceLevel::Messages; 166 return true; 167 } else if (*S == "verbose") { 168 Out = TraceLevel::Verbose; 169 return true; 170 } 171 } 172 return false; 173 } 174 175 bool fromJSON(const llvm::json::Value &E, SymbolKind &Out) { 176 if (auto T = E.getAsInteger()) { 177 if (*T < static_cast<int>(SymbolKind::File) || 178 *T > static_cast<int>(SymbolKind::TypeParameter)) 179 return false; 180 Out = static_cast<SymbolKind>(*T); 181 return true; 182 } 183 return false; 184 } 185 186 bool fromJSON(const llvm::json::Value &E, SymbolKindBitset &Out) { 187 if (auto *A = E.getAsArray()) { 188 for (size_t I = 0; I < A->size(); ++I) { 189 SymbolKind KindOut; 190 if (fromJSON((*A)[I], KindOut)) 191 Out.set(size_t(KindOut)); 192 } 193 return true; 194 } 195 return false; 196 } 197 198 SymbolKind adjustKindToCapability(SymbolKind Kind, 199 SymbolKindBitset &SupportedSymbolKinds) { 200 auto KindVal = static_cast<size_t>(Kind); 201 if (KindVal >= SymbolKindMin && KindVal <= SupportedSymbolKinds.size() && 202 SupportedSymbolKinds[KindVal]) 203 return Kind; 204 205 switch (Kind) { 206 // Provide some fall backs for common kinds that are close enough. 207 case SymbolKind::Struct: 208 return SymbolKind::Class; 209 case SymbolKind::EnumMember: 210 return SymbolKind::Enum; 211 default: 212 return SymbolKind::String; 213 } 214 } 215 216 SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind) { 217 switch (Kind) { 218 case index::SymbolKind::Unknown: 219 return SymbolKind::Variable; 220 case index::SymbolKind::Module: 221 return SymbolKind::Module; 222 case index::SymbolKind::Namespace: 223 return SymbolKind::Namespace; 224 case index::SymbolKind::NamespaceAlias: 225 return SymbolKind::Namespace; 226 case index::SymbolKind::Macro: 227 return SymbolKind::String; 228 case index::SymbolKind::Enum: 229 return SymbolKind::Enum; 230 case index::SymbolKind::Struct: 231 return SymbolKind::Struct; 232 case index::SymbolKind::Class: 233 return SymbolKind::Class; 234 case index::SymbolKind::Protocol: 235 return SymbolKind::Interface; 236 case index::SymbolKind::Extension: 237 return SymbolKind::Interface; 238 case index::SymbolKind::Union: 239 return SymbolKind::Class; 240 case index::SymbolKind::TypeAlias: 241 return SymbolKind::Class; 242 case index::SymbolKind::Function: 243 return SymbolKind::Function; 244 case index::SymbolKind::Variable: 245 return SymbolKind::Variable; 246 case index::SymbolKind::Field: 247 return SymbolKind::Field; 248 case index::SymbolKind::EnumConstant: 249 return SymbolKind::EnumMember; 250 case index::SymbolKind::InstanceMethod: 251 case index::SymbolKind::ClassMethod: 252 case index::SymbolKind::StaticMethod: 253 return SymbolKind::Method; 254 case index::SymbolKind::InstanceProperty: 255 case index::SymbolKind::ClassProperty: 256 case index::SymbolKind::StaticProperty: 257 return SymbolKind::Property; 258 case index::SymbolKind::Constructor: 259 case index::SymbolKind::Destructor: 260 return SymbolKind::Method; 261 case index::SymbolKind::ConversionFunction: 262 return SymbolKind::Function; 263 case index::SymbolKind::Parameter: 264 return SymbolKind::Variable; 265 case index::SymbolKind::Using: 266 return SymbolKind::Namespace; 267 } 268 llvm_unreachable("invalid symbol kind"); 269 } 270 271 bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R) { 272 const llvm::json::Object *O = Params.getAsObject(); 273 if (!O) 274 return false; 275 if (auto *TextDocument = O->getObject("textDocument")) { 276 if (auto *SemanticHighlighting = 277 TextDocument->getObject("semanticHighlightingCapabilities")) { 278 if (auto SemanticHighlightingSupport = 279 SemanticHighlighting->getBoolean("semanticHighlighting")) 280 R.SemanticHighlighting = *SemanticHighlightingSupport; 281 } 282 if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) { 283 if (auto CategorySupport = Diagnostics->getBoolean("categorySupport")) 284 R.DiagnosticCategory = *CategorySupport; 285 if (auto CodeActions = Diagnostics->getBoolean("codeActionsInline")) 286 R.DiagnosticFixes = *CodeActions; 287 if (auto RelatedInfo = Diagnostics->getBoolean("relatedInformation")) 288 R.DiagnosticRelatedInformation = *RelatedInfo; 289 } 290 if (auto *Completion = TextDocument->getObject("completion")) { 291 if (auto *Item = Completion->getObject("completionItem")) { 292 if (auto SnippetSupport = Item->getBoolean("snippetSupport")) 293 R.CompletionSnippets = *SnippetSupport; 294 } 295 if (auto *ItemKind = Completion->getObject("completionItemKind")) { 296 if (auto *ValueSet = ItemKind->get("valueSet")) { 297 R.CompletionItemKinds.emplace(); 298 if (!fromJSON(*ValueSet, *R.CompletionItemKinds)) 299 return false; 300 } 301 } 302 if (auto EditsNearCursor = Completion->getBoolean("editsNearCursor")) 303 R.CompletionFixes = *EditsNearCursor; 304 } 305 if (auto *CodeAction = TextDocument->getObject("codeAction")) { 306 if (CodeAction->getObject("codeActionLiteralSupport")) 307 R.CodeActionStructure = true; 308 } 309 if (auto *DocumentSymbol = TextDocument->getObject("documentSymbol")) { 310 if (auto HierarchicalSupport = 311 DocumentSymbol->getBoolean("hierarchicalDocumentSymbolSupport")) 312 R.HierarchicalDocumentSymbol = *HierarchicalSupport; 313 } 314 if (auto *Hover = TextDocument->getObject("hover")) { 315 if (auto *ContentFormat = Hover->getArray("contentFormat")) { 316 for (const auto &Format : *ContentFormat) { 317 MarkupKind K = MarkupKind::PlainText; 318 if (fromJSON(Format, K)) { 319 R.HoverContentFormat = K; 320 break; 321 } 322 } 323 } 324 } 325 if (auto *Help = TextDocument->getObject("signatureHelp")) { 326 R.HasSignatureHelp = true; 327 if (auto *Info = Help->getObject("signatureInformation")) { 328 if (auto *Parameter = Info->getObject("parameterInformation")) { 329 if (auto OffsetSupport = Parameter->getBoolean("labelOffsetSupport")) 330 R.OffsetsInSignatureHelp = *OffsetSupport; 331 } 332 } 333 } 334 if (auto *Rename = TextDocument->getObject("rename")) { 335 if (auto RenameSupport = Rename->getBoolean("prepareSupport")) 336 R.RenamePrepareSupport = *RenameSupport; 337 } 338 } 339 if (auto *Workspace = O->getObject("workspace")) { 340 if (auto *Symbol = Workspace->getObject("symbol")) { 341 if (auto *SymbolKind = Symbol->getObject("symbolKind")) { 342 if (auto *ValueSet = SymbolKind->get("valueSet")) { 343 R.WorkspaceSymbolKinds.emplace(); 344 if (!fromJSON(*ValueSet, *R.WorkspaceSymbolKinds)) 345 return false; 346 } 347 } 348 } 349 } 350 if (auto *OffsetEncoding = O->get("offsetEncoding")) { 351 R.offsetEncoding.emplace(); 352 if (!fromJSON(*OffsetEncoding, *R.offsetEncoding)) 353 return false; 354 } 355 return true; 356 } 357 358 bool fromJSON(const llvm::json::Value &Params, InitializeParams &R) { 359 llvm::json::ObjectMapper O(Params); 360 if (!O) 361 return false; 362 // We deliberately don't fail if we can't parse individual fields. 363 // Failing to handle a slightly malformed initialize would be a disaster. 364 O.map("processId", R.processId); 365 O.map("rootUri", R.rootUri); 366 O.map("rootPath", R.rootPath); 367 O.map("capabilities", R.capabilities); 368 O.map("trace", R.trace); 369 O.map("initializationOptions", R.initializationOptions); 370 return true; 371 } 372 373 llvm::json::Value toJSON(const MessageType &R) { 374 return static_cast<int64_t>(R); 375 } 376 377 llvm::json::Value toJSON(const ShowMessageParams &R) { 378 return llvm::json::Object{{"type", R.type}, {"message", R.message}}; 379 } 380 381 bool fromJSON(const llvm::json::Value &Params, DidOpenTextDocumentParams &R) { 382 llvm::json::ObjectMapper O(Params); 383 return O && O.map("textDocument", R.textDocument); 384 } 385 386 bool fromJSON(const llvm::json::Value &Params, DidCloseTextDocumentParams &R) { 387 llvm::json::ObjectMapper O(Params); 388 return O && O.map("textDocument", R.textDocument); 389 } 390 391 bool fromJSON(const llvm::json::Value &Params, DidChangeTextDocumentParams &R) { 392 llvm::json::ObjectMapper O(Params); 393 return O && O.map("textDocument", R.textDocument) && 394 O.map("contentChanges", R.contentChanges) && 395 O.map("wantDiagnostics", R.wantDiagnostics); 396 } 397 398 bool fromJSON(const llvm::json::Value &E, FileChangeType &Out) { 399 if (auto T = E.getAsInteger()) { 400 if (*T < static_cast<int>(FileChangeType::Created) || 401 *T > static_cast<int>(FileChangeType::Deleted)) 402 return false; 403 Out = static_cast<FileChangeType>(*T); 404 return true; 405 } 406 return false; 407 } 408 409 bool fromJSON(const llvm::json::Value &Params, FileEvent &R) { 410 llvm::json::ObjectMapper O(Params); 411 return O && O.map("uri", R.uri) && O.map("type", R.type); 412 } 413 414 bool fromJSON(const llvm::json::Value &Params, DidChangeWatchedFilesParams &R) { 415 llvm::json::ObjectMapper O(Params); 416 return O && O.map("changes", R.changes); 417 } 418 419 bool fromJSON(const llvm::json::Value &Params, 420 TextDocumentContentChangeEvent &R) { 421 llvm::json::ObjectMapper O(Params); 422 return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) && 423 O.map("text", R.text); 424 } 425 426 bool fromJSON(const llvm::json::Value &Params, 427 DocumentRangeFormattingParams &R) { 428 llvm::json::ObjectMapper O(Params); 429 return O && O.map("textDocument", R.textDocument) && O.map("range", R.range); 430 } 431 432 bool fromJSON(const llvm::json::Value &Params, 433 DocumentOnTypeFormattingParams &R) { 434 llvm::json::ObjectMapper O(Params); 435 return O && O.map("textDocument", R.textDocument) && 436 O.map("position", R.position) && O.map("ch", R.ch); 437 } 438 439 bool fromJSON(const llvm::json::Value &Params, DocumentFormattingParams &R) { 440 llvm::json::ObjectMapper O(Params); 441 return O && O.map("textDocument", R.textDocument); 442 } 443 444 bool fromJSON(const llvm::json::Value &Params, DocumentSymbolParams &R) { 445 llvm::json::ObjectMapper O(Params); 446 return O && O.map("textDocument", R.textDocument); 447 } 448 449 llvm::json::Value toJSON(const DiagnosticRelatedInformation &DRI) { 450 return llvm::json::Object{ 451 {"location", DRI.location}, 452 {"message", DRI.message}, 453 }; 454 } 455 456 llvm::json::Value toJSON(const Diagnostic &D) { 457 llvm::json::Object Diag{ 458 {"range", D.range}, 459 {"severity", D.severity}, 460 {"message", D.message}, 461 }; 462 if (D.category) 463 Diag["category"] = *D.category; 464 if (D.codeActions) 465 Diag["codeActions"] = D.codeActions; 466 if (!D.code.empty()) 467 Diag["code"] = D.code; 468 if (!D.source.empty()) 469 Diag["source"] = D.source; 470 if (D.relatedInformation) 471 Diag["relatedInformation"] = *D.relatedInformation; 472 return std::move(Diag); 473 } 474 475 bool fromJSON(const llvm::json::Value &Params, Diagnostic &R) { 476 llvm::json::ObjectMapper O(Params); 477 if (!O || !O.map("range", R.range) || !O.map("message", R.message)) 478 return false; 479 O.map("severity", R.severity); 480 O.map("category", R.category); 481 O.map("code", R.code); 482 O.map("source", R.source); 483 return true; 484 } 485 486 bool fromJSON(const llvm::json::Value &Params, CodeActionContext &R) { 487 llvm::json::ObjectMapper O(Params); 488 return O && O.map("diagnostics", R.diagnostics); 489 } 490 491 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) { 492 OS << D.range << " ["; 493 switch (D.severity) { 494 case 1: 495 OS << "error"; 496 break; 497 case 2: 498 OS << "warning"; 499 break; 500 case 3: 501 OS << "note"; 502 break; 503 case 4: 504 OS << "remark"; 505 break; 506 default: 507 OS << "diagnostic"; 508 break; 509 } 510 return OS << '(' << D.severity << "): " << D.message << "]"; 511 } 512 513 bool fromJSON(const llvm::json::Value &Params, CodeActionParams &R) { 514 llvm::json::ObjectMapper O(Params); 515 return O && O.map("textDocument", R.textDocument) && 516 O.map("range", R.range) && O.map("context", R.context); 517 } 518 519 bool fromJSON(const llvm::json::Value &Params, WorkspaceEdit &R) { 520 llvm::json::ObjectMapper O(Params); 521 return O && O.map("changes", R.changes); 522 } 523 524 const llvm::StringLiteral ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND = 525 "clangd.applyFix"; 526 const llvm::StringLiteral ExecuteCommandParams::CLANGD_APPLY_TWEAK = 527 "clangd.applyTweak"; 528 529 bool fromJSON(const llvm::json::Value &Params, ExecuteCommandParams &R) { 530 llvm::json::ObjectMapper O(Params); 531 if (!O || !O.map("command", R.command)) 532 return false; 533 534 auto Args = Params.getAsObject()->getArray("arguments"); 535 if (R.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) { 536 return Args && Args->size() == 1 && 537 fromJSON(Args->front(), R.workspaceEdit); 538 } 539 if (R.command == ExecuteCommandParams::CLANGD_APPLY_TWEAK) 540 return Args && Args->size() == 1 && fromJSON(Args->front(), R.tweakArgs); 541 return false; // Unrecognized command. 542 } 543 544 llvm::json::Value toJSON(const SymbolInformation &P) { 545 return llvm::json::Object{ 546 {"name", P.name}, 547 {"kind", static_cast<int>(P.kind)}, 548 {"location", P.location}, 549 {"containerName", P.containerName}, 550 }; 551 } 552 553 llvm::raw_ostream &operator<<(llvm::raw_ostream &O, 554 const SymbolInformation &SI) { 555 O << SI.containerName << "::" << SI.name << " - " << toJSON(SI); 556 return O; 557 } 558 559 bool operator==(const SymbolDetails &LHS, const SymbolDetails &RHS) { 560 return LHS.name == RHS.name && LHS.containerName == RHS.containerName && 561 LHS.USR == RHS.USR && LHS.ID == RHS.ID; 562 } 563 564 llvm::json::Value toJSON(const SymbolDetails &P) { 565 llvm::json::Object Result{{"name", llvm::json::Value(nullptr)}, 566 {"containerName", llvm::json::Value(nullptr)}, 567 {"usr", llvm::json::Value(nullptr)}, 568 {"id", llvm::json::Value(nullptr)}}; 569 570 if (!P.name.empty()) 571 Result["name"] = P.name; 572 573 if (!P.containerName.empty()) 574 Result["containerName"] = P.containerName; 575 576 if (!P.USR.empty()) 577 Result["usr"] = P.USR; 578 579 if (P.ID.hasValue()) 580 Result["id"] = P.ID.getValue().str(); 581 582 // Older clang cannot compile 'return Result', even though it is legal. 583 return llvm::json::Value(std::move(Result)); 584 } 585 586 llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const SymbolDetails &S) { 587 if (!S.containerName.empty()) { 588 O << S.containerName; 589 llvm::StringRef ContNameRef; 590 if (!ContNameRef.endswith("::")) { 591 O << " "; 592 } 593 } 594 O << S.name << " - " << toJSON(S); 595 return O; 596 } 597 598 bool fromJSON(const llvm::json::Value &Params, WorkspaceSymbolParams &R) { 599 llvm::json::ObjectMapper O(Params); 600 return O && O.map("query", R.query); 601 } 602 603 llvm::json::Value toJSON(const Command &C) { 604 auto Cmd = llvm::json::Object{{"title", C.title}, {"command", C.command}}; 605 if (C.workspaceEdit) 606 Cmd["arguments"] = {*C.workspaceEdit}; 607 if (C.tweakArgs) 608 Cmd["arguments"] = {*C.tweakArgs}; 609 return std::move(Cmd); 610 } 611 612 const llvm::StringLiteral CodeAction::QUICKFIX_KIND = "quickfix"; 613 const llvm::StringLiteral CodeAction::REFACTOR_KIND = "refactor"; 614 const llvm::StringLiteral CodeAction::INFO_KIND = "info"; 615 616 llvm::json::Value toJSON(const CodeAction &CA) { 617 auto CodeAction = llvm::json::Object{{"title", CA.title}}; 618 if (CA.kind) 619 CodeAction["kind"] = *CA.kind; 620 if (CA.diagnostics) 621 CodeAction["diagnostics"] = llvm::json::Array(*CA.diagnostics); 622 if (CA.edit) 623 CodeAction["edit"] = *CA.edit; 624 if (CA.command) 625 CodeAction["command"] = *CA.command; 626 return std::move(CodeAction); 627 } 628 629 llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const DocumentSymbol &S) { 630 return O << S.name << " - " << toJSON(S); 631 } 632 633 llvm::json::Value toJSON(const DocumentSymbol &S) { 634 llvm::json::Object Result{{"name", S.name}, 635 {"kind", static_cast<int>(S.kind)}, 636 {"range", S.range}, 637 {"selectionRange", S.selectionRange}}; 638 639 if (!S.detail.empty()) 640 Result["detail"] = S.detail; 641 if (!S.children.empty()) 642 Result["children"] = S.children; 643 if (S.deprecated) 644 Result["deprecated"] = true; 645 // Older gcc cannot compile 'return Result', even though it is legal. 646 return llvm::json::Value(std::move(Result)); 647 } 648 649 llvm::json::Value toJSON(const WorkspaceEdit &WE) { 650 if (!WE.changes) 651 return llvm::json::Object{}; 652 llvm::json::Object FileChanges; 653 for (auto &Change : *WE.changes) 654 FileChanges[Change.first] = llvm::json::Array(Change.second); 655 return llvm::json::Object{{"changes", std::move(FileChanges)}}; 656 } 657 658 bool fromJSON(const llvm::json::Value &Params, TweakArgs &A) { 659 llvm::json::ObjectMapper O(Params); 660 return O && O.map("file", A.file) && O.map("selection", A.selection) && 661 O.map("tweakID", A.tweakID); 662 } 663 664 llvm::json::Value toJSON(const TweakArgs &A) { 665 return llvm::json::Object{ 666 {"tweakID", A.tweakID}, {"selection", A.selection}, {"file", A.file}}; 667 } 668 669 llvm::json::Value toJSON(const ApplyWorkspaceEditParams &Params) { 670 return llvm::json::Object{{"edit", Params.edit}}; 671 } 672 673 bool fromJSON(const llvm::json::Value &Response, 674 ApplyWorkspaceEditResponse &R) { 675 llvm::json::ObjectMapper O(Response); 676 if (!O || !O.map("applied", R.applied)) 677 return false; 678 O.map("failureReason", R.failureReason); 679 return true; 680 } 681 682 bool fromJSON(const llvm::json::Value &Params, TextDocumentPositionParams &R) { 683 llvm::json::ObjectMapper O(Params); 684 return O && O.map("textDocument", R.textDocument) && 685 O.map("position", R.position); 686 } 687 688 bool fromJSON(const llvm::json::Value &Params, CompletionContext &R) { 689 llvm::json::ObjectMapper O(Params); 690 if (!O) 691 return false; 692 693 int TriggerKind; 694 if (!O.map("triggerKind", TriggerKind)) 695 return false; 696 R.triggerKind = static_cast<CompletionTriggerKind>(TriggerKind); 697 698 if (auto *TC = Params.getAsObject()->get("triggerCharacter")) 699 return fromJSON(*TC, R.triggerCharacter); 700 return true; 701 } 702 703 bool fromJSON(const llvm::json::Value &Params, CompletionParams &R) { 704 if (!fromJSON(Params, static_cast<TextDocumentPositionParams &>(R))) 705 return false; 706 if (auto *Context = Params.getAsObject()->get("context")) 707 return fromJSON(*Context, R.context); 708 return true; 709 } 710 711 static llvm::StringRef toTextKind(MarkupKind Kind) { 712 switch (Kind) { 713 case MarkupKind::PlainText: 714 return "plaintext"; 715 case MarkupKind::Markdown: 716 return "markdown"; 717 } 718 llvm_unreachable("Invalid MarkupKind"); 719 } 720 721 bool fromJSON(const llvm::json::Value &V, MarkupKind &K) { 722 auto Str = V.getAsString(); 723 if (!Str) { 724 elog("Failed to parse markup kind: expected a string"); 725 return false; 726 } 727 if (*Str == "plaintext") 728 K = MarkupKind::PlainText; 729 else if (*Str == "markdown") 730 K = MarkupKind::Markdown; 731 else { 732 elog("Unknown markup kind: {0}", *Str); 733 return false; 734 } 735 return true; 736 } 737 738 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind K) { 739 return OS << toTextKind(K); 740 } 741 742 llvm::json::Value toJSON(const MarkupContent &MC) { 743 if (MC.value.empty()) 744 return nullptr; 745 746 return llvm::json::Object{ 747 {"kind", toTextKind(MC.kind)}, 748 {"value", MC.value}, 749 }; 750 } 751 752 llvm::json::Value toJSON(const Hover &H) { 753 llvm::json::Object Result{{"contents", toJSON(H.contents)}}; 754 755 if (H.range.hasValue()) 756 Result["range"] = toJSON(*H.range); 757 758 return std::move(Result); 759 } 760 761 bool fromJSON(const llvm::json::Value &E, CompletionItemKind &Out) { 762 if (auto T = E.getAsInteger()) { 763 if (*T < static_cast<int>(CompletionItemKind::Text) || 764 *T > static_cast<int>(CompletionItemKind::TypeParameter)) 765 return false; 766 Out = static_cast<CompletionItemKind>(*T); 767 return true; 768 } 769 return false; 770 } 771 772 CompletionItemKind 773 adjustKindToCapability(CompletionItemKind Kind, 774 CompletionItemKindBitset &SupportedCompletionItemKinds) { 775 auto KindVal = static_cast<size_t>(Kind); 776 if (KindVal >= CompletionItemKindMin && 777 KindVal <= SupportedCompletionItemKinds.size() && 778 SupportedCompletionItemKinds[KindVal]) 779 return Kind; 780 781 switch (Kind) { 782 // Provide some fall backs for common kinds that are close enough. 783 case CompletionItemKind::Folder: 784 return CompletionItemKind::File; 785 case CompletionItemKind::EnumMember: 786 return CompletionItemKind::Enum; 787 case CompletionItemKind::Struct: 788 return CompletionItemKind::Class; 789 default: 790 return CompletionItemKind::Text; 791 } 792 } 793 794 bool fromJSON(const llvm::json::Value &E, CompletionItemKindBitset &Out) { 795 if (auto *A = E.getAsArray()) { 796 for (size_t I = 0; I < A->size(); ++I) { 797 CompletionItemKind KindOut; 798 if (fromJSON((*A)[I], KindOut)) 799 Out.set(size_t(KindOut)); 800 } 801 return true; 802 } 803 return false; 804 } 805 806 llvm::json::Value toJSON(const CompletionItem &CI) { 807 assert(!CI.label.empty() && "completion item label is required"); 808 llvm::json::Object Result{{"label", CI.label}}; 809 if (CI.kind != CompletionItemKind::Missing) 810 Result["kind"] = static_cast<int>(CI.kind); 811 if (!CI.detail.empty()) 812 Result["detail"] = CI.detail; 813 if (!CI.documentation.empty()) 814 Result["documentation"] = CI.documentation; 815 if (!CI.sortText.empty()) 816 Result["sortText"] = CI.sortText; 817 if (!CI.filterText.empty()) 818 Result["filterText"] = CI.filterText; 819 if (!CI.insertText.empty()) 820 Result["insertText"] = CI.insertText; 821 if (CI.insertTextFormat != InsertTextFormat::Missing) 822 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat); 823 if (CI.textEdit) 824 Result["textEdit"] = *CI.textEdit; 825 if (!CI.additionalTextEdits.empty()) 826 Result["additionalTextEdits"] = llvm::json::Array(CI.additionalTextEdits); 827 if (CI.deprecated) 828 Result["deprecated"] = CI.deprecated; 829 return std::move(Result); 830 } 831 832 llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) { 833 O << I.label << " - " << toJSON(I); 834 return O; 835 } 836 837 bool operator<(const CompletionItem &L, const CompletionItem &R) { 838 return (L.sortText.empty() ? L.label : L.sortText) < 839 (R.sortText.empty() ? R.label : R.sortText); 840 } 841 842 llvm::json::Value toJSON(const CompletionList &L) { 843 return llvm::json::Object{ 844 {"isIncomplete", L.isIncomplete}, 845 {"items", llvm::json::Array(L.items)}, 846 }; 847 } 848 849 llvm::json::Value toJSON(const ParameterInformation &PI) { 850 assert((PI.labelOffsets.hasValue() || !PI.labelString.empty()) && 851 "parameter information label is required"); 852 llvm::json::Object Result; 853 if (PI.labelOffsets) 854 Result["label"] = 855 llvm::json::Array({PI.labelOffsets->first, PI.labelOffsets->second}); 856 else 857 Result["label"] = PI.labelString; 858 if (!PI.documentation.empty()) 859 Result["documentation"] = PI.documentation; 860 return std::move(Result); 861 } 862 863 llvm::json::Value toJSON(const SignatureInformation &SI) { 864 assert(!SI.label.empty() && "signature information label is required"); 865 llvm::json::Object Result{ 866 {"label", SI.label}, 867 {"parameters", llvm::json::Array(SI.parameters)}, 868 }; 869 if (!SI.documentation.empty()) 870 Result["documentation"] = SI.documentation; 871 return std::move(Result); 872 } 873 874 llvm::raw_ostream &operator<<(llvm::raw_ostream &O, 875 const SignatureInformation &I) { 876 O << I.label << " - " << toJSON(I); 877 return O; 878 } 879 880 llvm::json::Value toJSON(const SignatureHelp &SH) { 881 assert(SH.activeSignature >= 0 && 882 "Unexpected negative value for number of active signatures."); 883 assert(SH.activeParameter >= 0 && 884 "Unexpected negative value for active parameter index"); 885 return llvm::json::Object{ 886 {"activeSignature", SH.activeSignature}, 887 {"activeParameter", SH.activeParameter}, 888 {"signatures", llvm::json::Array(SH.signatures)}, 889 }; 890 } 891 892 bool fromJSON(const llvm::json::Value &Params, RenameParams &R) { 893 llvm::json::ObjectMapper O(Params); 894 return O && O.map("textDocument", R.textDocument) && 895 O.map("position", R.position) && O.map("newName", R.newName); 896 } 897 898 llvm::json::Value toJSON(const DocumentHighlight &DH) { 899 return llvm::json::Object{ 900 {"range", toJSON(DH.range)}, 901 {"kind", static_cast<int>(DH.kind)}, 902 }; 903 } 904 905 llvm::json::Value toJSON(const FileStatus &FStatus) { 906 return llvm::json::Object{ 907 {"uri", FStatus.uri}, 908 {"state", FStatus.state}, 909 }; 910 } 911 912 llvm::raw_ostream &operator<<(llvm::raw_ostream &O, 913 const DocumentHighlight &V) { 914 O << V.range; 915 if (V.kind == DocumentHighlightKind::Read) 916 O << "(r)"; 917 if (V.kind == DocumentHighlightKind::Write) 918 O << "(w)"; 919 return O; 920 } 921 922 bool fromJSON(const llvm::json::Value &Params, 923 DidChangeConfigurationParams &CCP) { 924 llvm::json::ObjectMapper O(Params); 925 return O && O.map("settings", CCP.settings); 926 } 927 928 bool fromJSON(const llvm::json::Value &Params, 929 ClangdCompileCommand &CDbUpdate) { 930 llvm::json::ObjectMapper O(Params); 931 return O && O.map("workingDirectory", CDbUpdate.workingDirectory) && 932 O.map("compilationCommand", CDbUpdate.compilationCommand); 933 } 934 935 bool fromJSON(const llvm::json::Value &Params, ConfigurationSettings &S) { 936 llvm::json::ObjectMapper O(Params); 937 if (!O) 938 return true; // 'any' type in LSP. 939 O.map("compilationDatabaseChanges", S.compilationDatabaseChanges); 940 return true; 941 } 942 943 bool fromJSON(const llvm::json::Value &Params, InitializationOptions &Opts) { 944 llvm::json::ObjectMapper O(Params); 945 if (!O) 946 return true; // 'any' type in LSP. 947 948 fromJSON(Params, Opts.ConfigSettings); 949 O.map("compilationDatabasePath", Opts.compilationDatabasePath); 950 O.map("fallbackFlags", Opts.fallbackFlags); 951 O.map("clangdFileStatus", Opts.FileStatus); 952 return true; 953 } 954 955 bool fromJSON(const llvm::json::Value &E, TypeHierarchyDirection &Out) { 956 auto T = E.getAsInteger(); 957 if (!T) 958 return false; 959 if (*T < static_cast<int>(TypeHierarchyDirection::Children) || 960 *T > static_cast<int>(TypeHierarchyDirection::Both)) 961 return false; 962 Out = static_cast<TypeHierarchyDirection>(*T); 963 return true; 964 } 965 966 bool fromJSON(const llvm::json::Value &Params, TypeHierarchyParams &R) { 967 llvm::json::ObjectMapper O(Params); 968 return O && O.map("textDocument", R.textDocument) && 969 O.map("position", R.position) && O.map("resolve", R.resolve) && 970 O.map("direction", R.direction); 971 } 972 973 llvm::raw_ostream &operator<<(llvm::raw_ostream &O, 974 const TypeHierarchyItem &I) { 975 return O << I.name << " - " << toJSON(I); 976 } 977 978 llvm::json::Value toJSON(const TypeHierarchyItem &I) { 979 llvm::json::Object Result{{"name", I.name}, 980 {"kind", static_cast<int>(I.kind)}, 981 {"range", I.range}, 982 {"selectionRange", I.selectionRange}, 983 {"uri", I.uri}}; 984 985 if (I.detail) 986 Result["detail"] = I.detail; 987 if (I.deprecated) 988 Result["deprecated"] = I.deprecated; 989 if (I.parents) 990 Result["parents"] = I.parents; 991 if (I.children) 992 Result["children"] = I.children; 993 if (I.data) 994 Result["data"] = I.data; 995 return std::move(Result); 996 } 997 998 bool fromJSON(const llvm::json::Value &Params, TypeHierarchyItem &I) { 999 llvm::json::ObjectMapper O(Params); 1000 1001 // Required fields. 1002 if (!(O && O.map("name", I.name) && O.map("kind", I.kind) && 1003 O.map("uri", I.uri) && O.map("range", I.range) && 1004 O.map("selectionRange", I.selectionRange))) { 1005 return false; 1006 } 1007 1008 // Optional fields. 1009 O.map("detail", I.detail); 1010 O.map("deprecated", I.deprecated); 1011 O.map("parents", I.parents); 1012 O.map("children", I.children); 1013 O.map("data", I.data); 1014 1015 return true; 1016 } 1017 1018 bool fromJSON(const llvm::json::Value &Params, 1019 ResolveTypeHierarchyItemParams &P) { 1020 llvm::json::ObjectMapper O(Params); 1021 return O && O.map("item", P.item) && O.map("resolve", P.resolve) && 1022 O.map("direction", P.direction); 1023 } 1024 1025 bool fromJSON(const llvm::json::Value &Params, ReferenceParams &R) { 1026 TextDocumentPositionParams &Base = R; 1027 return fromJSON(Params, Base); 1028 } 1029 1030 static const char *toString(OffsetEncoding OE) { 1031 switch (OE) { 1032 case OffsetEncoding::UTF8: 1033 return "utf-8"; 1034 case OffsetEncoding::UTF16: 1035 return "utf-16"; 1036 case OffsetEncoding::UTF32: 1037 return "utf-32"; 1038 case OffsetEncoding::UnsupportedEncoding: 1039 return "unknown"; 1040 } 1041 llvm_unreachable("Unknown clang.clangd.OffsetEncoding"); 1042 } 1043 llvm::json::Value toJSON(const OffsetEncoding &OE) { return toString(OE); } 1044 bool fromJSON(const llvm::json::Value &V, OffsetEncoding &OE) { 1045 auto Str = V.getAsString(); 1046 if (!Str) 1047 return false; 1048 OE = llvm::StringSwitch<OffsetEncoding>(*Str) 1049 .Case("utf-8", OffsetEncoding::UTF8) 1050 .Case("utf-16", OffsetEncoding::UTF16) 1051 .Case("utf-32", OffsetEncoding::UTF32) 1052 .Default(OffsetEncoding::UnsupportedEncoding); 1053 return true; 1054 } 1055 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OffsetEncoding Enc) { 1056 return OS << toString(Enc); 1057 } 1058 1059 bool operator==(const SemanticHighlightingInformation &Lhs, 1060 const SemanticHighlightingInformation &Rhs) { 1061 return Lhs.Line == Rhs.Line && Lhs.Tokens == Rhs.Tokens; 1062 } 1063 1064 llvm::json::Value toJSON(const SemanticHighlightingInformation &Highlighting) { 1065 return llvm::json::Object{{"line", Highlighting.Line}, 1066 {"tokens", Highlighting.Tokens}}; 1067 } 1068 1069 llvm::json::Value toJSON(const SemanticHighlightingParams &Highlighting) { 1070 return llvm::json::Object{ 1071 {"textDocument", Highlighting.TextDocument}, 1072 {"lines", std::move(Highlighting.Lines)}, 1073 }; 1074 } 1075 1076 bool fromJSON(const llvm::json::Value &Params, SelectionRangeParams &P) { 1077 llvm::json::ObjectMapper O(Params); 1078 return O && O.map("textDocument", P.textDocument) && 1079 O.map("positions", P.positions); 1080 } 1081 1082 llvm::json::Value toJSON(const SelectionRange &Out) { 1083 if (Out.parent) { 1084 return llvm::json::Object{{"range", Out.range}, 1085 {"parent", toJSON(*Out.parent)}}; 1086 } 1087 return llvm::json::Object{{"range", Out.range}}; 1088 } 1089 } // namespace clangd 1090 } // namespace clang 1091