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