|  | //===--- Protocol.cpp - Language Server Protocol Implementation -----------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file contains the serialization code for the LSP structs. | 
|  | // FIXME: This is extremely repetetive and ugly. Is there a better way? | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "Protocol.h" | 
|  | #include "clang/Basic/LLVM.h" | 
|  | #include "llvm/ADT/SmallString.h" | 
|  | #include "llvm/Support/Format.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include "llvm/Support/Path.h" | 
|  | using namespace clang::clangd; | 
|  |  | 
|  |  | 
|  | URI URI::fromUri(llvm::StringRef uri) { | 
|  | URI Result; | 
|  | Result.uri = uri; | 
|  | uri.consume_front("file://"); | 
|  | // For Windows paths e.g. /X: | 
|  | if (uri.size() > 2 && uri[0] == '/' && uri[2] == ':') | 
|  | uri.consume_front("/"); | 
|  | // Make sure that file paths are in native separators | 
|  | Result.file = llvm::sys::path::convert_to_slash(uri); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | URI URI::fromFile(llvm::StringRef file) { | 
|  | using namespace llvm::sys; | 
|  | URI Result; | 
|  | Result.file = file; | 
|  | Result.uri = "file://"; | 
|  | // For Windows paths e.g. X: | 
|  | if (file.size() > 1 && file[1] == ':') | 
|  | Result.uri += "/"; | 
|  | // Make sure that uri paths are with posix separators | 
|  | Result.uri += path::convert_to_slash(file, path::Style::posix); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | URI URI::parse(llvm::yaml::ScalarNode *Param) { | 
|  | llvm::SmallString<10> Storage; | 
|  | return URI::fromUri(Param->getValue(Storage)); | 
|  | } | 
|  |  | 
|  | std::string URI::unparse(const URI &U) { | 
|  | return U.uri; | 
|  | } | 
|  |  | 
|  | llvm::Optional<TextDocumentIdentifier> | 
|  | TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params) { | 
|  | TextDocumentIdentifier Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  |  | 
|  | if (KeyValue == "uri") { | 
|  | Result.uri = URI::parse(Value); | 
|  | } else if (KeyValue == "version") { | 
|  | // FIXME: parse version, but only for VersionedTextDocumentIdentifiers. | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<Position> Position::parse(llvm::yaml::MappingNode *Params) { | 
|  | Position Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "line") { | 
|  | long long Val; | 
|  | if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val)) | 
|  | return llvm::None; | 
|  | Result.line = Val; | 
|  | } else if (KeyValue == "character") { | 
|  | long long Val; | 
|  | if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val)) | 
|  | return llvm::None; | 
|  | Result.character = Val; | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | std::string Position::unparse(const Position &P) { | 
|  | std::string Result; | 
|  | llvm::raw_string_ostream(Result) | 
|  | << llvm::format(R"({"line": %d, "character": %d})", P.line, P.character); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<Range> Range::parse(llvm::yaml::MappingNode *Params) { | 
|  | Range Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "start") { | 
|  | auto Parsed = Position::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.start = std::move(*Parsed); | 
|  | } else if (KeyValue == "end") { | 
|  | auto Parsed = Position::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.end = std::move(*Parsed); | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | std::string Range::unparse(const Range &P) { | 
|  | std::string Result; | 
|  | llvm::raw_string_ostream(Result) << llvm::format( | 
|  | R"({"start": %s, "end": %s})", Position::unparse(P.start).c_str(), | 
|  | Position::unparse(P.end).c_str()); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<TextDocumentItem> | 
|  | TextDocumentItem::parse(llvm::yaml::MappingNode *Params) { | 
|  | TextDocumentItem Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "uri") { | 
|  | Result.uri = URI::parse(Value); | 
|  | } else if (KeyValue == "languageId") { | 
|  | Result.languageId = Value->getValue(Storage); | 
|  | } else if (KeyValue == "version") { | 
|  | long long Val; | 
|  | if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val)) | 
|  | return llvm::None; | 
|  | Result.version = Val; | 
|  | } else if (KeyValue == "text") { | 
|  | Result.text = Value->getValue(Storage); | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<TextEdit> TextEdit::parse(llvm::yaml::MappingNode *Params) { | 
|  | TextEdit Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = NextKeyValue.getValue(); | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "range") { | 
|  | auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value); | 
|  | if (!Map) | 
|  | return llvm::None; | 
|  | auto Parsed = Range::parse(Map); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.range = std::move(*Parsed); | 
|  | } else if (KeyValue == "newText") { | 
|  | auto *Node = dyn_cast<llvm::yaml::ScalarNode>(Value); | 
|  | if (!Node) | 
|  | return llvm::None; | 
|  | Result.newText = Node->getValue(Storage); | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | std::string TextEdit::unparse(const TextEdit &P) { | 
|  | std::string Result; | 
|  | llvm::raw_string_ostream(Result) << llvm::format( | 
|  | R"({"range": %s, "newText": "%s"})", Range::unparse(P.range).c_str(), | 
|  | llvm::yaml::escape(P.newText).c_str()); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<DidOpenTextDocumentParams> | 
|  | DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params) { | 
|  | DidOpenTextDocumentParams Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "textDocument") { | 
|  | auto Parsed = TextDocumentItem::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.textDocument = std::move(*Parsed); | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<DidChangeTextDocumentParams> | 
|  | DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params) { | 
|  | DidChangeTextDocumentParams Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = NextKeyValue.getValue(); | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "textDocument") { | 
|  | auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value); | 
|  | if (!Map) | 
|  | return llvm::None; | 
|  | auto Parsed = TextDocumentIdentifier::parse(Map); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.textDocument = std::move(*Parsed); | 
|  | } else if (KeyValue == "contentChanges") { | 
|  | auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value); | 
|  | if (!Seq) | 
|  | return llvm::None; | 
|  | for (auto &Item : *Seq) { | 
|  | auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item); | 
|  | if (!I) | 
|  | return llvm::None; | 
|  | auto Parsed = TextDocumentContentChangeEvent::parse(I); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.contentChanges.push_back(std::move(*Parsed)); | 
|  | } | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<TextDocumentContentChangeEvent> | 
|  | TextDocumentContentChangeEvent::parse(llvm::yaml::MappingNode *Params) { | 
|  | TextDocumentContentChangeEvent Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "text") { | 
|  | Result.text = Value->getValue(Storage); | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<FormattingOptions> | 
|  | FormattingOptions::parse(llvm::yaml::MappingNode *Params) { | 
|  | FormattingOptions Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "tabSize") { | 
|  | long long Val; | 
|  | if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val)) | 
|  | return llvm::None; | 
|  | Result.tabSize = Val; | 
|  | } else if (KeyValue == "insertSpaces") { | 
|  | long long Val; | 
|  | StringRef Str = Value->getValue(Storage); | 
|  | if (llvm::getAsSignedInteger(Str, 0, Val)) { | 
|  | if (Str == "true") | 
|  | Val = 1; | 
|  | else if (Str == "false") | 
|  | Val = 0; | 
|  | else | 
|  | return llvm::None; | 
|  | } | 
|  | Result.insertSpaces = Val; | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | std::string FormattingOptions::unparse(const FormattingOptions &P) { | 
|  | std::string Result; | 
|  | llvm::raw_string_ostream(Result) << llvm::format( | 
|  | R"({"tabSize": %d, "insertSpaces": %d})", P.tabSize, P.insertSpaces); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<DocumentRangeFormattingParams> | 
|  | DocumentRangeFormattingParams::parse(llvm::yaml::MappingNode *Params) { | 
|  | DocumentRangeFormattingParams Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "textDocument") { | 
|  | auto Parsed = TextDocumentIdentifier::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.textDocument = std::move(*Parsed); | 
|  | } else if (KeyValue == "range") { | 
|  | auto Parsed = Range::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.range = std::move(*Parsed); | 
|  | } else if (KeyValue == "options") { | 
|  | auto Parsed = FormattingOptions::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.options = std::move(*Parsed); | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<DocumentOnTypeFormattingParams> | 
|  | DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params) { | 
|  | DocumentOnTypeFormattingParams Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  |  | 
|  | if (KeyValue == "ch") { | 
|  | auto *ScalarValue = | 
|  | dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue()); | 
|  | if (!ScalarValue) | 
|  | return llvm::None; | 
|  | llvm::SmallString<10> Storage; | 
|  | Result.ch = ScalarValue->getValue(Storage); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  | if (KeyValue == "textDocument") { | 
|  | auto Parsed = TextDocumentIdentifier::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.textDocument = std::move(*Parsed); | 
|  | } else if (KeyValue == "position") { | 
|  | auto Parsed = Position::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.position = std::move(*Parsed); | 
|  | } else if (KeyValue == "options") { | 
|  | auto Parsed = FormattingOptions::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.options = std::move(*Parsed); | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<DocumentFormattingParams> | 
|  | DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params) { | 
|  | DocumentFormattingParams Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "textDocument") { | 
|  | auto Parsed = TextDocumentIdentifier::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.textDocument = std::move(*Parsed); | 
|  | } else if (KeyValue == "options") { | 
|  | auto Parsed = FormattingOptions::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.options = std::move(*Parsed); | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<Diagnostic> Diagnostic::parse(llvm::yaml::MappingNode *Params) { | 
|  | Diagnostic Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "range") { | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  | auto Parsed = Range::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.range = std::move(*Parsed); | 
|  | } else if (KeyValue == "severity") { | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  | long long Val; | 
|  | if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val)) | 
|  | return llvm::None; | 
|  | Result.severity = Val; | 
|  | } else if (KeyValue == "message") { | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  | Result.message = Value->getValue(Storage); | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<CodeActionContext> | 
|  | CodeActionContext::parse(llvm::yaml::MappingNode *Params) { | 
|  | CodeActionContext Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = NextKeyValue.getValue(); | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "diagnostics") { | 
|  | auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value); | 
|  | if (!Seq) | 
|  | return llvm::None; | 
|  | for (auto &Item : *Seq) { | 
|  | auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item); | 
|  | if (!I) | 
|  | return llvm::None; | 
|  | auto Parsed = Diagnostic::parse(I); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.diagnostics.push_back(std::move(*Parsed)); | 
|  | } | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<CodeActionParams> | 
|  | CodeActionParams::parse(llvm::yaml::MappingNode *Params) { | 
|  | CodeActionParams Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "textDocument") { | 
|  | auto Parsed = TextDocumentIdentifier::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.textDocument = std::move(*Parsed); | 
|  | } else if (KeyValue == "range") { | 
|  | auto Parsed = Range::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.range = std::move(*Parsed); | 
|  | } else if (KeyValue == "context") { | 
|  | auto Parsed = CodeActionContext::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.context = std::move(*Parsed); | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | llvm::Optional<TextDocumentPositionParams> | 
|  | TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params) { | 
|  | TextDocumentPositionParams Result; | 
|  | for (auto &NextKeyValue : *Params) { | 
|  | auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey()); | 
|  | if (!KeyString) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> KeyStorage; | 
|  | StringRef KeyValue = KeyString->getValue(KeyStorage); | 
|  | auto *Value = | 
|  | dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue()); | 
|  | if (!Value) | 
|  | return llvm::None; | 
|  |  | 
|  | llvm::SmallString<10> Storage; | 
|  | if (KeyValue == "textDocument") { | 
|  | auto Parsed = TextDocumentIdentifier::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.textDocument = std::move(*Parsed); | 
|  | } else if (KeyValue == "position") { | 
|  | auto Parsed = Position::parse(Value); | 
|  | if (!Parsed) | 
|  | return llvm::None; | 
|  | Result.position = std::move(*Parsed); | 
|  | } else { | 
|  | return llvm::None; | 
|  | } | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | std::string CompletionItem::unparse(const CompletionItem &CI) { | 
|  | std::string Result = "{"; | 
|  | llvm::raw_string_ostream Os(Result); | 
|  | assert(!CI.label.empty() && "completion item label is required"); | 
|  | Os << R"("label":")" << llvm::yaml::escape(CI.label) << R"(",)"; | 
|  | if (CI.kind != CompletionItemKind::Missing) | 
|  | Os << R"("kind":)" << static_cast<int>(CI.kind) << R"(",)"; | 
|  | if (!CI.detail.empty()) | 
|  | Os << R"("detail":")" << llvm::yaml::escape(CI.detail) << R"(",)"; | 
|  | if (!CI.documentation.empty()) | 
|  | Os << R"("documentation":")" << llvm::yaml::escape(CI.documentation) | 
|  | << R"(",)"; | 
|  | if (!CI.sortText.empty()) | 
|  | Os << R"("sortText":")" << llvm::yaml::escape(CI.sortText) << R"(",)"; | 
|  | if (!CI.filterText.empty()) | 
|  | Os << R"("filterText":")" << llvm::yaml::escape(CI.filterText) << R"(",)"; | 
|  | if (!CI.insertText.empty()) | 
|  | Os << R"("insertText":")" << llvm::yaml::escape(CI.insertText) << R"(",)"; | 
|  | if (CI.insertTextFormat != InsertTextFormat::Missing) { | 
|  | Os << R"("insertTextFormat":")" << static_cast<int>(CI.insertTextFormat) | 
|  | << R"(",)"; | 
|  | } | 
|  | if (CI.textEdit) | 
|  | Os << R"("textEdit":)" << TextEdit::unparse(*CI.textEdit) << ','; | 
|  | if (!CI.additionalTextEdits.empty()) { | 
|  | Os << R"("additionalTextEdits":[)"; | 
|  | for (const auto &Edit : CI.additionalTextEdits) | 
|  | Os << TextEdit::unparse(Edit) << ","; | 
|  | Os.flush(); | 
|  | // The list additionalTextEdits is guaranteed nonempty at this point. | 
|  | // Replace the trailing comma with right brace. | 
|  | Result.back() = ']'; | 
|  | } | 
|  | Os.flush(); | 
|  | // Label is required, so Result is guaranteed to have a trailing comma. | 
|  | Result.back() = '}'; | 
|  | return Result; | 
|  | } |