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