xref: /llvm-project/mlir/lib/Tools/lsp-server-support/Protocol.cpp (revision db791b278a414fb6df1acc1799adcf11d8fb9169)
17bc52733SRiver Riddle //===--- Protocol.cpp - Language Server Protocol Implementation -----------===//
27bc52733SRiver Riddle //
37bc52733SRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47bc52733SRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
57bc52733SRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67bc52733SRiver Riddle //
77bc52733SRiver Riddle //===----------------------------------------------------------------------===//
87bc52733SRiver Riddle //
97bc52733SRiver Riddle // This file contains the serialization code for the LSP structs.
107bc52733SRiver Riddle //
117bc52733SRiver Riddle //===----------------------------------------------------------------------===//
127bc52733SRiver Riddle 
13305d7185SRiver Riddle #include "mlir/Tools/lsp-server-support/Protocol.h"
14305d7185SRiver Riddle #include "mlir/Tools/lsp-server-support/Logging.h"
157bc52733SRiver Riddle #include "llvm/ADT/Hashing.h"
167bc52733SRiver Riddle #include "llvm/ADT/SmallString.h"
17b0abd489SElliot Goodrich #include "llvm/ADT/StringExtras.h"
18f7b8a70eSRiver Riddle #include "llvm/ADT/StringSet.h"
197bc52733SRiver Riddle #include "llvm/Support/ErrorHandling.h"
207bc52733SRiver Riddle #include "llvm/Support/Format.h"
217bc52733SRiver Riddle #include "llvm/Support/FormatVariadic.h"
227bc52733SRiver Riddle #include "llvm/Support/JSON.h"
236187178eSRiver Riddle #include "llvm/Support/MemoryBuffer.h"
247bc52733SRiver Riddle #include "llvm/Support/Path.h"
257bc52733SRiver Riddle #include "llvm/Support/raw_ostream.h"
267bc52733SRiver Riddle 
277bc52733SRiver Riddle using namespace mlir;
287bc52733SRiver Riddle using namespace mlir::lsp;
297bc52733SRiver Riddle 
307bc52733SRiver Riddle // Helper that doesn't treat `null` and absent fields as failures.
317bc52733SRiver Riddle template <typename T>
mapOptOrNull(const llvm::json::Value & params,llvm::StringLiteral prop,T & out,llvm::json::Path path)327bc52733SRiver Riddle static bool mapOptOrNull(const llvm::json::Value &params,
337bc52733SRiver Riddle                          llvm::StringLiteral prop, T &out,
347bc52733SRiver Riddle                          llvm::json::Path path) {
357bc52733SRiver Riddle   const llvm::json::Object *o = params.getAsObject();
367bc52733SRiver Riddle   assert(o);
377bc52733SRiver Riddle 
387bc52733SRiver Riddle   // Field is missing or null.
397bc52733SRiver Riddle   auto *v = o->get(prop);
40037f0995SKazu Hirata   if (!v || v->getAsNull())
417bc52733SRiver Riddle     return true;
427bc52733SRiver Riddle   return fromJSON(*v, out, path.field(prop));
437bc52733SRiver Riddle }
447bc52733SRiver Riddle 
457bc52733SRiver Riddle //===----------------------------------------------------------------------===//
467bc52733SRiver Riddle // LSPError
477bc52733SRiver Riddle //===----------------------------------------------------------------------===//
487bc52733SRiver Riddle 
497bc52733SRiver Riddle char LSPError::ID;
507bc52733SRiver Riddle 
517bc52733SRiver Riddle //===----------------------------------------------------------------------===//
527bc52733SRiver Riddle // URIForFile
537bc52733SRiver Riddle //===----------------------------------------------------------------------===//
547bc52733SRiver Riddle 
isWindowsPath(StringRef path)557bc52733SRiver Riddle static bool isWindowsPath(StringRef path) {
567bc52733SRiver Riddle   return path.size() > 1 && llvm::isAlpha(path[0]) && path[1] == ':';
577bc52733SRiver Riddle }
587bc52733SRiver Riddle 
isNetworkPath(StringRef path)597bc52733SRiver Riddle static bool isNetworkPath(StringRef path) {
607bc52733SRiver Riddle   return path.size() > 2 && path[0] == path[1] &&
617bc52733SRiver Riddle          llvm::sys::path::is_separator(path[0]);
627bc52733SRiver Riddle }
637bc52733SRiver Riddle 
shouldEscapeInURI(unsigned char c)647bc52733SRiver Riddle static bool shouldEscapeInURI(unsigned char c) {
657bc52733SRiver Riddle   // Unreserved characters.
667bc52733SRiver Riddle   if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
677bc52733SRiver Riddle       (c >= '0' && c <= '9'))
687bc52733SRiver Riddle     return false;
697bc52733SRiver Riddle 
707bc52733SRiver Riddle   switch (c) {
717bc52733SRiver Riddle   case '-':
727bc52733SRiver Riddle   case '_':
737bc52733SRiver Riddle   case '.':
747bc52733SRiver Riddle   case '~':
757bc52733SRiver Riddle   // '/' is only reserved when parsing.
767bc52733SRiver Riddle   case '/':
777bc52733SRiver Riddle   // ':' is only reserved for relative URI paths, which we doesn't produce.
787bc52733SRiver Riddle   case ':':
797bc52733SRiver Riddle     return false;
807bc52733SRiver Riddle   }
817bc52733SRiver Riddle   return true;
827bc52733SRiver Riddle }
837bc52733SRiver Riddle 
847bc52733SRiver Riddle /// Encodes a string according to percent-encoding.
857bc52733SRiver Riddle /// - Unreserved characters are not escaped.
867bc52733SRiver Riddle /// - Reserved characters always escaped with exceptions like '/'.
877bc52733SRiver Riddle /// - All other characters are escaped.
percentEncode(StringRef content,std::string & out)887bc52733SRiver Riddle static void percentEncode(StringRef content, std::string &out) {
897bc52733SRiver Riddle   for (unsigned char c : content) {
907bc52733SRiver Riddle     if (shouldEscapeInURI(c)) {
917bc52733SRiver Riddle       out.push_back('%');
927bc52733SRiver Riddle       out.push_back(llvm::hexdigit(c / 16));
937bc52733SRiver Riddle       out.push_back(llvm::hexdigit(c % 16));
947bc52733SRiver Riddle     } else {
957bc52733SRiver Riddle       out.push_back(c);
967bc52733SRiver Riddle     }
977bc52733SRiver Riddle   }
987bc52733SRiver Riddle }
997bc52733SRiver Riddle 
1007bc52733SRiver Riddle /// Decodes a string according to percent-encoding.
percentDecode(StringRef content)1017bc52733SRiver Riddle static std::string percentDecode(StringRef content) {
1027bc52733SRiver Riddle   std::string result;
1037bc52733SRiver Riddle   for (auto i = content.begin(), e = content.end(); i != e; ++i) {
1047bc52733SRiver Riddle     if (*i != '%') {
1057bc52733SRiver Riddle       result += *i;
1067bc52733SRiver Riddle       continue;
1077bc52733SRiver Riddle     }
1087bc52733SRiver Riddle     if (*i == '%' && i + 2 < content.end() && llvm::isHexDigit(*(i + 1)) &&
1097bc52733SRiver Riddle         llvm::isHexDigit(*(i + 2))) {
1107bc52733SRiver Riddle       result.push_back(llvm::hexFromNibbles(*(i + 1), *(i + 2)));
1117bc52733SRiver Riddle       i += 2;
1127bc52733SRiver Riddle     } else {
1137bc52733SRiver Riddle       result.push_back(*i);
1147bc52733SRiver Riddle     }
1157bc52733SRiver Riddle   }
1167bc52733SRiver Riddle   return result;
1177bc52733SRiver Riddle }
1187bc52733SRiver Riddle 
119f7b8a70eSRiver Riddle /// Return the set containing the supported URI schemes.
getSupportedSchemes()120f7b8a70eSRiver Riddle static StringSet<> &getSupportedSchemes() {
121f7b8a70eSRiver Riddle   static StringSet<> schemes({"file", "test"});
122f7b8a70eSRiver Riddle   return schemes;
123f7b8a70eSRiver Riddle }
124f7b8a70eSRiver Riddle 
125f7b8a70eSRiver Riddle /// Returns true if the given scheme is structurally valid, i.e. it does not
126f7b8a70eSRiver Riddle /// contain any invalid scheme characters. This does not check that the scheme
127f7b8a70eSRiver Riddle /// is actually supported.
isStructurallyValidScheme(StringRef scheme)128f7b8a70eSRiver Riddle static bool isStructurallyValidScheme(StringRef scheme) {
1297bc52733SRiver Riddle   if (scheme.empty())
1307bc52733SRiver Riddle     return false;
1317bc52733SRiver Riddle   if (!llvm::isAlpha(scheme[0]))
1327bc52733SRiver Riddle     return false;
1336d9cd919SKazu Hirata   return llvm::all_of(llvm::drop_begin(scheme), [](char c) {
1347bc52733SRiver Riddle     return llvm::isAlnum(c) || c == '+' || c == '.' || c == '-';
1357bc52733SRiver Riddle   });
1367bc52733SRiver Riddle }
1377bc52733SRiver Riddle 
uriFromAbsolutePath(StringRef absolutePath,StringRef scheme)138f7b8a70eSRiver Riddle static llvm::Expected<std::string> uriFromAbsolutePath(StringRef absolutePath,
139f7b8a70eSRiver Riddle                                                        StringRef scheme) {
1407bc52733SRiver Riddle   std::string body;
1417bc52733SRiver Riddle   StringRef authority;
1427bc52733SRiver Riddle   StringRef root = llvm::sys::path::root_name(absolutePath);
1437bc52733SRiver Riddle   if (isNetworkPath(root)) {
1447bc52733SRiver Riddle     // Windows UNC paths e.g. \\server\share => file://server/share
1457bc52733SRiver Riddle     authority = root.drop_front(2);
1467bc52733SRiver Riddle     absolutePath.consume_front(root);
1477bc52733SRiver Riddle   } else if (isWindowsPath(root)) {
1487bc52733SRiver Riddle     // Windows paths e.g. X:\path => file:///X:/path
1497bc52733SRiver Riddle     body = "/";
1507bc52733SRiver Riddle   }
1517bc52733SRiver Riddle   body += llvm::sys::path::convert_to_slash(absolutePath);
1527bc52733SRiver Riddle 
153f7b8a70eSRiver Riddle   std::string uri = scheme.str() + ":";
1547bc52733SRiver Riddle   if (authority.empty() && body.empty())
1557bc52733SRiver Riddle     return uri;
1567bc52733SRiver Riddle 
1577bc52733SRiver Riddle   // If authority if empty, we only print body if it starts with "/"; otherwise,
1587bc52733SRiver Riddle   // the URI is invalid.
15988d319a2SKazu Hirata   if (!authority.empty() || StringRef(body).starts_with("/")) {
1607bc52733SRiver Riddle     uri.append("//");
1617bc52733SRiver Riddle     percentEncode(authority, uri);
1627bc52733SRiver Riddle   }
1637bc52733SRiver Riddle   percentEncode(body, uri);
1647bc52733SRiver Riddle   return uri;
1657bc52733SRiver Riddle }
1667bc52733SRiver Riddle 
getAbsolutePath(StringRef authority,StringRef body)1677bc52733SRiver Riddle static llvm::Expected<std::string> getAbsolutePath(StringRef authority,
1687bc52733SRiver Riddle                                                    StringRef body) {
16988d319a2SKazu Hirata   if (!body.starts_with("/"))
1707bc52733SRiver Riddle     return llvm::createStringError(
1717bc52733SRiver Riddle         llvm::inconvertibleErrorCode(),
1727bc52733SRiver Riddle         "File scheme: expect body to be an absolute path starting "
1737bc52733SRiver Riddle         "with '/': " +
1747bc52733SRiver Riddle             body);
1757bc52733SRiver Riddle   SmallString<128> path;
1767bc52733SRiver Riddle   if (!authority.empty()) {
1777bc52733SRiver Riddle     // Windows UNC paths e.g. file://server/share => \\server\share
1787bc52733SRiver Riddle     ("//" + authority).toVector(path);
1797bc52733SRiver Riddle   } else if (isWindowsPath(body.substr(1))) {
1807bc52733SRiver Riddle     // Windows paths e.g. file:///X:/path => X:\path
1817bc52733SRiver Riddle     body.consume_front("/");
1827bc52733SRiver Riddle   }
1837bc52733SRiver Riddle   path.append(body);
1847bc52733SRiver Riddle   llvm::sys::path::native(path);
1857bc52733SRiver Riddle   return std::string(path);
1867bc52733SRiver Riddle }
1877bc52733SRiver Riddle 
parseFilePathFromURI(StringRef origUri)1887bc52733SRiver Riddle static llvm::Expected<std::string> parseFilePathFromURI(StringRef origUri) {
1897bc52733SRiver Riddle   StringRef uri = origUri;
1907bc52733SRiver Riddle 
1917bc52733SRiver Riddle   // Decode the scheme of the URI.
1927bc52733SRiver Riddle   size_t pos = uri.find(':');
1937bc52733SRiver Riddle   if (pos == StringRef::npos)
1947bc52733SRiver Riddle     return llvm::createStringError(llvm::inconvertibleErrorCode(),
1957bc52733SRiver Riddle                                    "Scheme must be provided in URI: " +
1967bc52733SRiver Riddle                                        origUri);
1977bc52733SRiver Riddle   StringRef schemeStr = uri.substr(0, pos);
1987bc52733SRiver Riddle   std::string uriScheme = percentDecode(schemeStr);
199f7b8a70eSRiver Riddle   if (!isStructurallyValidScheme(uriScheme))
2007bc52733SRiver Riddle     return llvm::createStringError(llvm::inconvertibleErrorCode(),
2017bc52733SRiver Riddle                                    "Invalid scheme: " + schemeStr +
2027bc52733SRiver Riddle                                        " (decoded: " + uriScheme + ")");
2037bc52733SRiver Riddle   uri = uri.substr(pos + 1);
2047bc52733SRiver Riddle 
2057bc52733SRiver Riddle   // Decode the authority of the URI.
2067bc52733SRiver Riddle   std::string uriAuthority;
2077bc52733SRiver Riddle   if (uri.consume_front("//")) {
2087bc52733SRiver Riddle     pos = uri.find('/');
2097bc52733SRiver Riddle     uriAuthority = percentDecode(uri.substr(0, pos));
2107bc52733SRiver Riddle     uri = uri.substr(pos);
2117bc52733SRiver Riddle   }
2127bc52733SRiver Riddle 
2137bc52733SRiver Riddle   // Decode the body of the URI.
2147bc52733SRiver Riddle   std::string uriBody = percentDecode(uri);
2157bc52733SRiver Riddle 
2167bc52733SRiver Riddle   // Compute the absolute path for this uri.
217f7b8a70eSRiver Riddle   if (!getSupportedSchemes().contains(uriScheme)) {
218f7b8a70eSRiver Riddle     return llvm::createStringError(llvm::inconvertibleErrorCode(),
219f7b8a70eSRiver Riddle                                    "unsupported URI scheme `" + uriScheme +
220f7b8a70eSRiver Riddle                                        "' for workspace files");
2217bc52733SRiver Riddle   }
2227bc52733SRiver Riddle   return getAbsolutePath(uriAuthority, uriBody);
2237bc52733SRiver Riddle }
2247bc52733SRiver Riddle 
fromURI(StringRef uri)2257bc52733SRiver Riddle llvm::Expected<URIForFile> URIForFile::fromURI(StringRef uri) {
2267bc52733SRiver Riddle   llvm::Expected<std::string> filePath = parseFilePathFromURI(uri);
2277bc52733SRiver Riddle   if (!filePath)
2287bc52733SRiver Riddle     return filePath.takeError();
2297bc52733SRiver Riddle   return URIForFile(std::move(*filePath), uri.str());
2307bc52733SRiver Riddle }
2317bc52733SRiver Riddle 
fromFile(StringRef absoluteFilepath,StringRef scheme)232f7b8a70eSRiver Riddle llvm::Expected<URIForFile> URIForFile::fromFile(StringRef absoluteFilepath,
233f7b8a70eSRiver Riddle                                                 StringRef scheme) {
234f7b8a70eSRiver Riddle   llvm::Expected<std::string> uri =
235f7b8a70eSRiver Riddle       uriFromAbsolutePath(absoluteFilepath, scheme);
2367bc52733SRiver Riddle   if (!uri)
2377bc52733SRiver Riddle     return uri.takeError();
2387bc52733SRiver Riddle   return fromURI(*uri);
2397bc52733SRiver Riddle }
2407bc52733SRiver Riddle 
scheme() const241f7b8a70eSRiver Riddle StringRef URIForFile::scheme() const { return uri().split(':').first; }
242f7b8a70eSRiver Riddle 
registerSupportedScheme(StringRef scheme)243f7b8a70eSRiver Riddle void URIForFile::registerSupportedScheme(StringRef scheme) {
244f7b8a70eSRiver Riddle   getSupportedSchemes().insert(scheme);
245f7b8a70eSRiver Riddle }
246f7b8a70eSRiver Riddle 
fromJSON(const llvm::json::Value & value,URIForFile & result,llvm::json::Path path)2477bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value, URIForFile &result,
2487bc52733SRiver Riddle                          llvm::json::Path path) {
2491da3a795SFangrui Song   if (std::optional<StringRef> str = value.getAsString()) {
2507bc52733SRiver Riddle     llvm::Expected<URIForFile> expectedURI = URIForFile::fromURI(*str);
2517bc52733SRiver Riddle     if (!expectedURI) {
2527bc52733SRiver Riddle       path.report("unresolvable URI");
2537bc52733SRiver Riddle       consumeError(expectedURI.takeError());
2547bc52733SRiver Riddle       return false;
2557bc52733SRiver Riddle     }
2567bc52733SRiver Riddle     result = std::move(*expectedURI);
2577bc52733SRiver Riddle     return true;
2587bc52733SRiver Riddle   }
2597bc52733SRiver Riddle   return false;
2607bc52733SRiver Riddle }
2617bc52733SRiver Riddle 
toJSON(const URIForFile & value)2627bc52733SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const URIForFile &value) {
2637bc52733SRiver Riddle   return value.uri();
2647bc52733SRiver Riddle }
2657bc52733SRiver Riddle 
operator <<(raw_ostream & os,const URIForFile & value)2667bc52733SRiver Riddle raw_ostream &mlir::lsp::operator<<(raw_ostream &os, const URIForFile &value) {
2677bc52733SRiver Riddle   return os << value.uri();
2687bc52733SRiver Riddle }
2697bc52733SRiver Riddle 
2707bc52733SRiver Riddle //===----------------------------------------------------------------------===//
2717bc52733SRiver Riddle // ClientCapabilities
2727bc52733SRiver Riddle //===----------------------------------------------------------------------===//
2737bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,ClientCapabilities & result,llvm::json::Path path)2747bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
2757bc52733SRiver Riddle                          ClientCapabilities &result, llvm::json::Path path) {
2767bc52733SRiver Riddle   const llvm::json::Object *o = value.getAsObject();
2777bc52733SRiver Riddle   if (!o) {
2787bc52733SRiver Riddle     path.report("expected object");
2797bc52733SRiver Riddle     return false;
2807bc52733SRiver Riddle   }
2817bc52733SRiver Riddle   if (const llvm::json::Object *textDocument = o->getObject("textDocument")) {
2827bc52733SRiver Riddle     if (const llvm::json::Object *documentSymbol =
2837bc52733SRiver Riddle             textDocument->getObject("documentSymbol")) {
2841da3a795SFangrui Song       if (std::optional<bool> hierarchicalSupport =
2857bc52733SRiver Riddle               documentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))
2867bc52733SRiver Riddle         result.hierarchicalDocumentSymbol = *hierarchicalSupport;
2877bc52733SRiver Riddle     }
288ed344c88SRiver Riddle     if (auto *codeAction = textDocument->getObject("codeAction")) {
289ed344c88SRiver Riddle       if (codeAction->getObject("codeActionLiteralSupport"))
290ed344c88SRiver Riddle         result.codeActionStructure = true;
291ed344c88SRiver Riddle     }
2927bc52733SRiver Riddle   }
2937bc52733SRiver Riddle   return true;
2947bc52733SRiver Riddle }
2957bc52733SRiver Riddle 
2967bc52733SRiver Riddle //===----------------------------------------------------------------------===//
297857b0a1fSRiver Riddle // ClientInfo
298857b0a1fSRiver Riddle //===----------------------------------------------------------------------===//
299857b0a1fSRiver Riddle 
fromJSON(const llvm::json::Value & value,ClientInfo & result,llvm::json::Path path)300857b0a1fSRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value, ClientInfo &result,
301857b0a1fSRiver Riddle                          llvm::json::Path path) {
302857b0a1fSRiver Riddle   llvm::json::ObjectMapper o(value, path);
303857b0a1fSRiver Riddle   if (!o || !o.map("name", result.name))
304857b0a1fSRiver Riddle     return false;
305857b0a1fSRiver Riddle 
306857b0a1fSRiver Riddle   // Don't fail if we can't parse version.
307857b0a1fSRiver Riddle   o.map("version", result.version);
308857b0a1fSRiver Riddle   return true;
309857b0a1fSRiver Riddle }
310857b0a1fSRiver Riddle 
311857b0a1fSRiver Riddle //===----------------------------------------------------------------------===//
3127bc52733SRiver Riddle // InitializeParams
3137bc52733SRiver Riddle //===----------------------------------------------------------------------===//
3147bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,TraceLevel & result,llvm::json::Path path)3157bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value, TraceLevel &result,
3167bc52733SRiver Riddle                          llvm::json::Path path) {
3171da3a795SFangrui Song   if (std::optional<StringRef> str = value.getAsString()) {
3187bc52733SRiver Riddle     if (*str == "off") {
3197bc52733SRiver Riddle       result = TraceLevel::Off;
3207bc52733SRiver Riddle       return true;
3217bc52733SRiver Riddle     }
3227bc52733SRiver Riddle     if (*str == "messages") {
3237bc52733SRiver Riddle       result = TraceLevel::Messages;
3247bc52733SRiver Riddle       return true;
3257bc52733SRiver Riddle     }
3267bc52733SRiver Riddle     if (*str == "verbose") {
3277bc52733SRiver Riddle       result = TraceLevel::Verbose;
3287bc52733SRiver Riddle       return true;
3297bc52733SRiver Riddle     }
3307bc52733SRiver Riddle   }
3317bc52733SRiver Riddle   return false;
3327bc52733SRiver Riddle }
3337bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,InitializeParams & result,llvm::json::Path path)3347bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
3357bc52733SRiver Riddle                          InitializeParams &result, llvm::json::Path path) {
3367bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
3377bc52733SRiver Riddle   if (!o)
3387bc52733SRiver Riddle     return false;
3397bc52733SRiver Riddle   // We deliberately don't fail if we can't parse individual fields.
3407bc52733SRiver Riddle   o.map("capabilities", result.capabilities);
3417bc52733SRiver Riddle   o.map("trace", result.trace);
342857b0a1fSRiver Riddle   mapOptOrNull(value, "clientInfo", result.clientInfo, path);
343857b0a1fSRiver Riddle 
3447bc52733SRiver Riddle   return true;
3457bc52733SRiver Riddle }
3467bc52733SRiver Riddle 
3477bc52733SRiver Riddle //===----------------------------------------------------------------------===//
3487bc52733SRiver Riddle // TextDocumentItem
3497bc52733SRiver Riddle //===----------------------------------------------------------------------===//
3507bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,TextDocumentItem & result,llvm::json::Path path)3517bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
3527bc52733SRiver Riddle                          TextDocumentItem &result, llvm::json::Path path) {
3537bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
3547bc52733SRiver Riddle   return o && o.map("uri", result.uri) &&
3557bc52733SRiver Riddle          o.map("languageId", result.languageId) && o.map("text", result.text) &&
3567bc52733SRiver Riddle          o.map("version", result.version);
3577bc52733SRiver Riddle }
3587bc52733SRiver Riddle 
3597bc52733SRiver Riddle //===----------------------------------------------------------------------===//
3607bc52733SRiver Riddle // TextDocumentIdentifier
3617bc52733SRiver Riddle //===----------------------------------------------------------------------===//
3627bc52733SRiver Riddle 
toJSON(const TextDocumentIdentifier & value)3637bc52733SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const TextDocumentIdentifier &value) {
3647bc52733SRiver Riddle   return llvm::json::Object{{"uri", value.uri}};
3657bc52733SRiver Riddle }
3667bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,TextDocumentIdentifier & result,llvm::json::Path path)3677bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
3687bc52733SRiver Riddle                          TextDocumentIdentifier &result,
3697bc52733SRiver Riddle                          llvm::json::Path path) {
3707bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
3717bc52733SRiver Riddle   return o && o.map("uri", result.uri);
3727bc52733SRiver Riddle }
3737bc52733SRiver Riddle 
3747bc52733SRiver Riddle //===----------------------------------------------------------------------===//
3757bc52733SRiver Riddle // VersionedTextDocumentIdentifier
3767bc52733SRiver Riddle //===----------------------------------------------------------------------===//
3777bc52733SRiver Riddle 
3787bc52733SRiver Riddle llvm::json::Value
toJSON(const VersionedTextDocumentIdentifier & value)3797bc52733SRiver Riddle mlir::lsp::toJSON(const VersionedTextDocumentIdentifier &value) {
3807bc52733SRiver Riddle   return llvm::json::Object{
3817bc52733SRiver Riddle       {"uri", value.uri},
3827bc52733SRiver Riddle       {"version", value.version},
3837bc52733SRiver Riddle   };
3847bc52733SRiver Riddle }
3857bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,VersionedTextDocumentIdentifier & result,llvm::json::Path path)3867bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
3877bc52733SRiver Riddle                          VersionedTextDocumentIdentifier &result,
3887bc52733SRiver Riddle                          llvm::json::Path path) {
3897bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
3907bc52733SRiver Riddle   return o && o.map("uri", result.uri) && o.map("version", result.version);
3917bc52733SRiver Riddle }
3927bc52733SRiver Riddle 
3937bc52733SRiver Riddle //===----------------------------------------------------------------------===//
3947bc52733SRiver Riddle // Position
3957bc52733SRiver Riddle //===----------------------------------------------------------------------===//
3967bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,Position & result,llvm::json::Path path)3977bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value, Position &result,
3987bc52733SRiver Riddle                          llvm::json::Path path) {
3997bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
4007bc52733SRiver Riddle   return o && o.map("line", result.line) &&
4017bc52733SRiver Riddle          o.map("character", result.character);
4027bc52733SRiver Riddle }
4037bc52733SRiver Riddle 
toJSON(const Position & value)4047bc52733SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const Position &value) {
4057bc52733SRiver Riddle   return llvm::json::Object{
4067bc52733SRiver Riddle       {"line", value.line},
4077bc52733SRiver Riddle       {"character", value.character},
4087bc52733SRiver Riddle   };
4097bc52733SRiver Riddle }
4107bc52733SRiver Riddle 
operator <<(raw_ostream & os,const Position & value)4117bc52733SRiver Riddle raw_ostream &mlir::lsp::operator<<(raw_ostream &os, const Position &value) {
4127bc52733SRiver Riddle   return os << value.line << ':' << value.character;
4137bc52733SRiver Riddle }
4147bc52733SRiver Riddle 
4157bc52733SRiver Riddle //===----------------------------------------------------------------------===//
4167bc52733SRiver Riddle // Range
4177bc52733SRiver Riddle //===----------------------------------------------------------------------===//
4187bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,Range & result,llvm::json::Path path)4197bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value, Range &result,
4207bc52733SRiver Riddle                          llvm::json::Path path) {
4217bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
4227bc52733SRiver Riddle   return o && o.map("start", result.start) && o.map("end", result.end);
4237bc52733SRiver Riddle }
4247bc52733SRiver Riddle 
toJSON(const Range & value)4257bc52733SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const Range &value) {
4267bc52733SRiver Riddle   return llvm::json::Object{
4277bc52733SRiver Riddle       {"start", value.start},
4287bc52733SRiver Riddle       {"end", value.end},
4297bc52733SRiver Riddle   };
4307bc52733SRiver Riddle }
4317bc52733SRiver Riddle 
operator <<(raw_ostream & os,const Range & value)4327bc52733SRiver Riddle raw_ostream &mlir::lsp::operator<<(raw_ostream &os, const Range &value) {
4337bc52733SRiver Riddle   return os << value.start << '-' << value.end;
4347bc52733SRiver Riddle }
4357bc52733SRiver Riddle 
4367bc52733SRiver Riddle //===----------------------------------------------------------------------===//
4377bc52733SRiver Riddle // Location
4387bc52733SRiver Riddle //===----------------------------------------------------------------------===//
4397bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,Location & result,llvm::json::Path path)440ed344c88SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value, Location &result,
441ed344c88SRiver Riddle                          llvm::json::Path path) {
442ed344c88SRiver Riddle   llvm::json::ObjectMapper o(value, path);
443ed344c88SRiver Riddle   return o && o.map("uri", result.uri) && o.map("range", result.range);
444ed344c88SRiver Riddle }
445ed344c88SRiver Riddle 
toJSON(const Location & value)4467bc52733SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const Location &value) {
4477bc52733SRiver Riddle   return llvm::json::Object{
4487bc52733SRiver Riddle       {"uri", value.uri},
4497bc52733SRiver Riddle       {"range", value.range},
4507bc52733SRiver Riddle   };
4517bc52733SRiver Riddle }
4527bc52733SRiver Riddle 
operator <<(raw_ostream & os,const Location & value)4537bc52733SRiver Riddle raw_ostream &mlir::lsp::operator<<(raw_ostream &os, const Location &value) {
4547bc52733SRiver Riddle   return os << value.range << '@' << value.uri;
4557bc52733SRiver Riddle }
4567bc52733SRiver Riddle 
4577bc52733SRiver Riddle //===----------------------------------------------------------------------===//
4587bc52733SRiver Riddle // TextDocumentPositionParams
4597bc52733SRiver Riddle //===----------------------------------------------------------------------===//
4607bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,TextDocumentPositionParams & result,llvm::json::Path path)4617bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
4627bc52733SRiver Riddle                          TextDocumentPositionParams &result,
4637bc52733SRiver Riddle                          llvm::json::Path path) {
4647bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
4657bc52733SRiver Riddle   return o && o.map("textDocument", result.textDocument) &&
4667bc52733SRiver Riddle          o.map("position", result.position);
4677bc52733SRiver Riddle }
4687bc52733SRiver Riddle 
4697bc52733SRiver Riddle //===----------------------------------------------------------------------===//
4707bc52733SRiver Riddle // ReferenceParams
4717bc52733SRiver Riddle //===----------------------------------------------------------------------===//
4727bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,ReferenceContext & result,llvm::json::Path path)4737bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
4747bc52733SRiver Riddle                          ReferenceContext &result, llvm::json::Path path) {
4757bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
4767bc52733SRiver Riddle   return o && o.mapOptional("includeDeclaration", result.includeDeclaration);
4777bc52733SRiver Riddle }
4787bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,ReferenceParams & result,llvm::json::Path path)4797bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
4807bc52733SRiver Riddle                          ReferenceParams &result, llvm::json::Path path) {
4817bc52733SRiver Riddle   TextDocumentPositionParams &base = result;
4827bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
4837bc52733SRiver Riddle   return fromJSON(value, base, path) && o &&
4847bc52733SRiver Riddle          o.mapOptional("context", result.context);
4857bc52733SRiver Riddle }
4867bc52733SRiver Riddle 
4877bc52733SRiver Riddle //===----------------------------------------------------------------------===//
4887bc52733SRiver Riddle // DidOpenTextDocumentParams
4897bc52733SRiver Riddle //===----------------------------------------------------------------------===//
4907bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,DidOpenTextDocumentParams & result,llvm::json::Path path)4917bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
4927bc52733SRiver Riddle                          DidOpenTextDocumentParams &result,
4937bc52733SRiver Riddle                          llvm::json::Path path) {
4947bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
4957bc52733SRiver Riddle   return o && o.map("textDocument", result.textDocument);
4967bc52733SRiver Riddle }
4977bc52733SRiver Riddle 
4987bc52733SRiver Riddle //===----------------------------------------------------------------------===//
4997bc52733SRiver Riddle // DidCloseTextDocumentParams
5007bc52733SRiver Riddle //===----------------------------------------------------------------------===//
5017bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,DidCloseTextDocumentParams & result,llvm::json::Path path)5027bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
5037bc52733SRiver Riddle                          DidCloseTextDocumentParams &result,
5047bc52733SRiver Riddle                          llvm::json::Path path) {
5057bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
5067bc52733SRiver Riddle   return o && o.map("textDocument", result.textDocument);
5077bc52733SRiver Riddle }
5087bc52733SRiver Riddle 
5097bc52733SRiver Riddle //===----------------------------------------------------------------------===//
5107bc52733SRiver Riddle // DidChangeTextDocumentParams
5117bc52733SRiver Riddle //===----------------------------------------------------------------------===//
5127bc52733SRiver Riddle 
5136187178eSRiver Riddle LogicalResult
applyTo(std::string & contents) const5146187178eSRiver Riddle TextDocumentContentChangeEvent::applyTo(std::string &contents) const {
5156187178eSRiver Riddle   // If there is no range, the full document changed.
5166187178eSRiver Riddle   if (!range) {
5176187178eSRiver Riddle     contents = text;
5186187178eSRiver Riddle     return success();
5196187178eSRiver Riddle   }
5206187178eSRiver Riddle 
5216187178eSRiver Riddle   // Try to map the replacement range to the content.
5226187178eSRiver Riddle   llvm::SourceMgr tmpScrMgr;
5236187178eSRiver Riddle   tmpScrMgr.AddNewSourceBuffer(llvm::MemoryBuffer::getMemBuffer(contents),
5246187178eSRiver Riddle                                SMLoc());
5256187178eSRiver Riddle   SMRange rangeLoc = range->getAsSMRange(tmpScrMgr);
5266187178eSRiver Riddle   if (!rangeLoc.isValid())
5276187178eSRiver Riddle     return failure();
5286187178eSRiver Riddle 
5296187178eSRiver Riddle   contents.replace(rangeLoc.Start.getPointer() - contents.data(),
5306187178eSRiver Riddle                    rangeLoc.End.getPointer() - rangeLoc.Start.getPointer(),
5316187178eSRiver Riddle                    text);
5326187178eSRiver Riddle   return success();
5336187178eSRiver Riddle }
5346187178eSRiver Riddle 
applyTo(ArrayRef<TextDocumentContentChangeEvent> changes,std::string & contents)5356187178eSRiver Riddle LogicalResult TextDocumentContentChangeEvent::applyTo(
5366187178eSRiver Riddle     ArrayRef<TextDocumentContentChangeEvent> changes, std::string &contents) {
5376187178eSRiver Riddle   for (const auto &change : changes)
5386187178eSRiver Riddle     if (failed(change.applyTo(contents)))
5396187178eSRiver Riddle       return failure();
5406187178eSRiver Riddle   return success();
5416187178eSRiver Riddle }
5426187178eSRiver Riddle 
fromJSON(const llvm::json::Value & value,TextDocumentContentChangeEvent & result,llvm::json::Path path)5437bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
5447bc52733SRiver Riddle                          TextDocumentContentChangeEvent &result,
5457bc52733SRiver Riddle                          llvm::json::Path path) {
5467bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
5477bc52733SRiver Riddle   return o && o.map("range", result.range) &&
5487bc52733SRiver Riddle          o.map("rangeLength", result.rangeLength) && o.map("text", result.text);
5497bc52733SRiver Riddle }
5507bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,DidChangeTextDocumentParams & result,llvm::json::Path path)5517bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
5527bc52733SRiver Riddle                          DidChangeTextDocumentParams &result,
5537bc52733SRiver Riddle                          llvm::json::Path path) {
5547bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
5557bc52733SRiver Riddle   return o && o.map("textDocument", result.textDocument) &&
5567bc52733SRiver Riddle          o.map("contentChanges", result.contentChanges);
5577bc52733SRiver Riddle }
5587bc52733SRiver Riddle 
5597bc52733SRiver Riddle //===----------------------------------------------------------------------===//
5607bc52733SRiver Riddle // MarkupContent
5617bc52733SRiver Riddle //===----------------------------------------------------------------------===//
5627bc52733SRiver Riddle 
toTextKind(MarkupKind kind)5637bc52733SRiver Riddle static llvm::StringRef toTextKind(MarkupKind kind) {
5647bc52733SRiver Riddle   switch (kind) {
5657bc52733SRiver Riddle   case MarkupKind::PlainText:
5667bc52733SRiver Riddle     return "plaintext";
5677bc52733SRiver Riddle   case MarkupKind::Markdown:
5687bc52733SRiver Riddle     return "markdown";
5697bc52733SRiver Riddle   }
5707bc52733SRiver Riddle   llvm_unreachable("Invalid MarkupKind");
5717bc52733SRiver Riddle }
5727bc52733SRiver Riddle 
operator <<(raw_ostream & os,MarkupKind kind)5737bc52733SRiver Riddle raw_ostream &mlir::lsp::operator<<(raw_ostream &os, MarkupKind kind) {
5747bc52733SRiver Riddle   return os << toTextKind(kind);
5757bc52733SRiver Riddle }
5767bc52733SRiver Riddle 
toJSON(const MarkupContent & mc)5777bc52733SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const MarkupContent &mc) {
5787bc52733SRiver Riddle   if (mc.value.empty())
5797bc52733SRiver Riddle     return nullptr;
5807bc52733SRiver Riddle 
5817bc52733SRiver Riddle   return llvm::json::Object{
5827bc52733SRiver Riddle       {"kind", toTextKind(mc.kind)},
5837bc52733SRiver Riddle       {"value", mc.value},
5847bc52733SRiver Riddle   };
5857bc52733SRiver Riddle }
5867bc52733SRiver Riddle 
5877bc52733SRiver Riddle //===----------------------------------------------------------------------===//
5887bc52733SRiver Riddle // Hover
5897bc52733SRiver Riddle //===----------------------------------------------------------------------===//
5907bc52733SRiver Riddle 
toJSON(const Hover & hover)5917bc52733SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const Hover &hover) {
5927bc52733SRiver Riddle   llvm::json::Object result{{"contents", toJSON(hover.contents)}};
593037f0995SKazu Hirata   if (hover.range)
5947bc52733SRiver Riddle     result["range"] = toJSON(*hover.range);
5957bc52733SRiver Riddle   return std::move(result);
5967bc52733SRiver Riddle }
5977bc52733SRiver Riddle 
5987bc52733SRiver Riddle //===----------------------------------------------------------------------===//
5997bc52733SRiver Riddle // DocumentSymbol
6007bc52733SRiver Riddle //===----------------------------------------------------------------------===//
6017bc52733SRiver Riddle 
toJSON(const DocumentSymbol & symbol)6027bc52733SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const DocumentSymbol &symbol) {
6037bc52733SRiver Riddle   llvm::json::Object result{{"name", symbol.name},
6047bc52733SRiver Riddle                             {"kind", static_cast<int>(symbol.kind)},
6057bc52733SRiver Riddle                             {"range", symbol.range},
6067bc52733SRiver Riddle                             {"selectionRange", symbol.selectionRange}};
6077bc52733SRiver Riddle 
6087bc52733SRiver Riddle   if (!symbol.detail.empty())
6097bc52733SRiver Riddle     result["detail"] = symbol.detail;
6107bc52733SRiver Riddle   if (!symbol.children.empty())
6117bc52733SRiver Riddle     result["children"] = symbol.children;
6127bc52733SRiver Riddle   return std::move(result);
6137bc52733SRiver Riddle }
6147bc52733SRiver Riddle 
6157bc52733SRiver Riddle //===----------------------------------------------------------------------===//
6167bc52733SRiver Riddle // DocumentSymbolParams
6177bc52733SRiver Riddle //===----------------------------------------------------------------------===//
6187bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,DocumentSymbolParams & result,llvm::json::Path path)6197bc52733SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
6207bc52733SRiver Riddle                          DocumentSymbolParams &result, llvm::json::Path path) {
6217bc52733SRiver Riddle   llvm::json::ObjectMapper o(value, path);
6227bc52733SRiver Riddle   return o && o.map("textDocument", result.textDocument);
6237bc52733SRiver Riddle }
6247bc52733SRiver Riddle 
6257bc52733SRiver Riddle //===----------------------------------------------------------------------===//
6267bc52733SRiver Riddle // DiagnosticRelatedInformation
6277bc52733SRiver Riddle //===----------------------------------------------------------------------===//
6287bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,DiagnosticRelatedInformation & result,llvm::json::Path path)629ed344c88SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
630ed344c88SRiver Riddle                          DiagnosticRelatedInformation &result,
631ed344c88SRiver Riddle                          llvm::json::Path path) {
632ed344c88SRiver Riddle   llvm::json::ObjectMapper o(value, path);
633ed344c88SRiver Riddle   return o && o.map("location", result.location) &&
634ed344c88SRiver Riddle          o.map("message", result.message);
635ed344c88SRiver Riddle }
636ed344c88SRiver Riddle 
toJSON(const DiagnosticRelatedInformation & info)6377bc52733SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const DiagnosticRelatedInformation &info) {
6387bc52733SRiver Riddle   return llvm::json::Object{
6397bc52733SRiver Riddle       {"location", info.location},
6407bc52733SRiver Riddle       {"message", info.message},
6417bc52733SRiver Riddle   };
6427bc52733SRiver Riddle }
6437bc52733SRiver Riddle 
6447bc52733SRiver Riddle //===----------------------------------------------------------------------===//
6457bc52733SRiver Riddle // Diagnostic
6467bc52733SRiver Riddle //===----------------------------------------------------------------------===//
6477bc52733SRiver Riddle 
toJSON(DiagnosticTag tag)648*878c141aSLily Brown llvm::json::Value mlir::lsp::toJSON(DiagnosticTag tag) {
649*878c141aSLily Brown   return static_cast<int>(tag);
650*878c141aSLily Brown }
651*878c141aSLily Brown 
fromJSON(const llvm::json::Value & value,DiagnosticTag & result,llvm::json::Path path)652*878c141aSLily Brown bool mlir::lsp::fromJSON(const llvm::json::Value &value, DiagnosticTag &result,
653*878c141aSLily Brown                          llvm::json::Path path) {
654*878c141aSLily Brown   if (std::optional<int64_t> i = value.getAsInteger()) {
655*878c141aSLily Brown     result = (DiagnosticTag)*i;
656*878c141aSLily Brown     return true;
657*878c141aSLily Brown   }
658*878c141aSLily Brown 
659*878c141aSLily Brown   return false;
660*878c141aSLily Brown }
661*878c141aSLily Brown 
toJSON(const Diagnostic & diag)6627bc52733SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const Diagnostic &diag) {
6637bc52733SRiver Riddle   llvm::json::Object result{
6647bc52733SRiver Riddle       {"range", diag.range},
6657bc52733SRiver Riddle       {"severity", (int)diag.severity},
6667bc52733SRiver Riddle       {"message", diag.message},
6677bc52733SRiver Riddle   };
6687bc52733SRiver Riddle   if (diag.category)
6697bc52733SRiver Riddle     result["category"] = *diag.category;
6707bc52733SRiver Riddle   if (!diag.source.empty())
6717bc52733SRiver Riddle     result["source"] = diag.source;
6727bc52733SRiver Riddle   if (diag.relatedInformation)
6737bc52733SRiver Riddle     result["relatedInformation"] = *diag.relatedInformation;
674*878c141aSLily Brown   if (!diag.tags.empty())
675*878c141aSLily Brown     result["tags"] = diag.tags;
6767bc52733SRiver Riddle   return std::move(result);
6777bc52733SRiver Riddle }
6787bc52733SRiver Riddle 
fromJSON(const llvm::json::Value & value,Diagnostic & result,llvm::json::Path path)679ed344c88SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value, Diagnostic &result,
680ed344c88SRiver Riddle                          llvm::json::Path path) {
681ed344c88SRiver Riddle   llvm::json::ObjectMapper o(value, path);
682ed344c88SRiver Riddle   if (!o)
683ed344c88SRiver Riddle     return false;
684ed344c88SRiver Riddle   int severity = 0;
685ed344c88SRiver Riddle   if (!mapOptOrNull(value, "severity", severity, path))
686ed344c88SRiver Riddle     return false;
687ed344c88SRiver Riddle   result.severity = (DiagnosticSeverity)severity;
688ed344c88SRiver Riddle 
689ed344c88SRiver Riddle   return o.map("range", result.range) && o.map("message", result.message) &&
690ed344c88SRiver Riddle          mapOptOrNull(value, "category", result.category, path) &&
691ed344c88SRiver Riddle          mapOptOrNull(value, "source", result.source, path) &&
692ed344c88SRiver Riddle          mapOptOrNull(value, "relatedInformation", result.relatedInformation,
693*878c141aSLily Brown                       path) &&
694*878c141aSLily Brown          mapOptOrNull(value, "tags", result.tags, path);
695ed344c88SRiver Riddle }
696ed344c88SRiver Riddle 
6977bc52733SRiver Riddle //===----------------------------------------------------------------------===//
6987bc52733SRiver Riddle // PublishDiagnosticsParams
6997bc52733SRiver Riddle //===----------------------------------------------------------------------===//
7007bc52733SRiver Riddle 
toJSON(const PublishDiagnosticsParams & params)7017bc52733SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const PublishDiagnosticsParams &params) {
7027bc52733SRiver Riddle   return llvm::json::Object{
7037bc52733SRiver Riddle       {"uri", params.uri},
7047bc52733SRiver Riddle       {"diagnostics", params.diagnostics},
7057bc52733SRiver Riddle       {"version", params.version},
7067bc52733SRiver Riddle   };
7077bc52733SRiver Riddle }
708008de486SRiver Riddle 
709008de486SRiver Riddle //===----------------------------------------------------------------------===//
710008de486SRiver Riddle // TextEdit
711008de486SRiver Riddle //===----------------------------------------------------------------------===//
712008de486SRiver Riddle 
fromJSON(const llvm::json::Value & value,TextEdit & result,llvm::json::Path path)713008de486SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value, TextEdit &result,
714008de486SRiver Riddle                          llvm::json::Path path) {
715008de486SRiver Riddle   llvm::json::ObjectMapper o(value, path);
716008de486SRiver Riddle   return o && o.map("range", result.range) && o.map("newText", result.newText);
717008de486SRiver Riddle }
718008de486SRiver Riddle 
toJSON(const TextEdit & value)719008de486SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const TextEdit &value) {
720008de486SRiver Riddle   return llvm::json::Object{
721008de486SRiver Riddle       {"range", value.range},
722008de486SRiver Riddle       {"newText", value.newText},
723008de486SRiver Riddle   };
724008de486SRiver Riddle }
725008de486SRiver Riddle 
operator <<(raw_ostream & os,const TextEdit & value)726008de486SRiver Riddle raw_ostream &mlir::lsp::operator<<(raw_ostream &os, const TextEdit &value) {
727008de486SRiver Riddle   os << value.range << " => \"";
728008de486SRiver Riddle   llvm::printEscapedString(value.newText, os);
729008de486SRiver Riddle   return os << '"';
730008de486SRiver Riddle }
731008de486SRiver Riddle 
732008de486SRiver Riddle //===----------------------------------------------------------------------===//
733008de486SRiver Riddle // CompletionItemKind
734008de486SRiver Riddle //===----------------------------------------------------------------------===//
735008de486SRiver Riddle 
fromJSON(const llvm::json::Value & value,CompletionItemKind & result,llvm::json::Path path)736008de486SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
737008de486SRiver Riddle                          CompletionItemKind &result, llvm::json::Path path) {
7381da3a795SFangrui Song   if (std::optional<int64_t> intValue = value.getAsInteger()) {
739008de486SRiver Riddle     if (*intValue < static_cast<int>(CompletionItemKind::Text) ||
740008de486SRiver Riddle         *intValue > static_cast<int>(CompletionItemKind::TypeParameter))
741008de486SRiver Riddle       return false;
742008de486SRiver Riddle     result = static_cast<CompletionItemKind>(*intValue);
743008de486SRiver Riddle     return true;
744008de486SRiver Riddle   }
745008de486SRiver Riddle   return false;
746008de486SRiver Riddle }
747008de486SRiver Riddle 
adjustKindToCapability(CompletionItemKind kind,CompletionItemKindBitset & supportedCompletionItemKinds)748008de486SRiver Riddle CompletionItemKind mlir::lsp::adjustKindToCapability(
749008de486SRiver Riddle     CompletionItemKind kind,
750008de486SRiver Riddle     CompletionItemKindBitset &supportedCompletionItemKinds) {
751008de486SRiver Riddle   size_t kindVal = static_cast<size_t>(kind);
752008de486SRiver Riddle   if (kindVal >= kCompletionItemKindMin &&
753008de486SRiver Riddle       kindVal <= supportedCompletionItemKinds.size() &&
754008de486SRiver Riddle       supportedCompletionItemKinds[kindVal])
755008de486SRiver Riddle     return kind;
756008de486SRiver Riddle 
757008de486SRiver Riddle   // Provide some fall backs for common kinds that are close enough.
758008de486SRiver Riddle   switch (kind) {
759008de486SRiver Riddle   case CompletionItemKind::Folder:
760008de486SRiver Riddle     return CompletionItemKind::File;
761008de486SRiver Riddle   case CompletionItemKind::EnumMember:
762008de486SRiver Riddle     return CompletionItemKind::Enum;
763008de486SRiver Riddle   case CompletionItemKind::Struct:
764008de486SRiver Riddle     return CompletionItemKind::Class;
765008de486SRiver Riddle   default:
766008de486SRiver Riddle     return CompletionItemKind::Text;
767008de486SRiver Riddle   }
768008de486SRiver Riddle }
769008de486SRiver Riddle 
fromJSON(const llvm::json::Value & value,CompletionItemKindBitset & result,llvm::json::Path path)770008de486SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
771008de486SRiver Riddle                          CompletionItemKindBitset &result,
772008de486SRiver Riddle                          llvm::json::Path path) {
773008de486SRiver Riddle   if (const llvm::json::Array *arrayValue = value.getAsArray()) {
774008de486SRiver Riddle     for (size_t i = 0, e = arrayValue->size(); i < e; ++i) {
775008de486SRiver Riddle       CompletionItemKind kindOut;
776008de486SRiver Riddle       if (fromJSON((*arrayValue)[i], kindOut, path.index(i)))
777008de486SRiver Riddle         result.set(size_t(kindOut));
778008de486SRiver Riddle     }
779008de486SRiver Riddle     return true;
780008de486SRiver Riddle   }
781008de486SRiver Riddle   return false;
782008de486SRiver Riddle }
783008de486SRiver Riddle 
784008de486SRiver Riddle //===----------------------------------------------------------------------===//
785008de486SRiver Riddle // CompletionItem
786008de486SRiver Riddle //===----------------------------------------------------------------------===//
787008de486SRiver Riddle 
toJSON(const CompletionItem & value)788008de486SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const CompletionItem &value) {
789008de486SRiver Riddle   assert(!value.label.empty() && "completion item label is required");
790008de486SRiver Riddle   llvm::json::Object result{{"label", value.label}};
791008de486SRiver Riddle   if (value.kind != CompletionItemKind::Missing)
792008de486SRiver Riddle     result["kind"] = static_cast<int>(value.kind);
793008de486SRiver Riddle   if (!value.detail.empty())
794008de486SRiver Riddle     result["detail"] = value.detail;
795008de486SRiver Riddle   if (value.documentation)
796008de486SRiver Riddle     result["documentation"] = value.documentation;
797008de486SRiver Riddle   if (!value.sortText.empty())
798008de486SRiver Riddle     result["sortText"] = value.sortText;
799008de486SRiver Riddle   if (!value.filterText.empty())
800008de486SRiver Riddle     result["filterText"] = value.filterText;
801008de486SRiver Riddle   if (!value.insertText.empty())
802008de486SRiver Riddle     result["insertText"] = value.insertText;
803008de486SRiver Riddle   if (value.insertTextFormat != InsertTextFormat::Missing)
804008de486SRiver Riddle     result["insertTextFormat"] = static_cast<int>(value.insertTextFormat);
805008de486SRiver Riddle   if (value.textEdit)
806008de486SRiver Riddle     result["textEdit"] = *value.textEdit;
807008de486SRiver Riddle   if (!value.additionalTextEdits.empty()) {
808008de486SRiver Riddle     result["additionalTextEdits"] =
809008de486SRiver Riddle         llvm::json::Array(value.additionalTextEdits);
810008de486SRiver Riddle   }
811008de486SRiver Riddle   if (value.deprecated)
812008de486SRiver Riddle     result["deprecated"] = value.deprecated;
813008de486SRiver Riddle   return std::move(result);
814008de486SRiver Riddle }
815008de486SRiver Riddle 
operator <<(raw_ostream & os,const CompletionItem & value)816008de486SRiver Riddle raw_ostream &mlir::lsp::operator<<(raw_ostream &os,
817008de486SRiver Riddle                                    const CompletionItem &value) {
818008de486SRiver Riddle   return os << value.label << " - " << toJSON(value);
819008de486SRiver Riddle }
820008de486SRiver Riddle 
operator <(const CompletionItem & lhs,const CompletionItem & rhs)821008de486SRiver Riddle bool mlir::lsp::operator<(const CompletionItem &lhs,
822008de486SRiver Riddle                           const CompletionItem &rhs) {
823008de486SRiver Riddle   return (lhs.sortText.empty() ? lhs.label : lhs.sortText) <
824008de486SRiver Riddle          (rhs.sortText.empty() ? rhs.label : rhs.sortText);
825008de486SRiver Riddle }
826008de486SRiver Riddle 
827008de486SRiver Riddle //===----------------------------------------------------------------------===//
828008de486SRiver Riddle // CompletionList
829008de486SRiver Riddle //===----------------------------------------------------------------------===//
830008de486SRiver Riddle 
toJSON(const CompletionList & value)831008de486SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const CompletionList &value) {
832008de486SRiver Riddle   return llvm::json::Object{
833008de486SRiver Riddle       {"isIncomplete", value.isIncomplete},
834008de486SRiver Riddle       {"items", llvm::json::Array(value.items)},
835008de486SRiver Riddle   };
836008de486SRiver Riddle }
837008de486SRiver Riddle 
838008de486SRiver Riddle //===----------------------------------------------------------------------===//
839008de486SRiver Riddle // CompletionContext
840008de486SRiver Riddle //===----------------------------------------------------------------------===//
841008de486SRiver Riddle 
fromJSON(const llvm::json::Value & value,CompletionContext & result,llvm::json::Path path)842008de486SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
843008de486SRiver Riddle                          CompletionContext &result, llvm::json::Path path) {
844008de486SRiver Riddle   llvm::json::ObjectMapper o(value, path);
845008de486SRiver Riddle   int triggerKind;
846008de486SRiver Riddle   if (!o || !o.map("triggerKind", triggerKind) ||
847008de486SRiver Riddle       !mapOptOrNull(value, "triggerCharacter", result.triggerCharacter, path))
848008de486SRiver Riddle     return false;
849008de486SRiver Riddle   result.triggerKind = static_cast<CompletionTriggerKind>(triggerKind);
850008de486SRiver Riddle   return true;
851008de486SRiver Riddle }
852008de486SRiver Riddle 
853008de486SRiver Riddle //===----------------------------------------------------------------------===//
854008de486SRiver Riddle // CompletionParams
855008de486SRiver Riddle //===----------------------------------------------------------------------===//
856008de486SRiver Riddle 
fromJSON(const llvm::json::Value & value,CompletionParams & result,llvm::json::Path path)857008de486SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
858008de486SRiver Riddle                          CompletionParams &result, llvm::json::Path path) {
859008de486SRiver Riddle   if (!fromJSON(value, static_cast<TextDocumentPositionParams &>(result), path))
860008de486SRiver Riddle     return false;
861008de486SRiver Riddle   if (const llvm::json::Value *context = value.getAsObject()->get("context"))
862008de486SRiver Riddle     return fromJSON(*context, result.context, path.field("context"));
863008de486SRiver Riddle   return true;
864008de486SRiver Riddle }
865469c5894SRiver Riddle 
866469c5894SRiver Riddle //===----------------------------------------------------------------------===//
867469c5894SRiver Riddle // ParameterInformation
868469c5894SRiver Riddle //===----------------------------------------------------------------------===//
869469c5894SRiver Riddle 
toJSON(const ParameterInformation & value)870469c5894SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const ParameterInformation &value) {
8715413bf1bSKazu Hirata   assert((value.labelOffsets || !value.labelString.empty()) &&
872469c5894SRiver Riddle          "parameter information label is required");
873469c5894SRiver Riddle   llvm::json::Object result;
874469c5894SRiver Riddle   if (value.labelOffsets)
875469c5894SRiver Riddle     result["label"] = llvm::json::Array(
876469c5894SRiver Riddle         {value.labelOffsets->first, value.labelOffsets->second});
877469c5894SRiver Riddle   else
878469c5894SRiver Riddle     result["label"] = value.labelString;
879469c5894SRiver Riddle   if (!value.documentation.empty())
880469c5894SRiver Riddle     result["documentation"] = value.documentation;
881469c5894SRiver Riddle   return std::move(result);
882469c5894SRiver Riddle }
883469c5894SRiver Riddle 
884469c5894SRiver Riddle //===----------------------------------------------------------------------===//
885469c5894SRiver Riddle // SignatureInformation
886469c5894SRiver Riddle //===----------------------------------------------------------------------===//
887469c5894SRiver Riddle 
toJSON(const SignatureInformation & value)888469c5894SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const SignatureInformation &value) {
889469c5894SRiver Riddle   assert(!value.label.empty() && "signature information label is required");
890469c5894SRiver Riddle   llvm::json::Object result{
891469c5894SRiver Riddle       {"label", value.label},
892469c5894SRiver Riddle       {"parameters", llvm::json::Array(value.parameters)},
893469c5894SRiver Riddle   };
894469c5894SRiver Riddle   if (!value.documentation.empty())
895469c5894SRiver Riddle     result["documentation"] = value.documentation;
896469c5894SRiver Riddle   return std::move(result);
897469c5894SRiver Riddle }
898469c5894SRiver Riddle 
operator <<(raw_ostream & os,const SignatureInformation & value)899469c5894SRiver Riddle raw_ostream &mlir::lsp::operator<<(raw_ostream &os,
900469c5894SRiver Riddle                                    const SignatureInformation &value) {
901469c5894SRiver Riddle   return os << value.label << " - " << toJSON(value);
902469c5894SRiver Riddle }
903469c5894SRiver Riddle 
904469c5894SRiver Riddle //===----------------------------------------------------------------------===//
905469c5894SRiver Riddle // SignatureHelp
906469c5894SRiver Riddle //===----------------------------------------------------------------------===//
907469c5894SRiver Riddle 
toJSON(const SignatureHelp & value)908469c5894SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const SignatureHelp &value) {
909469c5894SRiver Riddle   assert(value.activeSignature >= 0 &&
910469c5894SRiver Riddle          "Unexpected negative value for number of active signatures.");
911469c5894SRiver Riddle   assert(value.activeParameter >= 0 &&
912469c5894SRiver Riddle          "Unexpected negative value for active parameter index");
913469c5894SRiver Riddle   return llvm::json::Object{
914469c5894SRiver Riddle       {"activeSignature", value.activeSignature},
915469c5894SRiver Riddle       {"activeParameter", value.activeParameter},
916469c5894SRiver Riddle       {"signatures", llvm::json::Array(value.signatures)},
917469c5894SRiver Riddle   };
918469c5894SRiver Riddle }
91909af7fefSRiver Riddle 
92009af7fefSRiver Riddle //===----------------------------------------------------------------------===//
92109af7fefSRiver Riddle // DocumentLinkParams
92209af7fefSRiver Riddle //===----------------------------------------------------------------------===//
92309af7fefSRiver Riddle 
fromJSON(const llvm::json::Value & value,DocumentLinkParams & result,llvm::json::Path path)92409af7fefSRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
92509af7fefSRiver Riddle                          DocumentLinkParams &result, llvm::json::Path path) {
92609af7fefSRiver Riddle   llvm::json::ObjectMapper o(value, path);
92709af7fefSRiver Riddle   return o && o.map("textDocument", result.textDocument);
92809af7fefSRiver Riddle }
92909af7fefSRiver Riddle 
93009af7fefSRiver Riddle //===----------------------------------------------------------------------===//
93109af7fefSRiver Riddle // DocumentLink
93209af7fefSRiver Riddle //===----------------------------------------------------------------------===//
93309af7fefSRiver Riddle 
toJSON(const DocumentLink & value)93409af7fefSRiver Riddle llvm::json::Value mlir::lsp::toJSON(const DocumentLink &value) {
93509af7fefSRiver Riddle   return llvm::json::Object{
93609af7fefSRiver Riddle       {"range", value.range},
93709af7fefSRiver Riddle       {"target", value.target},
93809af7fefSRiver Riddle   };
93909af7fefSRiver Riddle }
9405919eab5SRiver Riddle 
9415919eab5SRiver Riddle //===----------------------------------------------------------------------===//
9425919eab5SRiver Riddle // InlayHintsParams
9435919eab5SRiver Riddle //===----------------------------------------------------------------------===//
9445919eab5SRiver Riddle 
fromJSON(const llvm::json::Value & value,InlayHintsParams & result,llvm::json::Path path)9455919eab5SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
9465919eab5SRiver Riddle                          InlayHintsParams &result, llvm::json::Path path) {
9475919eab5SRiver Riddle   llvm::json::ObjectMapper o(value, path);
9485919eab5SRiver Riddle   return o && o.map("textDocument", result.textDocument) &&
9495919eab5SRiver Riddle          o.map("range", result.range);
9505919eab5SRiver Riddle }
9515919eab5SRiver Riddle 
9525919eab5SRiver Riddle //===----------------------------------------------------------------------===//
9535919eab5SRiver Riddle // InlayHint
9545919eab5SRiver Riddle //===----------------------------------------------------------------------===//
9555919eab5SRiver Riddle 
toJSON(const InlayHint & value)9565919eab5SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const InlayHint &value) {
9575919eab5SRiver Riddle   return llvm::json::Object{{"position", value.position},
9585919eab5SRiver Riddle                             {"kind", (int)value.kind},
9595919eab5SRiver Riddle                             {"label", value.label},
9605919eab5SRiver Riddle                             {"paddingLeft", value.paddingLeft},
9615919eab5SRiver Riddle                             {"paddingRight", value.paddingRight}};
9625919eab5SRiver Riddle }
operator ==(const InlayHint & lhs,const InlayHint & rhs)9635919eab5SRiver Riddle bool mlir::lsp::operator==(const InlayHint &lhs, const InlayHint &rhs) {
9645919eab5SRiver Riddle   return std::tie(lhs.position, lhs.kind, lhs.label) ==
9655919eab5SRiver Riddle          std::tie(rhs.position, rhs.kind, rhs.label);
9665919eab5SRiver Riddle }
operator <(const InlayHint & lhs,const InlayHint & rhs)9675919eab5SRiver Riddle bool mlir::lsp::operator<(const InlayHint &lhs, const InlayHint &rhs) {
9685919eab5SRiver Riddle   return std::tie(lhs.position, lhs.kind, lhs.label) <
9695919eab5SRiver Riddle          std::tie(rhs.position, rhs.kind, rhs.label);
9705919eab5SRiver Riddle }
9715919eab5SRiver Riddle 
operator <<(llvm::raw_ostream & os,InlayHintKind value)9725919eab5SRiver Riddle llvm::raw_ostream &mlir::lsp::operator<<(llvm::raw_ostream &os,
9735919eab5SRiver Riddle                                          InlayHintKind value) {
9745919eab5SRiver Riddle   switch (value) {
9755919eab5SRiver Riddle   case InlayHintKind::Parameter:
9765919eab5SRiver Riddle     return os << "parameter";
9775919eab5SRiver Riddle   case InlayHintKind::Type:
9785919eab5SRiver Riddle     return os << "type";
9795919eab5SRiver Riddle   }
9805919eab5SRiver Riddle   llvm_unreachable("Unknown InlayHintKind");
9815919eab5SRiver Riddle }
982ed344c88SRiver Riddle 
983ed344c88SRiver Riddle //===----------------------------------------------------------------------===//
984ed344c88SRiver Riddle // CodeActionContext
985ed344c88SRiver Riddle //===----------------------------------------------------------------------===//
986ed344c88SRiver Riddle 
fromJSON(const llvm::json::Value & value,CodeActionContext & result,llvm::json::Path path)987ed344c88SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
988ed344c88SRiver Riddle                          CodeActionContext &result, llvm::json::Path path) {
989ed344c88SRiver Riddle   llvm::json::ObjectMapper o(value, path);
990ed344c88SRiver Riddle   if (!o || !o.map("diagnostics", result.diagnostics))
991ed344c88SRiver Riddle     return false;
992ed344c88SRiver Riddle   o.map("only", result.only);
993ed344c88SRiver Riddle   return true;
994ed344c88SRiver Riddle }
995ed344c88SRiver Riddle 
996ed344c88SRiver Riddle //===----------------------------------------------------------------------===//
997ed344c88SRiver Riddle // CodeActionParams
998ed344c88SRiver Riddle //===----------------------------------------------------------------------===//
999ed344c88SRiver Riddle 
fromJSON(const llvm::json::Value & value,CodeActionParams & result,llvm::json::Path path)1000ed344c88SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value,
1001ed344c88SRiver Riddle                          CodeActionParams &result, llvm::json::Path path) {
1002ed344c88SRiver Riddle   llvm::json::ObjectMapper o(value, path);
1003ed344c88SRiver Riddle   return o && o.map("textDocument", result.textDocument) &&
1004ed344c88SRiver Riddle          o.map("range", result.range) && o.map("context", result.context);
1005ed344c88SRiver Riddle }
1006ed344c88SRiver Riddle 
1007ed344c88SRiver Riddle //===----------------------------------------------------------------------===//
1008ed344c88SRiver Riddle // WorkspaceEdit
1009ed344c88SRiver Riddle //===----------------------------------------------------------------------===//
1010ed344c88SRiver Riddle 
fromJSON(const llvm::json::Value & value,WorkspaceEdit & result,llvm::json::Path path)1011ed344c88SRiver Riddle bool mlir::lsp::fromJSON(const llvm::json::Value &value, WorkspaceEdit &result,
1012ed344c88SRiver Riddle                          llvm::json::Path path) {
1013ed344c88SRiver Riddle   llvm::json::ObjectMapper o(value, path);
1014ed344c88SRiver Riddle   return o && o.map("changes", result.changes);
1015ed344c88SRiver Riddle }
1016ed344c88SRiver Riddle 
toJSON(const WorkspaceEdit & value)1017ed344c88SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const WorkspaceEdit &value) {
1018ed344c88SRiver Riddle   llvm::json::Object fileChanges;
1019ed344c88SRiver Riddle   for (auto &change : value.changes)
1020ed344c88SRiver Riddle     fileChanges[change.first] = llvm::json::Array(change.second);
1021ed344c88SRiver Riddle   return llvm::json::Object{{"changes", std::move(fileChanges)}};
1022ed344c88SRiver Riddle }
1023ed344c88SRiver Riddle 
1024ed344c88SRiver Riddle //===----------------------------------------------------------------------===//
1025ed344c88SRiver Riddle // CodeAction
1026ed344c88SRiver Riddle //===----------------------------------------------------------------------===//
1027ed344c88SRiver Riddle 
1028ed344c88SRiver Riddle const llvm::StringLiteral CodeAction::kQuickFix = "quickfix";
1029ed344c88SRiver Riddle const llvm::StringLiteral CodeAction::kRefactor = "refactor";
1030ed344c88SRiver Riddle const llvm::StringLiteral CodeAction::kInfo = "info";
1031ed344c88SRiver Riddle 
toJSON(const CodeAction & value)1032ed344c88SRiver Riddle llvm::json::Value mlir::lsp::toJSON(const CodeAction &value) {
1033ed344c88SRiver Riddle   llvm::json::Object codeAction{{"title", value.title}};
1034ed344c88SRiver Riddle   if (value.kind)
1035ed344c88SRiver Riddle     codeAction["kind"] = *value.kind;
1036ed344c88SRiver Riddle   if (value.diagnostics)
1037ed344c88SRiver Riddle     codeAction["diagnostics"] = llvm::json::Array(*value.diagnostics);
1038ed344c88SRiver Riddle   if (value.isPreferred)
1039ed344c88SRiver Riddle     codeAction["isPreferred"] = true;
1040ed344c88SRiver Riddle   if (value.edit)
1041ed344c88SRiver Riddle     codeAction["edit"] = *value.edit;
1042ed344c88SRiver Riddle   return std::move(codeAction);
1043ed344c88SRiver Riddle }
1044