<div dir="ltr">Clang remembers the last name used to access the file in FileManager and we get the filename from FileManager later, so it's not that surprising that it all broke apart.<div>Sam said that using file:///c:/main.cpp crashes clang on Linux for some reason, we'll probably have to resort to regexes as an immediate solution and figure out how to fix the crash later.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Nov 8, 2017 at 8:47 PM, Marc-André Laperle <span dir="ltr"><<a href="mailto:marc-andre.laperle@ericsson.com" target="_blank">marc-andre.laperle@ericsson.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">
<div id="m_7519689754056656976divtagdefaultwrapper" style="font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif" dir="ltr">
<div id="m_7519689754056656976divtagdefaultwrapper" style="font-size:12pt;color:rgb(0,0,0);font-family:Calibri,Helvetica,sans-serif,"EmojiFont","Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols" dir="ltr">
<p>+1 for <span class="m_7519689754056656976OWAAutoLink">file://c:/main.cpp</span><a class="m_7519689754056656976OWAAutoLink"></a></p>
</div>
<div style="font-size:12pt;color:rgb(0,0,0);font-family:Calibri,Helvetica,sans-serif,"EmojiFont","Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols" dir="ltr">
<br>
</div>
<div style="font-size:12pt;color:rgb(0,0,0);font-family:Calibri,Helvetica,sans-serif,"EmojiFont","Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols" dir="ltr">
(A bit surprised we only see this problem now though?)<br>
</div>
<div style="font-size:12pt;color:rgb(0,0,0);font-family:Calibri,Helvetica,sans-serif,"EmojiFont","Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols" dir="ltr">
<br>
</div>
<div style="font-size:12pt;color:rgb(0,0,0);font-family:Calibri,Helvetica,sans-serif,"EmojiFont","Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols" dir="ltr">
Marc-André</div>
<div style="font-size:12pt;color:rgb(0,0,0);font-family:Calibri,Helvetica,sans-serif,"EmojiFont","Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols" dir="ltr">
<br>
<div style="color:rgb(0,0,0)">
<hr style="display:inline-block;width:98%">
<div id="m_7519689754056656976divRplyFwdMsg" dir="ltr"><font style="font-size:11pt" color="#000000" face="Calibri, sans-serif"><b>From:</b> Ilya Biryukov <<a href="mailto:ibiryukov@google.com" target="_blank">ibiryukov@google.com</a>><br>
<b>Sent:</b> Wednesday, November 8, 2017 8:29 AM<br>
<b>To:</b> Sam McCall<br>
<b>Cc:</b> Marc-André Laperle; cfe-commits; Yung, Douglas<br>
<b>Subject:</b> Re: [clang-tools-extra] r317486 - Adds a json::Expr type to represent intermediate JSON expressions.</font>
<div> </div>
</div>
<div>
<div dir="ltr">Yeah and `file://c:/main.cpp` looks like the best option to me.</div>
<div class="m_7519689754056656976x_gmail_extra"><br>
<div class="m_7519689754056656976x_gmail_quote">On Wed, Nov 8, 2017 at 6:26 PM, Sam McCall <span dir="ltr">
<<a href="mailto:sam.mccall@gmail.com" target="_blank">sam.mccall@gmail.com</a>></span> wrote:<br>
<blockquote class="m_7519689754056656976x_gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="ltr">Oops, +list.
<div><br>
</div>
<div>r317686 makes just this test fuzzy, to unbreak the buildbot.<br>
</div>
</div>
<div class="m_7519689754056656976x_gmail_extra"><br>
<div class="m_7519689754056656976x_gmail_quote">On Wed, Nov 8, 2017 at 1:15 PM, Sam McCall <span dir="ltr">
<<a href="mailto:sam.mccall@gmail.com" target="_blank">sam.mccall@gmail.com</a>></span> wrote:<br>
<blockquote class="m_7519689754056656976x_gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="ltr">
<div class="m_7519689754056656976x_gmail_extra">
<div class="m_7519689754056656976x_gmail_quote">On Wed, Nov 8, 2017 at 12:55 PM, Ilya Biryukov <span dir="ltr">
<<a href="mailto:ibiryukov@google.com" target="_blank">ibiryukov@google.com</a>></span> wrote:<br>
<blockquote class="m_7519689754056656976x_gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="ltr">What's the exact problem with "file://" URIs on Windows? How to properly convert the Windows-style absolute paths into those? (i.e. "C:\Users\Admin\MyProject\Main<wbr>.cpp"?)
<div>If so, there is an overview in Wikipedia (<a href="https://en.wikipedia.org/wiki/File_URI_scheme#Windows_2" target="_blank">https://en.wikipedia.org/wiki<wbr>/File_URI_scheme#Windows_2</a>). In short, they should look this way: file:///c/Users/Admin/MyProjec<wbr>t/Main.cpp..</div>
</div>
</blockquote>
<div>nit: the c needs to keep its colon: file:///c:/Users/...</div>
<div> </div>
<div>Yeah, when I thought about this some more, it's mostly that the tests assume we can pretend there's a file /main.cpp = file:///main.cpp.</div>
<div>On windows, canonicalizing that filename results in C:\main.cpp = file:///C:/main.cpp, which is not what our tests expect.</div>
<div><br>
</div>
<div>Options I see:</div>
<div> - make every test that checks a filename fuzzy (this seems doomed to failure)</div>
<div> - find a URI that works with both unix and windows paths (file:///C:/main.cpp?)</div>
<div> - avoid canonicalizing filenames in ways visible to tests</div>
<div> - ???</div>
<div> </div>
<blockquote class="m_7519689754056656976x_gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="m_7519689754056656976x_gmail_extra">
<div class="m_7519689754056656976x_gmail_quote">On Wed, Nov 8, 2017 at 4:37 PM, Sam McCall <span dir="ltr">
<<a href="mailto:sam.mccall@gmail.com" target="_blank">sam.mccall@gmail.com</a>></span> wrote:<br>
<blockquote class="m_7519689754056656976x_gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="ltr">I think all the JSON-related windows breakages are now fixed, and the remaining definitions.test breakage was caused by r317585.
<div>(Currently trying to get a windows machine to verify this)<br>
<div><br>
</div>
<div>I have to confess I don't know much about how file:// URIs should work on windows. Marc-Andre - any thoughts, or maybe we should revert until we can work this one out?</div>
</div>
</div>
<div class="m_7519689754056656976x_gmail_extra"><br>
<div class="m_7519689754056656976x_gmail_quote">On Wed, Nov 8, 2017 at 3:39 AM, Yung, Douglas <span dir="ltr">
<<a href="mailto:douglas.yung@sony.com" target="_blank">douglas.yung@sony.com</a>></span> wrote:<br>
<blockquote class="m_7519689754056656976x_gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi Sam,<br>
<br>
The test definitions.test is currently failing on the PS4 Windows bot because the URI returned is of the format "file:///C:/main.cpp" instead of the expected "file:///main.cpp" when run on a Windows machine. Can you please fix this ASAP so that we can get the
 bot green again?<br>
<br>
Here you can see the failure on the build bot:<br>
<a href="http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/13343" rel="noreferrer" target="_blank">http://lab.llvm.org:8011/build<wbr>ers/llvm-clang-lld-x86_64-scei<wbr>-ps4-windows10pro-fast/builds/<wbr>13343</a><br>
<br>
You can reproduce the failure by feeding the following file to clangd on Windows:<br>
<br>
# Begin failure.test<br>
Content-Length: 125<br>
<br>
{"jsonrpc":"2.0","id":0,"metho<wbr>d":"initialize","params":{"pro<wbr>cessId":123,"rootPath":"clangd<wbr>","capabilities":{},"trace":"o<wbr>ff"}}<br>
<br>
Content-Length: 217<br>
<br>
{"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"uri":"file:/<wbr>//main.cpp","version":7},"cont<wbr>entChanges":[{"text":"#define FOO 1\nint a = FOO;\n#define FOO 2\nint b = FOO;\n#undef FOO\n"}]}}<br>
<br>
Content-Length: 148<br>
<br>
{"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocument":{"uri"<wbr>:"file:///main.cpp"},"position<wbr>":{"line":1,"character":8}}}<br>
# End failure.test<br>
<br>
<br>
This is cut down from test\clangd\definitions.test. The failure is on line 337 where it is looking for this:<br>
<br>
# CHECK-NEXT:      "uri": "file:///main.cpp"<br>
<br>
However, clangd is generating:<br>
<br>
"uri": "file:///C:/main.cpp"<br>
<br>
If you could fix this as soon as possible it would be greatly appreciated since it is causing the PS4 Windows bot to be red.<br>
<br>
Thanks!<br>
<br>
Douglas Yung<br>
<br>
> -----Original Message-----<br>
> From: cfe-commits [mailto:<a href="mailto:cfe-commits-bounces@lists.llvm.org" target="_blank">cfe-commits-bounces@li<wbr>sts.llvm.org</a>] On Behalf Of Sam<br>
> McCall via cfe-commits<br>
> Sent: Monday, November 06, 2017 7:41<br>
> To: <a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
> Subject: [clang-tools-extra] r317486 - Adds a json::Expr type to represent<br>
> intermediate JSON expressions.<br>
><br>
> 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<br>
> 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]<br>
> <a href="https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM" rel="noreferrer" target="_blank">
https://docs.google.com/docume<wbr>nt/d/1OEF9IauWwNuSigZzvvbjc1cV<wbr>S1uGHRyGTXaoy3DjqM</a><br>
> 4/edit<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/clang<wbr>d/JSONExpr.cpp<br>
>     clang-tools-extra/trunk/clang<wbr>d/JSONExpr.h<br>
>     clang-tools-extra/trunk/unitt<wbr>ests/clangd/JSONExprTests.cpp<br>
> Modified:<br>
>     clang-tools-extra/trunk/clang<wbr>d/CMakeLists.txt<br>
>     clang-tools-extra/trunk/clang<wbr>d/ClangdLSPServer.cpp<br>
>     clang-tools-extra/trunk/clang<wbr>d/JSONRPCDispatcher.cpp<br>
>     clang-tools-extra/trunk/clang<wbr>d/JSONRPCDispatcher.h<br>
>     clang-tools-extra/trunk/clang<wbr>d/Protocol.cpp<br>
>     clang-tools-extra/trunk/clang<wbr>d/Protocol.h<br>
>     clang-tools-extra/trunk/clang<wbr>d/tool/ClangdMain.cpp<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/authority-less-uri.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/completion-items-kinds.<wbr>test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/completion-priorities.t<wbr>est<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/completion-qualifiers.t<wbr>est<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/completion-snippet.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/completion.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/definitions.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/diagnostics-preamble.te<wbr>st<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/diagnostics.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/did-change-watch-files.<wbr>test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/execute-command.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/extra-flags.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/fixits.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/formatting.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/initialize-params-inval<wbr>id.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/initialize-params.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/input-mirror.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/protocol.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/signature-help.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/unsupported-method.test<br>
>     clang-tools-extra/trunk/unitt<wbr>ests/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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/clangd/CMakeLists.<wbr>txt?rev=317486&r1=317485&r2=31<wbr>7486&view=diff<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/clangd/ClangdLSPSe<wbr>rver.cpp?rev=317486&r1=317485&<wbr>r2=317486&view=dif<br>
> f<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<br>
> 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({ReplacementRa<wbr>nge, 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":<br>
> {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
> -          "codeActionProvider": true,<br>
> -          "completionProvider": {"resolveProvider": false,<br>
> "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.root<wbr>Uri->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,<br>
> 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>
> {<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::Re<wbr>placement> Fixes =<br>
>          getFixIts(Params.textDocument.<wbr>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>
> {<br>
> @@ -177,15 +182,7 @@ void ClangdLSPServer::onCompletion(<wbr>Ctx C<br>
>                            // had an API that would allow to attach callbacks<br>
> 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.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.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::ClangdLSPServ<wbr>er(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.FixIts<wbr>.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>
> -<br>
> R"({"jsonrpc":"2.0","method":"<wbr>textDocument/publishDiagnostic<wbr>s","params":{"uri"<br>
> :")" +<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/clangd/JSONExpr.cp<wbr>p?rev=317486&view=auto<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/clangd/JSONExpr.h?<wbr>rev=317486&view=auto<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>
> +//<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>
> +<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<br>
> 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) {<br>
> 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>
> }<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<br>
> 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>
> {}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/clangd/JSONRPCDisp<wbr>atcher.cpp?rev=317486&r1=31748<wbr>5&r2=317486&view=d<br>
> iff<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<br>
> 2017<br>
> @@ -8,6 +8,7 @@<br>
>  //===-------------------------<wbr>------------------------------<wbr>---------------<br>
> ===//<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<br>
> 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<br>
> &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::S<wbr>calarNode>(NextKeyValue.getKey<wbr>());<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<br>
> 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,<br>
> 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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/clangd/JSONRPCDisp<wbr>atcher.h?rev=317486&r1=317485&<wbr>r2=317486&view=dif<br>
> f<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<br>
> 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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/clangd/Protocol.cp<wbr>p?rev=317486&r1=317485&r2=3174<wbr>86&view=diff<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<TextDocumentIde<wbr>ntifier><br>
>  TextDocumentIdentifier::parse(<wbr>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,<br>
> 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<TextDocumentIte<wbr>m><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<DocumentRangeFo<wbr>rmattingParams><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::unpa<wbr>rse(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<TextDocumentPos<wbr>itionParams><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) <<<br>
> R"(",)";<br>
> +    Result["filterText"] = CI.filterText;<br>
>    if (!CI.insertText.empty())<br>
> -    Os << R"("insertText":")" << llvm::yaml::escape(CI.insertTe<wbr>xt) <<<br>
> 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 <<<br>
> 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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/clangd/Protocol.h?<wbr>rev=317486&r1=317485&r2=317486<wbr>&view=diff<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<ParameterInformati<wbr>on> 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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/clangd/tool/Clangd<wbr>Main.cpp?rev=317486&r1=317485&<wbr>r2=317486&view=dif<br>
> f<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<br>
> 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() :<br>
> nullptr);<br>
> +                 InputMirrorStream ? InputMirrorStream.getPointer() :<br>
> nullptr,<br>
> +                 PrettyPrint);<br>
><br>
>    // If --compile-commands-dir arg was invoked, check value and override<br>
> 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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/author<wbr>ity-less-<br>
> uri.test?rev=317486&r1=317485&<wbr>r2=317486&view=diff<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<br>
> 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<br>
> %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>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:/main.cpp"}<wbr>,"position":{"line":3,"charact<wbr>er":5}}}<br>
>  # Test authority-less URI<br>
>  #<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[<br>
> -# CHECK-DAG:<br>
> {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","in<br>
> sertText":"a","insertTextForma<wbr>t":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>
><br>
> {"jsonrpc":"2.0","id":2,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"uri":"file:///main.cpp","p<wbr>osition":{"line":3<br>
> ,"character":5}}}<br>
>  # Test params parsing in the presence of a 1.x-compatible client (inlined<br>
> "uri")<br>
>  #<br>
> -# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[<br>
> -# CHECK-DAG:<br>
> {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","in<br>
> sertText":"a","insertTextForma<wbr>t":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,"metho<wbr>d":"shutdown"}<br>
> -# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/comple<wbr>tion-items-<br>
> kinds.test?rev=317486&r1=31748<wbr>5&r2=317486&view=diff<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<br>
> 07:40:30 2017<br>
> @@ -11,27 +11,26 @@ Content-Length: 148<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":4,"chara<wbr>cter":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:<br>
> {"label":"int","kind":14,"sort<wbr>Text":"000050int","filterText"<wbr>:"int","insertText<br>
> ":"int","insertTextFormat":1}<br>
> +# CHECK-DAG:<br>
> {"filterText":"int","insertTex<wbr>t":"int","insertTextFormat":1,<wbr>"kind":14,"label":<br>
> "int","sortText":"000050int"}<br>
>  #<br>
>  # Code pattern<br>
> -# CHECK-DAG:<br>
> {"label":"static_cast<type>(ex<wbr>pression)","kind":15,"sortText<wbr>":"000040static_ca<br>
> st","filterText":"static_cast"<wbr>,"insertText":"static_cast<${1<wbr>:type}>(${2:expres<br>
> sion})","insertTextFormat":2}<br>
> +# CHECK-DAG:<br>
> {"filterText":"static_cast","i<wbr>nsertText":"static_cast<${1:ty<wbr>pe}>(${2:expressio<br>
> n})","insertTextFormat":2,"kin<wbr>d":15,"label":"static_cast<typ<wbr>e>(expression)","s<br>
> ortText":"000040static_cast"}<br>
>  #<br>
>  # Struct<br>
> -# CHECK-DAG:<br>
> {"label":"Struct","kind":7,"so<wbr>rtText":"000050Struct","filter<wbr>Text":"Struct","in<br>
> sertText":"Struct","insertText<wbr>Format":1}<br>
> +# CHECK-DAG:<br>
> {"filterText":"Struct","insert<wbr>Text":"Struct","insertTextForm<wbr>at":1,"kind":7,"la<br>
> bel":"Struct","sortText":"0000<wbr>50Struct"}<br>
>  #<br>
>  # Macro<br>
> -# CHECK-DAG:<br>
> {"label":"MACRO","kind":1,"sor<wbr>tText":"000070MACRO","filterTe<wbr>xt":"MACRO","inser<br>
> tText":"MACRO","insertTextForm<wbr>at":1}<br>
> +# CHECK-DAG:<br>
> {"filterText":"MACRO","insertT<wbr>ext":"MACRO","insertTextFormat<wbr>":1,"kind":1,"labe<br>
> l":"MACRO","sortText":"000070M<wbr>ACRO"}<br>
>  #<br>
>  # Variable<br>
> -# CHECK-DAG:<br>
> {"label":"variable","kind":6,"<wbr>detail":"int","sortText":"0000<wbr>12variable","filte<br>
> rText":"variable","insertText"<wbr>:"variable","insertTextFormat"<wbr>:1}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>variable","insertText":"variab<wbr>le","insertTextFor<br>
> mat":1,"kind":6,"label":"varia<wbr>ble","sortText":"000012variabl<wbr>e"}<br>
>  #<br>
>  # Function<br>
> -# CHECK-DAG:<br>
> {"label":"function()","kind":3<wbr>,"detail":"int","sortText":"00<wbr>0012function","fil<br>
> terText":"function","insertTex<wbr>t":"function()","insertTextFor<wbr>mat":1}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>function","insertText":"functi<wbr>on()","insertTextF<br>
> ormat":1,"kind":3,"label":"fun<wbr>ction()","sortText":"000012fun<wbr>ction"}<br>
>  #<br>
> -#<br>
> -# CHECK: ]}<br>
> +# CHECK-SAME: ]}<br>
><br>
>  {"jsonrpc":"2.0","id":3,"metho<wbr>d":"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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/comple<wbr>tion-<br>
> priorities.test?rev=317486&r1=<wbr>317485&r2=317486&view=diff<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<br>
> 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:<br>
> {"label":"pub()","kind":2,"det<wbr>ail":"void","sortText":"000034<wbr>pub","filterText":<br>
> "pub","insertText":"pub","inse<wbr>rtTextFormat":1}<br>
> -# CHECK-DAG:<br>
> {"label":"prot()","kind":2,"de<wbr>tail":"void","sortText":"00003<wbr>4prot","filterText<br>
> ":"prot","insertText":"prot","<wbr>insertTextFormat":1}<br>
> -# CHECK-DAG:<br>
> {"label":"priv()","kind":2,"de<wbr>tail":"void","sortText":"00003<wbr>4priv","filterText<br>
> ":"priv","insertText":"priv","<wbr>insertTextFormat":1}<br>
> -# CHECK: ]}<br>
> +# CHECK: {"id":2,"jsonrpc":"2.0","resul<wbr>t":[<br>
> +# CHECK-DAG:<br>
> {"detail":"void","filterText":<wbr>"pub","insertText":"pub","inse<wbr>rtTextFormat":1,"k<br>
> ind":2,"label":"pub()","sortTe<wbr>xt":"000034pub"}<br>
> +# CHECK-DAG:<br>
> {"detail":"void","filterText":<wbr>"prot","insertText":"prot","in<wbr>sertTextFormat":1,<br>
> "kind":2,"label":"prot()","sor<wbr>tText":"000034prot"}<br>
> +# CHECK-DAG:<br>
> {"detail":"void","filterText":<wbr>"priv","insertText":"priv","in<wbr>sertTextFormat":1,<br>
> "kind":2,"label":"priv()","sor<wbr>tText":"000034priv"}<br>
> +# CHECK-SAME: ]}<br>
><br>
>  Content-Length: 151<br>
><br>
><br>
> {"jsonrpc":"2.0","id":3,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":17,"char<wbr>acter":4}}}<br>
> -# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":[<br>
> -# CHECK-DAG:<br>
> {"label":"pub()","kind":2,"det<wbr>ail":"void","sortText":"000034<wbr>pub","filterText":<br>
> "pub","insertText":"pub","inse<wbr>rtTextFormat":1}<br>
> -# CHECK-DAG:<br>
> {"label":"prot()","kind":2,"de<wbr>tail":"void","sortText":"20003<wbr>4prot","filterText<br>
> ":"prot","insertText":"prot","<wbr>insertTextFormat":1}<br>
> -# CHECK-DAG:<br>
> {"label":"priv()","kind":2,"de<wbr>tail":"void","sortText":"20003<wbr>4priv","filterText<br>
> ":"priv","insertText":"priv","<wbr>insertTextFormat":1}<br>
> -# CHECK: ]}<br>
> +# CHECK: {"id":3,"jsonrpc":"2.0","resul<wbr>t":[<br>
> +# CHECK-DAG:<br>
> {"detail":"void","filterText":<wbr>"pub","insertText":"pub","inse<wbr>rtTextFormat":1,"k<br>
> ind":2,"label":"pub()","sortTe<wbr>xt":"000034pub"}<br>
> +# CHECK-DAG:<br>
> {"detail":"void","filterText":<wbr>"prot","insertText":"prot","in<wbr>sertTextFormat":1,<br>
> "kind":2,"label":"prot()","sor<wbr>tText":"200034prot"}<br>
> +# CHECK-DAG:<br>
> {"detail":"void","filterText":<wbr>"priv","insertText":"priv","in<wbr>sertTextFormat":1,<br>
> "kind":2,"label":"priv()","sor<wbr>tText":"200034priv"}<br>
> +# CHECK-SAME: ]}<br>
><br>
>  Content-Length: 58<br>
><br>
>  {"jsonrpc":"2.0","id":4,"metho<wbr>d":"shutdown","params":null}<br>
> -# CHECK: {"jsonrpc":"2.0","id":4,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/comple<wbr>tion-<br>
> qualifiers.test?rev=317486&r1=<wbr>317485&r2=317486&view=diff<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<br>
> 07:40:30 2017<br>
> @@ -8,15 +8,14 @@ Content-Length: 297<br>
>  Content-Length: 151<br>
><br>
><br>
> {"jsonrpc":"2.0","id":2,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":11,"char<wbr>acter":8}}}<br>
> -# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[<br>
> -# CHECK-DAG: {"label":"foo()<br>
> const","kind":2,"detail":"int"<wbr>,"sortText":"200035foo","filte<wbr>rText":"foo","inse<br>
> rtText":"foo","insertTextForma<wbr>t":1}<br>
> -# CHECK-DAG: {"label":"bar()<br>
> const","kind":2,"detail":"int"<wbr>,"sortText":"000037bar","filte<wbr>rText":"bar","inse<br>
> rtText":"bar","insertTextForma<wbr>t":1}<br>
> -# CHECK-DAG: {"label":"Foo::foo()<br>
> const","kind":2,"detail":"int"<wbr>,"sortText":"000037foo","filte<wbr>rText":"foo","inse<br>
> rtText":"foo","insertTextForma<wbr>t":1}<br>
> -# CHECK: ]}<br>
> +# CHECK: {"id":2,"jsonrpc":"2.0","resul<wbr>t":[<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>foo","insertText":"foo","inser<wbr>tTextFormat":1,"ki<br>
> nd":2,"label":"foo() const","sortText":"200035foo"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>bar","insertText":"bar","inser<wbr>tTextFormat":1,"ki<br>
> nd":2,"label":"bar() const","sortText":"000037bar"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>foo","insertText":"foo","inser<wbr>tTextFormat":1,"ki<br>
> nd":2,"label":"Foo::foo() const","sortText":"000037foo"}<br>
> +# CHECK-SAME: ]}<br>
>  Content-Length: 44<br>
><br>
>  {"jsonrpc":"2.0","id":4,"metho<wbr>d":"shutdown"}<br>
> -# CHECK: {"jsonrpc":"2.0","id":4,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/comple<wbr>tion-<br>
> snippet.test?rev=317486&r1=317<wbr>485&r2=317486&view=diff<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<br>
> 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:<br>
> {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","in<br>
> sertText":"a","insertTextForma<wbr>t":1}<br>
> -# CHECK-DAG:<br>
> {"label":"bb","kind":5,"detail<wbr>":"int","sortText":"000035bb",<wbr>"filterText":"bb",<br>
> "insertText":"bb","insertTextF<wbr>ormat":1}<br>
> -# CHECK-DAG:<br>
> {"label":"ccc","kind":5,"detai<wbr>l":"int","sortText":"000035ccc<wbr>","filterText":"cc<br>
> c","insertText":"ccc","insertT<wbr>extFormat":1}<br>
> -# CHECK-DAG: {"label":"operator=(const fake &)","kind":2,"detail":"fake<br>
> &","sortText":"000079operator=<wbr>","filterText":"operator=","in<wbr>sertText":"operato<br>
> r=(${1:const fake &})","insertTextFormat":2}<br>
> -# CHECK-DAG:<br>
> {"label":"~fake()","kind":4,"d<wbr>etail":"void","sortText":"0000<wbr>79~fake","filterTe<br>
> xt":"~fake","insertText":"~fak<wbr>e()","insertTextFormat":1}<br>
> -# CHECK-DAG: {"label":"f(int i, const float f)<br>
> const","kind":2,"detail":"int"<wbr>,"sortText":"000035f","filterT<wbr>ext":"f","insertTe<br>
> xt":"f(${1:int i}, ${2:const float f})","insertTextFormat":2}<br>
> -# CHECK: ]}<br>
> +# CHECK: {"id":1,"jsonrpc":"2.0","resul<wbr>t":[<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>a","insertText":"a","insertTex<wbr>tFormat":1,"kind":<br>
> 5,"label":"a","sortText":"0000<wbr>35a"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>bb","insertText":"bb","insertT<wbr>extFormat":1,"kind<br>
> ":5,"label":"bb","sortText":"0<wbr>00035bb"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>ccc","insertText":"ccc","inser<wbr>tTextFormat":1,"ki<br>
> nd":5,"label":"ccc","sortText"<wbr>:"000035ccc"}<br>
> +# CHECK-DAG: {"detail":"fake<br>
> &","filterText":"operator=","i<wbr>nsertText":"operator=(${1:cons<wbr>t fake<br>
> &})","insertTextFormat":2,"kin<wbr>d":2,"label":"operator=(const fake<br>
> &)","sortText":"000079operator<wbr>="}<br>
> +# CHECK-DAG:<br>
> {"detail":"void","filterText":<wbr>"~fake","insertText":"~fake()"<wbr>,"insertTextFormat<br>
> ":1,"kind":4,"label":"~fake()"<wbr>,"sortText":"000079~fake"}<br>
> +# CHECK-DAG: {"detail":"int","filterText":"<wbr>f","insertText":"f(${1:int i},<br>
> ${2:const float f})","insertTextFormat":2,"kin<wbr>d":2,"label":"f(int i, const<br>
> float f) const","sortText":"000035f"}<br>
> +# CHECK-SAME: ]}<br>
>  Content-Length: 148<br>
><br>
><br>
> {"jsonrpc":"2.0","id":2,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":3,"chara<wbr>cter":5}}}<br>
>  # Repeat the completion request, expect the same results.<br>
>  #<br>
> -# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[<br>
> -# CHECK-DAG:<br>
> {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","in<br>
> sertText":"a","insertTextForma<wbr>t":1}<br>
> -# CHECK-DAG:<br>
> {"label":"bb","kind":5,"detail<wbr>":"int","sortText":"000035bb",<wbr>"filterText":"bb",<br>
> "insertText":"bb","insertTextF<wbr>ormat":1}<br>
> -# CHECK-DAG:<br>
> {"label":"ccc","kind":5,"detai<wbr>l":"int","sortText":"000035ccc<wbr>","filterText":"cc<br>
> c","insertText":"ccc","insertT<wbr>extFormat":1}<br>
> -# CHECK-DAG: {"label":"operator=(const fake &)","kind":2,"detail":"fake<br>
> &","sortText":"000079operator=<wbr>","filterText":"operator=","in<wbr>sertText":"operato<br>
> r=(${1:const fake &})","insertTextFormat":2}<br>
> -# CHECK-DAG:<br>
> {"label":"~fake()","kind":4,"d<wbr>etail":"void","sortText":"0000<wbr>79~fake","filterTe<br>
> xt":"~fake","insertText":"~fak<wbr>e()","insertTextFormat":1}<br>
> -# CHECK-DAG: {"label":"f(int i, const float f)<br>
> const","kind":2,"detail":"int"<wbr>,"sortText":"000035f","filterT<wbr>ext":"f","insertTe<br>
> xt":"f(${1:int i}, ${2:const float f})","insertTextFormat":2}<br>
> -# CHECK: ]}<br>
> +# CHECK: {"id":2,"jsonrpc":"2.0","resul<wbr>t":[<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>a","insertText":"a","insertTex<wbr>tFormat":1,"kind":<br>
> 5,"label":"a","sortText":"0000<wbr>35a"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>bb","insertText":"bb","insertT<wbr>extFormat":1,"kind<br>
> ":5,"label":"bb","sortText":"0<wbr>00035bb"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>ccc","insertText":"ccc","inser<wbr>tTextFormat":1,"ki<br>
> nd":5,"label":"ccc","sortText"<wbr>:"000035ccc"}<br>
> +# CHECK-DAG: {"detail":"fake<br>
> &","filterText":"operator=","i<wbr>nsertText":"operator=(${1:cons<wbr>t fake<br>
> &})","insertTextFormat":2,"kin<wbr>d":2,"label":"operator=(const fake<br>
> &)","sortText":"000079operator<wbr>="}<br>
> +# CHECK-DAG:<br>
> {"detail":"void","filterText":<wbr>"~fake","insertText":"~fake()"<wbr>,"insertTextFormat<br>
> ":1,"kind":4,"label":"~fake()"<wbr>,"sortText":"000079~fake"}<br>
> +# CHECK-DAG: {"detail":"int","filterText":"<wbr>f","insertText":"f(${1:int i},<br>
> ${2:const float f})","insertTextFormat":2,"kin<wbr>d":2,"label":"f(int i, const<br>
> 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>
><br>
> {"jsonrpc":"2.0","id":3,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":3,"chara<wbr>cter":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,<br>
> int)","sortText":"000034func",<wbr>"filterText":"func","insertTex<wbr>t":"func()","inser<br>
> tTextFormat":1}<br>
> -# CHECK: ]}<br>
> +# CHECK: {"id":3,"jsonrpc":"2.0","resul<wbr>t":[<br>
> +# CHECK-DAG: {"detail":"int (*)(int,<br>
> int)","filterText":"func","ins<wbr>ertText":"func()","insertTextF<wbr>ormat":1,"kind":2,<br>
> "label":"func()","sortText":"0<wbr>00034func"}<br>
> +# CHECK-SAME: ]}<br>
>  Content-Length: 44<br>
><br>
>  {"jsonrpc":"2.0","id":4,"metho<wbr>d":"shutdown"}<br>
> -# CHECK: {"jsonrpc":"2.0","id":4,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/comple<wbr>tion.test?rev=317486&r1=317485<wbr>&r2=317486&view=di<br>
> ff<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<br>
> 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:<br>
> {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","in<br>
> sertText":"a","insertTextForma<wbr>t":1}<br>
> -# CHECK-DAG:<br>
> {"label":"bb","kind":5,"detail<wbr>":"int","sortText":"000035bb",<wbr>"filterText":"bb",<br>
> "insertText":"bb","insertTextF<wbr>ormat":1}<br>
> -# CHECK-DAG:<br>
> {"label":"ccc","kind":5,"detai<wbr>l":"int","sortText":"000035ccc<wbr>","filterText":"cc<br>
> c","insertText":"ccc","insertT<wbr>extFormat":1}<br>
> -# CHECK-DAG: {"label":"operator=(const fake &)","kind":2,"detail":"fake<br>
> &","sortText":"000079operator=<wbr>","filterText":"operator=","in<wbr>sertText":"operato<br>
> r=","insertTextFormat":1}<br>
> -# CHECK-DAG:<br>
> {"label":"~fake()","kind":4,"d<wbr>etail":"void","sortText":"0000<wbr>79~fake","filterTe<br>
> xt":"~fake","insertText":"~fak<wbr>e","insertTextFormat":1}<br>
> -# CHECK-DAG: {"label":"f(int i, const float f)<br>
> const","kind":2,"detail":"int"<wbr>,"sortText":"000035f","filterT<wbr>ext":"f","insertTe<br>
> xt":"f","insertTextFormat":1}<br>
> -# CHECK: ]}<br>
> +# CHECK: {"id":1,"jsonrpc":"2.0","resul<wbr>t":[<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>a","insertText":"a","insertTex<wbr>tFormat":1,"kind":<br>
> 5,"label":"a","sortText":"0000<wbr>35a"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>bb","insertText":"bb","insertT<wbr>extFormat":1,"kind<br>
> ":5,"label":"bb","sortText":"0<wbr>00035bb"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>ccc","insertText":"ccc","inser<wbr>tTextFormat":1,"ki<br>
> nd":5,"label":"ccc","sortText"<wbr>:"000035ccc"}<br>
> +# CHECK-DAG: {"detail":"fake<br>
> &","filterText":"operator=","i<wbr>nsertText":"operator=","insert<wbr>TextFormat":1,"kin<br>
> d":2,"label":"operator=(const fake &)","sortText":"000079operator<wbr>="}<br>
> +# CHECK-DAG:<br>
> {"detail":"void","filterText":<wbr>"~fake","insertText":"~fake","<wbr>insertTextFormat":<br>
> 1,"kind":4,"label":"~fake()","<wbr>sortText":"000079~fake"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>f","insertText":"f","insertTex<wbr>tFormat":1,"kind":<br>
> 2,"label":"f(int i, const float f) const","sortText":"000035f"}<br>
> +# CHECK-SAME: ]}<br>
>  Content-Length: 148<br>
><br>
><br>
> {"jsonrpc":"2.0","id":2,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":3,"chara<wbr>cter":5}}}<br>
>  # Repeat the completion request, expect the same results.<br>
>  #<br>
> -# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[<br>
> -# CHECK-DAG:<br>
> {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","in<br>
> sertText":"a","insertTextForma<wbr>t":1}<br>
> -# CHECK-DAG:<br>
> {"label":"bb","kind":5,"detail<wbr>":"int","sortText":"000035bb",<wbr>"filterText":"bb",<br>
> "insertText":"bb","insertTextF<wbr>ormat":1}<br>
> -# CHECK-DAG:<br>
> {"label":"ccc","kind":5,"detai<wbr>l":"int","sortText":"000035ccc<wbr>","filterText":"cc<br>
> c","insertText":"ccc","insertT<wbr>extFormat":1}<br>
> -# CHECK-DAG: {"label":"operator=(const fake &)","kind":2,"detail":"fake<br>
> &","sortText":"000079operator=<wbr>","filterText":"operator=","in<wbr>sertText":"operato<br>
> r=","insertTextFormat":1}<br>
> -# CHECK-DAG:<br>
> {"label":"~fake()","kind":4,"d<wbr>etail":"void","sortText":"0000<wbr>79~fake","filterTe<br>
> xt":"~fake","insertText":"~fak<wbr>e","insertTextFormat":1}<br>
> -# CHECK-DAG: {"label":"f(int i, const float f)<br>
> const","kind":2,"detail":"int"<wbr>,"sortText":"000035f","filterT<wbr>ext":"f","insertTe<br>
> xt":"f","insertTextFormat":1}<br>
> -# CHECK: ]}<br>
> +# CHECK: {"id":2,"jsonrpc":"2.0","resul<wbr>t":[<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>a","insertText":"a","insertTex<wbr>tFormat":1,"kind":<br>
> 5,"label":"a","sortText":"0000<wbr>35a"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>bb","insertText":"bb","insertT<wbr>extFormat":1,"kind<br>
> ":5,"label":"bb","sortText":"0<wbr>00035bb"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>ccc","insertText":"ccc","inser<wbr>tTextFormat":1,"ki<br>
> nd":5,"label":"ccc","sortText"<wbr>:"000035ccc"}<br>
> +# CHECK-DAG: {"detail":"fake<br>
> &","filterText":"operator=","i<wbr>nsertText":"operator=","insert<wbr>TextFormat":1,"kin<br>
> d":2,"label":"operator=(const fake &)","sortText":"000079operator<wbr>="}<br>
> +# CHECK-DAG:<br>
> {"detail":"void","filterText":<wbr>"~fake","insertText":"~fake","<wbr>insertTextFormat":<br>
> 1,"kind":4,"label":"~fake()","<wbr>sortText":"000079~fake"}<br>
> +# CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>f","insertText":"f","insertTex<wbr>tFormat":1,"kind":<br>
> 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>
> @@ -46,13 +46,12 @@ Content-Length: 148<br>
><br>
> {"jsonrpc":"2.0","id":3,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":3,"chara<wbr>cter":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,<br>
> int)","sortText":"000034func",<wbr>"filterText":"func","insertTex<wbr>t":"func","insertT<br>
> extFormat":1}<br>
> -# CHECK: ]}<br>
> +# CHECK: {"id":3,"jsonrpc":"2.0","resul<wbr>t":[<br>
> +# CHECK-DAG: {"detail":"int (*)(int,<br>
> int)","filterText":"func","ins<wbr>ertText":"func","insertTextFor<wbr>mat":1,"kind":2,"l<br>
> abel":"func()","sortText":"000<wbr>034func"}<br>
> +# CHECK-SAME: ]}<br>
>  Content-Length: 44<br>
><br>
>  {"jsonrpc":"2.0","id":4,"metho<wbr>d":"shutdown"}<br>
> -# CHECK: {"jsonrpc":"2.0","id":4,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/defini<wbr>tions.test?rev=317486&r1=31748<wbr>5&r2=317486&view=d<br>
> iff<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<br>
> 2017<br>
> @@ -1,4 +1,4 @@<br>
> -# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
> +# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace<br>
> %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>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":2,"chara<wbr>cter":0}}}<br>
>  # Go to local variable<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1,<br>
> "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>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":2,"chara<wbr>cter":1}}}<br>
>  # Go to local variable, end of token<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":2},"contentChanges":[{"tex<wbr>t":"struct Foo<br>
> {\nint x;\n};\nint main() {\n  Foo bar = { x : 1 };\n}\n"}]}}<br>
> @@ -29,8 +59,23 @@ Content-Length: 149<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":4,"chara<wbr>cter":14}}}<br>
>  # Go to field, GNU old-style field designator<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":3},"contentChanges":[{"tex<wbr>t":"struct Foo<br>
> {\nint x;\n};\nint main() {\n  Foo baz = { .x = 2 };\n}\n"}]}}<br>
> @@ -39,8 +84,23 @@ Content-Length: 149<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":4,"chara<wbr>cter":15}}}<br>
>  # Go to field, field designator<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":4},"contentChanges":[{"tex<wbr>t":"int main() {\n<br>
> main();\n   return 0;\n}"}]}}<br>
> @@ -49,8 +109,23 @@ Content-Length: 148<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":1,"chara<wbr>cter":3}}}<br>
>  # Go to function declaration, function call<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 0, "character": 0}, "end": {"line": 3,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":5},"contentChanges":[{"tex<wbr>t":"struct Foo<br>
> {\n};\nint main() {\n   Foo bar;\n   return 0;\n}\n"}]}}<br>
> @@ -59,8 +134,23 @@ Content-Length: 148<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":3,"chara<wbr>cter":3}}}<br>
>  # Go to struct declaration, new struct instance<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 0, "character": 0}, "end": {"line": 1,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":5},"contentChanges":[{"tex<wbr>t":"namespace n1<br>
> {\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>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":5,"chara<wbr>cter":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",<br>
> "range": {"start": {"line": 0, "character": 0}, "end": {"line": 3,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":6},"contentChanges":[{"tex<wbr>t":"struct Foo {\n<br>
> int x;\n};\nint main() {\n   Foo bar;\n   bar.x;\n}\n"}]}}<br>
> @@ -79,8 +184,23 @@ Content-Length: 148<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":5,"chara<wbr>cter":7}}}<br>
>  # Go to field declaration, field reference<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 1, "character": 2}, "end": {"line": 1,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":7},"contentChanges":[{"tex<wbr>t":"struct Foo {\n<br>
> void x();\n};\nint main() {\n   Foo bar;\n   bar.x();\n}\n"}]}}<br>
> @@ -89,8 +209,23 @@ Content-Length: 148<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":5,"chara<wbr>cter":7}}}<br>
>  # Go to method declaration, method call<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 1, "character": 2}, "end": {"line": 1,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":7},"contentChanges":[{"tex<wbr>t":"struct Foo<br>
> {\n};\ntypedef Foo TypedefFoo;\nint main() {\n   TypedefFoo bar;\n   return<br>
> 0;\n}\n"}]}}<br>
> @@ -99,8 +234,23 @@ Content-Length: 149<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":4,"chara<wbr>cter":10}}}<br>
>  # Go to typedef<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 2, "character": 0}, "end": {"line": 2,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":7},"contentChanges":[{"tex<wbr>t":"template<br>
> <typename MyTemplateParam>\nvoid foo() {\n MyTemplateParam a;\n}\nint main()<br>
> {\n   return 0;\n}\n"}]}}<br>
> @@ -109,8 +259,9 @@ Content-Length: 149<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":2,"chara<wbr>cter":13}}}<br>
>  # Go to template type parameter. Fails until clangIndex is modified to handle<br>
> those.<br>
> -# no-CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 0, "character": 10}, "end": {"line": 0,<br>
> "character": 34}}}]}<br>
> -<br>
> +#      CHECK:  "id": 1,<br>
> +# CHECK-NEXT:  "jsonrpc": "2.0",<br>
> +# CHECK-NEXT:  "result": []<br>
>  Content-Length: 256<br>
><br>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":7},"contentChanges":[{"tex<wbr>t":"namespace ns<br>
> {\nstruct Foo {\nstatic void bar() {}\n};\n}\nint main() {\n<br>
> ns::Foo::bar();\n   return 0;\n}\n"}]}}<br>
> @@ -119,8 +270,23 @@ Content-Length: 148<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":6,"chara<wbr>cter":4}}}<br>
>  # Go to namespace, static method call<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 0, "character": 0}, "end": {"line": 4,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":7},"contentChanges":[{"tex<wbr>t":"namespace ns<br>
> {\nstruct Foo {\n  int field;\n  Foo(int param) : field(param) {}\n};\n}\nint<br>
> main() {\n   return 0;\n}\n"}]}}<br>
> @@ -128,9 +294,24 @@ Content-Length: 265<br>
>  Content-Length: 149<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":3,"chara<wbr>cter":21}}}<br>
> -# Go to field, member initializer<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 2, "character": 2}, "end": {"line": 2,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":7},"contentChanges":[{"tex<wbr>t":"#define<br>
> MY_MACRO 0\nint main() {\n  return MY_MACRO;\n}\n"}]}}<br>
> @@ -139,8 +320,23 @@ Content-Length: 148<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":2,"chara<wbr>cter":9}}}<br>
>  # Go to macro.<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///{{([A-Za-<br>
> z]:/)?}}main.cpp", "range": {"start": {"line": 0, "character": 8}, "end":<br>
> {"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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///main.cpp","versi<wbr>on":7},"contentChanges":[{"tex<wbr>t":"#define FOO<br>
> 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>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":1,"chara<wbr>cter":8}}}<br>
>  # Go to macro, re-defined later<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///{{([A-Za-<br>
> z]:/)?}}main.cpp", "range": {"start": {"line": 0, "character": 8}, "end":<br>
> {"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>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":3,"chara<wbr>cter":8}}}<br>
>  # Go to macro, undefined later<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 2, "character": 8}, "end": {"line": 2,<br>
> "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>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///main.cpp<wbr>"},"position":{"line":4,"chara<wbr>cter":7}}}<br>
>  # Go to macro, being undefined<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"uri": "file:///main.cpp",<br>
> "range": {"start": {"line": 2, "character": 8}, "end": {"line": 2,<br>
> "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>
><br>
> {"jsonrpc":"2.0","id":2,"metho<wbr>d":"textDocument/definition","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///doesnote<wbr>xist.cpp"},"position":{"line":<wbr>4,"character":7}}}<br>
> -# CHECK: {"jsonrpc":"2.0","id":2,"error<wbr>":{"code":-<br>
> 32602,"message":"findDefinitio<wbr>ns 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,"m<wbr>ethod":"shutdown"}<br>
> -# CHECK: {"jsonrpc":"2.0","id":10000,"r<wbr>esult":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/diagno<wbr>stics-<br>
> preamble.test?rev=317486&r1=31<wbr>7485&r2=317486&view=diff<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<br>
> 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<br>
> %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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didOpen","params":{"<wbr>textDocument":{"ur<br>
> i":"file:///main.cpp","languag<wbr>eId":"cpp","version":1,"text":<wbr>"#ifndef<br>
> FOO\n#define FOO\nint a;\n#else\nint a = b;#endif\n\n\n"}}}<br>
> -# CHECK:<br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"f<br>
> ile:///main.cpp","diagnostics"<wbr>:[]}}<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,"metho<wbr>d":"shutdown","params":null}<br>
> -# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/diagno<wbr>stics.test?rev=317486&r1=31748<wbr>5&r2=317486&view=d<br>
> iff<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<br>
> 2017<br>
> @@ -1,4 +1,4 @@<br>
> -# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
> +# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace<br>
> %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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didOpen","params":{"<wbr>textDocument":{"ur<br>
> i":"file:///foo.c","languageId<wbr>":"c","version":1,"text":"void main() {}"}}}<br>
> -#<br>
> -# CHECK:<br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"f<br>
> ile:///foo.c","diagnostics":[{<wbr>"range":{"start": {"line": 0, "character": 1},<br>
> "end": {"line": 0, "character": 1}},"severity":2,"message":"re<wbr>turn type of<br>
> 'main' is not 'int'"},{"range":{"start": {"line": 0, "character": 1}, "end":<br>
> {"line": 0, "character": 1}},"severity":3,"message":"ch<wbr>ange return type to<br>
> '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,"metho<wbr>d":"shutdown"}<br>
> -# CHECK: {"jsonrpc":"2.0","id":5,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/did-ch<wbr>ange-watch-<br>
> files.test?rev=317486&r1=31748<wbr>5&r2=317486&view=diff<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<br>
> 07:40:30 2017<br>
> @@ -5,18 +5,7 @@<br>
>  Content-Length: 143<br>
><br>
><br>
> {"jsonrpc":"2.0","id":0,"metho<wbr>d":"initialize","params":{"pro<wbr>cessId":123,"rootU<br>
> ri":"file:///path/to/workspace<wbr>","capabilities":{},"trace":"o<wbr>ff"}}<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":<br>
> {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
> -# CHECK:   "codeActionProvider": true,<br>
> -# CHECK:   "completionProvider": {"resolveProvider": false,<br>
> "triggerCharacters": [".",">",":"]},<br>
> -# CHECK:   "definitionProvider": true<br>
> -# CHECK: }}}<br>
> -#<br>
> -#Normal case<br>
> +# Normal case.<br>
>  Content-Length: 217<br>
><br>
><br>
> {"jsonrpc":"2.0","method":"wor<wbr>kspace/didChangeWatchedFiles",<wbr>"params":{"changes<br>
> ":[{"uri":"file:///path/to/fil<wbr>e.cpp","type":1},{"uri":"file:<wbr>///path/to/file2.c<br>
> pp","type":2},{"uri":"file:///<wbr>path/to/file3.cpp","type":3}]}<wbr>}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/execut<wbr>e-<br>
> command.test?rev=317486&r1=317<wbr>485&r2=317486&view=diff<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<br>
> 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<br>
> %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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didOpen","params":{"<wbr>textDocument":{"ur<br>
> i":"file:///foo.c","languageId<wbr>":"c","version":1,"text":"int main(int i, char<br>
> **a) { if (i = 2) {}}"}}}<br>
> -#<br>
> -# CHECK:<br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"f<br>
> ile:///foo.c","diagnostics":[{<wbr>"range":{"start": {"line": 0, "character": 35},<br>
> "end": {"line": 0, "character": 35}},"severity":2,"message":"u<wbr>sing the result<br>
> of an assignment as a condition without parentheses"},{"range":{"start<wbr>":<br>
> {"line": 0, "character": 35}, "end": {"line": 0, "character":<br>
> 35}},"severity":3,"message":"p<wbr>lace parentheses around the assignment to<br>
> silence this warning"},{"range":{"start": {"line": 0, "character": 35}, "end":<br>
> {"line": 0, "character": 35}},"severity":3,"message":"u<wbr>se '==' to turn this<br>
> 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<br>
> 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<br>
> 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<br>
> 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,"metho<wbr>d":"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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/extra-<br>
> flags.test?rev=317486&r1=31748<wbr>5&r2=317486&view=diff<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<br>
> 2017<br>
> @@ -1,4 +1,4 @@<br>
> -# RUN: clangd -run-synchronously < %s | FileCheck %s<br>
> +# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace<br>
> %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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didOpen","params":{"<wbr>textDocument":{"ur<br>
> i":"file:///foo.c","languageId<wbr>":"c","version":1,"text":"int main() { int i;<br>
> return i; }"},"metadata":{"extraFlags":[<wbr>"-Wall"]}}}<br>
> -# CHECK:<br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"f<br>
> ile:///foo.c","diagnostics":[{<wbr>"range":{"start": {"line": 0, "character": 28},<br>
> "end": {"line": 0, "character": 28}},"severity":2,"message":"v<wbr>ariable 'i' is<br>
> uninitialized when used here"},{"range":{"start": {"line": 0, "character":<br>
> 19}, "end": {"line": 0, "character": 19}},"severity":3,"message":"i<wbr>nitialize<br>
> 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<br>
> 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<br>
> 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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///foo.c","version"<wbr>:2},"contentChanges":[{"text":<wbr>"int main() { int<br>
> i; return i; }"}]}}<br>
> -# CHECK:<br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"f<br>
> ile:///foo.c","diagnostics":[{<wbr>"range":{"start": {"line": 0, "character": 28},<br>
> "end": {"line": 0, "character": 28}},"severity":2,"message":"v<wbr>ariable 'i' is<br>
> uninitialized when used here"},{"range":{"start": {"line": 0, "character":<br>
> 19}, "end": {"line": 0, "character": 19}},"severity":3,"message":"i<wbr>nitialize<br>
> 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<br>
> 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<br>
> 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,"metho<wbr>d":"shutdown"}<br>
> -# CHECK: {"jsonrpc":"2.0","id":5,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/fixits<wbr>.test?rev=317486&r1=317485&r2=<wbr>317486&view=diff<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<br>
> %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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didOpen","params":{"<wbr>textDocument":{"ur<br>
> i":"file:///foo.c","languageId<wbr>":"c","version":1,"text":"int main(int i, char<br>
> **a) { if (i = 2) {}}"}}}<br>
> -#<br>
> -# CHECK:<br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/publishDiagnostics",<wbr>"params":{"uri":"f<br>
> ile:///foo.c","diagnostics":[{<wbr>"range":{"start": {"line": 0, "character": 35},<br>
> "end": {"line": 0, "character": 35}},"severity":2,"message":"u<wbr>sing the result<br>
> of an assignment as a condition without parentheses"},{"range":{"start<wbr>":<br>
> {"line": 0, "character": 35}, "end": {"line": 0, "character":<br>
> 35}},"severity":3,"message":"p<wbr>lace parentheses around the assignment to<br>
> silence this warning"},{"range":{"start": {"line": 0, "character": 35}, "end":<br>
> {"line": 0, "character": 35}},"severity":3,"message":"u<wbr>se '==' to turn this<br>
> 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<br>
> 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<br>
> 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<br>
> 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>
><br>
> {"jsonrpc":"2.0","id":2,"metho<wbr>d":"textDocument/codeAction","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///foo.c"},<wbr>"range":{"start":{"line":104,"<wbr>character":13},"en<br>
> d":{"line":0,"character":35}},<wbr>"context":{"diagnostics":[{"ra<wbr>nge":{"start":<br>
> {"line": 0, "character": 35}, "end": {"line": 0, "character":<br>
> 35}},"severity":2,"message":"u<wbr>sing the result of an assignment as a condition<br>
> without parentheses"},{"range":{"start<wbr>": {"line": 0, "character": 35}, "end":<br>
> {"line": 0, "character": 35}},"severity":3,"message":"p<wbr>lace parentheses around<br>
> the assignment to silence this warning"},{"range":{"start": {"line": 0,<br>
> "character": 35}, "end": {"line": 0, "character":<br>
> 35}},"severity":3,"message":"u<wbr>se '==' to turn this assignment into an equality<br>
> comparison"}]}}}<br>
> -#<br>
> -# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":[{"title":"Apply FixIt 'place<br>
> parentheses around the assignment to silence this warning'", "command":<br>
> "clangd.applyFix", "arguments": [{"changes": {"file:///foo.c": [{"range":<br>
> {"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 32}},<br>
> "newText": "("},{"range": {"start": {"line": 0, "character": 37}, "end":<br>
> {"line": 0, "character": 37}}, "newText": ")"}]}}]},{"title":"Apply FixIt 'use<br>
> '==' to turn this assignment into an equality comparison'", "command":<br>
> "clangd.applyFix", "arguments": [{"changes": {"file:///foo.c": [{"range":<br>
> {"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}},<br>
> "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<br>
> 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<br>
> into an equality comparison"<br>
> +# CHECK-NEXT:    }<br>
> +# CHECK-NEXT:  ]<br>
>  Content-Length: 771<br>
><br>
> -<br>
> {"jsonrpc":"2.0","id":2,"metho<wbr>d":"textDocument/codeAction","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///foo.c"},<wbr>"range":{"start":{"line":104,"<wbr>character":13},"en<br>
> d":{"line":0,"character":35}},<wbr>"context":{"diagnostics":[{"ra<wbr>nge":{"start":<br>
> {"line": 0, "character": 35}, "end": {"line": 0, "character":<br>
> 35}},"severity":2,"code":"1","<wbr>source":"foo","message":"using the result of an<br>
> assignment as a condition without parentheses"},{"range":{"start<wbr>": {"line": 0,<br>
> "character": 35}, "end": {"line": 0, "character":<br>
> 35}},"severity":3,"message":"p<wbr>lace parentheses around the assignment to<br>
> silence this warning"},{"range":{"start": {"line": 0, "character": 35}, "end":<br>
> {"line": 0, "character": 35}},"severity":3,"message":"u<wbr>se '==' to turn this<br>
> assignment into an equality comparison"}]}}}<br>
> +{"jsonrpc":"2.0","id":3,"meth<wbr>od":"textDocument/codeAction",<wbr>"params":{"textDoc<br>
> ument":{"uri":"file:///foo.c"}<wbr>,"range":{"start":{"line":104,<wbr>"character":13},"e<br>
> nd":{"line":0,"character":35}}<wbr>,"context":{"diagnostics":[{"r<wbr>ange":{"start":<br>
> {"line": 0, "character": 35}, "end": {"line": 0, "character":<br>
> 35}},"severity":2,"code":"1","<wbr>source":"foo","message":"using the result of an<br>
> assignment as a condition without parentheses"},{"range":{"start<wbr>": {"line": 0,<br>
> "character": 35}, "end": {"line": 0, "character":<br>
> 35}},"severity":3,"message":"p<wbr>lace parentheses around the assignment to<br>
> silence this warning"},{"range":{"start": {"line": 0, "character": 35}, "end":<br>
> {"line": 0, "character": 35}},"severity":3,"message":"u<wbr>se '==' to turn this<br>
> 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<br>
> parentheses around the assignment to silence this warning'", "command":<br>
> "clangd.applyFix", "arguments": [{"changes": {"file:///foo.c": [{"range":<br>
> {"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 32}},<br>
> "newText": "("},{"range": {"start": {"line": 0, "character": 37}, "end":<br>
> {"line": 0, "character": 37}}, "newText": ")"}]}}]},{"title":"Apply FixIt 'use<br>
> '==' to turn this assignment into an equality comparison'", "command":<br>
> "clangd.applyFix", "arguments": [{"changes": {"file:///foo.c": [{"range":<br>
> {"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}},<br>
> "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<br>
> 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<br>
> into an equality comparison"<br>
> +# CHECK-NEXT:    }<br>
> +# CHECK-NEXT:  ]<br>
>  Content-Length: 329<br>
><br>
> -<br>
> {"jsonrpc":"2.0","id":3,"metho<wbr>d":"workspace/executeCommand",<wbr>"params":{"command<br>
> ":"clangd.applyFix","arguments<wbr>":[{"changes":{"file:///foo.c"<wbr>:[{"range":{"start<br>
> ":{"line":0,"character":32},"e<wbr>nd":{"line":0,"character":32}}<wbr>,"newText":"("},{"<br>
> range":{"start":{"line":0,"cha<wbr>racter":37},"end":{"line":0,"c<wbr>haracter":37}},"ne<br>
> wText":")"}]}}]}}<br>
> -# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":"Fix applied."}<br>
> -# CHECK:<br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"workspace/applyEdit","para<wbr>ms":{"edit":<br>
> {"changes": {"file:///foo.c": [{"range": {"start": {"line": 0, "character":<br>
> 32}, "end": {"line": 0, "character": 32}}, "newText": "("},{"range": {"start":<br>
> {"line": 0, "character": 37}, "end": {"line": 0, "character": 37}}, "newText":<br>
> ")"}]}}}}<br>
> +{"jsonrpc":"2.0","id":4,"meth<wbr>od":"workspace/executeCommand"<wbr>,"params":{"comman<br>
> d":"clangd.applyFix","argument<wbr>s":[{"changes":{"file:///foo.c<wbr>":[{"range":{"star<br>
> t":{"line":0,"character":32},"<wbr>end":{"line":0,"character":32}<wbr>},"newText":"("},{<br>
> "range":{"start":{"line":0,"ch<wbr>aracter":37},"end":{"line":0,"<wbr>character":37}},"n<br>
> ewText":")"}]}}]}}<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":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/format<wbr>ting.test?rev=317486&r1=317485<wbr>&r2=317486&view=di<br>
> ff<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<br>
> 2017<br>
> @@ -1,30 +1,71 @@<br>
> -# RUN: clangd < %s | FileCheck %s<br>
> +# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace<br>
> %s<br>
>  # It is absolutely vital that this file has CRLF line endings.<br>
>  #<br>
>  Content-Length: 125<br>
><br>
><br>
> {"jsonrpc":"2.0","id":0,"metho<wbr>d":"initialize","params":{"pro<wbr>cessId":123,"rootP<br>
> ath":"clangd","capabilities":{<wbr>},"trace":"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":<br>
> {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
> -# CHECK:   "codeActionProvider": true,<br>
> -# CHECK:   "completionProvider": {"resolveProvider": false,<br>
> "triggerCharacters": [".",">",":"]},<br>
> -# CHECK:   "definitionProvider": true<br>
> -# CHECK: }}}<br>
> -#<br>
>  Content-Length: 193<br>
><br>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didOpen","params":{"<wbr>textDocument":{"ur<br>
> i":"file:///foo.c","languageId<wbr>":"c","version":1,"text":"int foo ( int x ) {\n<br>
> x = x+1;\n    return x;\n    }"}}}<br>
> -#<br>
> -#<br>
>  Content-Length: 233<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/rangeFormatti<wbr>ng","params":{"tex<br>
> tDocument":{"uri":"file:///foo<wbr>.c"},"range":{"start":{"line":<wbr>1,"character":4},"<br>
> end":{"line":1,"character":12}<wbr>},"options":{"tabSize":4,"inse<wbr>rtSpaces":true}}}<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[{"range": {"start": {"line": 0,<br>
> "character": 19}, "end": {"line": 1, "character": 4}}, "newText": "\n<br>
> "},{"range": {"start": {"line": 1, "character": 9}, "end": {"line": 1,<br>
> "character": 9}}, "newText": " "},{"range": {"start": {"line": 1, "character":<br>
> 10}, "end": {"line": 1, "character": 10}}, "newText": " "},{"range": {"start":<br>
> {"line": 1, "character": 12}, "end": {"line": 2, "character": 4}}, "newText":<br>
> "\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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///foo.c","version"<wbr>:5},"contentChanges":[{"text":<wbr>"int foo ( int x )<br>
> {\n  x = x + 1;\n  return x;\n    }"}]}}<br>
> @@ -33,14 +74,68 @@ Content-Length: 197<br>
>  Content-Length: 233<br>
><br>
><br>
> {"jsonrpc":"2.0","id":2,"metho<wbr>d":"textDocument/rangeFormatti<wbr>ng","params":{"tex<br>
> tDocument":{"uri":"file:///foo<wbr>.c"},"range":{"start":{"line":<wbr>1,"character":2},"<br>
> end":{"line":1,"character":12}<wbr>},"options":{"tabSize":4,"inse<wbr>rtSpaces":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>
><br>
> {"jsonrpc":"2.0","id":3,"metho<wbr>d":"textDocument/formatting","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///foo.c"},<wbr>"options":{"tabSize":4,"insert<wbr>Spaces":true}}}<br>
> -# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":[{"range": {"start": {"line": 0,<br>
> "character": 7}, "end": {"line": 0, "character": 8}}, "newText": ""},{"range":<br>
> {"start": {"line": 0, "character": 9}, "end": {"line": 0, "character": 10}},<br>
> "newText": ""},{"range": {"start": {"line": 0, "character": 15}, "end":<br>
> {"line": 0, "character": 16}}, "newText": ""},{"range": {"start": {"line": 2,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///foo.c","version"<wbr>:9},"contentChanges":[{"text":<wbr>"int foo(int x)<br>
> {\n  x = x + 1;\n  return x;\n}"}]}}<br>
> @@ -49,8 +144,9 @@ Content-Length: 190<br>
>  Content-Length: 153<br>
><br>
><br>
> {"jsonrpc":"2.0","id":4,"metho<wbr>d":"textDocument/formatting","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:///foo.c"},<wbr>"options":{"tabSize":4,"insert<wbr>Spaces":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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didChange","params":<wbr>{"textDocument":{"<br>
> uri":"file:///foo.c","version"<wbr>:5},"contentChanges":[{"text":<wbr>"int foo ( int x )<br>
> {\n  x = x + 1;\n  return x;\n}"}]}}<br>
> @@ -59,13 +155,53 @@ Content-Length: 193<br>
>  Content-Length: 204<br>
><br>
><br>
> {"jsonrpc":"2.0","id":5,"metho<wbr>d":"textDocument/onTypeFormatt<wbr>ing","params":{"te<br>
> xtDocument":{"uri":"file:///fo<wbr>o.c"},"position":{"line":3,"ch<wbr>aracter":1},"ch":"<br>
> }","options":{"tabSize":4,"ins<wbr>ertSpaces":true}}}<br>
> -# CHECK: {"jsonrpc":"2.0","id":5,"resul<wbr>t":[{"range": {"start": {"line": 0,<br>
> "character": 7}, "end": {"line": 0, "character": 8}}, "newText": ""},{"range":<br>
> {"start": {"line": 0, "character": 9}, "end": {"line": 0, "character": 10}},<br>
> "newText": ""},{"range": {"start": {"line": 0, "character": 15}, "end":<br>
> {"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,"metho<wbr>d":"shutdown"}<br>
> -# CHECK: {"jsonrpc":"2.0","id":6,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/initia<wbr>lize-params-<br>
> invalid.test?rev=317486&r1=317<wbr>485&r2=317486&view=diff<br>
> ==============================<wbr>==============================<wbr>==================<br>
> --- clang-tools-extra/trunk/test/c<wbr>langd/initialize-params-invali<wbr>d.test<br>
> (original)<br>
> +++ clang-tools-extra/trunk/test/c<wbr>langd/initialize-params-invali<wbr>d.test Mon Nov<br>
> 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<br>
> %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>
><br>
> {"jsonrpc":"2.0","id":0,"metho<wbr>d":"initialize","params":{"pro<wbr>cessId":"","rootUr<br>
> i":"file:///path/to/workspace"<wbr>,"capabilities":{},"trace":"of<wbr>f"}}<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":<br>
> {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
> -# CHECK:   "codeActionProvider": true,<br>
> -# CHECK:   "completionProvider": {"resolveProvider": false,<br>
> "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,"metho<wbr>d":"shutdown"}<br>
> -# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/initia<wbr>lize-<br>
> params.test?rev=317486&r1=3174<wbr>85&r2=317486&view=diff<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<br>
> 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<br>
> %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>
><br>
> {"jsonrpc":"2.0","id":0,"metho<wbr>d":"initialize","params":{"pro<wbr>cessId":123,"rootU<br>
> ri":"file:///path/to/workspace<wbr>","capabilities":{},"trace":"o<wbr>ff"}}<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":<br>
> {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
> -# CHECK:   "codeActionProvider": true,<br>
> -# CHECK:   "completionProvider": {"resolveProvider": false,<br>
> "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,"metho<wbr>d":"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":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/input-<br>
> mirror.test?rev=317486&r1=3174<wbr>85&r2=317486&view=diff<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<br>
> 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<br>
> 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,"metho<wbr>d":"shutdown"}<br>
> -# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/protoc<wbr>ol.test?rev=317486&r1=317485&r<wbr>2=317486&view=diff<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-<br>
> prefix=STDERR %s<br>
> +# RUN: not clangd -pretty -run-synchronously < %s | FileCheck -strict-<br>
> whitespace %s<br>
> +# RUN: not clangd -pretty -run-synchronously < %s 2>&1 | FileCheck -check-<br>
> 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>
><br>
> {"jsonrpc":"2.0","id":0,"metho<wbr>d":"initialize","params":{"pro<wbr>cessId":123,"rootP<br>
> ath":"clangd","capabilities":{<wbr>},"trace":"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":<br>
> {"firstTriggerCharacter":"}","<wbr>moreTriggerCharacter":[]},<br>
> -# CHECK-DAG: "codeActionProvider": true,<br>
> -# CHECK-DAG: "completionProvider": {"resolveProvider": false,<br>
> "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>
><br>
> {"jsonrpc":"2.0","method":"tex<wbr>tDocument/didOpen","params":{"<wbr>textDocument":{"ur<br>
> i":"file:///main.cpp","languag<wbr>eId":"cpp","version":1,"text":<wbr>"struct fake { int<br>
> a, bb, ccc; int f(int i, const float f) const; };\nint main() {\n  fake f;\n<br>
> f.\n}\n"}}}<br>
> @@ -36,9 +29,16 @@ Content-Length: 146<br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:/main.cpp"}<wbr>,"position":{"line":3,"charact<wbr>er":5}}}<br>
>  # Test message with Content-Type before Content-Length<br>
>  #<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"resul<wbr>t":[<br>
> -# CHECK-DAG:<br>
> {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","in<br>
> sertText":"a","insertTextForma<wbr>t":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>
><br>
> {"jsonrpc":"2.0","id":3,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:/main.cpp"}<wbr>,"position":{"line":3,"charact<wbr>er":5}}}<br>
>  # Test message with duplicate Content-Length headers<br>
>  #<br>
> -# CHECK: {"jsonrpc":"2.0","id":3,"resul<wbr>t":[<br>
> -# CHECK-DAG:<br>
> {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","in<br>
> sertText":"a","insertTextForma<wbr>t":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<br>
> 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>
><br>
> {"jsonrpc":"2.0","id":5,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:/main.cpp"}<wbr>,"position":{"line":3,"charact<wbr>er":5}}}<br>
>  # Test message with Content-Type before Content-Length<br>
>  #<br>
> -# CHECK: {"jsonrpc":"2.0","id":5,"resul<wbr>t":[<br>
> -# CHECK-DAG:<br>
> {"label":"a","kind":5,"detail"<wbr>:"int","sortText":"000035a","f<wbr>ilterText":"a","in<br>
> sertText":"a","insertTextForma<wbr>t":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>
><br>
> {"jsonrpc":"2.0","id":5,"metho<wbr>d":"textDocument/completion","<wbr>params":{"textDocu<br>
> ment":{"uri":"file:/main.cpp"}<wbr>,"position":{"line":3,"charact<wbr>er":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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/signat<wbr>ure-<br>
> help.test?rev=317486&r1=317485<wbr>&r2=317486&view=diff<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<br>
> 07:40:30 2017<br>
> @@ -15,12 +15,12 @@ Content-Length: 333<br>
>  Content-Length: 151<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/signatureHelp<wbr>","params":{"textD<br>
> ocument":{"uri":"file:///main.<wbr>cpp"},"position":{"line":8,"ch<wbr>aracter":9}}}<br>
> -# CHECK:<br>
> {"jsonrpc":"2.0","id":1,"resul<wbr>t":{"activeSignature":0,"activ<wbr>eParameter":0,"sig<br>
> natures":[<br>
> +# CHECK:<br>
> {"id":1,"jsonrpc":"2.0","resul<wbr>t":{"activeParameter":0,"activ<wbr>eSignature":0,"sig<br>
> natures":[<br>
>  # CHECK-DAG: {"label":"foo(float x, float y) -><br>
> void","parameters":[{"label":"<wbr>float x"},{"label":"float y"}]}<br>
>  # CHECK-DAG: {"label":"foo(float x, int y) -><br>
> void","parameters":[{"label":"<wbr>float x"},{"label":"int y"}]}<br>
>  # CHECK-DAG: {"label":"foo(int x, float y) -><br>
> void","parameters":[{"label":"<wbr>int x"},{"label":"float y"}]}<br>
>  # CHECK-DAG: {"label":"foo(int x, int y) -> void","parameters":[{"label":"<wbr>int<br>
> 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>
><br>
> {"jsonrpc":"2.0","id":2,"metho<wbr>d":"textDocument/signatureHelp<wbr>","params":{"textD<br>
> ocument":{"uri":"file:///main.<wbr>cpp"},"position":{"line":8,"ch<wbr>aracter":9}}}<br>
> -# CHECK:<br>
> {"jsonrpc":"2.0","id":2,"resul<wbr>t":{"activeSignature":0,"activ<wbr>eParameter":0,"sig<br>
> natures":[<br>
> +# CHECK:<br>
> {"id":2,"jsonrpc":"2.0","resul<wbr>t":{"activeParameter":0,"activ<wbr>eSignature":0,"sig<br>
> natures":[<br>
>  # CHECK-DAG: {"label":"bar(int x, int y = 0) -><br>
> void","parameters":[{"label":"<wbr>int x"},{"label":"int y = 0"}]}<br>
>  # CHECK-DAG: {"label":"bar(float x = 0, int y = 42) -><br>
> void","parameters":[{"label":"<wbr>float x = 0"},{"label":"int y = 42"}]}<br>
> -# CHECK: ]}<br>
> +# CHECK-SAME: ]}<br>
><br>
>  Content-Length: 159<br>
><br>
><br>
> {"jsonrpc":"2.0","id":3,"metho<wbr>d":"textDocument/signatureHelp<wbr>","params":{"textD<br>
> ocument":{"uri":"file:///doesn<wbr>otexist.cpp"},"position":{"lin<wbr>e":8,"character":9<br>
> }}}<br>
> -# CHECK: {"jsonrpc":"2.0","id":3,"error<wbr>":{"code":-<br>
> 32602,"message":"signatureHelp is called for non-added document"}}<br>
> +# CHECK: {"error":{"code":-32602,"messa<wbr>ge":"signatureHelp is called for non-<br>
> 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":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/test/clangd/unsupp<wbr>orted-<br>
> method.test?rev=317486&r1=3174<wbr>85&r2=317486&view=diff<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<br>
> 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<br>
> %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>
><br>
> {"jsonrpc":"2.0","id":1,"metho<wbr>d":"textDocument/jumpInTheAirL<wbr>ikeYouJustDontCare<br>
> ","params":{}}<br>
> -# CHECK: {"jsonrpc":"2.0","id":1,"error<wbr>":{"code":-32601,"message":"me<wbr>thod not<br>
> 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,"metho<wbr>d":"shutdown"}<br>
> -# CHECK: {"jsonrpc":"2.0","id":2,"resul<wbr>t":null}<br>
>  Content-Length: 33<br>
><br>
>  {"jsonrpc":"2.0":"method":"exi<wbr>t"}<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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/unittests/clangd/C<wbr>MakeLists.txt?rev=317486&r1=31<wbr>7485&r2=317486&vie<br>
> w=diff<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<br>
> 07:40:30 2017<br>
> @@ -10,6 +10,7 @@ include_directories(<br>
><br>
>  add_extra_unittest(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-" rel="noreferrer" target="_blank">
http://llvm.org/viewvc/llvm-pr<wbr>oject/clang-tools-</a><br>
> extra/trunk/unittests/clangd/J<wbr>SONExprTests.cpp?rev=317486&vi<wbr>ew=auto<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<br>
> 07:40:30 2017<br>
> @@ -0,0 +1,112 @@<br>
> +//===-- JSONExprTests.cpp - JSON expression unit tests ----------*- C++ -*-<br>
> ===//<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>
> +<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>
<span class="m_7519689754056656976x_m_-775294545546306911m_-3093680711916208270HOEnZb"><font color="#888888"></font></span></blockquote>
</div>
<span class="m_7519689754056656976x_m_-775294545546306911m_-3093680711916208270HOEnZb"><font color="#888888"><br>
<br clear="all"><span class="HOEnZb"><font color="#888888">
<span class="m_7519689754056656976x_HOEnZb"><font color="#888888"><span class="m_7519689754056656976x_m_-775294545546306911HOEnZb"><font color="#888888">
<div><br>
</div>
-- <br>
<div class="m_7519689754056656976x_m_-775294545546306911m_-3093680711916208270m_1868236386276524260gmail_signature">
<div dir="ltr">
<div>
<div dir="ltr">
<div>Regards,</div>
<div>Ilya Biryukov</div>
</div>
</div>
</div>
</div>
</font></span></font></span></font></span></font></span></div><span class="HOEnZb"><font color="#888888">
<span class="m_7519689754056656976x_HOEnZb"><font color="#888888"></font></span></font></span></blockquote><span class="HOEnZb"><font color="#888888">
</font></span></div><span class="HOEnZb"><font color="#888888">
<span class="m_7519689754056656976x_HOEnZb"><font color="#888888"><br>
</font></span></font></span></div><span class="HOEnZb"><font color="#888888">
</font></span></div><span class="HOEnZb"><font color="#888888">
</font></span></blockquote><span class="HOEnZb"><font color="#888888">
</font></span></div><span class="HOEnZb"><font color="#888888">
<br>
</font></span></div><span class="HOEnZb"><font color="#888888">
</font></span></blockquote><span class="HOEnZb"><font color="#888888">
</font></span></div><span class="HOEnZb"><font color="#888888">
<br>
<br clear="all">
<div><br>
</div>
-- <br>
<div class="m_7519689754056656976x_gmail_signature">
<div dir="ltr">
<div>
<div dir="ltr">
<div>Regards,</div>
<div>Ilya Biryukov</div>
</div>
</div>
</div>
</div>
</font></span></div>
</div>
</div>
</div>
</div>
</div>

</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div>Regards,</div><div>Ilya Biryukov</div></div></div></div></div>
</div>