[clang-tools-extra] r319309 - [clangd] Simplify common JSON-parsing patterns in Protocol.

Sam McCall via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 29 03:36:47 PST 2017


Author: sammccall
Date: Wed Nov 29 03:36:46 2017
New Revision: 319309

URL: http://llvm.org/viewvc/llvm-project?rev=319309&view=rev
Log:
[clangd] Simplify common JSON-parsing patterns in Protocol.

Summary:
This makes the parse() functions about as short as they can be given the
current signature, and moves all array-traversal etc code to a
central location.

We keep the ability to distinguish between optional and required fields:
and we don't propagate parse errors for optional fields.

I've made most fields required per the LSP spec - the looseness we had
here was mostly a historical accident I think.

Reviewers: ioeric

Subscribers: klimek, cfe-commits, ilya-biryukov

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

Modified:
    clang-tools-extra/trunk/clangd/Protocol.cpp
    clang-tools-extra/trunk/clangd/Protocol.h
    clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test

Modified: clang-tools-extra/trunk/clangd/Protocol.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.cpp?rev=319309&r1=319308&r2=319309&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.cpp (original)
+++ clang-tools-extra/trunk/clangd/Protocol.cpp Wed Nov 29 03:36:46 2017
@@ -24,6 +24,149 @@
 using namespace clang;
 using namespace clang::clangd;
 
+namespace {
+// Helper for mapping JSON objects onto our protocol structs. Intended use:
+// Optional<Result> parse(json::Expr E) {
+//   ObjectParser O(E);
+//   if (!O || !O.parse("mandatory_field", Result.MandatoryField))
+//     return None;
+//   O.parse("optional_field", Result.OptionalField);
+//   return Result;
+// }
+// FIXME: the static methods here should probably become the public parse()
+// extension point. Overloading free functions allows us to uniformly handle
+// enums, vectors, etc.
+class ObjectParser {
+public:
+  ObjectParser(const json::Expr &E) : O(E.asObject()) {}
+
+  // True if the expression is an object.
+  operator bool() { return O; }
+
+  template <typename T> bool parse(const char *Prop, T &Out) {
+    assert(*this && "Must check this is an object before calling parse()");
+    if (const json::Expr *E = O->get(Prop))
+      return parse(*E, Out);
+    return false;
+  }
+
+  // Optional requires special handling, because missing keys are OK.
+  template <typename T> bool parse(const char *Prop, llvm::Optional<T> &Out) {
+    assert(*this && "Must check this is an object before calling parse()");
+    if (const json::Expr *E = O->get(Prop))
+      return parse(*E, Out);
+    Out = None;
+    return true;
+  }
+
+private:
+  // Primitives.
+  static bool parse(const json::Expr &E, std::string &Out) {
+    if (auto S = E.asString()) {
+      Out = *S;
+      return true;
+    }
+    return false;
+  }
+
+  static bool parse(const json::Expr &E, int &Out) {
+    if (auto S = E.asInteger()) {
+      Out = *S;
+      return true;
+    }
+    return false;
+  }
+
+  static bool parse(const json::Expr &E, bool &Out) {
+    if (auto S = E.asBoolean()) {
+      Out = *S;
+      return true;
+    }
+    return false;
+  }
+
+  // Types with a parse() function.
+  template <typename T> static bool parse(const json::Expr &E, T &Out) {
+    if (auto Parsed = std::remove_reference<T>::type::parse(E)) {
+      Out = std::move(*Parsed);
+      return true;
+    }
+    return false;
+  }
+
+  // Nullable values as Optional<T>.
+  template <typename T>
+  static bool parse(const json::Expr &E, llvm::Optional<T> &Out) {
+    if (E.asNull()) {
+      Out = None;
+      return true;
+    }
+    T Result;
+    if (!parse(E, Result))
+      return false;
+    Out = std::move(Result);
+    return true;
+  }
+
+  // Array values with std::vector type.
+  template <typename T>
+  static bool parse(const json::Expr &E, std::vector<T> &Out) {
+    if (auto *A = E.asArray()) {
+      Out.clear();
+      Out.resize(A->size());
+      for (size_t I = 0; I < A->size(); ++I)
+        if (!parse((*A)[I], Out[I]))
+          return false;
+      return true;
+    }
+    return false;
+  }
+
+  // Object values with std::map<std::string, ?>
+  template <typename T>
+  static bool parse(const json::Expr &E, std::map<std::string, T> &Out) {
+    if (auto *O = E.asObject()) {
+      for (const auto &KV : *O)
+        if (!parse(KV.second, Out[StringRef(KV.first)]))
+          return false;
+      return true;
+    }
+    return false;
+  }
+
+  // Special cased enums, which can't have T::parse() functions.
+  // FIXME: make everything free functions so there's no special casing.
+  static bool parse(const json::Expr &E, TraceLevel &Out) {
+    if (auto S = E.asString()) {
+      if (*S == "off") {
+        Out = TraceLevel::Off;
+        return true;
+      } else if (*S == "messages") {
+        Out = TraceLevel::Messages;
+        return true;
+      } else if (*S == "verbose") {
+        Out = TraceLevel::Verbose;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  static bool parse(const json::Expr &E, FileChangeType &Out) {
+    if (auto T = E.asInteger()) {
+      if (*T < static_cast<int>(FileChangeType::Created) ||
+          *T > static_cast<int>(FileChangeType::Deleted))
+        return false;
+      Out = static_cast<FileChangeType>(*T);
+      return true;
+    }
+    return false;
+  }
+
+  const json::obj *O;
+};
+} // namespace
+
 URI URI::fromUri(llvm::StringRef uri) {
   URI Result;
   Result.uri = uri;
@@ -51,32 +194,29 @@ URI URI::fromFile(llvm::StringRef file)
   return Result;
 }
 
+llvm::Optional<URI> URI::parse(const json::Expr &E) {
+  if (auto S = E.asString())
+    return fromUri(*S);
+  return None;
+}
+
 json::Expr URI::unparse(const URI &U) { return U.uri; }
 
 llvm::Optional<TextDocumentIdentifier>
 TextDocumentIdentifier::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  TextDocumentIdentifier R;
+  if (!O || !O.parse("uri", R.uri))
     return None;
-
-  TextDocumentIdentifier Result;
-  if (auto U = O->getString("uri"))
-    Result.uri = URI::parse(*U);
-  // FIXME: parse 'version', but only for VersionedTextDocumentIdentifiers.
-  return Result;
+  return R;
 }
 
 llvm::Optional<Position> Position::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  Position R;
+  if (!O || !O.parse("line", R.line) || !O.parse("character", R.character))
     return None;
-
-  Position Result;
-  if (auto L = O->getInteger("line"))
-    Result.line = *L;
-  if (auto C = O->getInteger("character"))
-    Result.character = *C;
-  return Result;
+  return R;
 }
 
 json::Expr Position::unparse(const Position &P) {
@@ -87,24 +227,11 @@ json::Expr Position::unparse(const Posit
 }
 
 llvm::Optional<Range> Range::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  Range R;
+  if (!O || !O.parse("start", R.start) || !O.parse("end", R.end))
     return None;
-
-  Range Result;
-  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;
+  return R;
 }
 
 json::Expr Range::unparse(const Range &P) {
@@ -123,53 +250,29 @@ json::Expr Location::unparse(const Locat
 
 llvm::Optional<TextDocumentItem>
 TextDocumentItem::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  TextDocumentItem R;
+  if (!O || !O.parse("uri", R.uri) || !O.parse("languageId", R.languageId) ||
+      !O.parse("version", R.version) || !O.parse("text", R.text))
     return None;
-
-  TextDocumentItem Result;
-  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;
+  return R;
 }
 
 llvm::Optional<Metadata> Metadata::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
+  ObjectParser O(Params);
+  Metadata R;
   if (!O)
     return None;
-
-  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;
-    }
-  return Result;
+  O.parse("extraFlags", R.extraFlags);
+  return R;
 }
 
 llvm::Optional<TextEdit> TextEdit::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  TextEdit R;
+  if (!O || !O.parse("range", R.range) || !O.parse("newText", R.newText))
     return None;
-
-  TextEdit Result;
-  if (auto *R = O->get("range")) {
-    if (auto Parsed = Range::parse(*R))
-      Result.range = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto T = O->getString("newText"))
-    Result.newText = *T;
-  return Result;
+  return R;
 }
 
 json::Expr TextEdit::unparse(const TextEdit &P) {
@@ -179,156 +282,85 @@ json::Expr TextEdit::unparse(const TextE
   };
 }
 
-namespace {
-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;
-  return TraceLevel::Off;
-}
-} // namespace
-
 llvm::Optional<InitializeParams>
 InitializeParams::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
+  ObjectParser O(Params);
+  InitializeParams R;
   if (!O)
     return None;
-
-  InitializeParams Result;
-  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);
+  // We deliberately don't fail if we can't parse individual fields.
+  // Failing to handle a slightly malformed initialize would be a disaster.
+  O.parse("processId", R.processId);
+  O.parse("rootUri", R.rootUri);
+  O.parse("rootPath", R.rootPath);
+  O.parse("trace", R.trace);
   // initializationOptions, capabilities unused
-  return Result;
+  return R;
 }
 
 llvm::Optional<DidOpenTextDocumentParams>
 DidOpenTextDocumentParams::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  DidOpenTextDocumentParams R;
+  if (!O || !O.parse("textDocument", R.textDocument) ||
+      !O.parse("metadata", R.metadata))
     return None;
-
-  DidOpenTextDocumentParams Result;
-  if (auto *D = O->get("textDocument")) {
-    if (auto Parsed = TextDocumentItem::parse(*D))
-      Result.textDocument = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto *M = O->get("metadata")) {
-    if (auto Parsed = Metadata::parse(*M))
-      Result.metadata = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  return Result;
+  return R;
 }
 
 llvm::Optional<DidCloseTextDocumentParams>
 DidCloseTextDocumentParams::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  DidCloseTextDocumentParams R;
+  if (!O || !O.parse("textDocument", R.textDocument))
     return None;
-
-  DidCloseTextDocumentParams Result;
-  if (auto *D = O->get("textDocument")) {
-    if (auto Parsed = TextDocumentIdentifier::parse(*D))
-      Result.textDocument = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  return Result;
+  return R;
 }
 
 llvm::Optional<DidChangeTextDocumentParams>
 DidChangeTextDocumentParams::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  DidChangeTextDocumentParams R;
+  if (!O || !O.parse("textDocument", R.textDocument) ||
+      !O.parse("contentChanges", R.contentChanges))
     return None;
-
-  DidChangeTextDocumentParams Result;
-  if (auto *D = O->get("textDocument")) {
-    if (auto Parsed = TextDocumentIdentifier::parse(*D))
-      Result.textDocument = std::move(*Parsed);
-    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
-        return llvm::None;
-    }
-  return Result;
+  return R;
 }
 
 llvm::Optional<FileEvent> FileEvent::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  FileEvent R;
+  if (!O || !O.parse("uri", R.uri) || !O.parse("type", R.type))
     return None;
-
-  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;
+  return R;
 }
 
 llvm::Optional<DidChangeWatchedFilesParams>
 DidChangeWatchedFilesParams::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  DidChangeWatchedFilesParams R;
+  if (!O || !O.parse("changes", R.changes))
     return None;
-
-  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;
-    }
-  return Result;
+  return R;
 }
 
 llvm::Optional<TextDocumentContentChangeEvent>
 TextDocumentContentChangeEvent::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  TextDocumentContentChangeEvent R;
+  if (!O || !O.parse("text", R.text))
     return None;
-
-  TextDocumentContentChangeEvent Result;
-  if (auto T = O->getString("text"))
-    Result.text = *T;
-  return Result;
+  return R;
 }
 
 llvm::Optional<FormattingOptions>
 FormattingOptions::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  FormattingOptions R;
+  if (!O || !O.parse("tabSize", R.tabSize) ||
+      !O.parse("insertSpaces", R.insertSpaces))
     return None;
-
-  FormattingOptions Result;
-  if (auto T = O->getInteger("tabSize"))
-    Result.tabSize = *T;
-  if (auto I = O->getBoolean("insertSpaces"))
-    Result.insertSpaces = *I;
-  return Result;
+  return R;
 }
 
 json::Expr FormattingOptions::unparse(const FormattingOptions &P) {
@@ -340,183 +372,69 @@ json::Expr FormattingOptions::unparse(co
 
 llvm::Optional<DocumentRangeFormattingParams>
 DocumentRangeFormattingParams::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  DocumentRangeFormattingParams R;
+  if (!O || !O.parse("textDocument", R.textDocument) ||
+      !O.parse("range", R.range) || !O.parse("options", R.options))
     return None;
-
-  DocumentRangeFormattingParams Result;
-  if (auto *D = O->get("textDocument")) {
-    if (auto Parsed = TextDocumentIdentifier::parse(*D))
-      Result.textDocument = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto *R = O->get("range")) {
-    if (auto Parsed = Range::parse(*R))
-      Result.range = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto *F = O->get("options")) {
-    if (auto Parsed = FormattingOptions::parse(*F))
-      Result.options = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  return Result;
+  return R;
 }
 
 llvm::Optional<DocumentOnTypeFormattingParams>
 DocumentOnTypeFormattingParams::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  DocumentOnTypeFormattingParams R;
+  if (!O || !O.parse("textDocument", R.textDocument) ||
+      !O.parse("position", R.position) || !O.parse("ch", R.ch) ||
+      !O.parse("options", R.options))
     return 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
-      return llvm::None;
-  }
-  if (auto *P = O->get("position")) {
-    if (auto Parsed = Position::parse(*P))
-      Result.position = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto *F = O->get("options")) {
-    if (auto Parsed = FormattingOptions::parse(*F))
-      Result.options = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  return Result;
+  return R;
 }
 
 llvm::Optional<DocumentFormattingParams>
 DocumentFormattingParams::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  DocumentFormattingParams R;
+  if (!O || !O.parse("textDocument", R.textDocument) ||
+      !O.parse("options", R.options))
     return None;
-
-  DocumentFormattingParams Result;
-  if (auto *D = O->get("textDocument")) {
-    if (auto Parsed = TextDocumentIdentifier::parse(*D))
-      Result.textDocument = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto *F = O->get("options")) {
-    if (auto Parsed = FormattingOptions::parse(*F))
-      Result.options = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  return Result;
+  return R;
 }
 
 llvm::Optional<Diagnostic> Diagnostic::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  Diagnostic R;
+  if (!O || !O.parse("range", R.range) || !O.parse("message", R.message))
     return None;
-
-  Diagnostic Result;
-  if (auto *R = O->get("range")) {
-    if (auto Parsed = Range::parse(*R))
-      Result.range = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto S = O->getInteger("severity"))
-    Result.severity = *S;
-  if (auto M = O->getString("message"))
-    Result.message = *M;
-  return Result;
+  O.parse("severity", R.severity);
+  return R;
 }
 
 llvm::Optional<CodeActionContext>
 CodeActionContext::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  CodeActionContext R;
+  if (!O || !O.parse("diagnostics", R.diagnostics))
     return 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
-        return llvm::None;
-    }
-  return Result;
+  return R;
 }
 
 llvm::Optional<CodeActionParams>
 CodeActionParams::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  CodeActionParams R;
+  if (!O || !O.parse("textDocument", R.textDocument) ||
+      !O.parse("range", R.range) || !O.parse("context", R.context))
     return None;
-
-  CodeActionParams Result;
-  if (auto *D = O->get("textDocument")) {
-    if (auto Parsed = TextDocumentIdentifier::parse(*D))
-      Result.textDocument = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto *R = O->get("range")) {
-    if (auto Parsed = Range::parse(*R))
-      Result.range = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto *R = O->get("context")) {
-    if (auto Parsed = CodeActionContext::parse(*R))
-      Result.context = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  return Result;
-}
-
-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 (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;
-  }
-  return Result;
+  return R;
 }
 
 llvm::Optional<WorkspaceEdit> WorkspaceEdit::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  WorkspaceEdit R;
+  if (!O || !O.parse("changes", R.changes))
     return None;
-
-  WorkspaceEdit Result;
-  if (auto *C = O->get("changes")) {
-    if (auto Parsed = parseWorkspaceEditChange(*C))
-      Result.changes = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  return Result;
+  return R;
 }
 
 const std::string ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
@@ -561,24 +479,12 @@ ApplyWorkspaceEditParams::unparse(const
 
 llvm::Optional<TextDocumentPositionParams>
 TextDocumentPositionParams::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  TextDocumentPositionParams R;
+  if (!O || !O.parse("textDocument", R.textDocument) ||
+      !O.parse("position", R.position))
     return None;
-
-  TextDocumentPositionParams Result;
-  if (auto *D = O->get("textDocument")) {
-    if (auto Parsed = TextDocumentIdentifier::parse(*D))
-      Result.textDocument = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto *P = O->get("position")) {
-    if (auto Parsed = Position::parse(*P))
-      Result.position = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  return Result;
+  return R;
 }
 
 json::Expr CompletionItem::unparse(const CompletionItem &CI) {
@@ -649,24 +555,10 @@ json::Expr SignatureHelp::unparse(const
 }
 
 llvm::Optional<RenameParams> RenameParams::parse(const json::Expr &Params) {
-  const json::obj *O = Params.asObject();
-  if (!O)
+  ObjectParser O(Params);
+  RenameParams R;
+  if (!O || !O.parse("textDocument", R.textDocument) ||
+      !O.parse("position", R.position) || !O.parse("newName", R.newName))
     return None;
-
-  RenameParams Result;
-  if (auto *D = O->get("textDocument")) {
-    if (auto Parsed = TextDocumentIdentifier::parse(*D))
-      Result.textDocument = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto *P = O->get("position")) {
-    if (auto Parsed = Position::parse(*P))
-      Result.position = std::move(*Parsed);
-    else
-      return llvm::None;
-  }
-  if (auto N = O->getString("newName"))
-    Result.newName = *N;
-  return Result;
+  return R;
 }

Modified: clang-tools-extra/trunk/clangd/Protocol.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.h?rev=319309&r1=319308&r2=319309&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.h (original)
+++ clang-tools-extra/trunk/clangd/Protocol.h Wed Nov 29 03:36:46 2017
@@ -51,7 +51,7 @@ struct URI {
   static URI fromUri(llvm::StringRef uri);
   static URI fromFile(llvm::StringRef file);
 
-  static URI parse(llvm::StringRef U) { return fromUri(U); }
+  static llvm::Optional<URI> parse(const json::Expr &U);
   static json::Expr unparse(const URI &U);
 
   friend bool operator==(const URI &LHS, const URI &RHS) {

Modified: clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test?rev=319309&r1=319308&r2=319309&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test (original)
+++ clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test Wed Nov 29 03:36:46 2017
@@ -45,4 +45,4 @@ Content-Length: 44
 {"jsonrpc":"2.0","id":3,"method":"shutdown"}
 Content-Length: 33
 
-{"jsonrpc":"2.0":"method":"exit"}
+{"jsonrpc":"2.0","method":"exit"}




More information about the cfe-commits mailing list