<div dir="ltr">One more broken builder:<br><a href="http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/13294">http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/13294</a><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Nov 6, 2017 at 4:24 PM, Galina Kistanova <span dir="ltr"><<a href="mailto:gkistanova@gmail.com" target="_blank">gkistanova@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hello Sam,<br><br>It looks like this commit broke one our builders:<br><a href="http://lab.llvm.org:8011/builders/clang-x86_64-linux-abi-test/builds/17766" target="_blank">http://lab.llvm.org:8011/<wbr>builders/clang-x86_64-linux-<wbr>abi-test/builds/17766</a><br><br>. . .<br>FAILED: /usr/bin/c++   -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools/clang/tools/extra/<wbr>clangd -I/home/buildslave/slave_as-<wbr>bldslv8/clang-x86_64-linux-<wbr>abi-test/llvm/tools/clang/<wbr>tools/extra/clangd -I/home/buildslave/slave_as-<wbr>bldslv8/clang-x86_64-linux-<wbr>abi-test/llvm/tools/clang/<wbr>include -Itools/clang/include -Iinclude -I/home/buildslave/slave_as-<wbr>bldslv8/clang-x86_64-linux-<wbr>abi-test/llvm/include -fPIC -fvisibility-inlines-hidden -std=c++11 -Wall -W -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-<wbr>initializers -pedantic -Wno-long-long -Wno-maybe-uninitialized -Wdelete-non-virtual-dtor -Wno-comment -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -fno-strict-aliasing -O3    -UNDEBUG  -fno-exceptions -fno-rtti -MMD -MT tools/clang/tools/extra/<wbr>clangd/CMakeFiles/clangDaemon.<wbr>dir/JSONExpr.cpp.o -MF tools/clang/tools/extra/<wbr>clangd/CMakeFiles/clangDaemon.<wbr>dir/JSONExpr.cpp.o.d -o tools/clang/tools/extra/<wbr>clangd/CMakeFiles/clangDaemon.<wbr>dir/JSONExpr.cpp.o -c /home/buildslave/slave_as-<wbr>bldslv8/clang-x86_64-linux-<wbr>abi-test/llvm/tools/clang/<wbr>tools/extra/clangd/JSONExpr.<wbr>cpp<br>/home/buildslave/slave_as-<wbr>bldslv8/clang-x86_64-linux-<wbr>abi-test/llvm/tools/clang/<wbr>tools/extra/clangd/JSONExpr.<wbr>cpp:184:65: error: ‘llvm::raw_ostream& clang::clangd::json::operator<<wbr><(llvm::raw_ostream&, const clang::clangd::json::Expr&)’ should have been declared inside ‘clang::clangd::json’<br>                              <wbr>                      const Expr &E) {<br>                              <wbr>                              <wbr>     ^<br><br>Please have a look?<br><br>Thanks<br><br>Galina<br><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Nov 6, 2017 at 7:40 AM, Sam McCall via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: sammccall<br>
Date: Mon Nov  6 07:40:30 2017<br>
New Revision: 317486<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=317486&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject?rev=317486&view=rev</a><br>
Log:<br>
Adds a json::Expr type to represent intermediate JSON expressions.<br>
<br>
Summary:<br>
This form can be created with a nice clang-format-friendly literal syntax,<br>
and gets escaping right. It knows how to call unparse() on our Protocol types.<br>
All the places where we pass around JSON internally now use this type.<br>
<br>
Object properties are sorted (stored as std::map) and so serialization is<br>
canonicalized, with optional prettyprinting (triggered by a -pretty flag).<br>
This makes the lit tests much nicer to read and somewhat nicer to debug.<br>
(Unfortunately the completion tests use CHECK-DAG, which only has<br>
line-granularity, so pretty-printing is disabled there. In future we<br>
could make completion ordering deterministic, or switch to unittests).<br>
<br>
Compared to the current approach, it has some efficiencies like avoiding copies<br>
of string literals used as object keys, but is probably slower overall.<br>
I think the code/test quality benefits are worth it.<br>
<br>
This patch doesn't attempt to do anything about JSON *parsing*.<br>
It takes direction from the proposal in this doc[1], but is limited in scope<br>
and visibility, for now.<br>
I am of half a mind just to use Expr as the target of a parser, and maybe do a<br>
little string deduplication, but not bother with clever memory allocation.<br>
That would be simple, and fast enough for clangd...<br>
[1] <a href="https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit" rel="noreferrer" target="_blank">https://docs.google.com/docume<wbr>nt/d/1OEF9IauWwNuSigZzvvbjc1cV<wbr>S1uGHRyGTXaoy3DjqM4/edit</a><br>
<br>
+cc d0k so he can tell me not to use std::map.<br>
<br>
Reviewers: ioeric, malaperle<br>
<br>
Subscribers: bkramer, ilya-biryukov, mgorny, klimek<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D39435" rel="noreferrer" target="_blank">https://reviews.llvm.org/D3943<wbr>5</a><br>
<br>
Added:<br>
    clang-tools-extra/trunk/clangd<wbr>/JSONExpr.cpp<br>
    clang-tools-extra/trunk/clangd<wbr>/JSONExpr.h<br>
    clang-tools-extra/trunk/unitte<wbr>sts/clangd/JSONExprTests.cpp<br>
Modified:<br>
    clang-tools-extra/trunk/clangd<wbr>/CMakeLists.txt<br>
    clang-tools-extra/trunk/clangd<wbr>/ClangdLSPServer.cpp<br>
    clang-tools-extra/trunk/clangd<wbr>/JSONRPCDispatcher.cpp<br>
    clang-tools-extra/trunk/clangd<wbr>/JSONRPCDispatcher.h<br>
    clang-tools-extra/trunk/clangd<wbr>/Protocol.cpp<br>
    clang-tools-extra/trunk/clangd<wbr>/Protocol.h<br>
    clang-tools-extra/trunk/clangd<wbr>/tool/ClangdMain.cpp<br>
    clang-tools-extra/trunk/test/c<wbr>langd/authority-less-uri.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/completion-items-kinds.t<wbr>est<br>
    clang-tools-extra/trunk/test/c<wbr>langd/completion-priorities.te<wbr>st<br>
    clang-tools-extra/trunk/test/c<wbr>langd/completion-qualifiers.te<wbr>st<br>
    clang-tools-extra/trunk/test/c<wbr>langd/completion-snippet.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/completion.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/definitions.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/diagnostics-preamble.tes<wbr>t<br>
    clang-tools-extra/trunk/test/c<wbr>langd/diagnostics.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/did-change-watch-files.t<wbr>est<br>
    clang-tools-extra/trunk/test/c<wbr>langd/execute-command.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/extra-flags.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/fixits.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/formatting.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/initialize-params-invali<wbr>d.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/initialize-params.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/input-mirror.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/protocol.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/signature-help.test<br>
    clang-tools-extra/trunk/test/c<wbr>langd/unsupported-method.test<br>
    clang-tools-extra/trunk/unitte<wbr>sts/clangd/CMakeLists.txt<br>
<br>
Modified: clang-tools-extra/trunk/clangd<wbr>/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CMakeLists.txt?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/CMakeLists.txt?rev=<wbr>317486&r1=317485&r2=317486&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/clangd<wbr>/CMakeLists.txt (original)<br>
+++ clang-tools-extra/trunk/clangd<wbr>/CMakeLists.txt Mon Nov  6 07:40:30 2017<br>
@@ -10,6 +10,7 @@ add_clang_library(clangDaemon<br>
   DraftStore.cpp<br>
   GlobalCompilationDatabase.cpp<br>
   JSONRPCDispatcher.cpp<br>
+  JSONExpr.cpp<br>
   Logger.cpp<br>
   Protocol.cpp<br>
   ProtocolHandlers.cpp<br>
<br>
Modified: clang-tools-extra/trunk/clangd<wbr>/ClangdLSPServer.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/ClangdLSPServer.cpp?<wbr>rev=317486&r1=317485&r2=317486<wbr>&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/clangd<wbr>/ClangdLSPServer.cpp (original)<br>
+++ clang-tools-extra/trunk/clangd<wbr>/ClangdLSPServer.cpp Mon Nov  6 07:40:30 2017<br>
@@ -20,35 +20,46 @@ namespace {<br>
 std::vector<TextEdit><br>
 replacementsToEdits(StringRef Code,<br>
                     const std::vector<tooling::Replaceme<wbr>nt> &Replacements) {<br>
-  std::vector<TextEdit> Edits;<br>
   // Turn the replacements into the format specified by the Language Server<br>
-  // Protocol.<br>
+  // Protocol. Fuse them into one big JSON array.<br>
+  std::vector<TextEdit> Edits;<br>
   for (auto &R : Replacements) {<br>
     Range ReplacementRange = {<br>
         offsetToPosition(Code, R.getOffset()),<br>
         offsetToPosition(Code, R.getOffset() + R.getLength())};<br>
     Edits.push_back({ReplacementR<wbr>ange, R.getReplacementText()});<br>
   }<br>
-<br>
   return Edits;<br>
 }<br>
<br>
 } // namespace<br>
<br>
 void ClangdLSPServer::onInitialize(<wbr>Ctx C, InitializeParams &Params) {<br>
-  C.reply(<br>
-      R"({"capabilities":{<br>
-          "textDocumentSync": 1,<br>
-          "documentFormattingProvider": true,<br>
-          "documentRangeFormattingProvid<wbr>er": true,<br>
-          "documentOnTypeFormattingProvi<wbr>der": {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
-          "codeActionProvider": true,<br>
-          "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">",":"]},<br>
-          "signatureHelpProvider": {"triggerCharacters": ["(",","]},<br>
-          "definitionProvider": true,<br>
-          "executeCommandProvider": {"commands": [")" +<br>
-      ExecuteCommandParams::CLANGD_A<wbr>PPLY_FIX_COMMAND + R"("]}<br>
-        }})");<br>
+  C.reply(json::obj{<br>
+      {"textDocumentSync", 1},<br>
+      {"documentFormattingProvider", true},<br>
+      {"documentRangeFormattingProvi<wbr>der", true},<br>
+      {"documentOnTypeFormattingProv<wbr>ider",<br>
+       json::obj{<br>
+           {"firstTriggerCharacter", "}"},<br>
+           {"moreTriggerCharacter", {}},<br>
+       }},<br>
+      {"codeActionProvider", true},<br>
+      {"completionProvider",<br>
+       json::obj{<br>
+           {"resolveProvider", false},<br>
+           {"triggerCharacters", {".", ">", ":"}},<br>
+       }},<br>
+      {"signatureHelpProvider",<br>
+       json::obj{<br>
+           {"triggerCharacters", {"(", ","}},<br>
+       }},<br>
+      {"definitionProvider", true},<br>
+      {"executeCommandProvider",<br>
+       json::obj{<br>
+           {"commands", {ExecuteCommandParams::CLANGD_<wbr>APPLY_FIX_COMMAND}},<br>
+       }},<br>
+  });<br>
   if (Params.rootUri && !Params.rootUri->file.empty())<br>
     Server.setRootPath(Params.roo<wbr>tUri->file);<br>
   else if (Params.rootPath && !Params.rootPath->empty())<br>
@@ -58,7 +69,7 @@ void ClangdLSPServer::onInitialize(<wbr>Ctx C<br>
 void ClangdLSPServer::onShutdown(Ct<wbr>x C, ShutdownParams &Params) {<br>
   // Do essentially nothing, just say we're ready to exit.<br>
   ShutdownRequestReceived = true;<br>
-  C.reply("null");<br>
+  C.reply(nullptr);<br>
 }<br>
<br>
 void ClangdLSPServer::onExit(Ctx C, ExitParams &Params) { IsDone = true; }<br>
@@ -98,7 +109,7 @@ void ClangdLSPServer::onCommand(Ctx C, E<br>
<br>
     ApplyWorkspaceEditParams ApplyEdit;<br>
     ApplyEdit.edit = *Params.workspaceEdit;<br>
-    C.reply("\"Fix applied.\"");<br>
+    C.reply("Fix applied.");<br>
     // We don't need the response so id == 1 is OK.<br>
     // Ideally, we would wait for the response and if there is no error, we<br>
     // would reply success/failure to the original RPC.<br>
@@ -121,51 +132,45 @@ void ClangdLSPServer::onDocumentOnT<wbr>ypeFo<br>
     Ctx C, DocumentOnTypeFormattingParams &Params) {<br>
   auto File = Params.textDocument.uri.file;<br>
   std::string Code = Server.getDocument(File);<br>
-  std::string Edits = TextEdit::unparse(<br>
-      replacementsToEdits(Code, Server.formatOnType(File, Params.position)));<br>
-  C.reply(Edits);<br>
+  C.reply(json::ary(<br>
+      replacementsToEdits(Code, Server.formatOnType(File, Params.position))));<br>
 }<br>
<br>
 void ClangdLSPServer::onDocumentRan<wbr>geFormatting(<br>
     Ctx C, DocumentRangeFormattingParams &Params) {<br>
   auto File = Params.textDocument.uri.file;<br>
   std::string Code = Server.getDocument(File);<br>
-  std::string Edits = TextEdit::unparse(<br>
-      replacementsToEdits(Code, Server.formatRange(File, Params.range)));<br>
-  C.reply(Edits);<br>
+  C.reply(json::ary(<br>
+      replacementsToEdits(Code, Server.formatRange(File, Params.range))));<br>
 }<br>
<br>
 void ClangdLSPServer::onDocumentFor<wbr>matting(Ctx C,<br>
                                            DocumentFormattingParams &Params) {<br>
   auto File = Params.textDocument.uri.file;<br>
   std::string Code = Server.getDocument(File);<br>
-  std::string Edits =<br>
-      TextEdit::unparse(replacements<wbr>ToEdits(Code, Server.formatFile(File)));<br>
-  C.reply(Edits);<br>
+  C.reply(json::ary(replacements<wbr>ToEdits(Code, Server.formatFile(File))));<br>
 }<br>
<br>
 void ClangdLSPServer::onCodeAction(<wbr>Ctx C, CodeActionParams &Params) {<br>
   // We provide a code action for each diagnostic at the requested location<br>
   // which has FixIts available.<br>
   std::string Code = Server.getDocument(Params.text<wbr>Document.uri.file);<br>
-  std::string Commands;<br>
+  json::ary Commands;<br>
   for (Diagnostic &D : Params.context.diagnostics) {<br>
     std::vector<clang::tooling::R<wbr>eplacement> Fixes =<br>
         getFixIts(Params.<wbr>textDocument.uri.file, D);<br>
     auto Edits = replacementsToEdits(Code, Fixes);<br>
-    WorkspaceEdit WE;<br>
-    WE.changes = {{llvm::yaml::escape(Params.te<wbr>xtDocument.uri.uri), Edits}};<br>
-<br>
-    if (!Edits.empty())<br>
-      Commands +=<br>
-          R"({"title":"Apply FixIt ')" + llvm::yaml::escape(D.message) +<br>
-          R"('", "command": ")" +<br>
-          ExecuteCommandParams::CLANGD_A<wbr>PPLY_FIX_COMMAND +<br>
-          R"(", "arguments": [)" + WorkspaceEdit::unparse(WE) + R"(]},)";<br>
+    if (!Edits.empty()) {<br>
+      WorkspaceEdit WE;<br>
+      WE.changes = {{Params.textDocument.uri.uri, std::move(Edits)}};<br>
+      Commands.push_back(json::obj{<br>
+          {"title", llvm::formatv("Apply FixIt {0}", D.message)},<br>
+          {"command", ExecuteCommandParams::CLANGD_A<wbr>PPLY_FIX_COMMAND},<br>
+          {"arguments", {WE}},<br>
+      });<br>
+    }<br>
   }<br>
-  if (!Commands.empty())<br>
-    Commands.pop_back();<br>
-  C.reply("[" + Commands + "]");<br>
+  C.reply(std::move(Commands));<br>
 }<br>
<br>
 void ClangdLSPServer::onCompletion(<wbr>Ctx C, TextDocumentPositionParams &Params) {<br>
@@ -177,15 +182,7 @@ void ClangdLSPServer::onCompletion(<wbr>Ctx C<br>
                           // had an API that would allow to attach callbacks to<br>
                           // futures returned by ClangdServer.<br>
                    .Value;<br>
-<br>
-  std::string Completions;<br>
-  for (const auto &Item : Items) {<br>
-    Completions += CompletionItem::unparse(Item);<br>
-    Completions += ",";<br>
-  }<br>
-  if (!Completions.empty())<br>
-    Completions.pop_back();<br>
-  C.reply("[" + Completions + "]");<br>
+  C.reply(json::ary(Items));<br>
 }<br>
<br>
 void ClangdLSPServer::onSignatureHe<wbr>lp(Ctx C,<br>
@@ -195,7 +192,7 @@ void ClangdLSPServer::onSignatureHe<wbr>lp(Ct<br>
       Position{Params.position.<wbr>line, Params.position.character});<br>
   if (!SignatureHelp)<br>
     return C.replyError(-32602, llvm::toString(SignatureHelp.t<wbr>akeError()));<br>
-  C.reply(SignatureHelp::unparse<wbr>(SignatureHelp->Value));<br>
+  C.reply(SignatureHelp->Value);<br>
 }<br>
<br>
 void ClangdLSPServer::onGoToDefinit<wbr>ion(Ctx C,<br>
@@ -205,22 +202,14 @@ void ClangdLSPServer::onGoToDefinit<wbr>ion(C<br>
       Position{Params.position.<wbr>line, Params.position.character});<br>
   if (!Items)<br>
     return C.replyError(-32602, llvm::toString(Items.takeError<wbr>()));<br>
-<br>
-  std::string Locations;<br>
-  for (const auto &Item : Items->Value) {<br>
-    Locations += Location::unparse(Item);<br>
-    Locations += ",";<br>
-  }<br>
-  if (!Locations.empty())<br>
-    Locations.pop_back();<br>
-  C.reply("[" + Locations + "]");<br>
+  C.reply(json::ary(Items->Value<wbr>));<br>
 }<br>
<br>
 void ClangdLSPServer::onSwitchSourc<wbr>eHeader(Ctx C,<br>
                                            TextDocumentIdentifier &Params) {<br>
   llvm::Optional<Path> Result = Server.switchSourceHeader(Para<wbr>ms.uri.file);<br>
   std::string ResultUri;<br>
-  C.reply(Result ? URI::unparse(URI::fromFile(*Re<wbr>sult)) : R"("")");<br>
+  C.reply(Result ? URI::fromFile(*Result).uri : "");<br>
 }<br>
<br>
 ClangdLSPServer::ClangdLSPSer<wbr>ver(JSONOutput &Out, unsigned AsyncThreadsCount,<br>
@@ -270,17 +259,16 @@ ClangdLSPServer::getFixIts(Str<wbr>ingRef Fil<br>
<br>
 void ClangdLSPServer::onDiagnostics<wbr>Ready(<br>
     PathRef File, Tagged<std::vector<DiagWithFix<wbr>Its>> Diagnostics) {<br>
-  std::string DiagnosticsJSON;<br>
+  json::ary DiagnosticsJSON;<br>
<br>
   DiagnosticToReplacementMap LocalFixIts; // Temporary storage<br>
   for (auto &DiagWithFixes : Diagnostics.Value) {<br>
     auto Diag = DiagWithFixes.Diag;<br>
-    DiagnosticsJSON +=<br>
-        R"({"range":)" + Range::unparse(Diag.range) +<br>
-        R"(,"severity":)" + std::to_string(Diag.severity) +<br>
-        R"(,"message":")" + llvm::yaml::escape(Diag.messag<wbr>e) +<br>
-        R"("},)";<br>
-<br>
+    DiagnosticsJSON.push_back(json<wbr>::obj{<br>
+        {"range", Diag.range},<br>
+        {"severity", Diag.severity},<br>
+        {"message", Diag.message},<br>
+    });<br>
     // We convert to Replacements to become independent of the SourceManager.<br>
     auto &FixItsForDiagnostic = LocalFixIts[Diag];<br>
     std::copy(DiagWithFixes.FixIt<wbr>s.begin(), DiagWithFixes.FixIts.end(),<br>
@@ -295,10 +283,13 @@ void ClangdLSPServer::onDiagnostics<wbr>Ready<br>
   }<br>
<br>
   // Publish diagnostics.<br>
-  if (!DiagnosticsJSON.empty())<br>
-    DiagnosticsJSON.pop_back(); // Drop trailing comma.<br>
-  Out.writeMessage(<br>
-      R"({"jsonrpc":"2.0","method":"<wbr>textDocument/publishDiagnostic<wbr>s","params":{"uri":")" +<br>
-      URI::fromFile(File).uri + R"(","diagnostics":[)" + DiagnosticsJSON +<br>
-      R"(]}})");<br>
+  Out.writeMessage(json::obj{<br>
+      {"jsonrpc", "2.0"},<br>
+      {"method", "textDocument/publishDiagnosti<wbr>cs"},<br>
+      {"params",<br>
+       json::obj{<br>
+           {"uri", URI::fromFile(File)},<br>
+           {"diagnostics", std::move(DiagnosticsJSON)},<br>
+       }},<br>
+  });<br>
 }<br>
<br>
Added: clang-tools-extra/trunk/clangd<wbr>/JSONExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/JSONExpr.cpp?rev=317486&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/JSONExpr.cpp?rev=317486<wbr>&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/clangd<wbr>/JSONExpr.cpp (added)<br>
+++ clang-tools-extra/trunk/clangd<wbr>/JSONExpr.cpp Mon Nov  6 07:40:30 2017<br>
@@ -0,0 +1,216 @@<br>
+#include "JSONExpr.h"<br>
+<br>
+#include "llvm/Support/Format.h"<br>
+<br>
+namespace clang {<br>
+namespace clangd {<br>
+namespace json {<br>
+using namespace llvm;<br>
+<br>
+void Expr::copyFrom(const Expr &M) {<br>
+  Type = M.Type;<br>
+  switch (Type) {<br>
+  case T_Null:<br>
+  case T_Boolean:<br>
+  case T_Number:<br>
+    memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));<br>
+    break;<br>
+  case T_StringRef:<br>
+    create<StringRef>(M.as<StringR<wbr>ef>());<br>
+    break;<br>
+  case T_String:<br>
+    create<std::string>(M.as<std::<wbr>string>());<br>
+    break;<br>
+  case T_Object:<br>
+    create<Object>(M.as<Object>())<wbr>;<br>
+    break;<br>
+  case T_Array:<br>
+    create<Array>(M.as<Array>());<br>
+    break;<br>
+  }<br>
+}<br>
+<br>
+void Expr::moveFrom(const Expr &&M) {<br>
+  Type = M.Type;<br>
+  switch (Type) {<br>
+  case T_Null:<br>
+  case T_Boolean:<br>
+  case T_Number:<br>
+    memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));<br>
+    break;<br>
+  case T_StringRef:<br>
+    create<StringRef>(M.as<StringR<wbr>ef>());<br>
+    break;<br>
+  case T_String:<br>
+    create<std::string>(std::move(<wbr>M.as<std::string>()));<br>
+    M.Type = T_Null;<br>
+    break;<br>
+  case T_Object:<br>
+    create<Object>(std::move(M.as<<wbr>Object>()));<br>
+    M.Type = T_Null;<br>
+    break;<br>
+  case T_Array:<br>
+    create<Array>(std::move(M.as<A<wbr>rray>()));<br>
+    M.Type = T_Null;<br>
+    break;<br>
+  }<br>
+}<br>
+<br>
+void Expr::destroy() {<br>
+  switch (Type) {<br>
+  case T_Null:<br>
+  case T_Boolean:<br>
+  case T_Number:<br>
+    break;<br>
+  case T_StringRef:<br>
+    as<StringRef>().~StringRef();<br>
+    break;<br>
+  case T_String:<br>
+    as<std::string>().~basic_strin<wbr>g();<br>
+    break;<br>
+  case T_Object:<br>
+    as<Object>().~Object();<br>
+    break;<br>
+  case T_Array:<br>
+    as<Array>().~Array();<br>
+    break;<br>
+  }<br>
+}<br>
+<br>
+} // namespace json<br>
+} // namespace clangd<br>
+} // namespace clang<br>
+<br>
+namespace {<br>
+void quote(llvm::raw_ostream &OS, llvm::StringRef S) {<br>
+  OS << '\"';<br>
+  for (unsigned char C : S) {<br>
+    if (C == 0x22 || C == 0x5C)<br>
+      OS << '\\';<br>
+    if (C >= 0x20) {<br>
+      OS << C;<br>
+      continue;<br>
+    }<br>
+    OS << '\\';<br>
+    switch (C) {<br>
+    // A few characters are common enough to make short escapes worthwhile.<br>
+    case '\t':<br>
+      OS << 't';<br>
+      break;<br>
+    case '\n':<br>
+      OS << 'n';<br>
+      break;<br>
+    case '\r':<br>
+      OS << 'r';<br>
+      break;<br>
+    default:<br>
+      OS << 'u';<br>
+      llvm::write_hex(OS, C, llvm::HexPrintStyle::Lower, 4);<br>
+      break;<br>
+    }<br>
+  }<br>
+  OS << '\"';<br>
+}<br>
+<br>
+enum IndenterAction {<br>
+  Indent,<br>
+  Outdent,<br>
+  Newline,<br>
+  Space,<br>
+};<br>
+} // namespace<br>
+<br>
+// Prints JSON. The indenter can be used to control formatting.<br>
+template <typename Indenter><br>
+void clang::clangd::json::Expr::pri<wbr>nt(raw_ostream &OS,<br>
+                                      const Indenter &I) const {<br>
+  switch (Type) {<br>
+  case T_Null:<br>
+    OS << "null";<br>
+    break;<br>
+  case T_Boolean:<br>
+    OS << (as<bool>() ? "true" : "false");<br>
+    break;<br>
+  case T_Number:<br>
+    OS << format("%g", as<double>());<br>
+    break;<br>
+  case T_StringRef:<br>
+    quote(OS, as<StringRef>());<br>
+    break;<br>
+  case T_String:<br>
+    quote(OS, as<std::string>());<br>
+    break;<br>
+  case T_Object: {<br>
+    bool Comma = false;<br>
+    OS << '{';<br>
+    I(Indent);<br>
+    for (const auto &P : as<Expr::Object>()) {<br>
+      if (Comma)<br>
+        OS << ',';<br>
+      Comma = true;<br>
+      I(Newline);<br>
+      quote(OS, P.first);<br>
+      OS << ':';<br>
+      I(Space);<br>
+      P.second.print(OS, I);<br>
+    }<br>
+    I(Outdent);<br>
+    if (Comma)<br>
+      I(Newline);<br>
+    OS << '}';<br>
+    break;<br>
+  }<br>
+  case T_Array: {<br>
+    bool Comma = false;<br>
+    OS << '[';<br>
+    I(Indent);<br>
+    for (const auto &E : as<Expr::Array>()) {<br>
+      if (Comma)<br>
+        OS << ',';<br>
+      Comma = true;<br>
+      I(Newline);<br>
+      E.print(OS, I);<br>
+    }<br>
+    I(Outdent);<br>
+    if (Comma)<br>
+      I(Newline);<br>
+    OS << ']';<br>
+    break;<br>
+  }<br>
+  }<br>
+}<br>
+<br>
+llvm::raw_ostream &clang::clangd::json::operator<wbr><<(raw_ostream &OS,<br>
+                                                   const Expr &E) {<br>
+  E.print(OS, [](IndenterAction A) { /*ignore*/ });<br>
+  return OS;<br>
+}<br>
+<br>
+void llvm::format_provider<clang::c<wbr>langd::json::Expr>::format(<br>
+    const clang::clangd::json::Expr &E, raw_ostream &OS, StringRef Options) {<br>
+  if (Options.empty()) {<br>
+    OS << E;<br>
+    return;<br>
+  }<br>
+  unsigned IndentAmount = 0;<br>
+  if (Options.getAsInteger(/*Radix=<wbr>*/10, IndentAmount))<br>
+    assert(false && "json::Expr format options should be an integer");<br>
+  unsigned IndentLevel = 0;<br>
+  E.print(OS, [&](IndenterAction A) {<br>
+    switch (A) {<br>
+    case Newline:<br>
+      OS << '\n';<br>
+      OS.indent(IndentLevel);<br>
+      break;<br>
+    case Space:<br>
+      OS << ' ';<br>
+      break;<br>
+    case Indent:<br>
+      IndentLevel += IndentAmount;<br>
+      break;<br>
+    case Outdent:<br>
+      IndentLevel -= IndentAmount;<br>
+      break;<br>
+    };<br>
+  });<br>
+}<br>
<br>
Added: clang-tools-extra/trunk/clangd<wbr>/JSONExpr.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/JSONExpr.h?rev=317486&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/JSONExpr.h?rev=317486&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/clangd<wbr>/JSONExpr.h (added)<br>
+++ clang-tools-extra/trunk/clangd<wbr>/JSONExpr.h Mon Nov  6 07:40:30 2017<br>
@@ -0,0 +1,247 @@<br>
+//===--- JSONExpr.h - composable JSON expressions ---------------*- C++ -*-===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>---------------===//<br>
+<br>
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>JSON_H<br>
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>JSON_H<br>
+<br>
+#include <map><br>
+<br>
+#include "llvm/ADT/SmallVector.h"<br>
+#include "llvm/ADT/StringRef.h"<br>
+#include "llvm/Support/FormatVariadic.h<wbr>"<br>
+#include "llvm/Support/raw_ostream.h"<br>
+<br>
+namespace clang {<br>
+namespace clangd {<br>
+namespace json {<br>
+<br>
+// An Expr is an opaque temporary JSON structure used to compose documents.<br>
+// They can be copied, but should generally be moved.<br>
+//<br>
+// You can implicitly construct literals from:<br>
+//   - strings: std::string, SmallString, formatv, StringRef, char*<br>
+//              (char*, and StringRef are references, not copies!)<br>
+//   - numbers<br>
+//   - booleans<br>
+//   - null: nullptr<br>
+//   - arrays: {"foo", 42.0, false}<br>
+//   - serializable things: any T with a T::unparse(const T&) -> Expr<br>
+//<br>
+// They can also be constructed from object/array helpers:<br>
+//   - json::obj is a type like map<StringExpr, Expr><br>
+//   - json::ary is a type like vector<Expr><br>
+// These can be list-initialized, or used to build up collections in a loop.<br>
+// json::ary(Collection) converts all items in a collection to Exprs.<br>
+//<br>
+// Exprs can be serialized to JSON:<br>
+//   1) raw_ostream << Expr                    // Basic formatting.<br>
+//   2) raw_ostream << formatv("{0}", Expr)    // Basic formatting.<br>
+//   3) raw_ostream << formatv("{0:2}", Expr)  // Pretty-print with indent 2.<br>
+class Expr {<br>
+public:<br>
+  class Object;<br>
+  class ObjectKey;<br>
+  class Array;<br>
+<br>
+  // It would be nice to have Expr() be null. But that would make {} null too...<br>
+  Expr(const Expr &M) { copyFrom(M); }<br>
+  Expr(Expr &&M) { moveFrom(std::move(M)); }<br>
+  // "cheating" move-constructor for moving from initializer_list.<br>
+  Expr(const Expr &&M) { moveFrom(std::move(M)); }<br>
+  Expr(std::initializer_list<Exp<wbr>r> Elements) : Expr(Array(Elements)) {}<br>
+  Expr(Array &&Elements) : Type(T_Array) { create<Array>(std::move(Elemen<wbr>ts)); }<br>
+  Expr(Object &&Properties) : Type(T_Object) {<br>
+    create<Object>(std::move(Prope<wbr>rties));<br>
+  }<br>
+  // Strings: types with value semantics.<br>
+  Expr(std::string &&V) : Type(T_String) { create<std::string>(std::move(<wbr>V)); }<br>
+  Expr(const std::string &V) : Type(T_String) { create<std::string>(V); }<br>
+  Expr(const llvm::SmallVectorImpl<char> &V) : Type(T_String) {<br>
+    create<std::string>(V.begin(), V.end());<br>
+  }<br>
+  Expr(const llvm::formatv_object_base &V) : Expr(V.str()){};<br>
+  // Strings: types with reference semantics.<br>
+  Expr(llvm::StringRef V) : Type(T_StringRef) { create<llvm::StringRef>(V); }<br>
+  Expr(const char *V) : Type(T_StringRef) { create<llvm::StringRef>(V); }<br>
+  Expr(std::nullptr_t) : Type(T_Null) {}<br>
+  // Prevent implicit conversions to boolean.<br>
+  template <typename T, typename = typename std::enable_if<<br>
+                            std::is_same<T, bool>::value>::type><br>
+  Expr(T B) : Type(T_Boolean) {<br>
+    create<bool>(B);<br>
+  }<br>
+  // Numbers: arithmetic types that are not boolean.<br>
+  template <<br>
+      typename T,<br>
+      typename = typename std::enable_if<std::is_arithme<wbr>tic<T>::value>::type,<br>
+      typename = typename std::enable_if<std::integral_c<wbr>onstant<<br>
+          bool, !std::is_same<T, bool>::value>::value>::type><br>
+  Expr(T D) : Type(T_Number) {<br>
+    create<double>(D);<br>
+  }<br>
+  // Types with a static T::unparse function returning an Expr.<br>
+  // FIXME: should this be a free unparse() function found by ADL?<br>
+  template <typename T,<br>
+            typename = typename std::enable_if<std::is_same<<br>
+                Expr, decltype(T::unparse(*(const T *)nullptr))>::value>><br>
+  Expr(const T &V) : Expr(T::unparse(V)) {}<br>
+<br>
+  Expr &operator=(const Expr &M) {<br>
+    destroy();<br>
+    copyFrom(M);<br>
+    return *this;<br>
+  }<br>
+  Expr &operator=(Expr &&M) {<br>
+    destroy();<br>
+    moveFrom(std::move(M));<br>
+    return *this;<br>
+  }<br>
+  ~Expr() { destroy(); }<br>
+<br>
+  friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Expr &);<br>
+<br>
+private:<br>
+  void destroy();<br>
+  void copyFrom(const Expr &M);<br>
+  // We allow moving from *const* Exprs, by marking all members as mutable!<br>
+  // This hack is needed to support initializer-list syntax efficiently.<br>
+  // (std::initializer_list<T> is a container of const T).<br>
+  void moveFrom(const Expr &&M);<br>
+<br>
+  template <typename T, typename... U> void create(U &&... V) {<br>
+    new (&as<T>()) T(std::forward<U>(V)...);<br>
+  }<br>
+  template <typename T> T &as() const {<br>
+    return *reinterpret_cast<T *>(Union.buffer);<br>
+  }<br>
+<br>
+  template <typename Indenter><br>
+  void print(llvm::raw_ostream &, const Indenter &) const;<br>
+  friend struct llvm::format_provider<clang::c<wbr>langd::json::Expr>;<br>
+<br>
+  enum ExprType : char {<br>
+    T_Null,<br>
+    T_Boolean,<br>
+    T_Number,<br>
+    T_StringRef,<br>
+    T_String,<br>
+    T_Object,<br>
+    T_Array,<br>
+  };<br>
+  mutable ExprType Type;<br>
+<br>
+public:<br>
+  // ObjectKey is a used to capture keys in Expr::Objects. It's like Expr but:<br>
+  //   - only strings are allowed<br>
+  //   - it's copyable (for std::map)<br>
+  //   - we're slightly more eager to copy, to allow efficient key compares<br>
+  //   - it's optimized for the string literal case (Owned == nullptr)<br>
+  class ObjectKey {<br>
+  public:<br>
+    ObjectKey(const char *S) : Data(S) {}<br>
+    ObjectKey(llvm::StringRef S) : Data(S) {}<br>
+    ObjectKey(std::string &&V)<br>
+        : Owned(new std::string(std::move(V))), Data(*Owned) {}<br>
+    ObjectKey(const std::string &V) : Owned(new std::string(V)), Data(*Owned) {}<br>
+    ObjectKey(const llvm::SmallVectorImpl<char> &V)<br>
+        : ObjectKey(std::string(V.begin(<wbr>), V.end())) {}<br>
+    ObjectKey(const llvm::formatv_object_base &V) : ObjectKey(V.str()) {}<br>
+<br>
+    ObjectKey(const ObjectKey &C) { *this = C; }<br>
+    ObjectKey(ObjectKey &&C) = default;<br>
+    ObjectKey &operator=(const ObjectKey &C) {<br>
+      if (C.Owned) {<br>
+        Owned.reset(new std::string(*C.Owned));<br>
+        Data = *Owned;<br>
+      } else {<br>
+        Data = C.Data;<br>
+      }<br>
+      return *this;<br>
+    }<br>
+    ObjectKey &operator=(ObjectKey &&) = default;<br>
+<br>
+    operator llvm::StringRef() const { return Data; }<br>
+<br>
+    friend bool operator<(const ObjectKey &L, const ObjectKey &R) {<br>
+      return L.Data < R.Data;<br>
+    }<br>
+<br>
+    // "cheating" move-constructor for moving from initializer_list.<br>
+    ObjectKey(const ObjectKey &&V) {<br>
+      Owned = std::move(V.Owned);<br>
+      Data = V.Data;<br>
+    }<br>
+<br>
+  private:<br>
+    mutable std::unique_ptr<std::string> Owned; // mutable for cheating.<br>
+    llvm::StringRef Data;<br>
+  };<br>
+<br>
+  class Object : public std::map<ObjectKey, Expr> {<br>
+  public:<br>
+    explicit Object() {}<br>
+    // Use a custom struct for list-init, because pair forces extra copies.<br>
+    struct KV;<br>
+    explicit Object(std::initializer_list<K<wbr>V> Properties);<br>
+<br>
+    // Allow [] as if Expr was default-constructible as null.<br>
+    Expr &operator[](const ObjectKey &K) {<br>
+      return emplace(K, Expr(nullptr)).first->second;<br>
+    }<br>
+    Expr &operator[](ObjectKey &&K) {<br>
+      return emplace(std::move(K), Expr(nullptr)).first->second;<br>
+    }<br>
+  };<br>
+<br>
+  class Array : public std::vector<Expr> {<br>
+  public:<br>
+    explicit Array() {}<br>
+    explicit Array(std::initializer_list<Ex<wbr>pr> Elements) {<br>
+      reserve(Elements.size());<br>
+      for (const Expr &V : Elements)<br>
+        emplace_back(std::move(V));<br>
+    };<br>
+    template <typename Collection> explicit Array(const Collection &C) {<br>
+      for (const auto &V : C)<br>
+        emplace_back(V);<br>
+    }<br>
+  };<br>
+<br>
+private:<br>
+  mutable llvm::AlignedCharArrayUnion<bo<wbr>ol, double, llvm::StringRef,<br>
+                                      std::string, Array, Object><br>
+      Union;<br>
+};<br>
+<br>
+struct Expr::Object::KV {<br>
+  ObjectKey K;<br>
+  Expr V;<br>
+};<br>
+<br>
+inline Expr::Object::Object(std::init<wbr>ializer_list<KV> Properties) {<br>
+  for (const auto &P : Properties)<br>
+    emplace(std::move(P.K), std::move(P.V));<br>
+}<br>
+<br>
+// Give Expr::{Object,Array} more convenient names for literal use.<br>
+using obj = Expr::Object;<br>
+using ary = Expr::Array;<br>
+<br>
+} // namespace json<br>
+} // namespace clangd<br>
+} // namespace clang<br>
+<br>
+namespace llvm {<br>
+template <> struct format_provider<clang::clangd:<wbr>:json::Expr> {<br>
+  static void format(const clang::clangd::json::Expr &, raw_ostream &,<br>
+                     StringRef);<br>
+};<br>
+} // namespace llvm<br>
+<br>
+#endif<br>
<br>
Modified: clang-tools-extra/trunk/clangd<wbr>/JSONRPCDispatcher.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/JSONRPCDispatcher.cpp?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/JSONRPCDispatcher.cpp?<wbr>rev=317486&r1=317485&r2=<wbr>317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/clangd<wbr>/JSONRPCDispatcher.cpp (original)<br>
+++ clang-tools-extra/trunk/clangd<wbr>/JSONRPCDispatcher.cpp Mon Nov  6 07:40:30 2017<br>
@@ -8,6 +8,7 @@<br>
 //===------------------------<wbr>------------------------------<wbr>----------------===//<br>
<br>
 #include "JSONRPCDispatcher.h"<br>
+#include "JSONExpr.h"<br>
 #include "ProtocolHandlers.h"<br>
 #include "Trace.h"<br>
 #include "llvm/ADT/SmallString.h"<br>
@@ -18,17 +19,22 @@<br>
 using namespace clang;<br>
 using namespace clangd;<br>
<br>
-void JSONOutput::writeMessage(const Twine &Message) {<br>
-  llvm::SmallString<128> Storage;<br>
-  StringRef M = Message.toStringRef(Storage);<br>
+void JSONOutput::writeMessage(const json::Expr &Message) {<br>
+  std::string S;<br>
+  llvm::raw_string_ostream OS(S);<br>
+  if (Pretty)<br>
+    OS << llvm::formatv("{0:2}", Message);<br>
+  else<br>
+    OS << Message;<br>
+  OS.flush();<br>
<br>
   std::lock_guard<std::mutex> Guard(StreamMutex);<br>
   // Log without headers.<br>
-  Logs << "--> " << M << '\n';<br>
+  Logs << "--> " << S << '\n';<br>
   Logs.flush();<br>
<br>
   // Emit message with header.<br>
-  Outs << "Content-Length: " << M.size() << "\r\n\r\n" << M;<br>
+  Outs << "Content-Length: " << S.size() << "\r\n\r\n" << S;<br>
   Outs.flush();<br>
 }<br>
<br>
@@ -47,30 +53,38 @@ void JSONOutput::mirrorInput(const Twine<br>
   InputMirror->flush();<br>
 }<br>
<br>
-void RequestContext::reply(const llvm::Twine &Result) {<br>
-  if (ID.empty()) {<br>
+void RequestContext::reply(json::Ex<wbr>pr &&Result) {<br>
+  if (!ID) {<br>
     Out.log("Attempted to reply to a notification!\n");<br>
     return;<br>
   }<br>
-  Out.writeMessage(llvm::Twine(R<wbr>"({"jsonrpc":"2.0","id":)") + ID +<br>
-                   R"(,"result":)" + Result + "}");<br>
+  Out.writeMessage(json::obj{<br>
+      {"jsonrpc", "2.0"},<br>
+      {"id", *ID},<br>
+      {"result", std::move(Result)},<br>
+  });<br>
 }<br>
<br>
 void RequestContext::replyError(int code, const llvm::StringRef &Message) {<br>
   Out.log("Error " + llvm::Twine(code) + ": " + Message + "\n");<br>
-  if (!ID.empty()) {<br>
-    Out.writeMessage(llvm::Twine(R<wbr>"({"jsonrpc":"2.0","id":)") + ID +<br>
-                     R"(,"error":{"code":)" + llvm::Twine(code) +<br>
-                     R"(,"message":")" + llvm::yaml::escape(Message) +<br>
-                     R"("}})");<br>
+  if (ID) {<br>
+    Out.writeMessage(json::obj{<br>
+        {"jsonrpc", "2.0"},<br>
+        {"id", *ID},<br>
+        {"error", json::obj{{"code", code}, {"message", Message}}},<br>
+    });<br>
   }<br>
 }<br>
<br>
-void RequestContext::call(StringRef Method, StringRef Params) {<br>
+void RequestContext::call(StringRef Method, json::Expr &&Params) {<br>
   // FIXME: Generate/Increment IDs for every request so that we can get proper<br>
   // replies once we need to.<br>
-  Out.writeMessage(llvm::Twine(R<wbr>"({"jsonrpc":"2.0","id":1,"met<wbr>hod":")" +<br>
-                               Method + R"(","params":)" + Params + R"(})"));<br>
+  Out.writeMessage(json::obj{<br>
+      {"jsonrpc", "2.0"},<br>
+      {"id", 1},<br>
+      {"method", Method},<br>
+      {"params", std::move(Params)},<br>
+  });<br>
 }<br>
<br>
 void JSONRPCDispatcher::registerHan<wbr>dler(StringRef Method, Handler H) {<br>
@@ -80,7 +94,7 @@ void JSONRPCDispatcher::registerHan<wbr>dler(<br>
<br>
 static void<br>
 callHandler(const llvm::StringMap<JSONRPCDispatc<wbr>her::Handler> &Handlers,<br>
-            llvm::yaml::ScalarNode *Method, llvm::yaml::ScalarNode *Id,<br>
+            llvm::yaml::ScalarNode *Method, llvm::Optional<json::Expr> ID,<br>
             llvm::yaml::MappingNode *Params,<br>
             const JSONRPCDispatcher::Handler &UnknownHandler, JSONOutput &Out) {<br>
   llvm::SmallString<64> MethodStorage;<br>
@@ -88,7 +102,7 @@ callHandler(const llvm::StringMap<JSONRP<br>
   auto I = Handlers.find(MethodStr);<br>
   auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;<br>
   trace::Span Tracer(MethodStr);<br>
-  Handler(RequestContext(Out, Id ? Id->getRawValue() : ""), Params);<br>
+  Handler(RequestContext(Out, std::move(ID)), Params);<br>
 }<br>
<br>
 bool JSONRPCDispatcher::call(String<wbr>Ref Content, JSONOutput &Out) const {<br>
@@ -106,7 +120,7 @@ bool JSONRPCDispatcher::call(String<wbr>Ref C<br>
   llvm::yaml::ScalarNode *Version = nullptr;<br>
   llvm::yaml::ScalarNode *Method = nullptr;<br>
   llvm::yaml::MappingNode *Params = nullptr;<br>
-  llvm::yaml::ScalarNode *Id = nullptr;<br>
+  llvm::Optional<json::Expr> ID;<br>
   for (auto &NextKeyValue : *Object) {<br>
     auto *KeyString =<br>
         dyn_cast_or_null<llvm::yaml::<wbr>ScalarNode>(NextKeyValue.getKe<wbr>y());<br>
@@ -127,7 +141,18 @@ bool JSONRPCDispatcher::call(String<wbr>Ref C<br>
     } else if (KeyValue == "method") {<br>
       Method = dyn_cast<llvm::yaml::ScalarNod<wbr>e>(Value);<br>
     } else if (KeyValue == "id") {<br>
-      Id = dyn_cast<llvm::yaml::ScalarNod<wbr>e>(Value);<br>
+      // ID may be either a string or a number.<br>
+      if (auto *IdNode = dyn_cast<llvm::yaml::ScalarNod<wbr>e>(Value)) {<br>
+        llvm::SmallString<32> S;<br>
+        llvm::StringRef V = IdNode->getValue(S);<br>
+        if (IdNode->getRawValue().startsw<wbr>ith("\"")) {<br>
+          ID.emplace(V.str());<br>
+        } else {<br>
+          double D;<br>
+          if (!V.getAsDouble(D))<br>
+            ID.emplace(D);<br>
+        }<br>
+      }<br>
     } else if (KeyValue == "params") {<br>
       if (!Method)<br>
         return false;<br>
@@ -136,7 +161,7 @@ bool JSONRPCDispatcher::call(String<wbr>Ref C<br>
       // because it will break clients that put the id after params. A possible<br>
       // fix would be to split the parsing and execution phases.<br>
       Params = dyn_cast<llvm::yaml::MappingNo<wbr>de>(Value);<br>
-      callHandler(Handlers, Method, Id, Params, UnknownHandler, Out);<br>
+      callHandler(Handlers, Method, std::move(ID), Params, UnknownHandler, Out);<br>
       return true;<br>
     } else {<br>
       return false;<br>
@@ -147,7 +172,7 @@ bool JSONRPCDispatcher::call(String<wbr>Ref C<br>
   // leftovers.<br>
   if (!Method)<br>
     return false;<br>
-  callHandler(Handlers, Method, Id, nullptr, UnknownHandler, Out);<br>
+  callHandler(Handlers, Method, std::move(ID), nullptr, UnknownHandler, Out);<br>
<br>
   return true;<br>
 }<br>
<br>
Modified: clang-tools-extra/trunk/clangd<wbr>/JSONRPCDispatcher.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/JSONRPCDispatcher.h?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/JSONRPCDispatcher.h?<wbr>rev=317486&r1=317485&r2=<wbr>317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/clangd<wbr>/JSONRPCDispatcher.h (original)<br>
+++ clang-tools-extra/trunk/clangd<wbr>/JSONRPCDispatcher.h Mon Nov  6 07:40:30 2017<br>
@@ -10,6 +10,7 @@<br>
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>JSONRPCDISPATCHER_H<br>
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>JSONRPCDISPATCHER_H<br>
<br>
+#include "JSONExpr.h"<br>
 #include "Logger.h"<br>
 #include "clang/Basic/LLVM.h"<br>
 #include "llvm/ADT/SmallString.h"<br>
@@ -26,11 +27,11 @@ namespace clangd {<br>
 class JSONOutput : public Logger {<br>
 public:<br>
   JSONOutput(llvm::raw_ostream &Outs, llvm::raw_ostream &Logs,<br>
-             llvm::raw_ostream *InputMirror = nullptr)<br>
-      : Outs(Outs), Logs(Logs), InputMirror(InputMirror) {}<br>
+             llvm::raw_ostream *InputMirror = nullptr, bool Pretty = false)<br>
+      : Outs(Outs), Logs(Logs), InputMirror(InputMirror), Pretty(Pretty) {}<br>
<br>
   /// Emit a JSONRPC message.<br>
-  void writeMessage(const Twine &Message);<br>
+  void writeMessage(const json::Expr &Result);<br>
<br>
   /// Write to the logging stream.<br>
   /// No newline is implicitly added. (TODO: we should fix this!)<br>
@@ -45,6 +46,7 @@ private:<br>
   llvm::raw_ostream &Outs;<br>
   llvm::raw_ostream &Logs;<br>
   llvm::raw_ostream *InputMirror;<br>
+  bool Pretty;<br>
<br>
   std::mutex StreamMutex;<br>
 };<br>
@@ -52,18 +54,19 @@ private:<br>
 /// Context object passed to handlers to allow replies.<br>
 class RequestContext {<br>
 public:<br>
-  RequestContext(JSONOutput &Out, StringRef ID) : Out(Out), ID(ID) {}<br>
+  RequestContext(JSONOutput &Out, llvm::Optional<json::Expr> ID)<br>
+      : Out(Out), ID(std::move(ID)) {}<br>
<br>
-  /// Sends a successful reply. Result should be well-formed JSON.<br>
-  void reply(const Twine &Result);<br>
+  /// Sends a successful reply.<br>
+  void reply(json::Expr &&Result);<br>
   /// Sends an error response to the client, and logs it.<br>
   void replyError(int code, const llvm::StringRef &Message);<br>
   /// Sends a request to the client.<br>
-  void call(llvm::StringRef Method, StringRef Params);<br>
+  void call(llvm::StringRef Method, json::Expr &&Params);<br>
<br>
 private:<br>
   JSONOutput &Out;<br>
-  llvm::SmallString<64> ID; // Valid JSON, or empty for a notification.<br>
+  llvm::Optional<json::Expr> ID;<br>
 };<br>
<br>
 /// Main JSONRPC entry point. This parses the JSONRPC "header" and calls the<br>
<br>
Modified: clang-tools-extra/trunk/clangd<wbr>/Protocol.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.cpp?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/Protocol.cpp?rev=317486<wbr>&r1=317485&r2=317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/clangd<wbr>/Protocol.cpp (original)<br>
+++ clang-tools-extra/trunk/clangd<wbr>/Protocol.cpp Mon Nov  6 07:40:30 2017<br>
@@ -63,7 +63,7 @@ URI URI::parse(llvm::yaml::ScalarN<wbr>ode *P<br>
   return URI::fromUri(Param->getValue(S<wbr>torage));<br>
 }<br>
<br>
-std::string URI::unparse(const URI &U) { return "\"" + U.uri + "\""; }<br>
+json::Expr URI::unparse(const URI &U) { return U.uri; }<br>
<br>
 llvm::Optional<TextDocumentId<wbr>entifier><br>
 TextDocumentIdentifier::<wbr>parse(llvm::yaml::MappingNode *Params,<br>
@@ -125,11 +125,11 @@ llvm::Optional<Position> Position::parse<br>
   return Result;<br>
 }<br>
<br>
-std::string Position::unparse(const Position &P) {<br>
-  std::string Result;<br>
-  llvm::raw_string_ostream(Resul<wbr>t)<br>
-      << llvm::format(R"({"line": %d, "character": %d})", P.line, P.character);<br>
-  return Result;<br>
+json::Expr Position::unparse(const Position &P) {<br>
+  return json::obj{<br>
+      {"line", P.line},<br>
+      {"character", P.character},<br>
+  };<br>
 }<br>
<br>
 llvm::Optional<Range> Range::parse(llvm::yaml::Mappi<wbr>ngNode *Params,<br>
@@ -165,20 +165,18 @@ llvm::Optional<Range> Range::parse(llvm:<br>
   return Result;<br>
 }<br>
<br>
-std::string Range::unparse(const Range &P) {<br>
-  std::string Result;<br>
-  llvm::raw_string_ostream(Resul<wbr>t) << llvm::format(<br>
-      R"({"start": %s, "end": %s})", Position::unparse(P.start).c_s<wbr>tr(),<br>
-      Position::unparse(P.end).c_str<wbr>());<br>
-  return Result;<br>
+json::Expr Range::unparse(const Range &P) {<br>
+  return json::obj{<br>
+      {"start", P.start},<br>
+      {"end", P.end},<br>
+  };<br>
 }<br>
<br>
-std::string Location::unparse(const Location &P) {<br>
-  std::string Result;<br>
-  llvm::raw_string_ostream(Resul<wbr>t) << llvm::format(<br>
-      R"({"uri": %s, "range": %s})", URI::unparse(P.uri).c_str(),<br>
-      Range::unparse(P.range).c_str(<wbr>));<br>
-  return Result;<br>
+json::Expr Location::unparse(const Location &P) {<br>
+  return json::obj{<br>
+      {"uri", P.uri},<br>
+      {"range", P.range},<br>
+  };<br>
 }<br>
<br>
 llvm::Optional<TextDocumentIt<wbr>em><br>
@@ -279,25 +277,11 @@ llvm::Optional<TextEdit> TextEdit::parse<br>
   return Result;<br>
 }<br>
<br>
-std::string TextEdit::unparse(const TextEdit &P) {<br>
-  std::string Result;<br>
-  llvm::raw_string_ostream(Resul<wbr>t) << llvm::format(<br>
-      R"({"range": %s, "newText": "%s"})", Range::unparse(P.range).c_str(<wbr>),<br>
-      llvm::yaml::escape(P.newText).<wbr>c_str());<br>
-  return Result;<br>
-}<br>
-<br>
-std::string TextEdit::unparse(const std::vector<TextEdit> &TextEdits) {<br>
-  // Fuse all edits into one big JSON array.<br>
-  std::string Edits;<br>
-  for (auto &TE : TextEdits) {<br>
-    Edits += TextEdit::unparse(TE);<br>
-    Edits += ',';<br>
-  }<br>
-  if (!Edits.empty())<br>
-    Edits.pop_back();<br>
-<br>
-  return "[" + Edits + "]";<br>
+json::Expr TextEdit::unparse(const TextEdit &P) {<br>
+  return json::obj{<br>
+      {"range", P.range},<br>
+      {"newText", P.newText},<br>
+  };<br>
 }<br>
<br>
 namespace {<br>
@@ -611,11 +595,11 @@ FormattingOptions::parse(llvm:<wbr>:yaml::Map<br>
   return Result;<br>
 }<br>
<br>
-std::string FormattingOptions::unparse(con<wbr>st FormattingOptions &P) {<br>
-  std::string Result;<br>
-  llvm::raw_string_ostream(Resul<wbr>t) << llvm::format(<br>
-      R"({"tabSize": %d, "insertSpaces": %d})", P.tabSize, P.insertSpaces);<br>
-  return Result;<br>
+json::Expr FormattingOptions::unparse(con<wbr>st FormattingOptions &P) {<br>
+  return json::obj{<br>
+      {"tabSize", P.tabSize},<br>
+      {"insertSpaces", P.insertSpaces},<br>
+  };<br>
 }<br>
<br>
 llvm::Optional<DocumentRangeF<wbr>ormattingParams><br>
@@ -982,28 +966,18 @@ ExecuteCommandParams::parse(ll<wbr>vm::yaml::<br>
   return Result;<br>
 }<br>
<br>
-std::string WorkspaceEdit::unparse(const WorkspaceEdit &WE) {<br>
-  std::string Changes;<br>
-  for (auto &Change : *WE.changes) {<br>
-    Changes += llvm::formatv(R"("{0}": {1})", Change.first,<br>
-                             TextEdit::unparse(Change.seco<wbr>nd));<br>
-    Changes += ',';<br>
-  }<br>
-  if (!Changes.empty())<br>
-    Changes.pop_back();<br>
-<br>
-  std::string Result;<br>
-  llvm::raw_string_ostream(Resul<wbr>t)<br>
-      << llvm::format(R"({"changes": {%s}})", Changes.c_str());<br>
-  return Result;<br>
+json::Expr WorkspaceEdit::unparse(const WorkspaceEdit &WE) {<br>
+  if (!WE.changes)<br>
+    return json::obj{};<br>
+  json::obj FileChanges;<br>
+  for (auto &Change : *WE.changes)<br>
+    FileChanges[Change.first] = json::ary(Change.second);<br>
+  return json::obj{{"changes", std::move(FileChanges)}};<br>
 }<br>
<br>
-std::string<br>
+json::Expr<br>
 ApplyWorkspaceEditParams::unp<wbr>arse(const ApplyWorkspaceEditParams &Params) {<br>
-  std::string Result;<br>
-  llvm::raw_string_ostream(Resul<wbr>t) << llvm::format(<br>
-      R"({"edit": %s})", WorkspaceEdit::unparse(Params.<wbr>edit).c_str());<br>
-  return Result;<br>
+  return json::obj{{"edit", Params.edit}};<br>
 }<br>
<br>
 llvm::Optional<TextDocumentPo<wbr>sitionParams><br>
@@ -1040,96 +1014,57 @@ TextDocumentPositionParams::pa<wbr>rse(llvm::<br>
   return Result;<br>
 }<br>
<br>
-std::string CompletionItem::unparse(const CompletionItem &CI) {<br>
-  std::string Result = "{";<br>
-  llvm::raw_string_ostream Os(Result);<br>
+json::Expr CompletionItem::unparse(const CompletionItem &CI) {<br>
   assert(!CI.label.empty() && "completion item label is required");<br>
-  Os << R"("label":")" << llvm::yaml::escape(CI.label) << R"(",)";<br>
+  json::obj Result{{"label", CI.label}};<br>
   if (CI.kind != CompletionItemKind::Missing)<br>
-    Os << R"("kind":)" << static_cast<int>(CI.kind) << R"(,)";<br>
+    Result["kind"] = static_cast<int>(CI.kind);<br>
   if (!CI.detail.empty())<br>
-    Os << R"("detail":")" << llvm::yaml::escape(CI.detail) << R"(",)";<br>
+    Result["detail"] = CI.detail;<br>
   if (!CI.documentation.empty())<br>
-    Os << R"("documentation":")" << llvm::yaml::escape(CI.document<wbr>ation)<br>
-       << R"(",)";<br>
+    Result["documentation"] = CI.documentation;<br>
   if (!CI.sortText.empty())<br>
-    Os << R"("sortText":")" << llvm::yaml::escape(CI.sortText<wbr>) << R"(",)";<br>
+    Result["sortText"] = CI.sortText;<br>
   if (!CI.filterText.empty())<br>
-    Os << R"("filterText":")" << llvm::yaml::escape(CI.filterTe<wbr>xt) << R"(",)";<br>
+    Result["filterText"] = CI.filterText;<br>
   if (!CI.insertText.empty())<br>
-    Os << R"("insertText":")" << llvm::yaml::escape(CI.insertTe<wbr>xt) << R"(",)";<br>
-  if (CI.insertTextFormat != InsertTextFormat::Missing) {<br>
-    Os << R"("insertTextFormat":)" << static_cast<int>(CI.insertText<wbr>Format)<br>
-       << R"(,)";<br>
-  }<br>
+    Result["insertText"] = CI.insertText;<br>
+  if (CI.insertTextFormat != InsertTextFormat::Missing)<br>
+    Result["insertTextFormat"] = static_cast<int>(CI.insertText<wbr>Format);<br>
   if (CI.textEdit)<br>
-    Os << R"("textEdit":)" << TextEdit::unparse(*CI.textEdit<wbr>) << ',';<br>
-  if (!CI.additionalTextEdits.empty<wbr>()) {<br>
-    Os << R"("additionalTextEdits":[)";<br>
-    for (const auto &Edit : CI.additionalTextEdits)<br>
-      Os << TextEdit::unparse(Edit) << ",";<br>
-    Os.flush();<br>
-    // The list additionalTextEdits is guaranteed nonempty at this point.<br>
-    // Replace the trailing comma with right brace.<br>
-    Result.back() = ']';<br>
-  }<br>
-  Os.flush();<br>
-  // Label is required, so Result is guaranteed to have a trailing comma.<br>
-  Result.back() = '}';<br>
-  return Result;<br>
+    Result["textEdit"] = *CI.textEdit;<br>
+  if (!CI.additionalTextEdits.empty<wbr>())<br>
+    Result["additionalTextEdits"] = json::ary(CI.additionalTextEdi<wbr>ts);<br>
+  return std::move(Result);<br>
 }<br>
<br>
-std::string ParameterInformation::unparse(<wbr>const ParameterInformation &PI) {<br>
-  std::string Result = "{";<br>
-  llvm::raw_string_ostream Os(Result);<br>
+json::Expr ParameterInformation::unparse(<wbr>const ParameterInformation &PI) {<br>
   assert(!PI.label.empty() && "parameter information label is required");<br>
-  Os << R"("label":")" << llvm::yaml::escape(PI.label) << '\"';<br>
+  json::obj Result{{"label", PI.label}};<br>
   if (!PI.documentation.empty())<br>
-    Os << R"(,"documentation":")" << llvm::yaml::escape(PI.document<wbr>ation)<br>
-       << '\"';<br>
-  Os << '}';<br>
-  Os.flush();<br>
-  return Result;<br>
+    Result["documentation"] = PI.documentation;<br>
+  return std::move(Result);<br>
 }<br>
<br>
-std::string SignatureInformation::unparse(<wbr>const SignatureInformation &SI) {<br>
-  std::string Result = "{";<br>
-  llvm::raw_string_ostream Os(Result);<br>
+json::Expr SignatureInformation::unparse(<wbr>const SignatureInformation &SI) {<br>
   assert(!SI.label.empty() && "signature information label is required");<br>
-  Os << R"("label":")" << llvm::yaml::escape(SI.label) << '\"';<br>
+  json::obj Result{<br>
+      {"label", SI.label},<br>
+      {"parameters", json::ary(SI.parameters)},<br>
+  };<br>
   if (!SI.documentation.empty())<br>
-    Os << R"(,"documentation":")" << llvm::yaml::escape(SI.document<wbr>ation)<br>
-       << '\"';<br>
-  Os << R"(,"parameters":[)";<br>
-  for (const auto &Parameter : SI.parameters) {<br>
-    Os << ParameterInformation::unparse(<wbr>Parameter) << ',';<br>
-  }<br>
-  Os.flush();<br>
-  if (SI.parameters.empty())<br>
-    Result.push_back(']');<br>
-  else<br>
-    Result.back() = ']'; // Replace the last `,` with an `]`.<br>
-  Result.push_back('}');<br>
-  return Result;<br>
+    Result["documentation"] = SI.documentation;<br>
+  return std::move(Result);<br>
 }<br>
<br>
-std::string SignatureHelp::unparse(const SignatureHelp &SH) {<br>
-  std::string Result = "{";<br>
-  llvm::raw_string_ostream Os(Result);<br>
+json::Expr SignatureHelp::unparse(const SignatureHelp &SH) {<br>
   assert(SH.activeSignature >= 0 &&<br>
          "Unexpected negative value for number of active signatures.");<br>
   assert(SH.activeParameter >= 0 &&<br>
          "Unexpected negative value for active parameter index");<br>
-  Os << R"("activeSignature":)" << SH.activeSignature<br>
-     << R"(,"activeParameter":)" << SH.activeParameter << R"(,"signatures":[)";<br>
-  for (const auto &Signature : SH.signatures) {<br>
-    Os << SignatureInformation::unparse(<wbr>Signature) << ',';<br>
-  }<br>
-  Os.flush();<br>
-  if (SH.signatures.empty())<br>
-    Result.push_back(']');<br>
-  else<br>
-    Result.back() = ']'; // Replace the last `,` with an `]`.<br>
-  Result.push_back('}');<br>
-  return Result;<br>
+  return json::obj{<br>
+      {"activeSignature", SH.activeSignature},<br>
+      {"activeParameter", SH.activeParameter},<br>
+      {"signatures", json::ary(SH.signatures)},<br>
+  };<br>
 }<br>
<br>
Modified: clang-tools-extra/trunk/clangd<wbr>/Protocol.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.h?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/Protocol.h?rev=317486&<wbr>r1=317485&r2=317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/clangd<wbr>/Protocol.h (original)<br>
+++ clang-tools-extra/trunk/clangd<wbr>/Protocol.h Mon Nov  6 07:40:30 2017<br>
@@ -21,6 +21,7 @@<br>
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>PROTOCOL_H<br>
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_<wbr>PROTOCOL_H<br>
<br>
+#include "JSONExpr.h"<br>
 #include "llvm/ADT/Optional.h"<br>
 #include "llvm/Support/YAMLParser.h"<br>
 #include <string><br>
@@ -39,7 +40,7 @@ struct URI {<br>
   static URI fromFile(llvm::StringRef file);<br>
<br>
   static URI parse(llvm::yaml::ScalarNode *Param);<br>
-  static std::string unparse(const URI &U);<br>
+  static json::Expr unparse(const URI &U);<br>
<br>
   friend bool operator==(const URI &LHS, const URI &RHS) {<br>
     return LHS.uri == RHS.uri;<br>
@@ -80,7 +81,7 @@ struct Position {<br>
<br>
   static llvm::Optional<Position> parse(llvm::yaml::MappingNode *Params,<br>
                                         clangd::Logger &Logger);<br>
-  static std::string unparse(const Position &P);<br>
+  static json::Expr unparse(const Position &P);<br>
 };<br>
<br>
 struct Range {<br>
@@ -99,7 +100,7 @@ struct Range {<br>
<br>
   static llvm::Optional<Range> parse(llvm::yaml::MappingNode *Params,<br>
                                      clangd::Logger &Logger);<br>
-  static std::string unparse(const Range &P);<br>
+  static json::Expr unparse(const Range &P);<br>
 };<br>
<br>
 struct Location {<br>
@@ -119,7 +120,7 @@ struct Location {<br>
     return std::tie(LHS.uri, LHS.range) < std::tie(RHS.uri, RHS.range);<br>
   }<br>
<br>
-  static std::string unparse(const Location &P);<br>
+  static json::Expr unparse(const Location &P);<br>
 };<br>
<br>
 struct Metadata {<br>
@@ -140,8 +141,7 @@ struct TextEdit {<br>
<br>
   static llvm::Optional<TextEdit> parse(llvm::yaml::MappingNode *Params,<br>
                                         clangd::Logger &Logger);<br>
-  static std::string unparse(const TextEdit &P);<br>
-  static std::string unparse(const std::vector<TextEdit> &TextEdits);<br>
+  static json::Expr unparse(const TextEdit &P);<br>
 };<br>
<br>
 struct TextDocumentItem {<br>
@@ -283,7 +283,7 @@ struct FormattingOptions {<br>
<br>
   static llvm::Optional<FormattingOptio<wbr>ns><br>
   parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger);<br>
-  static std::string unparse(const FormattingOptions &P);<br>
+  static json::Expr unparse(const FormattingOptions &P);<br>
 };<br>
<br>
 struct DocumentRangeFormattingParams {<br>
@@ -392,7 +392,7 @@ struct WorkspaceEdit {<br>
<br>
   static llvm::Optional<WorkspaceEdit> parse(llvm::yaml::MappingNode *Params,<br>
                                              clangd::Logger &Logger);<br>
-  static std::string unparse(const WorkspaceEdit &WE);<br>
+  static json::Expr unparse(const WorkspaceEdit &WE);<br>
 };<br>
<br>
 /// Exact commands are not specified in the protocol so we define the<br>
@@ -420,7 +420,7 @@ struct ExecuteCommandParams {<br>
<br>
 struct ApplyWorkspaceEditParams {<br>
   WorkspaceEdit edit;<br>
-  static std::string unparse(const ApplyWorkspaceEditParams &Params);<br>
+  static json::Expr unparse(const ApplyWorkspaceEditParams &Params);<br>
 };<br>
<br>
 struct TextDocumentPositionParams {<br>
@@ -527,7 +527,7 @@ struct CompletionItem {<br>
   //<br>
   // data?: any - A data entry field that is preserved on a completion item<br>
   //              between a completion and a completion resolve request.<br>
-  static std::string unparse(const CompletionItem &P);<br>
+  static json::Expr unparse(const CompletionItem &P);<br>
 };<br>
<br>
 /// A single parameter of a particular signature.<br>
@@ -539,7 +539,7 @@ struct ParameterInformation {<br>
   /// The documentation of this parameter. Optional.<br>
   std::string documentation;<br>
<br>
-  static std::string unparse(const ParameterInformation &);<br>
+  static json::Expr unparse(const ParameterInformation &);<br>
 };<br>
<br>
 /// Represents the signature of something callable.<br>
@@ -554,7 +554,7 @@ struct SignatureInformation {<br>
   /// The parameters of this signature.<br>
   std::vector<ParameterInformat<wbr>ion> parameters;<br>
<br>
-  static std::string unparse(const SignatureInformation &);<br>
+  static json::Expr unparse(const SignatureInformation &);<br>
 };<br>
<br>
 /// Represents the signature of a callable.<br>
@@ -569,7 +569,7 @@ struct SignatureHelp {<br>
   /// The active parameter of the active signature.<br>
   int activeParameter = 0;<br>
<br>
-  static std::string unparse(const SignatureHelp &);<br>
+  static json::Expr unparse(const SignatureHelp &);<br>
 };<br>
<br>
 } // namespace clangd<br>
<br>
Modified: clang-tools-extra/trunk/clangd<wbr>/tool/ClangdMain.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/tool/ClangdMain.cpp?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>clangd/tool/ClangdMain.cpp?<wbr>rev=317486&r1=317485&r2=317486<wbr>&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/clangd<wbr>/tool/ClangdMain.cpp (original)<br>
+++ clang-tools-extra/trunk/clangd<wbr>/tool/ClangdMain.cpp Mon Nov  6 07:40:30 2017<br>
@@ -41,6 +41,10 @@ static llvm::cl::opt<bool> EnableSnippet<br>
         "Present snippet completions instead of plaintext completions"),<br>
     llvm::cl::init(false));<br>
<br>
+static llvm::cl::opt<bool><br>
+    PrettyPrint("pretty", llvm::cl::desc("Pretty-print JSON output"),<br>
+                llvm::cl::init(false));<br>
+<br>
 static llvm::cl::opt<bool> RunSynchronously(<br>
     "run-synchronously",<br>
     llvm::cl::desc("Parse on main thread. If set, -j is ignored"),<br>
@@ -104,7 +108,8 @@ int main(int argc, char *argv[]) {<br>
   llvm::raw_ostream &Outs = llvm::outs();<br>
   llvm::raw_ostream &Logs = llvm::errs();<br>
   JSONOutput Out(Outs, Logs,<br>
-                 InputMirrorStream ? InputMirrorStream.getPointer() : nullptr);<br>
+                 InputMirrorStream ? InputMirrorStream.getPointer() : nullptr,<br>
+                 PrettyPrint);<br>
<br>
   // If --compile-commands-dir arg was invoked, check value and override default<br>
   // path.<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/authority-less-uri.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/authority-less-uri.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/authority-less-<wbr>uri.test?rev=317486&r1=317485&<wbr>r2=317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/authority-less-uri.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/authority-less-uri.test Mon Nov  6 07:40:30 2017<br>
@@ -1,4 +1,4 @@<br>
-# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
 # Test authority-less URI<br>
@@ -15,22 +15,34 @@ Content-Length: 146<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:/main.cpp"},"<wbr>position":{"line":3,"<wbr>character":5}}}<br>
 # Test authority-less URI<br>
 #<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","insertText":"a<wbr>","insertTextFormat":1}<br>
-# CHECK: ]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+#      CHECK:      "filterText": "fake",<br>
+# CHECK-NEXT:      "insertText": "fake",<br>
+# CHECK-NEXT:      "insertTextFormat": 1,<br>
+# CHECK-NEXT:      "kind": 7,<br>
+# CHECK-NEXT:      "label": "fake::",<br>
+# CHECK-NEXT:      "sortText": "000075fake"<br>
+#      CHECK:  ]<br>
 Content-Length: 172<br>
<br>
 {"jsonrpc":"2.0","id":2,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"uri"<wbr>:"file:///main.cpp","position"<wbr>:{"line":3,"character":5}}}<br>
 # Test params parsing in the presence of a 1.x-compatible client (inlined "uri")<br>
 #<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","insertText":"a<wbr>","insertTextFormat":1}<br>
-# CHECK: ]}<br>
+#      CHECK:  "id": 2,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+#      CHECK:      "filterText": "fake",<br>
+# CHECK-NEXT:      "insertText": "fake",<br>
+# CHECK-NEXT:      "insertTextFormat": 1,<br>
+# CHECK-NEXT:      "kind": 7,<br>
+# CHECK-NEXT:      "label": "fake::",<br>
+# CHECK-NEXT:      "sortText": "000075fake"<br>
+#      CHECK:  ]<br>
 Content-Length: 44<br>
<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/completion-items-kinds.t<wbr>est<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/completion-items-kinds.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/completion-items-<wbr>kinds.test?rev=317486&r1=<wbr>317485&r2=317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/completion-items-kinds.t<wbr>est (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/completion-items-kinds.t<wbr>est Mon Nov  6 07:40:30 2017<br>
@@ -11,27 +11,26 @@ Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":4,"<wbr>character":7}}}<br>
 Content-Length: 58<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[<br>
+# CHECK: {"id":1,"jsonrpc":"2.0","resul<wbr>t":[<br>
 #<br>
 # Keyword<br>
-# CHECK-DAG: {"label":"int","kind":14,"sort<wbr>Text":"000050int","filterText"<wbr>:"int","insertText":"int","<wbr>insertTextFormat":1}<br>
+# CHECK-DAG: {"filterText":"int","insertTex<wbr>t":"int","insertTextFormat":1,<wbr>"kind":14,"label":"int","<wbr>sortText":"000050int"}<br>
 #<br>
 # Code pattern<br>
-# CHECK-DAG: {"label":"static_cast<type>(ex<wbr>pression)","kind":15,"sortText<wbr>":"000040static_cast","<wbr>filterText":"static_cast","ins<wbr>ertText":"static_cast<${1:type<wbr>}>(${2:expression})","insertTe<wbr>xtFormat":2}<br>
+# CHECK-DAG: {"filterText":"static_cast","i<wbr>nsertText":"static_cast<${1:ty<wbr>pe}>(${2:expression})","insert<wbr>TextFormat":2,"kind":15,"<wbr>label":"static_cast<type>(expr<wbr>ession)","sortText":"000040sta<wbr>tic_cast"}<br>
 #<br>
 # Struct<br>
-# CHECK-DAG: {"label":"Struct","kind":7,"so<wbr>rtText":"000050Struct","filter<wbr>Text":"Struct","insertText":"<wbr>Struct","insertTextFormat":1}<br>
+# CHECK-DAG: {"filterText":"Struct","insert<wbr>Text":"Struct","insertTextForm<wbr>at":1,"kind":7,"label":"<wbr>Struct","sortText":"000050Stru<wbr>ct"}<br>
 #<br>
 # Macro<br>
-# CHECK-DAG: {"label":"MACRO","kind":1,"sor<wbr>tText":"000070MACRO","filterTe<wbr>xt":"MACRO","insertText":"<wbr>MACRO","insertTextFormat":1}<br>
+# CHECK-DAG: {"filterText":"MACRO","insertT<wbr>ext":"MACRO","insertTextFormat<wbr>":1,"kind":1,"label":"MACRO","<wbr>sortText":"000070MACRO"}<br>
 #<br>
 # Variable<br>
-# CHECK-DAG: {"label":"variable","kind":6,"<wbr>detail":"int","sortText":"0000<wbr>12variable","filterText":"vari<wbr>able","insertText":"variable",<wbr>"insertTextFormat":1}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>variable","insertText":"variab<wbr>le","insertTextFormat":1,"<wbr>kind":6,"label":"variable","<wbr>sortText":"000012variable"}<br>
 #<br>
 # Function<br>
-# CHECK-DAG: {"label":"function()","kind":3<wbr>,"detail":"int","sortText":"00<wbr>0012function","filterText":"fu<wbr>nction","insertText":"function<wbr>()","insertTextFormat":1}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>function","insertText":"functi<wbr>on()","insertTextFormat":1,"<wbr>kind":3,"label":"function()","<wbr>sortText":"000012function"}<br>
 #<br>
-#<br>
-# CHECK: ]}<br>
+# CHECK-SAME: ]}<br>
<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"shutdown","params":null}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/completion-priorities.te<wbr>st<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/completion-priorities.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/completion-priorit<wbr>ies.test?rev=317486&r1=317485&<wbr>r2=317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/completion-priorities.te<wbr>st (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/completion-priorities.te<wbr>st Mon Nov  6 07:40:30 2017<br>
@@ -16,25 +16,24 @@ Content-Length: 151<br>
 # The order of results returned by codeComplete seems to be<br>
 # nondeterministic, so we check regardless of order.<br>
 #<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"pub()","kind":2,"det<wbr>ail":"void","sortText":"000034<wbr>pub","filterText":"pub","<wbr>insertText":"pub","insertTextF<wbr>ormat":1}<br>
-# CHECK-DAG: {"label":"prot()","kind":2,"de<wbr>tail":"void","sortText":"00003<wbr>4prot","filterText":"prot","<wbr>insertText":"prot","insertText<wbr>Format":1}<br>
-# CHECK-DAG: {"label":"priv()","kind":2,"de<wbr>tail":"void","sortText":"00003<wbr>4priv","filterText":"priv","<wbr>insertText":"priv","insertText<wbr>Format":1}<br>
-# CHECK: ]}<br>
+# CHECK: {"id":2,"jsonrpc":"2.0","resul<wbr>t":[<br>
+# CHECK-DAG: {"detail":"void","filterText":<wbr>"pub","insertText":"pub","inse<wbr>rtTextFormat":1,"kind":2,"labe<wbr>l":"pub()","sortText":"000034p<wbr>ub"}<br>
+# CHECK-DAG: {"detail":"void","filterText":<wbr>"prot","insertText":"prot","in<wbr>sertTextFormat":1,"kind":2,"la<wbr>bel":"prot()","sortText":"0000<wbr>34prot"}<br>
+# CHECK-DAG: {"detail":"void","filterText":<wbr>"priv","insertText":"priv","in<wbr>sertTextFormat":1,"kind":2,"la<wbr>bel":"priv()","sortText":"0000<wbr>34priv"}<br>
+# CHECK-SAME: ]}<br>
<br>
 Content-Length: 151<br>
<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":17,"<wbr>character":4}}}<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"pub()","kind":2,"det<wbr>ail":"void","sortText":"000034<wbr>pub","filterText":"pub","<wbr>insertText":"pub","insertTextF<wbr>ormat":1}<br>
-# CHECK-DAG: {"label":"prot()","kind":2,"de<wbr>tail":"void","sortText":"20003<wbr>4prot","filterText":"prot","<wbr>insertText":"prot","insertText<wbr>Format":1}<br>
-# CHECK-DAG: {"label":"priv()","kind":2,"de<wbr>tail":"void","sortText":"20003<wbr>4priv","filterText":"priv","<wbr>insertText":"priv","insertText<wbr>Format":1}<br>
-# CHECK: ]}<br>
+# CHECK: {"id":3,"jsonrpc":"2.0","resul<wbr>t":[<br>
+# CHECK-DAG: {"detail":"void","filterText":<wbr>"pub","insertText":"pub","inse<wbr>rtTextFormat":1,"kind":2,"labe<wbr>l":"pub()","sortText":"000034p<wbr>ub"}<br>
+# CHECK-DAG: {"detail":"void","filterText":<wbr>"prot","insertText":"prot","in<wbr>sertTextFormat":1,"kind":2,"la<wbr>bel":"prot()","sortText":"2000<wbr>34prot"}<br>
+# CHECK-DAG: {"detail":"void","filterText":<wbr>"priv","insertText":"priv","in<wbr>sertTextFormat":1,"kind":2,"la<wbr>bel":"priv()","sortText":"2000<wbr>34priv"}<br>
+# CHECK-SAME: ]}<br>
<br>
 Content-Length: 58<br>
<br>
 {"jsonrpc":"2.0","id":4,"meth<wbr>od":"shutdown","params":null}<br>
-# CHECK: {"jsonrpc":"2.0","id":4,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/completion-qualifiers.te<wbr>st<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/completion-qualifiers.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/completion-qualifi<wbr>ers.test?rev=317486&r1=317485&<wbr>r2=317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/completion-qualifiers.te<wbr>st (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/completion-qualifiers.te<wbr>st Mon Nov  6 07:40:30 2017<br>
@@ -8,15 +8,14 @@ Content-Length: 297<br>
 Content-Length: 151<br>
<br>
 {"jsonrpc":"2.0","id":2,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":11,"<wbr>character":8}}}<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"foo() const","kind":2,"detail":"int"<wbr>,"sortText":"200035foo","filte<wbr>rText":"foo","insertText":"<wbr>foo","insertTextFormat":1}<br>
-# CHECK-DAG: {"label":"bar() const","kind":2,"detail":"int"<wbr>,"sortText":"000037bar","filte<wbr>rText":"bar","insertText":"<wbr>bar","insertTextFormat":1}<br>
-# CHECK-DAG: {"label":"Foo::foo() const","kind":2,"detail":"int"<wbr>,"sortText":"000037foo","filte<wbr>rText":"foo","insertText":"<wbr>foo","insertTextFormat":1}<br>
-# CHECK: ]}<br>
+# CHECK: {"id":2,"jsonrpc":"2.0","resul<wbr>t":[<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>foo","insertText":"foo","inser<wbr>tTextFormat":1,"kind":2,"label<wbr>":"foo() const","sortText":"200035foo"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>bar","insertText":"bar","inser<wbr>tTextFormat":1,"kind":2,"label<wbr>":"bar() const","sortText":"000037bar"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>foo","insertText":"foo","inser<wbr>tTextFormat":1,"kind":2,"label<wbr>":"Foo::foo() const","sortText":"000037foo"}<br>
+# CHECK-SAME: ]}<br>
 Content-Length: 44<br>
<br>
 {"jsonrpc":"2.0","id":4,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":4,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/completion-snippet.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/completion-snippet.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/completion-snippet<wbr>.test?rev=317486&r1=317485&r2=<wbr>317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/completion-snippet.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/completion-snippet.test Mon Nov  6 07:40:30 2017<br>
@@ -15,27 +15,27 @@ Content-Length: 148<br>
 # The order of results returned by codeComplete seems to be<br>
 # nondeterministic, so we check regardless of order.<br>
 #<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","insertText":"a<wbr>","insertTextFormat":1}<br>
-# CHECK-DAG: {"label":"bb","kind":5,"detail<wbr>":"int","sortText":"000035bb",<wbr>"filterText":"bb","insertText"<wbr>:"bb","insertTextFormat":1}<br>
-# CHECK-DAG: {"label":"ccc","kind":5,"detai<wbr>l":"int","sortText":"000035ccc<wbr>","filterText":"ccc","<wbr>insertText":"ccc","insertTextF<wbr>ormat":1}<br>
-# CHECK-DAG: {"label":"operator=(const fake &)","kind":2,"detail":"fake &","sortText":"000079operator=<wbr>","filterText":"operator=","in<wbr>sertText":"operator=(${1:const fake &})","insertTextFormat":2}<br>
-# CHECK-DAG: {"label":"~fake()","kind":4,"d<wbr>etail":"void","sortText":"0000<wbr>79~fake","filterText":"~fake",<wbr>"insertText":"~fake()","insert<wbr>TextFormat":1}<br>
-# CHECK-DAG: {"label":"f(int i, const float f) const","kind":2,"detail":"int"<wbr>,"sortText":"000035f","filterT<wbr>ext":"f","insertText":"f(${1:<wbr>int i}, ${2:const float f})","insertTextFormat":2}<br>
-# CHECK: ]}<br>
+# CHECK: {"id":1,"jsonrpc":"2.0","resul<wbr>t":[<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>a","insertText":"a","insertTex<wbr>tFormat":1,"kind":5,"label":"<wbr>a","sortText":"000035a"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>bb","insertText":"bb","insertT<wbr>extFormat":1,"kind":5,"label":<wbr>"bb","sortText":"000035bb"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>ccc","insertText":"ccc","inser<wbr>tTextFormat":1,"kind":5,"label<wbr>":"ccc","sortText":"000035ccc"<wbr>}<br>
+# CHECK-DAG: {"detail":"fake &","filterText":"operator=","i<wbr>nsertText":"operator=(${1:cons<wbr>t fake &})","insertTextFormat":2,"kin<wbr>d":2,"label":"operator=(const fake &)","sortText":"000079operator<wbr>="}<br>
+# CHECK-DAG: {"detail":"void","filterText":<wbr>"~fake","insertText":"~fake()"<wbr>,"insertTextFormat":1,"kind":4<wbr>,"label":"~fake()","sortText":<wbr>"000079~fake"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>f","insertText":"f(${1:int i}, ${2:const float f})","insertTextFormat":2,"kin<wbr>d":2,"label":"f(int i, const float f) const","sortText":"000035f"}<br>
+# CHECK-SAME: ]}<br>
 Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":2,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":3,"<wbr>character":5}}}<br>
 # Repeat the completion request, expect the same results.<br>
 #<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","insertText":"a<wbr>","insertTextFormat":1}<br>
-# CHECK-DAG: {"label":"bb","kind":5,"detail<wbr>":"int","sortText":"000035bb",<wbr>"filterText":"bb","insertText"<wbr>:"bb","insertTextFormat":1}<br>
-# CHECK-DAG: {"label":"ccc","kind":5,"detai<wbr>l":"int","sortText":"000035ccc<wbr>","filterText":"ccc","<wbr>insertText":"ccc","insertTextF<wbr>ormat":1}<br>
-# CHECK-DAG: {"label":"operator=(const fake &)","kind":2,"detail":"fake &","sortText":"000079operator=<wbr>","filterText":"operator=","in<wbr>sertText":"operator=(${1:const fake &})","insertTextFormat":2}<br>
-# CHECK-DAG: {"label":"~fake()","kind":4,"d<wbr>etail":"void","sortText":"0000<wbr>79~fake","filterText":"~fake",<wbr>"insertText":"~fake()","insert<wbr>TextFormat":1}<br>
-# CHECK-DAG: {"label":"f(int i, const float f) const","kind":2,"detail":"int"<wbr>,"sortText":"000035f","filterT<wbr>ext":"f","insertText":"f(${1:<wbr>int i}, ${2:const float f})","insertTextFormat":2}<br>
-# CHECK: ]}<br>
+# CHECK: {"id":2,"jsonrpc":"2.0","resul<wbr>t":[<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>a","insertText":"a","insertTex<wbr>tFormat":1,"kind":5,"label":"<wbr>a","sortText":"000035a"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>bb","insertText":"bb","insertT<wbr>extFormat":1,"kind":5,"label":<wbr>"bb","sortText":"000035bb"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>ccc","insertText":"ccc","inser<wbr>tTextFormat":1,"kind":5,"label<wbr>":"ccc","sortText":"000035ccc"<wbr>}<br>
+# CHECK-DAG: {"detail":"fake &","filterText":"operator=","i<wbr>nsertText":"operator=(${1:cons<wbr>t fake &})","insertTextFormat":2,"kin<wbr>d":2,"label":"operator=(const fake &)","sortText":"000079operator<wbr>="}<br>
+# CHECK-DAG: {"detail":"void","filterText":<wbr>"~fake","insertText":"~fake()"<wbr>,"insertTextFormat":1,"kind":4<wbr>,"label":"~fake()","sortText":<wbr>"000079~fake"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>f","insertText":"f(${1:int i}, ${2:const float f})","insertTextFormat":2,"kin<wbr>d":2,"label":"f(int i, const float f) const","sortText":"000035f"}<br>
+# CHECK-SAME: ]}<br>
 # Update the source file and check for completions again.<br>
 Content-Length: 226<br>
<br>
@@ -44,15 +44,12 @@ Content-Length: 226<br>
 Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":3,"<wbr>character":5}}}<br>
-# Repeat the completion request, expect the same results.<br>
-#<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"func()","kind":2,"de<wbr>tail":"int (*)(int, int)","sortText":"000034func",<wbr>"filterText":"func","insertTex<wbr>t":"func()","insertTextFormat"<wbr>:1}<br>
-# CHECK: ]}<br>
+# CHECK: {"id":3,"jsonrpc":"2.0","resul<wbr>t":[<br>
+# CHECK-DAG: {"detail":"int (*)(int, int)","filterText":"func","ins<wbr>ertText":"func()","insertTextF<wbr>ormat":1,"kind":2,"label":"<wbr>func()","sortText":"000034func<wbr>"}<br>
+# CHECK-SAME: ]}<br>
 Content-Length: 44<br>
<br>
 {"jsonrpc":"2.0","id":4,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":4,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/completion.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/completion.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/completion.test?<wbr>rev=317486&r1=317485&r2=317486<wbr>&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/completion.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/completion.test Mon Nov  6 07:40:30 2017<br>
@@ -15,27 +15,27 @@ Content-Length: 148<br>
 # The order of results returned by codeComplete seems to be<br>
 # nondeterministic, so we check regardless of order.<br>
 #<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","insertText":"a<wbr>","insertTextFormat":1}<br>
-# CHECK-DAG: {"label":"bb","kind":5,"detail<wbr>":"int","sortText":"000035bb",<wbr>"filterText":"bb","insertText"<wbr>:"bb","insertTextFormat":1}<br>
-# CHECK-DAG: {"label":"ccc","kind":5,"detai<wbr>l":"int","sortText":"000035ccc<wbr>","filterText":"ccc","<wbr>insertText":"ccc","insertTextF<wbr>ormat":1}<br>
-# CHECK-DAG: {"label":"operator=(const fake &)","kind":2,"detail":"fake &","sortText":"000079operator=<wbr>","filterText":"operator=","in<wbr>sertText":"operator=","insertT<wbr>extFormat":1}<br>
-# CHECK-DAG: {"label":"~fake()","kind":4,"d<wbr>etail":"void","sortText":"0000<wbr>79~fake","filterText":"~fake",<wbr>"insertText":"~fake","insertTe<wbr>xtFormat":1}<br>
-# CHECK-DAG: {"label":"f(int i, const float f) const","kind":2,"detail":"int"<wbr>,"sortText":"000035f","filterT<wbr>ext":"f","insertText":"f","<wbr>insertTextFormat":1}<br>
-# CHECK: ]}<br>
+# CHECK: {"id":1,"jsonrpc":"2.0","resul<wbr>t":[<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>a","insertText":"a","insertTex<wbr>tFormat":1,"kind":5,"label":"<wbr>a","sortText":"000035a"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>bb","insertText":"bb","insertT<wbr>extFormat":1,"kind":5,"label":<wbr>"bb","sortText":"000035bb"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>ccc","insertText":"ccc","inser<wbr>tTextFormat":1,"kind":5,"label<wbr>":"ccc","sortText":"000035ccc"<wbr>}<br>
+# CHECK-DAG: {"detail":"fake &","filterText":"operator=","i<wbr>nsertText":"operator=","insert<wbr>TextFormat":1,"kind":2,"label"<wbr>:"operator=(const fake &)","sortText":"000079operator<wbr>="}<br>
+# CHECK-DAG: {"detail":"void","filterText":<wbr>"~fake","insertText":"~fake","<wbr>insertTextFormat":1,"kind":4,"<wbr>label":"~fake()","sortText":"0<wbr>00079~fake"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>f","insertText":"f","insertTex<wbr>tFormat":1,"kind":2,"label":"<wbr>f(int i, const float f) const","sortText":"000035f"}<br>
+# CHECK-SAME: ]}<br>
 Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":2,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":3,"<wbr>character":5}}}<br>
 # Repeat the completion request, expect the same results.<br>
 #<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","insertText":"a<wbr>","insertTextFormat":1}<br>
-# CHECK-DAG: {"label":"bb","kind":5,"detail<wbr>":"int","sortText":"000035bb",<wbr>"filterText":"bb","insertText"<wbr>:"bb","insertTextFormat":1}<br>
-# CHECK-DAG: {"label":"ccc","kind":5,"detai<wbr>l":"int","sortText":"000035ccc<wbr>","filterText":"ccc","<wbr>insertText":"ccc","insertTextF<wbr>ormat":1}<br>
-# CHECK-DAG: {"label":"operator=(const fake &)","kind":2,"detail":"fake &","sortText":"000079operator=<wbr>","filterText":"operator=","in<wbr>sertText":"operator=","insertT<wbr>extFormat":1}<br>
-# CHECK-DAG: {"label":"~fake()","kind":4,"d<wbr>etail":"void","sortText":"0000<wbr>79~fake","filterText":"~fake",<wbr>"insertText":"~fake","insertTe<wbr>xtFormat":1}<br>
-# CHECK-DAG: {"label":"f(int i, const float f) const","kind":2,"detail":"int"<wbr>,"sortText":"000035f","filterT<wbr>ext":"f","insertText":"f","<wbr>insertTextFormat":1}<br>
-# CHECK: ]}<br>
+# CHECK: {"id":2,"jsonrpc":"2.0","resul<wbr>t":[<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>a","insertText":"a","insertTex<wbr>tFormat":1,"kind":5,"label":"<wbr>a","sortText":"000035a"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>bb","insertText":"bb","insertT<wbr>extFormat":1,"kind":5,"label":<wbr>"bb","sortText":"000035bb"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>ccc","insertText":"ccc","inser<wbr>tTextFormat":1,"kind":5,"label<wbr>":"ccc","sortText":"000035ccc"<wbr>}<br>
+# CHECK-DAG: {"detail":"fake &","filterText":"operator=","i<wbr>nsertText":"operator=","insert<wbr>TextFormat":1,"kind":2,"label"<wbr>:"operator=(const fake &)","sortText":"000079operator<wbr>="}<br>
+# CHECK-DAG: {"detail":"void","filterText":<wbr>"~fake","insertText":"~fake","<wbr>insertTextFormat":1,"kind":4,"<wbr>label":"~fake()","sortText":"0<wbr>00079~fake"}<br>
+# CHECK-DAG: {"detail":"int","filterText":"<wbr>f","insertText":"f","insertTex<wbr>tFormat":1,"kind":2,"label":"<wbr>f(int i, const float f) const","sortText":"000035f"}<br>
+# CHECK-SAME: ]}<br>
 # Update the source file and check for completions again.<br>
 Content-Length: 226<br>
<br>
@@ -46,13 +46,12 @@ Content-Length: 148<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":3,"<wbr>character":5}}}<br>
 # Repeat the completion request, expect the same results.<br>
 #<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"func()","kind":2,"de<wbr>tail":"int (*)(int, int)","sortText":"000034func",<wbr>"filterText":"func","insertTex<wbr>t":"func","insertTextFormat":<wbr>1}<br>
-# CHECK: ]}<br>
+# CHECK: {"id":3,"jsonrpc":"2.0","resul<wbr>t":[<br>
+# CHECK-DAG: {"detail":"int (*)(int, int)","filterText":"func","ins<wbr>ertText":"func","insertTextFor<wbr>mat":1,"kind":2,"label":"func(<wbr>)","sortText":"000034func"}<br>
+# CHECK-SAME: ]}<br>
 Content-Length: 44<br>
<br>
 {"jsonrpc":"2.0","id":4,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":4,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/definitions.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/definitions.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/definitions.test?<wbr>rev=317486&r1=317485&r2=317486<wbr>&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/definitions.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/definitions.test Mon Nov  6 07:40:30 2017<br>
@@ -1,4 +1,4 @@<br>
-# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
 Content-Length: 125<br>
@@ -13,14 +13,44 @@ Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":2,"<wbr>character":0}}}<br>
 # Go to local variable<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 5,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 0,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":2,"<wbr>character":1}}}<br>
 # Go to local variable, end of token<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 5,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 0,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 214<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":2},"<wbr>contentChanges":[{"text":"stru<wbr>ct Foo {\nint x;\n};\nint main() {\n  Foo bar = { x : 1 };\n}\n"}]}}<br>
@@ -29,8 +59,23 @@ Content-Length: 149<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":4,"<wbr>character":14}}}<br>
 # Go to field, GNU old-style field designator<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 5,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 0,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 215<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":3},"<wbr>contentChanges":[{"text":"stru<wbr>ct Foo {\nint x;\n};\nint main() {\n  Foo baz = { .x = 2 };\n}\n"}]}}<br>
@@ -39,8 +84,23 @@ Content-Length: 149<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":4,"<wbr>character":15}}}<br>
 # Go to field, field designator<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 5,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 0,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 187<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":4},"<wbr>contentChanges":[{"text":"int main() {\n   main();\n   return 0;\n}"}]}}<br>
@@ -49,8 +109,23 @@ Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":1,"<wbr>character":3}}}<br>
 # Go to function declaration, function call<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 3, "character": 1}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 1,<br>
+# CHECK-NEXT:          "line": 3<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 0,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 208<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":5},"<wbr>contentChanges":[{"text":"stru<wbr>ct Foo {\n};\nint main() {\n   Foo bar;\n   return 0;\n}\n"}]}}<br>
@@ -59,8 +134,23 @@ Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":3,"<wbr>character":3}}}<br>
 # Go to struct declaration, new struct instance<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 1, "character": 1}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 1,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 0,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 231<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":5},"<wbr>contentChanges":[{"text":"name<wbr>space n1 {\nstruct Foo {\n};\n}\nint main() {\n   n1::Foo bar;\n   return 0;\n}\n"}]}}<br>
@@ -69,8 +159,23 @@ Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":5,"<wbr>character":4}}}<br>
 # Go to struct declaration, new struct instance, qualified name<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 3, "character": 1}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 1,<br>
+# CHECK-NEXT:          "line": 3<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 0,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 215<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":6},"<wbr>contentChanges":[{"text":"stru<wbr>ct Foo {\n  int x;\n};\nint main() {\n   Foo bar;\n   bar.x;\n}\n"}]}}<br>
@@ -79,8 +184,23 @@ Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":5,"<wbr>character":7}}}<br>
 # Go to field declaration, field reference<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 2}, "end": {"line": 1, "character": 7}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 7,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 2,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 220<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":7},"<wbr>contentChanges":[{"text":"stru<wbr>ct Foo {\n  void x();\n};\nint main() {\n   Foo bar;\n   bar.x();\n}\n"}]}}<br>
@@ -89,8 +209,23 @@ Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":5,"<wbr>character":7}}}<br>
 # Go to method declaration, method call<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 2}, "end": {"line": 1, "character": 10}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 10,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 2,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 240<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":7},"<wbr>contentChanges":[{"text":"stru<wbr>ct Foo {\n};\ntypedef Foo TypedefFoo;\nint main() {\n   TypedefFoo bar;\n   return 0;\n}\n"}]}}<br>
@@ -99,8 +234,23 @@ Content-Length: 149<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":4,"<wbr>character":10}}}<br>
 # Go to typedef<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 0}, "end": {"line": 2, "character": 22}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 22,<br>
+# CHECK-NEXT:          "line": 2<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 0,<br>
+# CHECK-NEXT:          "line": 2<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 254<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":7},"<wbr>contentChanges":[{"text":"temp<wbr>late <typename MyTemplateParam>\nvoid foo() {\n MyTemplateParam a;\n}\nint main() {\n   return 0;\n}\n"}]}}<br>
@@ -109,8 +259,9 @@ Content-Length: 149<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":2,"<wbr>character":13}}}<br>
 # Go to template type parameter. Fails until clangIndex is modified to handle those.<br>
-# no-CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 10}, "end": {"line": 0, "character": 34}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": []<br>
 Content-Length: 256<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":7},"<wbr>contentChanges":[{"text":"name<wbr>space ns {\nstruct Foo {\nstatic void bar() {}\n};\n}\nint main() {\n   ns::Foo::bar();\n   return 0;\n}\n"}]}}<br>
@@ -119,8 +270,23 @@ Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":6,"<wbr>character":4}}}<br>
 # Go to namespace, static method call<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 4, "character": 1}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 1,<br>
+# CHECK-NEXT:          "line": 4<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 0,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 265<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":7},"<wbr>contentChanges":[{"text":"name<wbr>space ns {\nstruct Foo {\n  int field;\n  Foo(int param) : field(param) {}\n};\n}\nint main() {\n   return 0;\n}\n"}]}}<br>
@@ -128,9 +294,24 @@ Content-Length: 265<br>
 Content-Length: 149<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":3,"<wbr>character":21}}}<br>
-# Go to field, member initializer<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 2}, "end": {"line": 2, "character": 11}}}]}<br>
-<br>
+# Go to field, member initializer<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 11,<br>
+# CHECK-NEXT:          "line": 2<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 2,<br>
+# CHECK-NEXT:          "line": 2<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 204<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":7},"<wbr>contentChanges":[{"text":"#<wbr>define MY_MACRO 0\nint main() {\n  return MY_MACRO;\n}\n"}]}}<br>
@@ -139,8 +320,23 @@ Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":2,"<wbr>character":9}}}<br>
 # Go to macro.<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///{{([A-Za-z]:/)?}}main<wbr>.cpp", "range": {"start": {"line": 0, "character": 8}, "end": {"line": 0, "character": 18}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 18,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 8,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 217<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///main.cpp","version":7},"<wbr>contentChanges":[{"text":"#<wbr>define FOO 1\nint a = FOO;\n#define FOO 2\nint b = FOO;\n#undef FOO\n"}]}}<br>
@@ -149,29 +345,77 @@ Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":1,"<wbr>character":8}}}<br>
 # Go to macro, re-defined later<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///{{([A-Za-z]:/)?}}main<wbr>.cpp", "range": {"start": {"line": 0, "character": 8}, "end": {"line": 0, "character": 13}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 13,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 8,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":3,"<wbr>character":8}}}<br>
 # Go to macro, undefined later<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 8}, "end": {"line": 2, "character": 13}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 13,<br>
+# CHECK-NEXT:          "line": 2<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 8,<br>
+# CHECK-NEXT:          "line": 2<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 148<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":4,"<wbr>character":7}}}<br>
 # Go to macro, being undefined<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 8}, "end": {"line": 2, "character": 13}}}]}<br>
-<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 13,<br>
+# CHECK-NEXT:          "line": 2<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 8,<br>
+# CHECK-NEXT:          "line": 2<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 156<br>
<br>
 {"jsonrpc":"2.0","id":2,"meth<wbr>od":"textDocument/definition",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///doesnotexist.<wbr>cpp"},"position":{"line":4,"<wbr>character":7}}}<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"error<wbr>":{"code":-32602,"message":"<wbr>findDefinitions called on non-added file"}}<br>
-<br>
+#      CHECK:  "error": {<br>
+# CHECK-NEXT:    "code": -32602,<br>
+# CHECK-NEXT:    "message": "findDefinitions called on non-added file"<br>
+# CHECK-NEXT:  },<br>
+# CHECK-NEXT:  "id": 2,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0"<br>
 Content-Length: 48<br>
<br>
 {"jsonrpc":"2.0","id":10000,"<wbr>method":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":10000,"r<wbr>esult":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/diagnostics-preamble.tes<wbr>t<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/diagnostics-preamble.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/diagnostics-preamb<wbr>le.test?rev=317486&r1=317485&<wbr>r2=317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/diagnostics-preamble.tes<wbr>t (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/diagnostics-preamble.tes<wbr>t Mon Nov  6 07:40:30 2017<br>
@@ -1,4 +1,4 @@<br>
-# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
 Content-Length: 125<br>
@@ -8,12 +8,14 @@ Content-Length: 125<br>
 Content-Length: 206<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didOpen","params":{<wbr>"textDocument":{"uri":"file://<wbr>/main.cpp","languageId":"cpp",<wbr>"version":1,"text":"#ifndef FOO\n#define FOO\nint a;\n#else\nint a = b;#endif\n\n\n"}}}<br>
-# CHECK: {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"file:///main.<wbr>cpp","diagnostics":[]}}<br>
-<br>
+#      CHECK:  "method": "textDocument/publishDiagnosti<wbr>cs",<br>
+# CHECK-NEXT:  "params": {<br>
+# CHECK-NEXT:    "diagnostics": [],<br>
+# CHECK-NEXT:    "uri": "file:///main.cpp"<br>
+# CHECK-NEXT:  }<br>
 Content-Length: 58<br>
<br>
 {"jsonrpc":"2.0","id":2,"meth<wbr>od":"shutdown","params":null}<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/diagnostics.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/diagnostics.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/diagnostics.test?<wbr>rev=317486&r1=317485&r2=317486<wbr>&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/diagnostics.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/diagnostics.test Mon Nov  6 07:40:30 2017<br>
@@ -1,4 +1,4 @@<br>
-# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
 Content-Length: 125<br>
@@ -8,14 +8,43 @@ Content-Length: 125<br>
 Content-Length: 152<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didOpen","params":{<wbr>"textDocument":{"uri":"file://<wbr>/foo.c","languageId":"c","vers<wbr>ion":1,"text":"void main() {}"}}}<br>
-#<br>
-# CHECK: {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"file:///foo.<wbr>c","diagnostics":[{"range":{"s<wbr>tart": {"line": 0, "character": 1}, "end": {"line": 0, "character": 1}},"severity":2,"message":"re<wbr>turn type of 'main' is not 'int'"},{"range":{"start": {"line": 0, "character": 1}, "end": {"line": 0, "character": 1}},"severity":3,"message":"ch<wbr>ange return type to 'int'"}]}}<br>
-#<br>
-#<br>
+#      CHECK:  "method": "textDocument/publishDiagnosti<wbr>cs",<br>
+# CHECK-NEXT:  "params": {<br>
+# CHECK-NEXT:    "diagnostics": [<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "return type of 'main' is not 'int'",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 1,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 1,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 2<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "change return type to 'int'",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 1,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 1,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 3<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    ],<br>
+# CHECK-NEXT:    "uri": "file:///foo.c"<br>
+# CHECK-NEXT:  }<br>
 Content-Length: 44<br>
<br>
 {"jsonrpc":"2.0","id":5,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":5,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/did-change-watch-files.t<wbr>est<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/did-change-watch-files.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/did-change-watch-<wbr>files.test?rev=317486&r1=<wbr>317485&r2=317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/did-change-watch-files.t<wbr>est (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/did-change-watch-files.t<wbr>est Mon Nov  6 07:40:30 2017<br>
@@ -5,18 +5,7 @@<br>
 Content-Length: 143<br>
<br>
 {"jsonrpc":"2.0","id":0,"meth<wbr>od":"initialize","params":{"<wbr>processId":123,"rootUri":"file<wbr>:///path/to/workspace","capabi<wbr>lities":{},"trace":"off"}}<br>
-# CHECK: Content-Length: 466<br>
-# CHECK: {"jsonrpc":"2.0","id":0,"resul<wbr>t":{"capabilities":{<br>
-# CHECK:   "textDocumentSync": 1,<br>
-# CHECK:   "documentFormattingProvider": true,<br>
-# CHECK:   "documentRangeFormattingProvi<wbr>der": true,<br>
-# CHECK:   "documentOnTypeFormattingProv<wbr>ider": {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
-# CHECK:   "codeActionProvider": true,<br>
-# CHECK:   "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">",":"]},<br>
-# CHECK:   "definitionProvider": true<br>
-# CHECK: }}}<br>
-#<br>
-#Normal case<br>
+# Normal case.<br>
 Content-Length: 217<br>
<br>
 {"jsonrpc":"2.0","method":"wo<wbr>rkspace/didChangeWatchedFiles"<wbr>,"params":{"changes":[{"uri":"<wbr>file:///path/to/file.cpp","typ<wbr>e":1},{"uri":"file:///path/to/<wbr>file2.cpp","type":2},{"uri":"<wbr>file:///path/to/file3.cpp","ty<wbr>pe":3}]}}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/execute-command.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/execute-command.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/execute-command.<wbr>test?rev=317486&r1=317485&r2=<wbr>317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/execute-command.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/execute-command.test Mon Nov  6 07:40:30 2017<br>
@@ -1,4 +1,4 @@<br>
-# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
 Content-Length: 125<br>
@@ -8,9 +8,54 @@ Content-Length: 125<br>
 Content-Length: 180<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didOpen","params":{<wbr>"textDocument":{"uri":"file://<wbr>/foo.c","languageId":"c","vers<wbr>ion":1,"text":"int main(int i, char **a) { if (i = 2) {}}"}}}<br>
-#<br>
-# CHECK: {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"file:///foo.<wbr>c","diagnostics":[{"range":{"s<wbr>tart": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":2,"message":"u<wbr>sing the result of an assignment as a condition without parentheses"},{"range":{"start<wbr>": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"p<wbr>lace parentheses around the assignment to silence this warning"},{"range":{"start": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"u<wbr>se '==' to turn this assignment into an equality comparison"}]}}<br>
-#<br>
+#      CHECK:  "method": "textDocument/publishDiagnosti<wbr>cs",<br>
+# CHECK-NEXT:  "params": {<br>
+# CHECK-NEXT:    "diagnostics": [<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "using the result of an assignment as a condition without parentheses",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 2<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "place parentheses around the assignment to silence this warning",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 3<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "use '==' to turn this assignment into an equality comparison",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 3<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    ],<br>
+# CHECK-NEXT:    "uri": "file:///foo.c"<br>
+# CHECK-NEXT:  }<br>
 Content-Length: 72<br>
<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"workspace/executeCommand"<wbr>,"params":{}}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/extra-flags.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/extra-flags.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/extra-flags.test?<wbr>rev=317486&r1=317485&r2=317486<wbr>&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/extra-flags.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/extra-flags.test Mon Nov  6 07:40:30 2017<br>
@@ -1,4 +1,4 @@<br>
-# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
 Content-Length: 125<br>
@@ -8,17 +8,80 @@ Content-Length: 125<br>
 Content-Length: 205<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didOpen","params":{<wbr>"textDocument":{"uri":"file://<wbr>/foo.c","languageId":"c","vers<wbr>ion":1,"text":"int main() { int i; return i; }"},"metadata":{"extraFlags":[<wbr>"-Wall"]}}}<br>
-# CHECK: {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"file:///foo.<wbr>c","diagnostics":[{"range":{"s<wbr>tart": {"line": 0, "character": 28}, "end": {"line": 0, "character": 28}},"severity":2,"message":"v<wbr>ariable 'i' is uninitialized when used here"},{"range":{"start": {"line": 0, "character": 19}, "end": {"line": 0, "character": 19}},"severity":3,"message":"i<wbr>nitialize the variable 'i' to silence this warning"}]}}<br>
-#<br>
+#      CHECK:  "method": "textDocument/publishDiagnosti<wbr>cs",<br>
+# CHECK-NEXT:  "params": {<br>
+# CHECK-NEXT:    "diagnostics": [<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "variable 'i' is uninitialized when used here",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 28,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 28,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 2<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "initialize the variable 'i' to silence this warning",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 19,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 19,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 3<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    ],<br>
+# CHECK-NEXT:    "uri": "file:///foo.c"<br>
+# CHECK-NEXT:  }<br>
 Content-Length: 175<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///foo.c","version":2},"<wbr>contentChanges":[{"text":"int main() { int i; return i; }"}]}}<br>
-# CHECK: {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"file:///foo.<wbr>c","diagnostics":[{"range":{"s<wbr>tart": {"line": 0, "character": 28}, "end": {"line": 0, "character": 28}},"severity":2,"message":"v<wbr>ariable 'i' is uninitialized when used here"},{"range":{"start": {"line": 0, "character": 19}, "end": {"line": 0, "character": 19}},"severity":3,"message":"i<wbr>nitialize the variable 'i' to silence this warning"}]}}<br>
-#<br>
+#      CHECK:  "method": "textDocument/publishDiagnosti<wbr>cs",<br>
+# CHECK-NEXT:  "params": {<br>
+# CHECK-NEXT:    "diagnostics": [<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "variable 'i' is uninitialized when used here",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 28,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 28,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 2<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "initialize the variable 'i' to silence this warning",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 19,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 19,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 3<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    ],<br>
+# CHECK-NEXT:    "uri": "file:///foo.c"<br>
+# CHECK-NEXT:  }<br>
 Content-Length: 44<br>
<br>
 {"jsonrpc":"2.0","id":5,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":5,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/fixits.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/fixits.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/fixits.test?rev=<wbr>317486&r1=317485&r2=317486&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/fixits.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/fixits.test Mon Nov  6 07:40:30 2017<br>
@@ -1,4 +1,4 @@<br>
-# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
 Content-Length: 125<br>
@@ -8,30 +8,242 @@ Content-Length: 125<br>
 Content-Length: 180<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didOpen","params":{<wbr>"textDocument":{"uri":"file://<wbr>/foo.c","languageId":"c","vers<wbr>ion":1,"text":"int main(int i, char **a) { if (i = 2) {}}"}}}<br>
-#<br>
-# CHECK: {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"file:///foo.<wbr>c","diagnostics":[{"range":{"s<wbr>tart": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":2,"message":"u<wbr>sing the result of an assignment as a condition without parentheses"},{"range":{"start<wbr>": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"p<wbr>lace parentheses around the assignment to silence this warning"},{"range":{"start": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"u<wbr>se '==' to turn this assignment into an equality comparison"}]}}<br>
-#<br>
+#      CHECK:    "method": "textDocument/publishDiagnosti<wbr>cs",<br>
+# CHECK-NEXT:  "params": {<br>
+# CHECK-NEXT:    "diagnostics": [<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "using the result of an assignment as a condition without parentheses",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 2<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "place parentheses around the assignment to silence this warning",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 3<br>
+# CHECK-NEXT:      },<br>
+# CHECK-NEXT:      {<br>
+# CHECK-NEXT:        "message": "use '==' to turn this assignment into an equality comparison",<br>
+# CHECK-NEXT:        "range": {<br>
+# CHECK-NEXT:          "end": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          "start": {<br>
+# CHECK-NEXT:            "character": 35,<br>
+# CHECK-NEXT:            "line": 0<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "severity": 3<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    ],<br>
+# CHECK-NEXT:    "uri": "file:///foo.c"<br>
+# CHECK-NEXT:  }<br>
 Content-Length: 746<br>
<br>
 {"jsonrpc":"2.0","id":2,"meth<wbr>od":"textDocument/codeAction",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///foo.c"},"range":<wbr>{"start":{"line":104,"<wbr>character":13},"end":{"line":<wbr>0,"character":35}},"context":{<wbr>"diagnostics":[{"range":{"<wbr>start": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":2,"message":"u<wbr>sing the result of an assignment as a condition without parentheses"},{"range":{"start<wbr>": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"p<wbr>lace parentheses around the assignment to silence this warning"},{"range":{"start": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"u<wbr>se '==' to turn this assignment into an equality comparison"}]}}}<br>
-#<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[{"title":"Apply FixIt 'place parentheses around the assignment to silence this warning'", "command": "clangd.applyFix", "arguments": [{"changes": {"file:///foo.c": [{"range": {"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 32}}, "newText": "("},{"range": {"start": {"line": 0, "character": 37}, "end": {"line": 0, "character": 37}}, "newText": ")"}]}}]},{"title":"Apply FixIt 'use '==' to turn this assignment into an equality comparison'", "command": "clangd.applyFix", "arguments": [{"changes": {"file:///foo.c": [{"range": {"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}}, "newText": "=="}]}}]}]}<br>
-#<br>
+#      CHECK:  "id": 2,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "arguments": [<br>
+# CHECK-NEXT:        {<br>
+# CHECK-NEXT:          "changes": {<br>
+# CHECK-NEXT:            "file:///foo.c": [<br>
+# CHECK-NEXT:              {<br>
+# CHECK-NEXT:                "newText": "(",<br>
+# CHECK-NEXT:                "range": {<br>
+# CHECK-NEXT:                  "end": {<br>
+# CHECK-NEXT:                    "character": 32,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  },<br>
+# CHECK-NEXT:                  "start": {<br>
+# CHECK-NEXT:                    "character": 32,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  }<br>
+# CHECK-NEXT:                }<br>
+# CHECK-NEXT:              },<br>
+# CHECK-NEXT:              {<br>
+# CHECK-NEXT:                "newText": ")",<br>
+# CHECK-NEXT:                "range": {<br>
+# CHECK-NEXT:                  "end": {<br>
+# CHECK-NEXT:                    "character": 37,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  },<br>
+# CHECK-NEXT:                  "start": {<br>
+# CHECK-NEXT:                    "character": 37,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  }<br>
+# CHECK-NEXT:                }<br>
+# CHECK-NEXT:              }<br>
+# CHECK-NEXT:            ]<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      ],<br>
+# CHECK-NEXT:      "command": "clangd.applyFix",<br>
+# CHECK-NEXT:      "title": "Apply FixIt place parentheses around the assignment to silence this warning"<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "arguments": [<br>
+# CHECK-NEXT:        {<br>
+# CHECK-NEXT:          "changes": {<br>
+# CHECK-NEXT:            "file:///foo.c": [<br>
+# CHECK-NEXT:              {<br>
+# CHECK-NEXT:                "newText": "==",<br>
+# CHECK-NEXT:                "range": {<br>
+# CHECK-NEXT:                  "end": {<br>
+# CHECK-NEXT:                    "character": 35,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  },<br>
+# CHECK-NEXT:                  "start": {<br>
+# CHECK-NEXT:                    "character": 34,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  }<br>
+# CHECK-NEXT:                }<br>
+# CHECK-NEXT:              }<br>
+# CHECK-NEXT:            ]<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      ],<br>
+# CHECK-NEXT:      "command": "clangd.applyFix",<br>
+# CHECK-NEXT:      "title": "Apply FixIt use '==' to turn this assignment into an equality comparison"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 771<br>
<br>
-{"jsonrpc":"2.0","id":2,"meth<wbr>od":"textDocument/codeAction",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///foo.c"},"range":<wbr>{"start":{"line":104,"<wbr>character":13},"end":{"line":<wbr>0,"character":35}},"context":{<wbr>"diagnostics":[{"range":{"<wbr>start": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":2,"code":"1","<wbr>source":"foo","message":"using the result of an assignment as a condition without parentheses"},{"range":{"start<wbr>": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"p<wbr>lace parentheses around the assignment to silence this warning"},{"range":{"start": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"u<wbr>se '==' to turn this assignment into an equality comparison"}]}}}<br>
+{"jsonrpc":"2.0","id":3,"meth<wbr>od":"textDocument/codeAction",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///foo.c"},"range":<wbr>{"start":{"line":104,"<wbr>character":13},"end":{"line":<wbr>0,"character":35}},"context":{<wbr>"diagnostics":[{"range":{"<wbr>start": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":2,"code":"1","<wbr>source":"foo","message":"using the result of an assignment as a condition without parentheses"},{"range":{"start<wbr>": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"p<wbr>lace parentheses around the assignment to silence this warning"},{"range":{"start": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"u<wbr>se '==' to turn this assignment into an equality comparison"}]}}}<br>
 # Make sure unused "code" and "source" fields ignored gracefully<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[{"title":"Apply FixIt 'place parentheses around the assignment to silence this warning'", "command": "clangd.applyFix", "arguments": [{"changes": {"file:///foo.c": [{"range": {"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 32}}, "newText": "("},{"range": {"start": {"line": 0, "character": 37}, "end": {"line": 0, "character": 37}}, "newText": ")"}]}}]},{"title":"Apply FixIt 'use '==' to turn this assignment into an equality comparison'", "command": "clangd.applyFix", "arguments": [{"changes": {"file:///foo.c": [{"range": {"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}}, "newText": "=="}]}}]}]}<br>
-#<br>
+#      CHECK:  "id": 3,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "arguments": [<br>
+# CHECK-NEXT:        {<br>
+# CHECK-NEXT:          "changes": {<br>
+# CHECK-NEXT:            "file:///foo.c": [<br>
+# CHECK-NEXT:              {<br>
+# CHECK-NEXT:                "newText": "(",<br>
+# CHECK-NEXT:                "range": {<br>
+# CHECK-NEXT:                  "end": {<br>
+# CHECK-NEXT:                    "character": 32,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  },<br>
+# CHECK-NEXT:                  "start": {<br>
+# CHECK-NEXT:                    "character": 32,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  }<br>
+# CHECK-NEXT:                }<br>
+# CHECK-NEXT:              },<br>
+# CHECK-NEXT:              {<br>
+# CHECK-NEXT:                "newText": ")",<br>
+# CHECK-NEXT:                "range": {<br>
+# CHECK-NEXT:                  "end": {<br>
+# CHECK-NEXT:                    "character": 37,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  },<br>
+# CHECK-NEXT:                  "start": {<br>
+# CHECK-NEXT:                    "character": 37,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  }<br>
+# CHECK-NEXT:                }<br>
+# CHECK-NEXT:              }<br>
+# CHECK-NEXT:            ]<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      ],<br>
+# CHECK-NEXT:      "command": "clangd.applyFix",<br>
+# CHECK-NEXT:      "title": "Apply FixIt place parentheses around the assignment to silence this warning"<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "arguments": [<br>
+# CHECK-NEXT:        {<br>
+# CHECK-NEXT:          "changes": {<br>
+# CHECK-NEXT:            "file:///foo.c": [<br>
+# CHECK-NEXT:              {<br>
+# CHECK-NEXT:                "newText": "==",<br>
+# CHECK-NEXT:                "range": {<br>
+# CHECK-NEXT:                  "end": {<br>
+# CHECK-NEXT:                    "character": 35,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  },<br>
+# CHECK-NEXT:                  "start": {<br>
+# CHECK-NEXT:                    "character": 34,<br>
+# CHECK-NEXT:                    "line": 0<br>
+# CHECK-NEXT:                  }<br>
+# CHECK-NEXT:                }<br>
+# CHECK-NEXT:              }<br>
+# CHECK-NEXT:            ]<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      ],<br>
+# CHECK-NEXT:      "command": "clangd.applyFix",<br>
+# CHECK-NEXT:      "title": "Apply FixIt use '==' to turn this assignment into an equality comparison"<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 329<br>
<br>
-{"jsonrpc":"2.0","id":3,"meth<wbr>od":"workspace/executeCommand"<wbr>,"params":{"command":"clangd.<wbr>applyFix","arguments":[{"<wbr>changes":{"file:///foo.c":[{"<wbr>range":{"start":{"line":0,"<wbr>character":32},"end":{"line":<wbr>0,"character":32}},"newText":"<wbr>("},{"range":{"start":{"line":<wbr>0,"character":37},"end":{"<wbr>line":0,"character":37}},"<wbr>newText":")"}]}}]}}<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":"Fix applied."}<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"metho<wbr>d":"workspace/applyEdit","<wbr>params":{"edit": {"changes": {"file:///foo.c": [{"range": {"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 32}}, "newText": "("},{"range": {"start": {"line": 0, "character": 37}, "end": {"line": 0, "character": 37}}, "newText": ")"}]}}}}<br>
+{"jsonrpc":"2.0","id":4,"meth<wbr>od":"workspace/executeCommand"<wbr>,"params":{"command":"clangd.<wbr>applyFix","arguments":[{"<wbr>changes":{"file:///foo.c":[{"<wbr>range":{"start":{"line":0,"<wbr>character":32},"end":{"line":<wbr>0,"character":32}},"newText":"<wbr>("},{"range":{"start":{"line":<wbr>0,"character":37},"end":{"<wbr>line":0,"character":37}},"<wbr>newText":")"}]}}]}}<br>
+#      CHECK:  "id": 4,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": "Fix applied."<br>
+#<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "method": "workspace/applyEdit",<br>
+# CHECK-NEXT:  "params": {<br>
+# CHECK-NEXT:    "edit": {<br>
+# CHECK-NEXT:      "changes": {<br>
+# CHECK-NEXT:        "file:///foo.c": [<br>
+# CHECK-NEXT:          {<br>
+# CHECK-NEXT:            "newText": "(",<br>
+# CHECK-NEXT:            "range": {<br>
+# CHECK-NEXT:              "end": {<br>
+# CHECK-NEXT:                "character": 32,<br>
+# CHECK-NEXT:                "line": 0<br>
+# CHECK-NEXT:              },<br>
+# CHECK-NEXT:              "start": {<br>
+# CHECK-NEXT:                "character": 32,<br>
+# CHECK-NEXT:                "line": 0<br>
+# CHECK-NEXT:              }<br>
+# CHECK-NEXT:            }<br>
+# CHECK-NEXT:          },<br>
+# CHECK-NEXT:          {<br>
+# CHECK-NEXT:            "newText": ")",<br>
+# CHECK-NEXT:            "range": {<br>
+# CHECK-NEXT:              "end": {<br>
+# CHECK-NEXT:                "character": 37,<br>
+# CHECK-NEXT:                "line": 0<br>
+# CHECK-NEXT:              },<br>
+# CHECK-NEXT:              "start": {<br>
+# CHECK-NEXT:                "character": 37,<br>
+# CHECK-NEXT:                "line": 0<br>
+# CHECK-NEXT:              }<br>
+# CHECK-NEXT:            }<br>
+# CHECK-NEXT:          }<br>
+# CHECK-NEXT:        ]<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  }<br>
 Content-Length: 44<br>
<br>
-{"jsonrpc":"2.0","id":3,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":null}<br>
+{"jsonrpc":"2.0","id":4,"meth<wbr>od":"shutdown"}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/formatting.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/formatting.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/formatting.test?<wbr>rev=317486&r1=317485&r2=317486<wbr>&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/formatting.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/formatting.test Mon Nov  6 07:40:30 2017<br>
@@ -1,30 +1,71 @@<br>
-# RUN: clangd < %s | FileCheck %s<br>
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
 Content-Length: 125<br>
<br>
 {"jsonrpc":"2.0","id":0,"meth<wbr>od":"initialize","params":{"<wbr>processId":123,"rootPath":"cla<wbr>ngd","capabilities":{},"trace"<wbr>:"off"}}<br>
-# CHECK: {"jsonrpc":"2.0","id":0,"resul<wbr>t":{"capabilities":{<br>
-# CHECK:   "textDocumentSync": 1,<br>
-# CHECK:   "documentFormattingProvider": true,<br>
-# CHECK:   "documentRangeFormattingProvi<wbr>der": true,<br>
-# CHECK:   "documentOnTypeFormattingProv<wbr>ider": {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
-# CHECK:   "codeActionProvider": true,<br>
-# CHECK:   "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">",":"]},<br>
-# CHECK:   "definitionProvider": true<br>
-# CHECK: }}}<br>
-#<br>
 Content-Length: 193<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didOpen","params":{<wbr>"textDocument":{"uri":"file://<wbr>/foo.c","languageId":"c","vers<wbr>ion":1,"text":"int foo ( int x ) {\n    x = x+1;\n    return x;\n    }"}}}<br>
-#<br>
-#<br>
 Content-Length: 233<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/rangeFormatt<wbr>ing","params":{"textDocument":<wbr>{"uri":"file:///foo.c"},"<wbr>range":{"start":{"line":1,"<wbr>character":4},"end":{"line":1,<wbr>"character":12}},"options":{"<wbr>tabSize":4,"insertSpaces":<wbr>true}}}<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"range": {"start": {"line": 0, "character": 19}, "end": {"line": 1, "character": 4}}, "newText": "\n  "},{"range": {"start": {"line": 1, "character": 9}, "end": {"line": 1, "character": 9}}, "newText": " "},{"range": {"start": {"line": 1, "character": 10}, "end": {"line": 1, "character": 10}}, "newText": " "},{"range": {"start": {"line": 1, "character": 12}, "end": {"line": 2, "character": 4}}, "newText": "\n  "}]}<br>
-#<br>
-#<br>
+#      CHECK:   "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "newText": "\n  ",<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 4,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 19,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "newText": " ",<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 9,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 9,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "newText": " ",<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 10,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 10,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "newText": "\n  ",<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 4,<br>
+# CHECK-NEXT:          "line": 2<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 12,<br>
+# CHECK-NEXT:          "line": 1<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 197<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///foo.c","version":5},"<wbr>contentChanges":[{"text":"int foo ( int x ) {\n  x = x + 1;\n  return x;\n    }"}]}}<br>
@@ -33,14 +74,68 @@ Content-Length: 197<br>
 Content-Length: 233<br>
<br>
 {"jsonrpc":"2.0","id":2,"meth<wbr>od":"textDocument/rangeFormatt<wbr>ing","params":{"textDocument":<wbr>{"uri":"file:///foo.c"},"<wbr>range":{"start":{"line":1,"<wbr>character":2},"end":{"line":1,<wbr>"character":12}},"options":{"<wbr>tabSize":4,"insertSpaces":<wbr>true}}}<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[]}<br>
-#<br>
+#      CHECK:  "id": 2,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": []<br>
 Content-Length: 153<br>
<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"textDocument/formatting",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///foo.c"},"<wbr>options":{"tabSize":4,"<wbr>insertSpaces":true}}}<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":[{"range": {"start": {"line": 0, "character": 7}, "end": {"line": 0, "character": 8}}, "newText": ""},{"range": {"start": {"line": 0, "character": 9}, "end": {"line": 0, "character": 10}}, "newText": ""},{"range": {"start": {"line": 0, "character": 15}, "end": {"line": 0, "character": 16}}, "newText": ""},{"range": {"start": {"line": 2, "character": 11}, "end": {"line": 3, "character": 4}}, "newText": "\n"}]}<br>
-#<br>
-#<br>
+#      CHECK:  "id": 3,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "newText": "",<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 8,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 7,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "newText": "",<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 10,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 9,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "newText": "",<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 16,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 15,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "newText": "\n",<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 4,<br>
+# CHECK-NEXT:          "line": 3<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 11,<br>
+# CHECK-NEXT:          "line": 2<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
 Content-Length: 190<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///foo.c","version":9},"<wbr>contentChanges":[{"text":"int foo(int x) {\n  x = x + 1;\n  return x;\n}"}]}}<br>
@@ -49,8 +144,9 @@ Content-Length: 190<br>
 Content-Length: 153<br>
<br>
 {"jsonrpc":"2.0","id":4,"meth<wbr>od":"textDocument/formatting",<wbr>"params":{"textDocument":{"<wbr>uri":"file:///foo.c"},"<wbr>options":{"tabSize":4,"<wbr>insertSpaces":true}}}<br>
-# CHECK: {"jsonrpc":"2.0","id":4,"resul<wbr>t":[]}<br>
-#<br>
+#      CHECK:  "id": 4,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": []<br>
 Content-Length: 193<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didChange","params"<wbr>:{"textDocument":{"uri":"file:<wbr>///foo.c","version":5},"<wbr>contentChanges":[{"text":"int foo ( int x ) {\n  x = x + 1;\n  return x;\n}"}]}}<br>
@@ -59,13 +155,53 @@ Content-Length: 193<br>
 Content-Length: 204<br>
<br>
 {"jsonrpc":"2.0","id":5,"meth<wbr>od":"textDocument/onTypeFormat<wbr>ting","params":{"textDocument"<wbr>:{"uri":"file:///foo.c"},"<wbr>position":{"line":3,"character<wbr>":1},"ch":"}","options":{"<wbr>tabSize":4,"insertSpaces":<wbr>true}}}<br>
-# CHECK: {"jsonrpc":"2.0","id":5,"resul<wbr>t":[{"range": {"start": {"line": 0, "character": 7}, "end": {"line": 0, "character": 8}}, "newText": ""},{"range": {"start": {"line": 0, "character": 9}, "end": {"line": 0, "character": 10}}, "newText": ""},{"range": {"start": {"line": 0, "character": 15}, "end": {"line": 0, "character": 16}}, "newText": ""}]}<br>
-#<br>
+#      CHECK:  "id": 5,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "newText": "",<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 8,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 7,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "newText": "",<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 10,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 9,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    {<br>
+# CHECK-NEXT:      "newText": "",<br>
+# CHECK-NEXT:      "range": {<br>
+# CHECK-NEXT:        "end": {<br>
+# CHECK-NEXT:          "character": 16,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        },<br>
+# CHECK-NEXT:        "start": {<br>
+# CHECK-NEXT:          "character": 15,<br>
+# CHECK-NEXT:          "line": 0<br>
+# CHECK-NEXT:        }<br>
+# CHECK-NEXT:      }<br>
+# CHECK-NEXT:    }<br>
+# CHECK-NEXT:  ]<br>
<br>
 Content-Length: 44<br>
<br>
 {"jsonrpc":"2.0","id":6,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":6,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/initialize-params-invali<wbr>d.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/initialize-params-<wbr>invalid.test?rev=317486&r1=<wbr>317485&r2=317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/initialize-params-invali<wbr>d.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/initialize-params-invali<wbr>d.test Mon Nov  6 07:40:30 2017<br>
@@ -1,27 +1,45 @@<br>
-# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
 # Test with invalid initialize request parameters<br>
 Content-Length: 142<br>
<br>
 {"jsonrpc":"2.0","id":0,"meth<wbr>od":"initialize","params":{"<wbr>processId":"","rootUri":"file:<wbr>///path/to/workspace","capabil<wbr>ities":{},"trace":"off"}}<br>
-# CHECK: Content-Length: 606<br>
-# CHECK: {"jsonrpc":"2.0","id":0,"resul<wbr>t":{"capabilities":{<br>
-# CHECK:   "textDocumentSync": 1,<br>
-# CHECK:   "documentFormattingProvider": true,<br>
-# CHECK:   "documentRangeFormattingProvi<wbr>der": true,<br>
-# CHECK:   "documentOnTypeFormattingProv<wbr>ider": {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
-# CHECK:   "codeActionProvider": true,<br>
-# CHECK:   "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">",":"]},<br>
-# CHECK:   "signatureHelpProvider": {"triggerCharacters": ["(",","]},<br>
-# CHECK:   "definitionProvider": true,<br>
-# CHECK:   "executeCommandProvider": {"commands": ["clangd.applyFix"]}<br>
-# CHECK: }}}<br>
-#<br>
+#      CHECK:  "id": 0,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": {<br>
+# CHECK-NEXT:    "codeActionProvider": true,<br>
+# CHECK-NEXT:    "completionProvider": {<br>
+# CHECK-NEXT:      "resolveProvider": false,<br>
+# CHECK-NEXT:      "triggerCharacters": [<br>
+# CHECK-NEXT:        ".",<br>
+# CHECK-NEXT:        ">",<br>
+# CHECK-NEXT:        ":"<br>
+# CHECK-NEXT:      ]<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    "definitionProvider": true,<br>
+# CHECK-NEXT:    "documentFormattingProvider": true,<br>
+# CHECK-NEXT:    "documentOnTypeFormattingProvi<wbr>der": {<br>
+# CHECK-NEXT:      "firstTriggerCharacter": "}",<br>
+# CHECK-NEXT:      "moreTriggerCharacter": []<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    "documentRangeFormattingProvid<wbr>er": true,<br>
+# CHECK-NEXT:    "executeCommandProvider": {<br>
+# CHECK-NEXT:      "commands": [<br>
+# CHECK-NEXT:        "clangd.applyFix"<br>
+# CHECK-NEXT:      ]<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    "signatureHelpProvider": {<br>
+# CHECK-NEXT:      "triggerCharacters": [<br>
+# CHECK-NEXT:        "(",<br>
+# CHECK-NEXT:        ","<br>
+# CHECK-NEXT:      ]<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    "textDocumentSync": 1<br>
+# CHECK-NEXT:  }<br>
 Content-Length: 44<br>
<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/initialize-params.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/initialize-params.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/initialize-params.<wbr>test?rev=317486&r1=317485&r2=<wbr>317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/initialize-params.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/initialize-params.test Mon Nov  6 07:40:30 2017<br>
@@ -1,27 +1,48 @@<br>
-# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
 # Test initialize request parameters with rootUri<br>
 Content-Length: 143<br>
<br>
 {"jsonrpc":"2.0","id":0,"meth<wbr>od":"initialize","params":{"<wbr>processId":123,"rootUri":"file<wbr>:///path/to/workspace","capabi<wbr>lities":{},"trace":"off"}}<br>
-# CHECK: Content-Length: 606<br>
-# CHECK: {"jsonrpc":"2.0","id":0,"resul<wbr>t":{"capabilities":{<br>
-# CHECK:   "textDocumentSync": 1,<br>
-# CHECK:   "documentFormattingProvider": true,<br>
-# CHECK:   "documentRangeFormattingProvi<wbr>der": true,<br>
-# CHECK:   "documentOnTypeFormattingProv<wbr>ider": {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
-# CHECK:   "codeActionProvider": true,<br>
-# CHECK:   "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">",":"]},<br>
-# CHECK:   "signatureHelpProvider": {"triggerCharacters": ["(",","]},<br>
-# CHECK:   "definitionProvider": true,<br>
-# CHECK:   "executeCommandProvider": {"commands": ["clangd.applyFix"]}<br>
-# CHECK: }}}<br>
-#<br>
+#      CHECK:  "id": 0,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": {<br>
+# CHECK-NEXT:    "codeActionProvider": true,<br>
+# CHECK-NEXT:    "completionProvider": {<br>
+# CHECK-NEXT:      "resolveProvider": false,<br>
+# CHECK-NEXT:      "triggerCharacters": [<br>
+# CHECK-NEXT:        ".",<br>
+# CHECK-NEXT:        ">",<br>
+# CHECK-NEXT:        ":"<br>
+# CHECK-NEXT:      ]<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    "definitionProvider": true,<br>
+# CHECK-NEXT:    "documentFormattingProvider": true,<br>
+# CHECK-NEXT:    "documentOnTypeFormattingProvi<wbr>der": {<br>
+# CHECK-NEXT:      "firstTriggerCharacter": "}",<br>
+# CHECK-NEXT:      "moreTriggerCharacter": []<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    "documentRangeFormattingProvid<wbr>er": true,<br>
+# CHECK-NEXT:    "executeCommandProvider": {<br>
+# CHECK-NEXT:      "commands": [<br>
+# CHECK-NEXT:        "clangd.applyFix"<br>
+# CHECK-NEXT:      ]<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    "signatureHelpProvider": {<br>
+# CHECK-NEXT:      "triggerCharacters": [<br>
+# CHECK-NEXT:        "(",<br>
+# CHECK-NEXT:        ","<br>
+# CHECK-NEXT:      ]<br>
+# CHECK-NEXT:    },<br>
+# CHECK-NEXT:    "textDocumentSync": 1<br>
+# CHECK-NEXT:  }<br>
 Content-Length: 44<br>
<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":null}<br>
+#      CHECK:  "id": 3,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": null<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/input-mirror.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/input-mirror.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/input-mirror.test?<wbr>rev=317486&r1=317485&r2=<wbr>317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/input-mirror.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/input-mirror.test Mon Nov  6 07:40:30 2017<br>
@@ -1,4 +1,4 @@<br>
-# RUN: clangd -run-synchronously -input-mirror-file %t < %s<br>
+# RUN: clangd -pretty -run-synchronously -input-mirror-file %t < %s<br>
 # Note that we have to use '-b' as -input-mirror-file does not have a newline at the end of file.<br>
 # RUN: diff -b %t %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
@@ -152,7 +152,6 @@ Content-Length: 148<br>
 Content-Length: 44<br>
<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/protocol.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/protocol.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/protocol.test?rev=<wbr>317486&r1=317485&r2=317486&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/protocol.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/protocol.test Mon Nov  6 07:40:30 2017<br>
@@ -1,5 +1,5 @@<br>
-# RUN: not clangd -run-synchronously < %s | FileCheck %s<br>
-# RUN: not clangd -run-synchronously < %s 2>&1 | FileCheck -check-prefix=STDERR %s<br>
+# RUN: not clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
+# RUN: not clangd -pretty -run-synchronously < %s 2>&1 | FileCheck -check-prefix=STDERR %s<br>
 # vim: fileformat=dos<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
@@ -12,16 +12,9 @@ Content-Type: application/vscode-jsonrpc<br>
 {"jsonrpc":"2.0","id":0,"meth<wbr>od":"initialize","params":{"<wbr>processId":123,"rootPath":"cla<wbr>ngd","capabilities":{},"trace"<wbr>:"off"}}<br>
 # Test message with Content-Type after Content-Length<br>
 #<br>
-# CHECK: "jsonrpc":"2.0","id":0,"result<wbr>":{"capabilities":{<br>
-# CHECK-DAG: "textDocumentSync": 1,<br>
-# CHECK-DAG: "documentFormattingProvider": true,<br>
-# CHECK-DAG: "documentRangeFormattingProvid<wbr>er": true,<br>
-# CHECK-DAG: "documentOnTypeFormattingProvi<wbr>der": {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
-# CHECK-DAG: "codeActionProvider": true,<br>
-# CHECK-DAG: "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">",":"]},<br>
-# CHECK-DAG: "definitionProvider": true<br>
-# CHECK: }}<br>
-<br>
+#      CHECK:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": {<br>
+#      CHECK:  }<br>
 Content-Length: 246<br>
<br>
 {"jsonrpc":"2.0","method":"te<wbr>xtDocument/didOpen","params":{<wbr>"textDocument":{"uri":"file://<wbr>/main.cpp","languageId":"cpp",<wbr>"version":1,"text":"struct fake { int a, bb, ccc; int f(int i, const float f) const; };\nint main() {\n  fake f;\n  f.\n}\n"}}}<br>
@@ -36,9 +29,16 @@ Content-Length: 146<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:/main.cpp"},"<wbr>position":{"line":3,"<wbr>character":5}}}<br>
 # Test message with Content-Type before Content-Length<br>
 #<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","insertText":"a<wbr>","insertTextFormat":1}<br>
-# CHECK: ]}<br>
+#      CHECK:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+#      CHECK:      "filterText": "fake",<br>
+# CHECK-NEXT:      "insertText": "fake",<br>
+# CHECK-NEXT:      "insertTextFormat": 1,<br>
+# CHECK-NEXT:      "kind": 7,<br>
+# CHECK-NEXT:      "label": "fake::",<br>
+# CHECK-NEXT:      "sortText": "000075fake"<br>
+#      CHECK:  ]<br>
<br>
 X-Test: Testing<br>
 Content-Type: application/vscode-jsonrpc; charset-utf-8<br>
@@ -55,9 +55,16 @@ Content-Length: 146<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:/main.cpp"},"<wbr>position":{"line":3,"<wbr>character":5}}}<br>
 # Test message with duplicate Content-Length headers<br>
 #<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","insertText":"a<wbr>","insertTextFormat":1}<br>
-# CHECK: ]}<br>
+#      CHECK:  "id": 3,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+#      CHECK:      "filterText": "fake",<br>
+# CHECK-NEXT:      "insertText": "fake",<br>
+# CHECK-NEXT:      "insertTextFormat": 1,<br>
+# CHECK-NEXT:      "kind": 7,<br>
+# CHECK-NEXT:      "label": "fake::",<br>
+# CHECK-NEXT:      "sortText": "000075fake"<br>
+#      CHECK:  ]<br>
 # STDERR: Warning: Duplicate Content-Length header received. The previous value for this message (10) was ignored.<br>
<br>
 Content-Type: application/vscode-jsonrpc; charset-utf-8<br>
@@ -74,10 +81,16 @@ Content-Length: 146<br>
 {"jsonrpc":"2.0","id":5,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:/main.cpp"},"<wbr>position":{"line":3,"<wbr>character":5}}}<br>
 # Test message with Content-Type before Content-Length<br>
 #<br>
-# CHECK: {"jsonrpc":"2.0","id":5,"resul<wbr>t":[<br>
-# CHECK-DAG: {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","insertText":"a<wbr>","insertTextFormat":1}<br>
-# CHECK: ]}<br>
-<br>
+#      CHECK:  "id": 5,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0",<br>
+# CHECK-NEXT:  "result": [<br>
+#      CHECK:      "filterText": "fake",<br>
+# CHECK-NEXT:      "insertText": "fake",<br>
+# CHECK-NEXT:      "insertTextFormat": 1,<br>
+# CHECK-NEXT:      "kind": 7,<br>
+# CHECK-NEXT:      "label": "fake::",<br>
+# CHECK-NEXT:      "sortText": "000075fake"<br>
+#      CHECK:  ]<br>
 Content-Length: 1024<br>
<br>
 {"jsonrpc":"2.0","id":5,"meth<wbr>od":"textDocument/completion",<wbr>"params":{"textDocument":{"<wbr>uri":"file:/main.cpp"},"<wbr>position":{"line":3,"<wbr>character":5}}}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/signature-help.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/signature-help.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/signature-help.<wbr>test?rev=317486&r1=317485&r2=<wbr>317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/signature-help.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/signature-help.test Mon Nov  6 07:40:30 2017<br>
@@ -15,12 +15,12 @@ Content-Length: 333<br>
 Content-Length: 151<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/signatureHel<wbr>p","params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":8,"<wbr>character":9}}}<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":{"activeSignature":0,"activ<wbr>eParameter":0,"signatures":[<br>
+# CHECK: {"id":1,"jsonrpc":"2.0","resul<wbr>t":{"activeParameter":0,"activ<wbr>eSignature":0,"signatures":[<br>
 # CHECK-DAG: {"label":"foo(float x, float y) -> void","parameters":[{"label":"<wbr>float x"},{"label":"float y"}]}<br>
 # CHECK-DAG: {"label":"foo(float x, int y) -> void","parameters":[{"label":"<wbr>float x"},{"label":"int y"}]}<br>
 # CHECK-DAG: {"label":"foo(int x, float y) -> void","parameters":[{"label":"<wbr>int x"},{"label":"float y"}]}<br>
 # CHECK-DAG: {"label":"foo(int x, int y) -> void","parameters":[{"label":"<wbr>int x"},{"label":"int y"}]}<br>
-# CHECK: ]}<br>
+# CHECK-SAME: ]}<br>
<br>
 # Modify the document<br>
 Content-Length: 333<br>
@@ -31,21 +31,20 @@ Content-Length: 333<br>
 Content-Length: 151<br>
<br>
 {"jsonrpc":"2.0","id":2,"meth<wbr>od":"textDocument/signatureHel<wbr>p","params":{"textDocument":{"<wbr>uri":"file:///main.cpp"},"<wbr>position":{"line":8,"<wbr>character":9}}}<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":{"activeSignature":0,"activ<wbr>eParameter":0,"signatures":[<br>
+# CHECK: {"id":2,"jsonrpc":"2.0","resul<wbr>t":{"activeParameter":0,"activ<wbr>eSignature":0,"signatures":[<br>
 # CHECK-DAG: {"label":"bar(int x, int y = 0) -> void","parameters":[{"label":"<wbr>int x"},{"label":"int y = 0"}]}<br>
 # CHECK-DAG: {"label":"bar(float x = 0, int y = 42) -> void","parameters":[{"label":"<wbr>float x = 0"},{"label":"int y = 42"}]}<br>
-# CHECK: ]}<br>
+# CHECK-SAME: ]}<br>
<br>
 Content-Length: 159<br>
<br>
 {"jsonrpc":"2.0","id":3,"meth<wbr>od":"textDocument/signatureHel<wbr>p","params":{"textDocument":{"<wbr>uri":"file:///doesnotexist.<wbr>cpp"},"position":{"line":8,"<wbr>character":9}}}<br>
-# CHECK: {"jsonrpc":"2.0","id":3,"error<wbr>":{"code":-32602,"message":"<wbr>signatureHelp is called for non-added document"}}<br>
+# CHECK: {"error":{"code":-32602,"messa<wbr>ge":"signatureHelp is called for non-added document"},"id":3,"jsonrpc":"2<wbr>.0"}<br>
<br>
 # Shutdown.<br>
 Content-Length: 49<br>
<br>
 {"jsonrpc":"2.0","id":100000,<wbr>"method":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":100000,"<wbr>result":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/test/c<wbr>langd/unsupported-method.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/unsupported-method.test?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>test/clangd/unsupported-method<wbr>.test?rev=317486&r1=317485&r2=<wbr>317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/test/c<wbr>langd/unsupported-method.test (original)<br>
+++ clang-tools-extra/trunk/test/c<wbr>langd/unsupported-method.test Mon Nov  6 07:40:30 2017<br>
@@ -1,4 +1,4 @@<br>
-# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s<br>
 # It is absolutely vital that this file has CRLF line endings.<br>
 #<br>
 Content-Length: 125<br>
@@ -12,12 +12,16 @@ Content-Length: 143<br>
 Content-Length: 92<br>
<br>
 {"jsonrpc":"2.0","id":1,"meth<wbr>od":"textDocument/jumpInTheAir<wbr>LikeYouJustDontCare","params":<wbr>{}}<br>
-# CHECK: {"jsonrpc":"2.0","id":1,"error<wbr>":{"code":-32601,"message":"<wbr>method not found"}}<br>
+#      CHECK:  "error": {<br>
+# CHECK-NEXT:    "code": -32601,<br>
+# CHECK-NEXT:    "message": "method not found"<br>
+# CHECK-NEXT:  },<br>
+# CHECK-NEXT:  "id": 1,<br>
+# CHECK-NEXT:  "jsonrpc": "2.0"<br>
<br>
 Content-Length: 44<br>
<br>
 {"jsonrpc":"2.0","id":2,"meth<wbr>od":"shutdown"}<br>
-# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":null}<br>
 Content-Length: 33<br>
<br>
 {"jsonrpc":"2.0":"method":"ex<wbr>it"}<br>
<br>
Modified: clang-tools-extra/trunk/unitte<wbr>sts/clangd/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt?rev=317486&r1=317485&r2=317486&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>unittests/clangd/CMakeLists.<wbr>txt?rev=317486&r1=317485&r2=<wbr>317486&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/unitte<wbr>sts/clangd/CMakeLists.txt (original)<br>
+++ clang-tools-extra/trunk/unitte<wbr>sts/clangd/CMakeLists.txt Mon Nov  6 07:40:30 2017<br>
@@ -10,6 +10,7 @@ include_directories(<br>
<br>
 add_extra_unittest(<wbr>ClangdTests<br>
   ClangdTests.cpp<br>
+  JSONExprTests.cpp<br>
   TraceTests.cpp<br>
   )<br>
<br>
<br>
Added: clang-tools-extra/trunk/unitte<wbr>sts/clangd/JSONExprTests.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/JSONExprTests.cpp?rev=317486&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-extra/trunk/<wbr>unittests/clangd/JSONExprTests<wbr>.cpp?rev=317486&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- clang-tools-extra/trunk/unitte<wbr>sts/clangd/JSONExprTests.cpp (added)<br>
+++ clang-tools-extra/trunk/unitte<wbr>sts/clangd/JSONExprTests.cpp Mon Nov  6 07:40:30 2017<br>
@@ -0,0 +1,112 @@<br>
+//===-- JSONExprTests.cpp - JSON expression unit tests ----------*- C++ -*-===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#include "JSONExpr.h"<br>
+<br>
+#include "gmock/gmock.h"<br>
+#include "gtest/gtest.h"<br>
+<br>
+namespace clang {<br>
+namespace clangd {<br>
+namespace json {<br>
+namespace {<br>
+<br>
+std::string s(const Expr &E) { return llvm::formatv("{0}", E).str(); }<br>
+std::string sp(const Expr &E) { return llvm::formatv("{0:2}", E).str(); }<br>
+<br>
+TEST(JSONExprTests, Types) {<br>
+  EXPECT_EQ("true", s(true));<br>
+  EXPECT_EQ("null", s(nullptr));<br>
+  EXPECT_EQ("2.5", s(2.5));<br>
+  EXPECT_EQ(R"("foo")", s("foo"));<br>
+  EXPECT_EQ("[1,2,3]", s({1, 2, 3}));<br>
+  EXPECT_EQ(R"({"x":10,"y":20})"<wbr>, s(obj{{"x", 10}, {"y", 20}}));<br>
+}<br>
+<br>
+TEST(JSONExprTests, Constructors) {<br>
+  // Lots of edge cases around empty and singleton init lists.<br>
+  EXPECT_EQ("[[[3]]]", s({{{3}}}));<br>
+  EXPECT_EQ("[[[]]]", s({{{}}}));<br>
+  EXPECT_EQ("[[{}]]", s({{obj{}}}));<br>
+  EXPECT_EQ(R"({"A":{"B":{}}})", s(obj{{"A", obj{{"B", obj{}}}}}));<br>
+  EXPECT_EQ(R"({"A":{"B":{"X":"Y<wbr>"}}})",<br>
+            s(obj{{"A", obj{{"B", obj{{"X", "Y"}}}}}}));<br>
+}<br>
+<br>
+TEST(JSONExprTests, StringOwnership) {<br>
+  char X[] = "Hello";<br>
+  Expr Alias = static_cast<const char *>(X);<br>
+  X[1] = 'a';<br>
+  EXPECT_EQ(R"("Hallo")", s(Alias));<br>
+<br>
+  std::string Y = "Hello";<br>
+  Expr Copy = Y;<br>
+  Y[1] = 'a';<br>
+  EXPECT_EQ(R"("Hello")", s(Copy));<br>
+}<br>
+<br>
+TEST(JSONExprTests, CanonicalOutput) {<br>
+  // Objects are sorted (but arrays aren't)!<br>
+  EXPECT_EQ(R"({"a":1,"b":2,"c":<wbr>3})", s(obj{{"a", 1}, {"c", 3}, {"b", 2}}));<br>
+  EXPECT_EQ(R"(["a","c","b"])", s({"a", "c", "b"}));<br>
+  EXPECT_EQ("3", s(3.0));<br>
+}<br>
+<br>
+TEST(JSONExprTests, Escaping) {<br>
+  std::string test = {<br>
+      0,                    // Strings may contain nulls.<br>
+      '\b',   '\f',         // Have mnemonics, but we escape numerically.<br>
+      '\r',   '\n',   '\t', // Escaped with mnemonics.<br>
+      'S',    '\"',   '\\', // Printable ASCII characters.<br>
+      '\x7f',               // Delete is not escaped.<br>
+      '\xce', '\x94',       // Non-ASCII UTF-8 is not escaped.<br>
+  };<br>
+  EXPECT_EQ(R"("\u0000\u0008\u00<wbr>0c\r\n\tS\"\\)"<br>
+            u8"\x7fΔ\"",<br>
+            s(test));<br>
+<br>
+  EXPECT_EQ(R"({"object keys are\nescaped":true})",<br>
+            s(obj{{"object keys are\nescaped", true}}));<br>
+}<br>
+<br>
+TEST(JSONExprTests, PrettyPrinting) {<br>
+  EXPECT_EQ(<br>
+      R"({<br>
+  "empty_array": [],<br>
+  "empty_object": {},<br>
+  "full_array": [<br>
+    1,<br>
+    null<br>
+  ],<br>
+  "full_object": {<br>
+    "nested_array": [<br>
+      {<br>
+        "property": "value"<br>
+      }<br>
+    ]<br>
+  }<br>
+})",<br>
+      sp(obj{<br>
+          {"empty_object", obj{}},<br>
+          {"empty_array", {}},<br>
+          {"full_array", {1, nullptr}},<br>
+          {"full_object",<br>
+           obj{<br>
+               {"nested_array",<br>
+                {obj{<br>
+                    {"property", "value"},<br>
+                }}},<br>
+           }},<br>
+      }));<br>
+}<br>
+<br>
+} // namespace<br>
+} // namespace json<br>
+} // namespace clangd<br>
+} // namespace clang<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>
</blockquote></div><br></div>