[clang-tools-extra] r319159 - [clangd] Switch from YAMLParser to JSONExpr

Sam McCall via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 28 01:37:43 PST 2017


Author: sammccall
Date: Tue Nov 28 01:37:43 2017
New Revision: 319159

URL: http://llvm.org/viewvc/llvm-project?rev=319159&view=rev
Log:
[clangd] Switch from YAMLParser to JSONExpr

Summary:
 - Converted Protocol.h parse() functions to take JSON::Expr.
   These no longer detect and log unknown fields, as this is not that
   useful and no longer free.
   I haven't changed the error handling too much: fields that were
   treated as optional before are still optional, even when it's wrong.
   Exception: object properties with the wrong type are now ignored.
 - Made JSONRPCDispatcher parse using json::parse
 - The bug where 'method' must come before 'params' in the stream is
 fixed as a side-effect. (And the same bug in executeCommand).
 - Some parser crashers fixed as a side effect.
   e.g. https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3890
 - The debug stream now prettyprints the input messages with --pretty.
 - Request params are attached to traces when tracing is enabled.
 - Fixed some bugs in tests (errors tolerated by YAMLParser, and
 off-by-ones in Content-Length that our null-termination was masking)
 - Fixed a random double-escape bug in ClangdLSPServer (it was our last
 use of YAMLParser!)

Reviewers: ilya-biryukov

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D40406

Removed:
    clang-tools-extra/trunk/test/clangd/did-change-watch-files.test
Modified:
    clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
    clang-tools-extra/trunk/clangd/JSONExpr.h
    clang-tools-extra/trunk/clangd/JSONRPCDispatcher.cpp
    clang-tools-extra/trunk/clangd/JSONRPCDispatcher.h
    clang-tools-extra/trunk/clangd/Protocol.cpp
    clang-tools-extra/trunk/clangd/Protocol.h
    clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
    clang-tools-extra/trunk/clangd/Trace.cpp
    clang-tools-extra/trunk/test/clangd/authority-less-uri.test
    clang-tools-extra/trunk/test/clangd/definitions.test
    clang-tools-extra/trunk/test/clangd/diagnostics.test
    clang-tools-extra/trunk/test/clangd/protocol.test
    clang-tools-extra/trunk/unittests/clangd/JSONExprTests.cpp

Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp Tue Nov 28 01:37:43 2017
@@ -139,7 +139,7 @@ void ClangdLSPServer::onRename(Ctx C, Re
   std::string Code = Server.getDocument(File);
   std::vector<TextEdit> Edits = replacementsToEdits(Code, *Replacements);
   WorkspaceEdit WE;
-  WE.changes = {{llvm::yaml::escape(Params.textDocument.uri.uri), Edits}};
+  WE.changes = {{Params.textDocument.uri.uri, Edits}};
   C.reply(WorkspaceEdit::unparse(WE));
 }
 
@@ -249,7 +249,7 @@ bool ClangdLSPServer::run(std::istream &
 
   // Set up JSONRPCDispatcher.
   JSONRPCDispatcher Dispatcher(
-      [](RequestContext Ctx, llvm::yaml::MappingNode *Params) {
+      [](RequestContext Ctx, const json::Expr &Params) {
         Ctx.replyError(ErrorCode::MethodNotFound, "method not found");
       });
   registerCallbackHandlers(Dispatcher, Out, /*Callbacks=*/*this);

Modified: clang-tools-extra/trunk/clangd/JSONExpr.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/JSONExpr.h?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/JSONExpr.h (original)
+++ clang-tools-extra/trunk/clangd/JSONExpr.h Tue Nov 28 01:37:43 2017
@@ -181,6 +181,16 @@ public:
       return as<double>();
     return llvm::None;
   }
+  llvm::Optional<int64_t> asInteger() const {
+    if (LLVM_LIKELY(Type == T_Number)) {
+      double D = as<double>();
+      if (LLVM_LIKELY(std::modf(D, &D) == 0 &&
+                      D >= std::numeric_limits<int64_t>::min() &&
+                      D <= std::numeric_limits<int64_t>::max()))
+        return D;
+    }
+    return llvm::None;
+  }
   llvm::Optional<llvm::StringRef> asString() const {
     if (Type == T_String)
       return llvm::StringRef(as<std::string>());
@@ -324,6 +334,11 @@ public:
         return V->asNumber();
       return llvm::None;
     }
+    llvm::Optional<int64_t> getInteger(const ObjectKey &K) const {
+      if (auto *V = get(K))
+        return V->asInteger();
+      return llvm::None;
+    }
     llvm::Optional<llvm::StringRef> getString(const ObjectKey &K) const {
       if (auto *V = get(K))
         return V->asString();
@@ -374,6 +389,9 @@ public:
     llvm::Optional<double> getNumber(size_t I) const {
       return (*this)[I].asNumber();
     }
+    llvm::Optional<int64_t> getInteger(size_t I) const {
+      return (*this)[I].asInteger();
+    }
     llvm::Optional<llvm::StringRef> getString(size_t I) const {
       return (*this)[I].asString();
     }

Modified: clang-tools-extra/trunk/clangd/JSONRPCDispatcher.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/JSONRPCDispatcher.cpp?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/JSONRPCDispatcher.cpp (original)
+++ clang-tools-extra/trunk/clangd/JSONRPCDispatcher.cpp Tue Nov 28 01:37:43 2017
@@ -14,7 +14,6 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/YAMLParser.h"
 #include <istream>
 
 using namespace clang;
@@ -101,88 +100,29 @@ void JSONRPCDispatcher::registerHandler(
   Handlers[Method] = std::move(H);
 }
 
-static void
-callHandler(const llvm::StringMap<JSONRPCDispatcher::Handler> &Handlers,
-            llvm::yaml::ScalarNode *Method, llvm::Optional<json::Expr> ID,
-            llvm::yaml::MappingNode *Params,
-            const JSONRPCDispatcher::Handler &UnknownHandler, JSONOutput &Out) {
-  llvm::SmallString<64> MethodStorage;
-  llvm::StringRef MethodStr = Method->getValue(MethodStorage);
-  auto I = Handlers.find(MethodStr);
-  auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;
-  Handler(RequestContext(Out, MethodStr, std::move(ID)), Params);
-}
-
-bool JSONRPCDispatcher::call(StringRef Content, JSONOutput &Out) const {
-  llvm::SourceMgr SM;
-  llvm::yaml::Stream YAMLStream(Content, SM);
-
-  auto Doc = YAMLStream.begin();
-  if (Doc == YAMLStream.end())
+bool JSONRPCDispatcher::call(const json::Expr &Message, JSONOutput &Out) const {
+  // Message must be an object with "jsonrpc":"2.0".
+  auto *Object = Message.asObject();
+  if (!Object || Object->getString("jsonrpc") != Optional<StringRef>("2.0"))
     return false;
-
-  auto *Object = dyn_cast_or_null<llvm::yaml::MappingNode>(Doc->getRoot());
-  if (!Object)
-    return false;
-
-  llvm::yaml::ScalarNode *Version = nullptr;
-  llvm::yaml::ScalarNode *Method = nullptr;
-  llvm::yaml::MappingNode *Params = nullptr;
+  // ID may be any JSON value. If absent, this is a notification.
   llvm::Optional<json::Expr> ID;
-  for (auto &NextKeyValue : *Object) {
-    auto *KeyString =
-        dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return false;
-
-    llvm::SmallString<10> KeyStorage;
-    StringRef KeyValue = KeyString->getValue(KeyStorage);
-    llvm::yaml::Node *Value = NextKeyValue.getValue();
-    if (!Value)
-      return false;
-
-    if (KeyValue == "jsonrpc") {
-      // This should be "2.0". Always.
-      Version = dyn_cast<llvm::yaml::ScalarNode>(Value);
-      if (!Version || Version->getRawValue() != "\"2.0\"")
-        return false;
-    } else if (KeyValue == "method") {
-      Method = dyn_cast<llvm::yaml::ScalarNode>(Value);
-    } else if (KeyValue == "id") {
-      // ID may be either a string or a number.
-      if (auto *IdNode = dyn_cast<llvm::yaml::ScalarNode>(Value)) {
-        llvm::SmallString<32> S;
-        llvm::StringRef V = IdNode->getValue(S);
-        if (IdNode->getRawValue().startswith("\"")) {
-          ID.emplace(V.str());
-        } else {
-          double D;
-          // FIXME: this is locale-sensitive.
-          if (llvm::to_float(V, D))
-            ID.emplace(D);
-        }
-      }
-    } else if (KeyValue == "params") {
-      if (!Method)
-        return false;
-      // We have to interleave the call of the function here, otherwise the
-      // YAMLParser will die because it can't go backwards. This is unfortunate
-      // because it will break clients that put the id after params. A possible
-      // fix would be to split the parsing and execution phases.
-      Params = dyn_cast<llvm::yaml::MappingNode>(Value);
-      callHandler(Handlers, Method, std::move(ID), Params, UnknownHandler, Out);
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  // In case there was a request with no params, call the handler on the
-  // leftovers.
+  if (auto *I = Object->get("id"))
+    ID = std::move(*I);
+  // Method must be given.
+  auto Method = Object->getString("method");
   if (!Method)
     return false;
-  callHandler(Handlers, Method, std::move(ID), nullptr, UnknownHandler, Out);
+  // Params should be given, use null if not.
+  json::Expr Params = nullptr;
+  if (auto *P = Object->get("params"))
+    Params = std::move(*P);
 
+  auto I = Handlers.find(*Method);
+  auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;
+  RequestContext Ctx(Out, *Method, std::move(ID));
+  SPAN_ATTACH(Ctx.tracer(), "Params", Params);
+  Handler(std::move(Ctx), std::move(Params));
   return true;
 }
 
@@ -211,7 +151,7 @@ void clangd::runLanguageServerLoop(std::
 
       llvm::StringRef LineRef(Line);
 
-      // We allow YAML-style comments in headers. Technically this isn't part
+      // We allow comments in headers. Technically this isn't part
       // of the LSP specification, but makes writing tests easier.
       if (LineRef.startswith("#"))
         continue;
@@ -251,11 +191,9 @@ void clangd::runLanguageServerLoop(std::
     }
 
     if (ContentLength > 0) {
-      std::vector<char> JSON(ContentLength + 1, '\0');
+      std::vector<char> JSON(ContentLength);
       llvm::StringRef JSONRef;
       {
-        // Now read the JSON. Insert a trailing null byte as required by the
-        // YAML parser.
         In.read(JSON.data(), ContentLength);
         Out.mirrorInput(StringRef(JSON.data(), In.gcount()));
 
@@ -271,12 +209,18 @@ void clangd::runLanguageServerLoop(std::
         JSONRef = StringRef(JSON.data(), ContentLength);
       }
 
-      // Log the message.
-      Out.log("<-- " + JSONRef + "\n");
-
-      // Finally, execute the action for this JSON message.
-      if (!Dispatcher.call(JSONRef, Out))
-        Out.log("JSON dispatch failed!\n");
+      if (auto Doc = json::parse(JSONRef)) {
+        // Log the formatted message.
+        Out.log(llvm::formatv(Out.Pretty ? "<-- {0:2}\n" : "<-- {0}\n", *Doc));
+        // Finally, execute the action for this JSON message.
+        if (!Dispatcher.call(*Doc, Out))
+          Out.log("JSON dispatch failed!\n");
+      } else {
+        // Parse error. Log the raw message.
+        Out.log("<-- " + JSONRef + "\n");
+        Out.log(llvm::Twine("JSON parse error: ") +
+                llvm::toString(Doc.takeError()) + "\n");
+      }
 
       // If we're done, exit the loop.
       if (IsDone)

Modified: clang-tools-extra/trunk/clangd/JSONRPCDispatcher.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/JSONRPCDispatcher.h?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/JSONRPCDispatcher.h (original)
+++ clang-tools-extra/trunk/clangd/JSONRPCDispatcher.h Tue Nov 28 01:37:43 2017
@@ -17,7 +17,6 @@
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/Support/YAMLParser.h"
 #include <iosfwd>
 #include <mutex>
 
@@ -30,7 +29,7 @@ class JSONOutput : public Logger {
 public:
   JSONOutput(llvm::raw_ostream &Outs, llvm::raw_ostream &Logs,
              llvm::raw_ostream *InputMirror = nullptr, bool Pretty = false)
-      : Outs(Outs), Logs(Logs), InputMirror(InputMirror), Pretty(Pretty) {}
+      : Pretty(Pretty), Outs(Outs), Logs(Logs), InputMirror(InputMirror) {}
 
   /// Emit a JSONRPC message.
   void writeMessage(const json::Expr &Result);
@@ -44,11 +43,13 @@ public:
   /// Unlike other methods of JSONOutput, mirrorInput is not thread-safe.
   void mirrorInput(const Twine &Message);
 
+  // Whether output should be pretty-printed.
+  const bool Pretty;
+
 private:
   llvm::raw_ostream &Outs;
   llvm::raw_ostream &Logs;
   llvm::raw_ostream *InputMirror;
-  bool Pretty;
 
   std::mutex StreamMutex;
 };
@@ -84,8 +85,7 @@ private:
 class JSONRPCDispatcher {
 public:
   // A handler responds to requests for a particular method name.
-  using Handler =
-      std::function<void(RequestContext, llvm::yaml::MappingNode *)>;
+  using Handler = std::function<void(RequestContext, const json::Expr &)>;
 
   /// Create a new JSONRPCDispatcher. UnknownHandler is called when an unknown
   /// method is received.
@@ -96,7 +96,7 @@ public:
   void registerHandler(StringRef Method, Handler H);
 
   /// Parses a JSONRPC message and calls the Handler for it.
-  bool call(StringRef Content, JSONOutput &Out) const;
+  bool call(const json::Expr &Message, JSONOutput &Out) const;
 
 private:
   llvm::StringMap<Handler> Handlers;

Modified: clang-tools-extra/trunk/clangd/Protocol.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.cpp?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.cpp (original)
+++ clang-tools-extra/trunk/clangd/Protocol.cpp Tue Nov 28 01:37:43 2017
@@ -13,7 +13,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "Protocol.h"
-#include "Logger.h"
 
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/SmallString.h"
@@ -25,12 +24,6 @@
 using namespace clang;
 using namespace clang::clangd;
 
-namespace {
-void logIgnoredField(llvm::StringRef KeyValue, clangd::Logger &Logger) {
-  Logger.log(llvm::formatv("Ignored unknown field \"{0}\"\n", KeyValue));
-}
-} // namespace
-
 URI URI::fromUri(llvm::StringRef uri) {
   URI Result;
   Result.uri = uri;
@@ -58,70 +51,31 @@ URI URI::fromFile(llvm::StringRef file)
   return Result;
 }
 
-URI URI::parse(llvm::yaml::ScalarNode *Param) {
-  llvm::SmallString<10> Storage;
-  return URI::fromUri(Param->getValue(Storage));
-}
-
 json::Expr URI::unparse(const URI &U) { return U.uri; }
 
 llvm::Optional<TextDocumentIdentifier>
-TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params,
-                              clangd::Logger &Logger) {
+TextDocumentIdentifier::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   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 {
-      logIgnoredField(KeyValue, Logger);
-    }
-  }
+  if (auto U = O->getString("uri"))
+    Result.uri = URI::parse(*U);
+  // FIXME: parse 'version', but only for VersionedTextDocumentIdentifiers.
   return Result;
 }
 
-llvm::Optional<Position> Position::parse(llvm::yaml::MappingNode *Params,
-                                         clangd::Logger &Logger) {
+llvm::Optional<Position> Position::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   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 {
-      logIgnoredField(KeyValue, Logger);
-    }
-  }
+  if (auto L = O->getInteger("line"))
+    Result.line = *L;
+  if (auto C = O->getInteger("character"))
+    Result.character = *C;
   return Result;
 }
 
@@ -132,35 +86,23 @@ json::Expr Position::unparse(const Posit
   };
 }
 
-llvm::Optional<Range> Range::parse(llvm::yaml::MappingNode *Params,
-                                   clangd::Logger &Logger) {
+llvm::Optional<Range> Range::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   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, Logger);
-      if (!Parsed)
-        return llvm::None;
-      Result.start = std::move(*Parsed);
-    } else if (KeyValue == "end") {
-      auto Parsed = Position::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
-      Result.end = std::move(*Parsed);
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
+  if (auto *S = O->get("start")) {
+    if (auto P = Position::parse(*S))
+      Result.start = std::move(*P);
+    else
+      return None;
+  }
+  if (auto *E = O->get("end")) {
+    if (auto P = Position::parse(*E))
+      Result.end = std::move(*P);
+    else
+      return None;
   }
   return Result;
 }
@@ -180,100 +122,53 @@ json::Expr Location::unparse(const Locat
 }
 
 llvm::Optional<TextDocumentItem>
-TextDocumentItem::parse(llvm::yaml::MappingNode *Params,
-                        clangd::Logger &Logger) {
+TextDocumentItem::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   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 {
-      logIgnoredField(KeyValue, Logger);
-    }
-  }
+  if (auto U = O->getString("uri"))
+    Result.uri = URI::parse(*U);
+  if (auto L = O->getString("languageId"))
+    Result.languageId = *L;
+  if (auto V = O->getInteger("version"))
+    Result.version = *V;
+  if (auto T = O->getString("text"))
+    Result.text = *T;
   return Result;
 }
 
-llvm::Optional<Metadata> Metadata::parse(llvm::yaml::MappingNode *Params,
-                                         clangd::Logger &Logger) {
-  Metadata Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return llvm::None;
+llvm::Optional<Metadata> Metadata::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
 
-    llvm::SmallString<10> KeyStorage;
-    StringRef KeyValue = KeyString->getValue(KeyStorage);
-    auto *Value = NextKeyValue.getValue();
-
-    llvm::SmallString<10> Storage;
-    if (KeyValue == "extraFlags") {
-      auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
-      if (!Seq)
+  Metadata Result;
+  if (auto *Flags = O->getArray("extraFlags"))
+    for (auto &F : *Flags) {
+      if (auto S = F.asString())
+        Result.extraFlags.push_back(*S);
+      else
         return llvm::None;
-      for (auto &Item : *Seq) {
-        auto *Node = dyn_cast<llvm::yaml::ScalarNode>(&Item);
-        if (!Node)
-          return llvm::None;
-        Result.extraFlags.push_back(Node->getValue(Storage));
-      }
-    } else {
-      logIgnoredField(KeyValue, Logger);
     }
-  }
   return Result;
 }
 
-llvm::Optional<TextEdit> TextEdit::parse(llvm::yaml::MappingNode *Params,
-                                         clangd::Logger &Logger) {
-  TextEdit Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return llvm::None;
+llvm::Optional<TextEdit> TextEdit::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return 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, Logger);
-      if (!Parsed)
-        return llvm::None;
+  TextEdit Result;
+  if (auto *R = O->get("range")) {
+    if (auto Parsed = Range::parse(*R))
       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 {
-      logIgnoredField(KeyValue, Logger);
-    }
+    else
+      return llvm::None;
   }
+  if (auto T = O->getString("newText"))
+    Result.newText = *T;
   return Result;
 }
 
@@ -285,313 +180,154 @@ json::Expr TextEdit::unparse(const TextE
 }
 
 namespace {
-TraceLevel getTraceLevel(llvm::StringRef TraceLevelStr,
-                         clangd::Logger &Logger) {
+TraceLevel getTraceLevel(llvm::StringRef TraceLevelStr) {
   if (TraceLevelStr == "off")
     return TraceLevel::Off;
   else if (TraceLevelStr == "messages")
     return TraceLevel::Messages;
   else if (TraceLevelStr == "verbose")
     return TraceLevel::Verbose;
-
-  Logger.log(llvm::formatv("Unknown trace level \"{0}\"\n", TraceLevelStr));
   return TraceLevel::Off;
 }
 } // namespace
 
 llvm::Optional<InitializeParams>
-InitializeParams::parse(llvm::yaml::MappingNode *Params,
-                        clangd::Logger &Logger) {
-  // If we don't understand the params, proceed with default parameters.
-  auto ParseFailure = [&] {
-    Logger.log("Failed to decode InitializeParams\n");
-    return InitializeParams();
-  };
+InitializeParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   InitializeParams Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return ParseFailure();
-
-    llvm::SmallString<10> KeyStorage;
-    StringRef KeyValue = KeyString->getValue(KeyStorage);
-    auto *Value =
-        dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
-    if (!Value)
-      continue;
-
-    if (KeyValue == "processId") {
-      auto *Value =
-          dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
-      if (!Value)
-        return ParseFailure();
-      long long Val;
-      if (llvm::getAsSignedInteger(Value->getValue(KeyStorage), 0, Val))
-        return ParseFailure();
-      Result.processId = Val;
-    } else if (KeyValue == "rootPath") {
-      Result.rootPath = Value->getValue(KeyStorage);
-    } else if (KeyValue == "rootUri") {
-      Result.rootUri = URI::parse(Value);
-    } else if (KeyValue == "initializationOptions") {
-      // Not used
-    } else if (KeyValue == "capabilities") {
-      // Not used
-    } else if (KeyValue == "trace") {
-      Result.trace = getTraceLevel(Value->getValue(KeyStorage), Logger);
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
-  }
+  if (auto P = O->getInteger("processId"))
+    Result.processId = *P;
+  if (auto R = O->getString("rootPath"))
+    Result.rootPath = *R;
+  if (auto R = O->getString("rootUri"))
+    Result.rootUri = URI::parse(*R);
+  if (auto T = O->getString("trace"))
+    Result.trace = getTraceLevel(*T);
+  // initializationOptions, capabilities unused
   return Result;
 }
 
 llvm::Optional<DidOpenTextDocumentParams>
-DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
-                                 clangd::Logger &Logger) {
+DidOpenTextDocumentParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   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, Logger);
-      if (!Parsed)
-        return llvm::None;
+  if (auto *D = O->get("textDocument")) {
+    if (auto Parsed = TextDocumentItem::parse(*D))
       Result.textDocument = std::move(*Parsed);
-    } else if (KeyValue == "metadata") {
-      auto Parsed = Metadata::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+    else
+      return llvm::None;
+  }
+  if (auto *M = O->get("metadata")) {
+    if (auto Parsed = Metadata::parse(*M))
       Result.metadata = std::move(*Parsed);
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
+    else
+      return llvm::None;
   }
   return Result;
 }
 
 llvm::Optional<DidCloseTextDocumentParams>
-DidCloseTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
-                                  clangd::Logger &Logger) {
-  DidCloseTextDocumentParams Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return llvm::None;
+DidCloseTextDocumentParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
 
-    llvm::SmallString<10> KeyStorage;
-    StringRef KeyValue = KeyString->getValue(KeyStorage);
-    auto *Value = NextKeyValue.getValue();
-
-    if (KeyValue == "textDocument") {
-      auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
-      if (!Map)
-        return llvm::None;
-      auto Parsed = TextDocumentIdentifier::parse(Map, Logger);
-      if (!Parsed)
-        return llvm::None;
+  DidCloseTextDocumentParams Result;
+  if (auto *D = O->get("textDocument")) {
+    if (auto Parsed = TextDocumentIdentifier::parse(*D))
       Result.textDocument = std::move(*Parsed);
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
+    else
+      return llvm::None;
   }
   return Result;
 }
 
 llvm::Optional<DidChangeTextDocumentParams>
-DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
-                                   clangd::Logger &Logger) {
-  DidChangeTextDocumentParams Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return llvm::None;
+DidChangeTextDocumentParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return 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, Logger);
-      if (!Parsed)
-        return llvm::None;
+  DidChangeTextDocumentParams Result;
+  if (auto *D = O->get("textDocument")) {
+    if (auto Parsed = TextDocumentIdentifier::parse(*D))
       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, Logger);
-        if (!Parsed)
-          return llvm::None;
+    else
+      return llvm::None;
+  }
+  if (auto *A = O->getArray("contentChanges"))
+    for (auto &E : *A) {
+      if (auto Parsed = TextDocumentContentChangeEvent::parse(E))
         Result.contentChanges.push_back(std::move(*Parsed));
-      }
-    } else {
-      logIgnoredField(KeyValue, Logger);
+      else
+        return llvm::None;
     }
-  }
   return Result;
 }
 
-llvm::Optional<FileEvent> FileEvent::parse(llvm::yaml::MappingNode *Params,
-                                           clangd::Logger &Logger) {
-  llvm::Optional<FileEvent> Result = FileEvent();
-  for (auto &NextKeyValue : *Params) {
-    // We have to consume the whole MappingNode because it doesn't support
-    // skipping and we want to be able to parse further valid events.
-    if (!Result)
-      continue;
-
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString) {
-      Result.reset();
-      continue;
-    }
+llvm::Optional<FileEvent> FileEvent::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
 
-    llvm::SmallString<10> KeyStorage;
-    StringRef KeyValue = KeyString->getValue(KeyStorage);
-    auto *Value =
-        dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
-    if (!Value) {
-      Result.reset();
-      continue;
-    }
-    llvm::SmallString<10> Storage;
-    if (KeyValue == "uri") {
-      Result->uri = URI::parse(Value);
-    } else if (KeyValue == "type") {
-      long long Val;
-      if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val)) {
-        Result.reset();
-        continue;
-      }
-      Result->type = static_cast<FileChangeType>(Val);
-      if (Result->type < FileChangeType::Created ||
-          Result->type > FileChangeType::Deleted)
-        Result.reset();
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
+  FileEvent Result;
+  if (auto U = O->getString("uri"))
+    Result.uri = URI::parse(*U);
+  if (auto T = O->getInteger("type")) {
+    if (*T < static_cast<int>(FileChangeType::Created) ||
+        *T > static_cast<int>(FileChangeType::Deleted))
+      return llvm::None;
+    Result.type = static_cast<FileChangeType>(*T);
   }
   return Result;
 }
 
 llvm::Optional<DidChangeWatchedFilesParams>
-DidChangeWatchedFilesParams::parse(llvm::yaml::MappingNode *Params,
-                                   clangd::Logger &Logger) {
-  DidChangeWatchedFilesParams Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return llvm::None;
+DidChangeWatchedFilesParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
 
-    llvm::SmallString<10> KeyStorage;
-    StringRef KeyValue = KeyString->getValue(KeyStorage);
-    auto *Value = NextKeyValue.getValue();
-
-    llvm::SmallString<10> Storage;
-    if (KeyValue == "changes") {
-      auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
-      if (!Seq)
+  DidChangeWatchedFilesParams Result;
+  if (auto *C = O->getArray("changes"))
+    for (auto &E : *C) {
+      if (auto Parsed = FileEvent::parse(E))
+        Result.changes.push_back(std::move(*Parsed));
+      else
         return llvm::None;
-      for (auto &Item : *Seq) {
-        auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
-        if (!I)
-          return llvm::None;
-        auto Parsed = FileEvent::parse(I, Logger);
-        if (Parsed)
-          Result.changes.push_back(std::move(*Parsed));
-        else
-          Logger.log("Failed to decode a FileEvent.\n");
-      }
-    } else {
-      logIgnoredField(KeyValue, Logger);
     }
-  }
   return Result;
 }
 
 llvm::Optional<TextDocumentContentChangeEvent>
-TextDocumentContentChangeEvent::parse(llvm::yaml::MappingNode *Params,
-                                      clangd::Logger &Logger) {
+TextDocumentContentChangeEvent::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   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 {
-      logIgnoredField(KeyValue, Logger);
-    }
-  }
+  if (auto T = O->getString("text"))
+    Result.text = *T;
   return Result;
 }
 
 llvm::Optional<FormattingOptions>
-FormattingOptions::parse(llvm::yaml::MappingNode *Params,
-                         clangd::Logger &Logger) {
+FormattingOptions::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   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 {
-      logIgnoredField(KeyValue, Logger);
-    }
-  }
+  if (auto T = O->getInteger("tabSize"))
+    Result.tabSize = *T;
+  if (auto I = O->getBoolean("insertSpaces"))
+    Result.insertSpaces = *I;
   return Result;
 }
 
@@ -603,305 +339,182 @@ json::Expr FormattingOptions::unparse(co
 }
 
 llvm::Optional<DocumentRangeFormattingParams>
-DocumentRangeFormattingParams::parse(llvm::yaml::MappingNode *Params,
-                                     clangd::Logger &Logger) {
+DocumentRangeFormattingParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   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, Logger);
-      if (!Parsed)
-        return llvm::None;
+  if (auto *D = O->get("textDocument")) {
+    if (auto Parsed = TextDocumentIdentifier::parse(*D))
       Result.textDocument = std::move(*Parsed);
-    } else if (KeyValue == "range") {
-      auto Parsed = Range::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+    else
+      return llvm::None;
+  }
+  if (auto *R = O->get("range")) {
+    if (auto Parsed = Range::parse(*R))
       Result.range = std::move(*Parsed);
-    } else if (KeyValue == "options") {
-      auto Parsed = FormattingOptions::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+    else
+      return llvm::None;
+  }
+  if (auto *F = O->get("options")) {
+    if (auto Parsed = FormattingOptions::parse(*F))
       Result.options = std::move(*Parsed);
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
+    else
+      return llvm::None;
   }
   return Result;
 }
 
 llvm::Optional<DocumentOnTypeFormattingParams>
-DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params,
-                                      clangd::Logger &Logger) {
-  DocumentOnTypeFormattingParams Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return llvm::None;
+DocumentOnTypeFormattingParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return 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, Logger);
-      if (!Parsed)
-        return llvm::None;
+  DocumentOnTypeFormattingParams Result;
+  if (auto Ch = O->getString("ch"))
+    Result.ch = *Ch;
+  if (auto *D = O->get("textDocument")) {
+    if (auto Parsed = TextDocumentIdentifier::parse(*D))
       Result.textDocument = std::move(*Parsed);
-    } else if (KeyValue == "position") {
-      auto Parsed = Position::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+    else
+      return llvm::None;
+  }
+  if (auto *P = O->get("position")) {
+    if (auto Parsed = Position::parse(*P))
       Result.position = std::move(*Parsed);
-    } else if (KeyValue == "options") {
-      auto Parsed = FormattingOptions::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+    else
+      return llvm::None;
+  }
+  if (auto *F = O->get("options")) {
+    if (auto Parsed = FormattingOptions::parse(*F))
       Result.options = std::move(*Parsed);
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
+    else
+      return llvm::None;
   }
   return Result;
 }
 
 llvm::Optional<DocumentFormattingParams>
-DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params,
-                                clangd::Logger &Logger) {
+DocumentFormattingParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   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, Logger);
-      if (!Parsed)
-        return llvm::None;
+  if (auto *D = O->get("textDocument")) {
+    if (auto Parsed = TextDocumentIdentifier::parse(*D))
       Result.textDocument = std::move(*Parsed);
-    } else if (KeyValue == "options") {
-      auto Parsed = FormattingOptions::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+    else
+      return llvm::None;
+  }
+  if (auto *F = O->get("options")) {
+    if (auto Parsed = FormattingOptions::parse(*F))
       Result.options = std::move(*Parsed);
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
+    else
+      return llvm::None;
   }
   return Result;
 }
 
-llvm::Optional<Diagnostic> Diagnostic::parse(llvm::yaml::MappingNode *Params,
-                                             clangd::Logger &Logger) {
-  Diagnostic Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return llvm::None;
+llvm::Optional<Diagnostic> Diagnostic::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return 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, Logger);
-      if (!Parsed)
-        return llvm::None;
+  Diagnostic Result;
+  if (auto *R = O->get("range")) {
+    if (auto Parsed = Range::parse(*R))
       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 == "code") {
-      // Not currently used
-    } else if (KeyValue == "source") {
-      // Not currently used
-    } 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 {
-      logIgnoredField(KeyValue, Logger);
-    }
+    else
+      return llvm::None;
   }
+  if (auto S = O->getInteger("severity"))
+    Result.severity = *S;
+  if (auto M = O->getString("message"))
+    Result.message = *M;
   return Result;
 }
 
 llvm::Optional<CodeActionContext>
-CodeActionContext::parse(llvm::yaml::MappingNode *Params,
-                         clangd::Logger &Logger) {
-  CodeActionContext Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return llvm::None;
+CodeActionContext::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return 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, Logger);
-        if (!Parsed)
-          return llvm::None;
+  CodeActionContext Result;
+  if (auto *D = O->getArray("diagnostics"))
+    for (auto &E : *D) {
+      if (auto Parsed = Diagnostic::parse(E))
         Result.diagnostics.push_back(std::move(*Parsed));
-      }
-    } else {
-      logIgnoredField(KeyValue, Logger);
+      else
+        return llvm::None;
     }
-  }
   return Result;
 }
 
 llvm::Optional<CodeActionParams>
-CodeActionParams::parse(llvm::yaml::MappingNode *Params,
-                        clangd::Logger &Logger) {
+CodeActionParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   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, Logger);
-      if (!Parsed)
-        return llvm::None;
+  if (auto *D = O->get("textDocument")) {
+    if (auto Parsed = TextDocumentIdentifier::parse(*D))
       Result.textDocument = std::move(*Parsed);
-    } else if (KeyValue == "range") {
-      auto Parsed = Range::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+    else
+      return llvm::None;
+  }
+  if (auto *R = O->get("range")) {
+    if (auto Parsed = Range::parse(*R))
       Result.range = std::move(*Parsed);
-    } else if (KeyValue == "context") {
-      auto Parsed = CodeActionContext::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+    else
+      return llvm::None;
+  }
+  if (auto *R = O->get("context")) {
+    if (auto Parsed = CodeActionContext::parse(*R))
       Result.context = std::move(*Parsed);
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
+    else
+      return llvm::None;
   }
   return Result;
 }
 
-static llvm::Optional<std::map<std::string, std::vector<TextEdit>>>
-parseWorkspaceEditChange(llvm::yaml::MappingNode *Params,
-                         clangd::Logger &Logger) {
+llvm::Optional<std::map<std::string, std::vector<TextEdit>>>
+parseWorkspaceEditChange(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   std::map<std::string, std::vector<TextEdit>> Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
+  for (const auto &KV : *O) {
+    auto &Values = Result[StringRef(KV.first)];
+    if (auto *Edits = KV.second.asArray())
+      for (auto &Edit : *Edits) {
+        if (auto Parsed = TextEdit::parse(Edit))
+          Values.push_back(std::move(*Parsed));
+        else
+          return llvm::None;
+      }
+    else
       return llvm::None;
-
-    llvm::SmallString<10> KeyStorage;
-    StringRef KeyValue = KeyString->getValue(KeyStorage);
-    if (Result.count(KeyValue)) {
-      logIgnoredField(KeyValue, Logger);
-      continue;
-    }
-
-    auto *Value =
-        dyn_cast_or_null<llvm::yaml::SequenceNode>(NextKeyValue.getValue());
-    if (!Value)
-      return llvm::None;
-    for (auto &Item : *Value) {
-      auto *ItemValue = dyn_cast_or_null<llvm::yaml::MappingNode>(&Item);
-      if (!ItemValue)
-        return llvm::None;
-      auto Parsed = TextEdit::parse(ItemValue, Logger);
-      if (!Parsed)
-        return llvm::None;
-
-      Result[KeyValue].push_back(*Parsed);
-    }
   }
-
   return Result;
 }
 
-llvm::Optional<WorkspaceEdit>
-WorkspaceEdit::parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger) {
-  WorkspaceEdit Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return llvm::None;
+llvm::Optional<WorkspaceEdit> WorkspaceEdit::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
 
-    llvm::SmallString<10> KeyStorage;
-    StringRef KeyValue = KeyString->getValue(KeyStorage);
-
-    llvm::SmallString<10> Storage;
-    if (KeyValue == "changes") {
-      auto *Value =
-          dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
-      if (!Value)
-        return llvm::None;
-      auto Parsed = parseWorkspaceEditChange(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+  WorkspaceEdit Result;
+  if (auto *C = O->get("changes")) {
+    if (auto Parsed = parseWorkspaceEditChange(*C))
       Result.changes = std::move(*Parsed);
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
+    else
+      return llvm::None;
   }
   return Result;
 }
@@ -910,59 +523,25 @@ const std::string ExecuteCommandParams::
     "clangd.applyFix";
 
 llvm::Optional<ExecuteCommandParams>
-ExecuteCommandParams::parse(llvm::yaml::MappingNode *Params,
-                            clangd::Logger &Logger) {
-  ExecuteCommandParams Result;
-  // Depending on which "command" we parse, we will use this function to parse
-  // the command "arguments".
-  std::function<bool(llvm::yaml::MappingNode * Params)> ArgParser = nullptr;
-
-  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);
-
-    // Note that "commands" has to be parsed before "arguments" for this to
-    // work properly.
-    if (KeyValue == "command") {
-      auto *ScalarValue =
-          dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
-      if (!ScalarValue)
-        return llvm::None;
-      llvm::SmallString<10> Storage;
-      Result.command = ScalarValue->getValue(Storage);
-      if (Result.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
-        ArgParser = [&Result, &Logger](llvm::yaml::MappingNode *Params) {
-          auto WE = WorkspaceEdit::parse(Params, Logger);
-          if (WE)
-            Result.workspaceEdit = WE;
-          return WE.hasValue();
-        };
-      } else {
-        return llvm::None;
-      }
-    } else if (KeyValue == "arguments") {
-      auto *Value = NextKeyValue.getValue();
-      auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
-      if (!Seq)
-        return llvm::None;
-      for (auto &Item : *Seq) {
-        auto *ItemValue = dyn_cast_or_null<llvm::yaml::MappingNode>(&Item);
-        if (!ItemValue || !ArgParser)
-          return llvm::None;
-        if (!ArgParser(ItemValue))
-          return llvm::None;
-      }
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
-  }
-  if (Result.command.empty())
-    return llvm::None;
+ExecuteCommandParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
 
+  ExecuteCommandParams Result;
+  if (auto Command = O->getString("command"))
+    Result.command = *Command;
+  auto Args = O->getArray("arguments");
+
+  if (Result.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
+    if (!Args || Args->size() != 1)
+      return llvm::None;
+    if (auto Parsed = WorkspaceEdit::parse(Args->front()))
+      Result.workspaceEdit = std::move(*Parsed);
+    else
+      return llvm::None;
+  } else
+    return llvm::None; // Unrecognized command.
   return Result;
 }
 
@@ -981,35 +560,23 @@ ApplyWorkspaceEditParams::unparse(const
 }
 
 llvm::Optional<TextDocumentPositionParams>
-TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params,
-                                  clangd::Logger &Logger) {
+TextDocumentPositionParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
+
   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)
-      continue;
-
-    llvm::SmallString<10> Storage;
-    if (KeyValue == "textDocument") {
-      auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+  if (auto *D = O->get("textDocument")) {
+    if (auto Parsed = TextDocumentIdentifier::parse(*D))
       Result.textDocument = std::move(*Parsed);
-    } else if (KeyValue == "position") {
-      auto Parsed = Position::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+    else
+      return llvm::None;
+  }
+  if (auto *P = O->get("position")) {
+    if (auto Parsed = Position::parse(*P))
       Result.position = std::move(*Parsed);
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
+    else
+      return llvm::None;
   }
   return Result;
 }
@@ -1081,50 +648,25 @@ json::Expr SignatureHelp::unparse(const
   };
 }
 
-llvm::Optional<RenameParams>
-RenameParams::parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger) {
-  RenameParams Result;
-  for (auto &NextKeyValue : *Params) {
-    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-    if (!KeyString)
-      return llvm::None;
+llvm::Optional<RenameParams> RenameParams::parse(const json::Expr &Params) {
+  const json::obj *O = Params.asObject();
+  if (!O)
+    return None;
 
-    llvm::SmallString<10> KeyStorage;
-    StringRef KeyValue = KeyString->getValue(KeyStorage);
-
-    if (KeyValue == "textDocument") {
-      auto *Value =
-          dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
-      if (!Value)
-        continue;
-      auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
-      if (!Map)
-        return llvm::None;
-      auto Parsed = TextDocumentIdentifier::parse(Map, Logger);
-      if (!Parsed)
-        return llvm::None;
+  RenameParams Result;
+  if (auto *D = O->get("textDocument")) {
+    if (auto Parsed = TextDocumentIdentifier::parse(*D))
       Result.textDocument = std::move(*Parsed);
-    } else if (KeyValue == "position") {
-      auto *Value =
-          dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
-      if (!Value)
-        continue;
-      auto Parsed = Position::parse(Value, Logger);
-      if (!Parsed)
-        return llvm::None;
+    else
+      return llvm::None;
+  }
+  if (auto *P = O->get("position")) {
+    if (auto Parsed = Position::parse(*P))
       Result.position = std::move(*Parsed);
-    } else if (KeyValue == "newName") {
-      auto *Value = NextKeyValue.getValue();
-      if (!Value)
-        continue;
-      auto *Node = dyn_cast<llvm::yaml::ScalarNode>(Value);
-      if (!Node)
-        return llvm::None;
-      llvm::SmallString<10> Storage;
-      Result.newName = Node->getValue(Storage);
-    } else {
-      logIgnoredField(KeyValue, Logger);
-    }
+    else
+      return llvm::None;
   }
+  if (auto N = O->getString("newName"))
+    Result.newName = *N;
   return Result;
 }

Modified: clang-tools-extra/trunk/clangd/Protocol.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.h?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.h (original)
+++ clang-tools-extra/trunk/clangd/Protocol.h Tue Nov 28 01:37:43 2017
@@ -23,15 +23,12 @@
 
 #include "JSONExpr.h"
 #include "llvm/ADT/Optional.h"
-#include "llvm/Support/YAMLParser.h"
 #include <string>
 #include <vector>
 
 namespace clang {
 namespace clangd {
 
-class Logger;
-
 enum class ErrorCode {
   // Defined by JSON RPC.
   ParseError = -32700,
@@ -54,7 +51,7 @@ struct URI {
   static URI fromUri(llvm::StringRef uri);
   static URI fromFile(llvm::StringRef file);
 
-  static URI parse(llvm::yaml::ScalarNode *Param);
+  static URI parse(llvm::StringRef U) { return fromUri(U); }
   static json::Expr unparse(const URI &U);
 
   friend bool operator==(const URI &LHS, const URI &RHS) {
@@ -74,8 +71,7 @@ struct TextDocumentIdentifier {
   /// The text document's URI.
   URI uri;
 
-  static llvm::Optional<TextDocumentIdentifier>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  static llvm::Optional<TextDocumentIdentifier> parse(const json::Expr &Params);
 };
 
 struct Position {
@@ -94,8 +90,7 @@ struct Position {
            std::tie(RHS.line, RHS.character);
   }
 
-  static llvm::Optional<Position> parse(llvm::yaml::MappingNode *Params,
-                                        clangd::Logger &Logger);
+  static llvm::Optional<Position> parse(const json::Expr &Params);
   static json::Expr unparse(const Position &P);
 };
 
@@ -113,8 +108,7 @@ struct Range {
     return std::tie(LHS.start, LHS.end) < std::tie(RHS.start, RHS.end);
   }
 
-  static llvm::Optional<Range> parse(llvm::yaml::MappingNode *Params,
-                                     clangd::Logger &Logger);
+  static llvm::Optional<Range> parse(const json::Expr &Params);
   static json::Expr unparse(const Range &P);
 };
 
@@ -141,8 +135,7 @@ struct Location {
 struct Metadata {
   std::vector<std::string> extraFlags;
 
-  static llvm::Optional<Metadata> parse(llvm::yaml::MappingNode *Params,
-                                        clangd::Logger &Logger);
+  static llvm::Optional<Metadata> parse(const json::Expr &Params);
 };
 
 struct TextEdit {
@@ -154,8 +147,7 @@ struct TextEdit {
   /// empty string.
   std::string newText;
 
-  static llvm::Optional<TextEdit> parse(llvm::yaml::MappingNode *Params,
-                                        clangd::Logger &Logger);
+  static llvm::Optional<TextEdit> parse(const json::Expr &Params);
   static json::Expr unparse(const TextEdit &P);
 };
 
@@ -172,8 +164,7 @@ struct TextDocumentItem {
   /// The content of the opened text document.
   std::string text;
 
-  static llvm::Optional<TextDocumentItem> parse(llvm::yaml::MappingNode *Params,
-                                                clangd::Logger &Logger);
+  static llvm::Optional<TextDocumentItem> parse(const json::Expr &Params);
 };
 
 enum class TraceLevel {
@@ -183,8 +174,7 @@ enum class TraceLevel {
 };
 
 struct NoParams {
-  static llvm::Optional<NoParams> parse(llvm::yaml::MappingNode *Params,
-                                        Logger &Logger) {
+  static llvm::Optional<NoParams> parse(const json::Expr &Params) {
     return NoParams{};
   }
 };
@@ -218,8 +208,7 @@ struct InitializeParams {
 
   /// The initial trace setting. If omitted trace is disabled ('off').
   llvm::Optional<TraceLevel> trace;
-  static llvm::Optional<InitializeParams> parse(llvm::yaml::MappingNode *Params,
-                                                clangd::Logger &Logger);
+  static llvm::Optional<InitializeParams> parse(const json::Expr &Params);
 };
 
 struct DidOpenTextDocumentParams {
@@ -230,7 +219,7 @@ struct DidOpenTextDocumentParams {
   llvm::Optional<Metadata> metadata;
 
   static llvm::Optional<DidOpenTextDocumentParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(const json::Expr &Params);
 };
 
 struct DidCloseTextDocumentParams {
@@ -238,7 +227,7 @@ struct DidCloseTextDocumentParams {
   TextDocumentIdentifier textDocument;
 
   static llvm::Optional<DidCloseTextDocumentParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(const json::Expr &Params);
 };
 
 struct TextDocumentContentChangeEvent {
@@ -246,7 +235,7 @@ struct TextDocumentContentChangeEvent {
   std::string text;
 
   static llvm::Optional<TextDocumentContentChangeEvent>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(const json::Expr &Params);
 };
 
 struct DidChangeTextDocumentParams {
@@ -259,7 +248,7 @@ struct DidChangeTextDocumentParams {
   std::vector<TextDocumentContentChangeEvent> contentChanges;
 
   static llvm::Optional<DidChangeTextDocumentParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(const json::Expr &Params);
 };
 
 enum class FileChangeType {
@@ -277,8 +266,7 @@ struct FileEvent {
   /// The change type.
   FileChangeType type;
 
-  static llvm::Optional<FileEvent> parse(llvm::yaml::MappingNode *Params,
-                                         clangd::Logger &Logger);
+  static llvm::Optional<FileEvent> parse(const json::Expr &Params);
 };
 
 struct DidChangeWatchedFilesParams {
@@ -286,7 +274,7 @@ struct DidChangeWatchedFilesParams {
   std::vector<FileEvent> changes;
 
   static llvm::Optional<DidChangeWatchedFilesParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(const json::Expr &Params);
 };
 
 struct FormattingOptions {
@@ -296,8 +284,7 @@ struct FormattingOptions {
   /// Prefer spaces over tabs.
   bool insertSpaces;
 
-  static llvm::Optional<FormattingOptions>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  static llvm::Optional<FormattingOptions> parse(const json::Expr &Params);
   static json::Expr unparse(const FormattingOptions &P);
 };
 
@@ -312,7 +299,7 @@ struct DocumentRangeFormattingParams {
   FormattingOptions options;
 
   static llvm::Optional<DocumentRangeFormattingParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(const json::Expr &Params);
 };
 
 struct DocumentOnTypeFormattingParams {
@@ -329,7 +316,7 @@ struct DocumentOnTypeFormattingParams {
   FormattingOptions options;
 
   static llvm::Optional<DocumentOnTypeFormattingParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(const json::Expr &Params);
 };
 
 struct DocumentFormattingParams {
@@ -340,7 +327,7 @@ struct DocumentFormattingParams {
   FormattingOptions options;
 
   static llvm::Optional<DocumentFormattingParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(const json::Expr &Params);
 };
 
 struct Diagnostic {
@@ -372,16 +359,14 @@ struct Diagnostic {
            std::tie(RHS.range, RHS.severity, RHS.message);
   }
 
-  static llvm::Optional<Diagnostic> parse(llvm::yaml::MappingNode *Params,
-                                          clangd::Logger &Logger);
+  static llvm::Optional<Diagnostic> parse(const json::Expr &Params);
 };
 
 struct CodeActionContext {
   /// An array of diagnostics.
   std::vector<Diagnostic> diagnostics;
 
-  static llvm::Optional<CodeActionContext>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  static llvm::Optional<CodeActionContext> parse(const json::Expr &Params);
 };
 
 struct CodeActionParams {
@@ -394,8 +379,7 @@ struct CodeActionParams {
   /// Context carrying additional information.
   CodeActionContext context;
 
-  static llvm::Optional<CodeActionParams> parse(llvm::yaml::MappingNode *Params,
-                                                clangd::Logger &Logger);
+  static llvm::Optional<CodeActionParams> parse(const json::Expr &Params);
 };
 
 struct WorkspaceEdit {
@@ -405,8 +389,7 @@ struct WorkspaceEdit {
   /// Note: "documentChanges" is not currently used because currently there is
   /// no support for versioned edits.
 
-  static llvm::Optional<WorkspaceEdit> parse(llvm::yaml::MappingNode *Params,
-                                             clangd::Logger &Logger);
+  static llvm::Optional<WorkspaceEdit> parse(const json::Expr &Params);
   static json::Expr unparse(const WorkspaceEdit &WE);
 };
 
@@ -429,8 +412,7 @@ struct ExecuteCommandParams {
 
   llvm::Optional<WorkspaceEdit> workspaceEdit;
 
-  static llvm::Optional<ExecuteCommandParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  static llvm::Optional<ExecuteCommandParams> parse(const json::Expr &Params);
 };
 
 struct ApplyWorkspaceEditParams {
@@ -446,7 +428,7 @@ struct TextDocumentPositionParams {
   Position position;
 
   static llvm::Optional<TextDocumentPositionParams>
-  parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);
+  parse(const json::Expr &Params);
 };
 
 /// The kind of a completion entry.
@@ -611,8 +593,7 @@ struct RenameParams {
   /// The new name of the symbol.
   std::string newName;
 
-  static llvm::Optional<RenameParams> parse(llvm::yaml::MappingNode *Params,
-                                            clangd::Logger &Logger);
+  static llvm::Optional<RenameParams> parse(const json::Expr &Params);
 };
 
 } // namespace clangd

Modified: clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp (original)
+++ clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp Tue Nov 28 01:37:43 2017
@@ -21,7 +21,7 @@ namespace {
 // Helper for attaching ProtocolCallbacks methods to a JSONRPCDispatcher.
 // Invoke like: Registerer("foo", &ProtocolCallbacks::onFoo)
 // onFoo should be: void onFoo(Ctx &C, FooParams &Params)
-// FooParams should have a static factory method: parse(yaml::MappingNode*).
+// FooParams should have a static factory method: parse(const json::Expr&).
 struct HandlerRegisterer {
   template <typename Param>
   void operator()(StringRef Method,
@@ -30,10 +30,10 @@ struct HandlerRegisterer {
     auto *Out = this->Out;
     auto *Callbacks = this->Callbacks;
     Dispatcher.registerHandler(
-        Method, [=](RequestContext C, llvm::yaml::MappingNode *RawParams) {
+        Method, [=](RequestContext C, const json::Expr &RawParams) {
           if (auto P = [&] {
                 trace::Span Tracer("Parse");
-                return std::decay<Param>::type::parse(RawParams, *Out);
+                return std::decay<Param>::type::parse(RawParams);
               }()) {
             (Callbacks->*Handler)(std::move(C), *P);
           } else {

Modified: clang-tools-extra/trunk/clangd/Trace.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Trace.cpp?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Trace.cpp (original)
+++ clang-tools-extra/trunk/clangd/Trace.cpp Tue Nov 28 01:37:43 2017
@@ -14,7 +14,6 @@
 #include "llvm/Support/FormatProviders.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Threading.h"
-#include "llvm/Support/YAMLParser.h"
 #include <mutex>
 
 namespace clang {

Modified: clang-tools-extra/trunk/test/clangd/authority-less-uri.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/authority-less-uri.test?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/authority-less-uri.test (original)
+++ clang-tools-extra/trunk/test/clangd/authority-less-uri.test Tue Nov 28 01:37:43 2017
@@ -28,7 +28,7 @@ Content-Length: 146
 # CHECK-NEXT:        "sortText": "{{.*}}fake"
 #      CHECK:    ]
 # CHECK-NEXT:  }
-Content-Length: 172
+Content-Length: 173
 
 {"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"uri":"file:///main.cpp","position":{"line":3,"character":5}}}
 # Test params parsing in the presence of a 1.x-compatible client (inlined "uri")
@@ -51,4 +51,4 @@ Content-Length: 44
 {"jsonrpc":"2.0","id":3,"method":"shutdown"}
 Content-Length: 33
 
-{"jsonrpc":"2.0":"method":"exit"}
+{"jsonrpc":"2.0","method":"exit"}

Modified: clang-tools-extra/trunk/test/clangd/definitions.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/definitions.test?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/definitions.test (original)
+++ clang-tools-extra/trunk/test/clangd/definitions.test Tue Nov 28 01:37:43 2017
@@ -101,7 +101,7 @@ Content-Length: 149
 # CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
 # CHECK-NEXT:    }
 # CHECK-NEXT:  ]
-Content-Length: 187
+Content-Length: 188
 
 {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":4},"contentChanges":[{"text":"int main() {\n   main();\n   return 0;\n}"}]}}
 
@@ -126,7 +126,7 @@ Content-Length: 148
 # CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
 # CHECK-NEXT:    }
 # CHECK-NEXT:  ]
-Content-Length: 208
+Content-Length: 209
 
 {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":5},"contentChanges":[{"text":"struct Foo {\n};\nint main() {\n   Foo bar;\n   return 0;\n}\n"}]}}
 
@@ -151,7 +151,7 @@ Content-Length: 148
 # CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
 # CHECK-NEXT:    }
 # CHECK-NEXT:  ]
-Content-Length: 231
+Content-Length: 232
 
 {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":5},"contentChanges":[{"text":"namespace n1 {\nstruct Foo {\n};\n}\nint main() {\n   n1::Foo bar;\n   return 0;\n}\n"}]}}
 
@@ -176,7 +176,7 @@ Content-Length: 148
 # CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
 # CHECK-NEXT:    }
 # CHECK-NEXT:  ]
-Content-Length: 215
+Content-Length: 216
 
 {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":6},"contentChanges":[{"text":"struct Foo {\n  int x;\n};\nint main() {\n   Foo bar;\n   bar.x;\n}\n"}]}}
 
@@ -201,7 +201,7 @@ Content-Length: 148
 # CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
 # CHECK-NEXT:    }
 # CHECK-NEXT:  ]
-Content-Length: 220
+Content-Length: 221
 
 {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"struct Foo {\n  void x();\n};\nint main() {\n   Foo bar;\n   bar.x();\n}\n"}]}}
 
@@ -226,7 +226,7 @@ Content-Length: 148
 # CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
 # CHECK-NEXT:    }
 # CHECK-NEXT:  ]
-Content-Length: 240
+Content-Length: 241
 
 {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"struct Foo {\n};\ntypedef Foo TypedefFoo;\nint main() {\n   TypedefFoo bar;\n   return 0;\n}\n"}]}}
 
@@ -251,7 +251,7 @@ Content-Length: 149
 # CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
 # CHECK-NEXT:    }
 # CHECK-NEXT:  ]
-Content-Length: 254
+Content-Length: 253
 
 {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"template <typename MyTemplateParam>\nvoid foo() {\n MyTemplateParam a;\n}\nint main() {\n   return 0;\n}\n"}]}}
 
@@ -262,7 +262,7 @@ Content-Length: 149
 #      CHECK:  "id": 1,
 # CHECK-NEXT:  "jsonrpc": "2.0",
 # CHECK-NEXT:  "result": []
-Content-Length: 256
+Content-Length: 257
 
 {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"namespace ns {\nstruct Foo {\nstatic void bar() {}\n};\n}\nint main() {\n   ns::Foo::bar();\n   return 0;\n}\n"}]}}
 
@@ -418,4 +418,4 @@ Content-Length: 48
 {"jsonrpc":"2.0","id":10000,"method":"shutdown"}
 Content-Length: 33
 
-{"jsonrpc":"2.0":"method":"exit"}
+{"jsonrpc":"2.0","method":"exit"}

Modified: clang-tools-extra/trunk/test/clangd/diagnostics.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/diagnostics.test?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/diagnostics.test (original)
+++ clang-tools-extra/trunk/test/clangd/diagnostics.test Tue Nov 28 01:37:43 2017
@@ -47,4 +47,4 @@ Content-Length: 44
 {"jsonrpc":"2.0","id":5,"method":"shutdown"}
 Content-Length: 33
 
-{"jsonrpc":"2.0":"method":"exit"}
+{"jsonrpc":"2.0","method":"exit"}

Removed: clang-tools-extra/trunk/test/clangd/did-change-watch-files.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/did-change-watch-files.test?rev=319158&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clangd/did-change-watch-files.test (original)
+++ clang-tools-extra/trunk/test/clangd/did-change-watch-files.test (removed)
@@ -1,53 +0,0 @@
-# RUN: clangd -run-synchronously < %s 2>&1 | FileCheck -check-prefix=STDERR %s
-# It is absolutely vital that this file has CRLF line endings.
-#
-# Test initialize request parameters with rootUri
-Content-Length: 143
-
-{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootUri":"file:///path/to/workspace","capabilities":{},"trace":"off"}}
-# Normal case.
-Content-Length: 217
-
-{"jsonrpc":"2.0","method":"workspace/didChangeWatchedFiles","params":{"changes":[{"uri":"file:///path/to/file.cpp","type":1},{"uri":"file:///path/to/file2.cpp","type":2},{"uri":"file:///path/to/file3.cpp","type":3}]}}
-
-# Wrong event type, integer
-Content-Length: 173
-
-{"jsonrpc":"2.0","method":"workspace/didChangeWatchedFiles","params":{"changes":[{"uri":"file:///path/to/file2.cpp","type":0},{"uri":"file:///path/to/file3.cpp","type":4}]}}
-# STDERR: Failed to decode a FileEvent.
-# Wrong event type, string
-Content-Length: 132
-
-{"jsonrpc":"2.0","method":"workspace/didChangeWatchedFiles","params":{"changes":[{"uri":"file:///path/to/file2.cpp","type":"foo"}]}}
-# STDERR: Failed to decode a FileEvent.
-#Custom event field
-Content-Length: 143
-
-{"jsonrpc":"2.0","method":"workspace/didChangeWatchedFiles","params":{"changes":[{"uri":"file:///path/to/file2.cpp","type":1,"custom":"foo"}]}}
-# STDERR: Failed to decode a FileEvent.
-#Event field with object
-Content-Length: 140
-
-{"jsonrpc":"2.0","method":"workspace/didChangeWatchedFiles","params":{"changes":[{"uri":"file:///path/to/file2.cpp","type":{"foo":"bar"}}]}}
-# STDERR: Failed to decode a FileEvent.
-# Changes field with sequence but no object
-Content-Length: 86
-
-{"jsonrpc":"2.0","method":"workspace/didChangeWatchedFiles","params":{"changes":[""]}}
-# STDERR: Failed to decode workspace/didChangeWatchedFiles request.
-# Changes field with no sequence
-Content-Length: 84
-
-{"jsonrpc":"2.0","method":"workspace/didChangeWatchedFiles","params":{"changes":""}}
-# STDERR: Failed to decode workspace/didChangeWatchedFiles request.
-# Custom field
-Content-Length: 86
-
-{"jsonrpc":"2.0","method":"workspace/didChangeWatchedFiles","params":{"custom":"foo"}}
-# STDERR: Ignored unknown field "custom"
-Content-Length: 44
-
-{"jsonrpc":"2.0","id":3,"method":"shutdown"}
-Content-Length: 33
-
-{"jsonrpc":"2.0":"method":"exit"}

Modified: clang-tools-extra/trunk/test/clangd/protocol.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/protocol.test?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/protocol.test (original)
+++ clang-tools-extra/trunk/test/clangd/protocol.test Tue Nov 28 01:37:43 2017
@@ -79,7 +79,7 @@ Content-Length: 10
 {"jsonrpc":"2.0","id":4,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:/main.cpp"},"position":{"line":3,"character":5}}}
 # Test message with malformed Content-Length
 #
-# STDERR: JSON dispatch failed!
+# STDERR: JSON parse error
 # Ensure we recover by sending another (valid) message
 
 Content-Length: 146

Modified: clang-tools-extra/trunk/unittests/clangd/JSONExprTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/JSONExprTests.cpp?rev=319159&r1=319158&r2=319159&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/JSONExprTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/clangd/JSONExprTests.cpp Tue Nov 28 01:37:43 2017
@@ -205,6 +205,7 @@ TEST(JSONTest, Inspection) {
   EXPECT_TRUE(O->getNull("null"));
 
   EXPECT_EQ(O->getNumber("number"), llvm::Optional<double>(2.78));
+  EXPECT_FALSE(O->getInteger("number"));
   EXPECT_EQ(O->getString("string"), llvm::Optional<llvm::StringRef>("json"));
   ASSERT_FALSE(O->getObject("missing"));
   ASSERT_FALSE(O->getObject("array"));
@@ -216,6 +217,7 @@ TEST(JSONTest, Inspection) {
   EXPECT_EQ(A->getBoolean(1), llvm::Optional<bool>(true));
   ASSERT_TRUE(A->getArray(4));
   EXPECT_EQ(*A->getArray(4), (ary{1, 2, 3}));
+  EXPECT_EQ(A->getArray(4)->getInteger(1), llvm::Optional<int64_t>(2));
   int I = 0;
   for (Expr &E : *A) {
     if (I++ == 5) {




More information about the cfe-commits mailing list