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