[clang-tools-extra] r317486 - Adds a json::Expr type to represent intermediate JSON expressions.

Galina Kistanova via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 6 16:27:56 PST 2017


One more broken builder:
http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/13294

On Mon, Nov 6, 2017 at 4:24 PM, Galina Kistanova <gkistanova at gmail.com>
wrote:

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


More information about the cfe-commits mailing list