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

Ilya Biryukov via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 8 05:29:42 PST 2017


Yeah and `file://c:/main.cpp` looks like the best option to me.

On Wed, Nov 8, 2017 at 6:26 PM, Sam McCall <sam.mccall at gmail.com> wrote:

> Oops, +list.
>
> r317686 makes just this test fuzzy, to unbreak the buildbot.
>
> On Wed, Nov 8, 2017 at 1:15 PM, Sam McCall <sam.mccall at gmail.com> wrote:
>
>> On Wed, Nov 8, 2017 at 12:55 PM, Ilya Biryukov <ibiryukov at google.com>
>> wrote:
>>
>>> What's the exact problem with "file://" URIs on Windows? How to properly
>>> convert the Windows-style absolute paths into those? (i.e.
>>> "C:\Users\Admin\MyProject\Main.cpp"?)
>>> If so, there is an overview in Wikipedia (https://en.wikipedia.org/wiki
>>> /File_URI_scheme#Windows_2). In short, they should look this way:
>>> file:///c/Users/Admin/MyProject/Main.cpp.
>>>
>> nit: the c needs to keep its colon: file:///c:/Users/...
>>
>> Yeah, when I thought about this some more, it's mostly that the tests
>> assume we can pretend there's a file /main.cpp = file:///main.cpp.
>> On windows, canonicalizing that filename results in C:\main.cpp =
>> file:///C:/main.cpp, which is not what our tests expect.
>>
>> Options I see:
>>  - make every test that checks a filename fuzzy (this seems doomed to
>> failure)
>>  - find a URI that works with both unix and windows paths
>> (file:///C:/main.cpp?)
>>  - avoid canonicalizing filenames in ways visible to tests
>>  - ???
>>
>>
>>> On Wed, Nov 8, 2017 at 4:37 PM, Sam McCall <sam.mccall at gmail.com> wrote:
>>>
>>>> I think all the JSON-related windows breakages are now fixed, and the
>>>> remaining definitions.test breakage was caused by r317585.
>>>> (Currently trying to get a windows machine to verify this)
>>>>
>>>> I have to confess I don't know much about how file:// URIs should work
>>>> on windows. Marc-Andre - any thoughts, or maybe we should revert until we
>>>> can work this one out?
>>>>
>>>> On Wed, Nov 8, 2017 at 3:39 AM, Yung, Douglas <douglas.yung at sony.com>
>>>> wrote:
>>>>
>>>>> Hi Sam,
>>>>>
>>>>> The test definitions.test is currently failing on the PS4 Windows bot
>>>>> because the URI returned is of the format "file:///C:/main.cpp" instead of
>>>>> the expected "file:///main.cpp" when run on a Windows machine. Can you
>>>>> please fix this ASAP so that we can get the bot green again?
>>>>>
>>>>> Here you can see the failure on the build bot:
>>>>> http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei
>>>>> -ps4-windows10pro-fast/builds/13343
>>>>>
>>>>> You can reproduce the failure by feeding the following file to clangd
>>>>> on Windows:
>>>>>
>>>>> # Begin failure.test
>>>>> Content-Length: 125
>>>>>
>>>>> {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"pro
>>>>> cessId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
>>>>>
>>>>> 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"}]}}
>>>>>
>>>>> Content-Length: 148
>>>>>
>>>>> {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","
>>>>> params":{"textDocument":{"uri":"file:///main.cpp"},"position
>>>>> ":{"line":1,"character":8}}}
>>>>> # End failure.test
>>>>>
>>>>>
>>>>> This is cut down from test\clangd\definitions.test. The failure is on
>>>>> line 337 where it is looking for this:
>>>>>
>>>>> # CHECK-NEXT:      "uri": "file:///main.cpp"
>>>>>
>>>>> However, clangd is generating:
>>>>>
>>>>> "uri": "file:///C:/main.cpp"
>>>>>
>>>>> If you could fix this as soon as possible it would be greatly
>>>>> appreciated since it is causing the PS4 Windows bot to be red.
>>>>>
>>>>> Thanks!
>>>>>
>>>>> Douglas Yung
>>>>>
>>>>> > -----Original Message-----
>>>>> > From: cfe-commits [mailto:cfe-commits-bounces at lists.llvm.org] On
>>>>> Behalf Of Sam
>>>>> > McCall via cfe-commits
>>>>> > Sent: Monday, November 06, 2017 7:41
>>>>> > To: cfe-commits at lists.llvm.org
>>>>> > Subject: [clang-tools-extra] r317486 - Adds a json::Expr type to
>>>>> represent
>>>>> > intermediate JSON expressions.
>>>>> >
>>>>> > 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
>>>>> S1uGHRyGTXaoy3DjqM
>>>>> > 4/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-inval
>>>>> id.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=31
>>>>> 7486&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=dif
>>>>> > f
>>>>> > ============================================================
>>>>> ==================
>>>>> > --- 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.text
>>>>> Document.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_A
>>>>> PPLY_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/publishDiagnostic
>>>>> s","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=31748
>>>>> 5&r2=317486&view=d
>>>>> > iff
>>>>> > ============================================================
>>>>> ==================
>>>>> > --- 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::S
>>>>> calarNode>(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=dif
>>>>> > f
>>>>> > ============================================================
>>>>> ==================
>>>>> > --- 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=3174
>>>>> 86&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_s
>>>>> tr(),
>>>>> > -      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.document
>>>>> ation)
>>>>> > -       << 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.insertText
>>>>> Format);
>>>>> >    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.additionalTextEdi
>>>>> ts);
>>>>> > +  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=dif
>>>>> > f
>>>>> > ============================================================
>>>>> ==================
>>>>> > --- 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/c
>>>>> langd/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":{"textDocu
>>>>> > ment":{"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","f
>>>>> ilterText":"a","in
>>>>> > sertText":"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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"uri":"file:///main.cpp","p
>>>>> osition":{"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","f
>>>>> ilterText":"a","in
>>>>> > sertText":"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/c
>>>>> langd/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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":4,"chara
>>>>> cter":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,"sortText":"000050int","filterText"
>>>>> :"int","insertText
>>>>> > ":"int","insertTextFormat":1}
>>>>> > +# CHECK-DAG:
>>>>> > {"filterText":"int","insertText":"int","insertTextFormat":1,
>>>>> "kind":14,"label":
>>>>> > "int","sortText":"000050int"}
>>>>> >  #
>>>>> >  # Code pattern
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"static_cast<type>(expression)","kind":15,"sortText
>>>>> ":"000040static_ca
>>>>> > st","filterText":"static_cast","insertText":"static_cast<${1
>>>>> :type}>(${2:expres
>>>>> > sion})","insertTextFormat":2}
>>>>> > +# CHECK-DAG:
>>>>> > {"filterText":"static_cast","insertText":"static_cast<${1:ty
>>>>> pe}>(${2:expressio
>>>>> > n})","insertTextFormat":2,"kind":15,"label":"static_cast<typ
>>>>> e>(expression)","s
>>>>> > ortText":"000040static_cast"}
>>>>> >  #
>>>>> >  # Struct
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"Struct","kind":7,"sortText":"000050Struct","filter
>>>>> Text":"Struct","in
>>>>> > sertText":"Struct","insertTextFormat":1}
>>>>> > +# CHECK-DAG:
>>>>> > {"filterText":"Struct","insertText":"Struct","insertTextForm
>>>>> at":1,"kind":7,"la
>>>>> > bel":"Struct","sortText":"000050Struct"}
>>>>> >  #
>>>>> >  # Macro
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"MACRO","kind":1,"sortText":"000070MACRO","filterTe
>>>>> xt":"MACRO","inser
>>>>> > tText":"MACRO","insertTextFormat":1}
>>>>> > +# CHECK-DAG:
>>>>> > {"filterText":"MACRO","insertText":"MACRO","insertTextFormat
>>>>> ":1,"kind":1,"labe
>>>>> > l":"MACRO","sortText":"000070MACRO"}
>>>>> >  #
>>>>> >  # Variable
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"variable","kind":6,"detail":"int","sortText":"0000
>>>>> 12variable","filte
>>>>> > rText":"variable","insertText":"variable","insertTextFormat":1}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"variable","insertText":"variab
>>>>> le","insertTextFor
>>>>> > mat":1,"kind":6,"label":"variable","sortText":"000012variable"}
>>>>> >  #
>>>>> >  # Function
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"function()","kind":3,"detail":"int","sortText":"00
>>>>> 0012function","fil
>>>>> > terText":"function","insertText":"function()","insertTextFormat":1}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"function","insertText":"functi
>>>>> on()","insertTextF
>>>>> > ormat":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/c
>>>>> langd/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,"detail":"void","sortText":"000034
>>>>> pub","filterText":
>>>>> > "pub","insertText":"pub","insertTextFormat":1}
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"prot()","kind":2,"detail":"void","sortText":"00003
>>>>> 4prot","filterText
>>>>> > ":"prot","insertText":"prot","insertTextFormat":1}
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"priv()","kind":2,"detail":"void","sortText":"00003
>>>>> 4priv","filterText
>>>>> > ":"priv","insertText":"priv","insertTextFormat":1}
>>>>> > -# CHECK: ]}
>>>>> > +# CHECK: {"id":2,"jsonrpc":"2.0","result":[
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"void","filterText":"pub","insertText":"pub","inse
>>>>> rtTextFormat":1,"k
>>>>> > ind":2,"label":"pub()","sortText":"000034pub"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"void","filterText":"prot","insertText":"prot","in
>>>>> sertTextFormat":1,
>>>>> > "kind":2,"label":"prot()","sortText":"000034prot"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"void","filterText":"priv","insertText":"priv","in
>>>>> sertTextFormat":1,
>>>>> > "kind":2,"label":"priv()","sortText":"000034priv"}
>>>>> > +# CHECK-SAME: ]}
>>>>> >
>>>>> >  Content-Length: 151
>>>>> >
>>>>> >
>>>>> > {"jsonrpc":"2.0","id":3,"method":"textDocument/completion","
>>>>> params":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":17,"char
>>>>> acter":4}}}
>>>>> > -# CHECK: {"jsonrpc":"2.0","id":3,"result":[
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"pub()","kind":2,"detail":"void","sortText":"000034
>>>>> pub","filterText":
>>>>> > "pub","insertText":"pub","insertTextFormat":1}
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"prot()","kind":2,"detail":"void","sortText":"20003
>>>>> 4prot","filterText
>>>>> > ":"prot","insertText":"prot","insertTextFormat":1}
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"priv()","kind":2,"detail":"void","sortText":"20003
>>>>> 4priv","filterText
>>>>> > ":"priv","insertText":"priv","insertTextFormat":1}
>>>>> > -# CHECK: ]}
>>>>> > +# CHECK: {"id":3,"jsonrpc":"2.0","result":[
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"void","filterText":"pub","insertText":"pub","inse
>>>>> rtTextFormat":1,"k
>>>>> > ind":2,"label":"pub()","sortText":"000034pub"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"void","filterText":"prot","insertText":"prot","in
>>>>> sertTextFormat":1,
>>>>> > "kind":2,"label":"prot()","sortText":"200034prot"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"void","filterText":"priv","insertText":"priv","in
>>>>> sertTextFormat":1,
>>>>> > "kind":2,"label":"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/c
>>>>> langd/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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":11,"char
>>>>> acter":8}}}
>>>>> > -# CHECK: {"jsonrpc":"2.0","id":2,"result":[
>>>>> > -# CHECK-DAG: {"label":"foo()
>>>>> > const","kind":2,"detail":"int","sortText":"200035foo","filte
>>>>> rText":"foo","inse
>>>>> > rtText":"foo","insertTextFormat":1}
>>>>> > -# CHECK-DAG: {"label":"bar()
>>>>> > const","kind":2,"detail":"int","sortText":"000037bar","filte
>>>>> rText":"bar","inse
>>>>> > rtText":"bar","insertTextFormat":1}
>>>>> > -# CHECK-DAG: {"label":"Foo::foo()
>>>>> > const","kind":2,"detail":"int","sortText":"000037foo","filte
>>>>> rText":"foo","inse
>>>>> > rtText":"foo","insertTextFormat":1}
>>>>> > -# CHECK: ]}
>>>>> > +# CHECK: {"id":2,"jsonrpc":"2.0","result":[
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"foo","insertText":"foo","inser
>>>>> tTextFormat":1,"ki
>>>>> > nd":2,"label":"foo() const","sortText":"200035foo"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"bar","insertText":"bar","inser
>>>>> tTextFormat":1,"ki
>>>>> > nd":2,"label":"bar() const","sortText":"000037bar"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"foo","insertText":"foo","inser
>>>>> tTextFormat":1,"ki
>>>>> > nd":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/c
>>>>> langd/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","f
>>>>> ilterText":"a","in
>>>>> > sertText":"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,"detail":"int","sortText":"000035ccc
>>>>> ","filterText":"cc
>>>>> > c","insertText":"ccc","insertTextFormat":1}
>>>>> > -# CHECK-DAG: {"label":"operator=(const fake
>>>>> &)","kind":2,"detail":"fake
>>>>> > &","sortText":"000079operator=","filterText":"operator=","in
>>>>> sertText":"operato
>>>>> > r=(${1:const fake &})","insertTextFormat":2}
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"~fake()","kind":4,"detail":"void","sortText":"0000
>>>>> 79~fake","filterTe
>>>>> > xt":"~fake","insertText":"~fake()","insertTextFormat":1}
>>>>> > -# CHECK-DAG: {"label":"f(int i, const float f)
>>>>> > const","kind":2,"detail":"int","sortText":"000035f","filterT
>>>>> ext":"f","insertTe
>>>>> > xt":"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","insertTex
>>>>> tFormat":1,"kind":
>>>>> > 5,"label":"a","sortText":"000035a"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"bb","insertText":"bb","insertT
>>>>> extFormat":1,"kind
>>>>> > ":5,"label":"bb","sortText":"000035bb"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"ccc","insertText":"ccc","inser
>>>>> tTextFormat":1,"ki
>>>>> > nd":5,"label":"ccc","sortText":"000035ccc"}
>>>>> > +# CHECK-DAG: {"detail":"fake
>>>>> > &","filterText":"operator=","insertText":"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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":3,"chara
>>>>> cter":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","f
>>>>> ilterText":"a","in
>>>>> > sertText":"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,"detail":"int","sortText":"000035ccc
>>>>> ","filterText":"cc
>>>>> > c","insertText":"ccc","insertTextFormat":1}
>>>>> > -# CHECK-DAG: {"label":"operator=(const fake
>>>>> &)","kind":2,"detail":"fake
>>>>> > &","sortText":"000079operator=","filterText":"operator=","in
>>>>> sertText":"operato
>>>>> > r=(${1:const fake &})","insertTextFormat":2}
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"~fake()","kind":4,"detail":"void","sortText":"0000
>>>>> 79~fake","filterTe
>>>>> > xt":"~fake","insertText":"~fake()","insertTextFormat":1}
>>>>> > -# CHECK-DAG: {"label":"f(int i, const float f)
>>>>> > const","kind":2,"detail":"int","sortText":"000035f","filterT
>>>>> ext":"f","insertTe
>>>>> > xt":"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","insertTex
>>>>> tFormat":1,"kind":
>>>>> > 5,"label":"a","sortText":"000035a"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"bb","insertText":"bb","insertT
>>>>> extFormat":1,"kind
>>>>> > ":5,"label":"bb","sortText":"000035bb"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"ccc","insertText":"ccc","inser
>>>>> tTextFormat":1,"ki
>>>>> > nd":5,"label":"ccc","sortText":"000035ccc"}
>>>>> > +# CHECK-DAG: {"detail":"fake
>>>>> > &","filterText":"operator=","insertText":"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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":3,"chara
>>>>> cter":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()","inser
>>>>> > tTextFormat":1}
>>>>> > -# CHECK: ]}
>>>>> > +# CHECK: {"id":3,"jsonrpc":"2.0","result":[
>>>>> > +# CHECK-DAG: {"detail":"int (*)(int,
>>>>> > int)","filterText":"func","insertText":"func()","insertTextF
>>>>> ormat":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=di
>>>>> > ff
>>>>> > ============================================================
>>>>> ==================
>>>>> > --- 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","f
>>>>> ilterText":"a","in
>>>>> > sertText":"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,"detail":"int","sortText":"000035ccc
>>>>> ","filterText":"cc
>>>>> > c","insertText":"ccc","insertTextFormat":1}
>>>>> > -# CHECK-DAG: {"label":"operator=(const fake
>>>>> &)","kind":2,"detail":"fake
>>>>> > &","sortText":"000079operator=","filterText":"operator=","in
>>>>> sertText":"operato
>>>>> > r=","insertTextFormat":1}
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"~fake()","kind":4,"detail":"void","sortText":"0000
>>>>> 79~fake","filterTe
>>>>> > xt":"~fake","insertText":"~fake","insertTextFormat":1}
>>>>> > -# CHECK-DAG: {"label":"f(int i, const float f)
>>>>> > const","kind":2,"detail":"int","sortText":"000035f","filterT
>>>>> ext":"f","insertTe
>>>>> > xt":"f","insertTextFormat":1}
>>>>> > -# CHECK: ]}
>>>>> > +# CHECK: {"id":1,"jsonrpc":"2.0","result":[
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"a","insertText":"a","insertTex
>>>>> tFormat":1,"kind":
>>>>> > 5,"label":"a","sortText":"000035a"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"bb","insertText":"bb","insertT
>>>>> extFormat":1,"kind
>>>>> > ":5,"label":"bb","sortText":"000035bb"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"ccc","insertText":"ccc","inser
>>>>> tTextFormat":1,"ki
>>>>> > nd":5,"label":"ccc","sortText":"000035ccc"}
>>>>> > +# CHECK-DAG: {"detail":"fake
>>>>> > &","filterText":"operator=","insertText":"operator=","insert
>>>>> TextFormat":1,"kin
>>>>> > d":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","insertTex
>>>>> tFormat":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":3,"chara
>>>>> cter":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","f
>>>>> ilterText":"a","in
>>>>> > sertText":"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,"detail":"int","sortText":"000035ccc
>>>>> ","filterText":"cc
>>>>> > c","insertText":"ccc","insertTextFormat":1}
>>>>> > -# CHECK-DAG: {"label":"operator=(const fake
>>>>> &)","kind":2,"detail":"fake
>>>>> > &","sortText":"000079operator=","filterText":"operator=","in
>>>>> sertText":"operato
>>>>> > r=","insertTextFormat":1}
>>>>> > -# CHECK-DAG:
>>>>> > {"label":"~fake()","kind":4,"detail":"void","sortText":"0000
>>>>> 79~fake","filterTe
>>>>> > xt":"~fake","insertText":"~fake","insertTextFormat":1}
>>>>> > -# CHECK-DAG: {"label":"f(int i, const float f)
>>>>> > const","kind":2,"detail":"int","sortText":"000035f","filterT
>>>>> ext":"f","insertTe
>>>>> > xt":"f","insertTextFormat":1}
>>>>> > -# CHECK: ]}
>>>>> > +# CHECK: {"id":2,"jsonrpc":"2.0","result":[
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"a","insertText":"a","insertTex
>>>>> tFormat":1,"kind":
>>>>> > 5,"label":"a","sortText":"000035a"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"bb","insertText":"bb","insertT
>>>>> extFormat":1,"kind
>>>>> > ":5,"label":"bb","sortText":"000035bb"}
>>>>> > +# CHECK-DAG:
>>>>> > {"detail":"int","filterText":"ccc","insertText":"ccc","inser
>>>>> tTextFormat":1,"ki
>>>>> > nd":5,"label":"ccc","sortText":"000035ccc"}
>>>>> > +# CHECK-DAG: {"detail":"fake
>>>>> > &","filterText":"operator=","insertText":"operator=","insert
>>>>> TextFormat":1,"kin
>>>>> > d":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","insertTex
>>>>> tFormat":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":3,"chara
>>>>> cter":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","insertT
>>>>> > extFormat":1}
>>>>> > -# CHECK: ]}
>>>>> > +# CHECK: {"id":3,"jsonrpc":"2.0","result":[
>>>>> > +# CHECK-DAG: {"detail":"int (*)(int,
>>>>> > int)","filterText":"func","insertText":"func","insertTextFor
>>>>> mat":1,"kind":2,"l
>>>>> > abel":"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=31748
>>>>> 5&r2=317486&view=d
>>>>> > iff
>>>>> > ============================================================
>>>>> ==================
>>>>> > --- 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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":2,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":2,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":4,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":4,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":1,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":3,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":5,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":5,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":5,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":4,"chara
>>>>> cter":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":[{"tex
>>>>> t":"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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":2,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":6,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":3,"chara
>>>>> cter":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":[{"tex
>>>>> t":"#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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":2,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":1,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":3,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"uri":"file:///main.cpp"},"position":{"line":4,"chara
>>>>> cter":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":{"textDocu
>>>>> > ment":{"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/c
>>>>> langd/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":{"ur
>>>>> > i":"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":"f
>>>>> > ile:///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=31748
>>>>> 5&r2=317486&view=d
>>>>> > iff
>>>>> > ============================================================
>>>>> ==================
>>>>> > --- 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":{"ur
>>>>> > i":"file:///foo.c","languageId":"c","version":1,"text":"void main()
>>>>> {}"}}}
>>>>> > -#
>>>>> > -# CHECK:
>>>>> > {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics",
>>>>> "params":{"uri":"f
>>>>> > ile:///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/c
>>>>> langd/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":{"pro
>>>>> cessId":123,"rootU
>>>>> > ri":"file:///path/to/workspace","capabilities":{},"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","type":1},{"uri":"file:
>>>>> ///path/to/file2.c
>>>>> > pp","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":{"ur
>>>>> > i":"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":"f
>>>>> > ile:///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":{"ur
>>>>> > i":"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":"f
>>>>> > ile:///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":"i
>>>>> nitialize
>>>>> > 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":"f
>>>>> > ile:///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":"i
>>>>> nitialize
>>>>> > 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":{"ur
>>>>> > i":"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":"f
>>>>> > ile:///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":{"textDocu
>>>>> > ment":{"uri":"file:///foo.c"},"range":{"start":{"line":104,"
>>>>> character":13},"en
>>>>> > d":{"line":0,"character":35}},"context":{"diagnostics":[{"ra
>>>>> nge":{"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":{"textDocu
>>>>> > ment":{"uri":"file:///foo.c"},"range":{"start":{"line":104,"
>>>>> character":13},"en
>>>>> > d":{"line":0,"character":35}},"context":{"diagnostics":[{"ra
>>>>> nge":{"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":{"textDoc
>>>>> > ument":{"uri":"file:///foo.c"},"range":{"start":{"line":104,
>>>>> "character":13},"e
>>>>> > nd":{"line":0,"character":35}},"context":{"diagnostics":[{"r
>>>>> ange":{"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,"c
>>>>> haracter":37}},"ne
>>>>> > wText":")"}]}}]}}
>>>>> > -# CHECK: {"jsonrpc":"2.0","id":3,"result":"Fix applied."}
>>>>> > -# CHECK:
>>>>> > {"jsonrpc":"2.0","id":1,"method":"workspace/applyEdit","para
>>>>> ms":{"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":{"comman
>>>>> > d":"clangd.applyFix","arguments":[{"changes":{"file:///foo.c
>>>>> ":[{"range":{"star
>>>>> > t":{"line":0,"character":32},"end":{"line":0,"character":32}
>>>>> },"newText":"("},{
>>>>> > "range":{"start":{"line":0,"character":37},"end":{"line":0,"
>>>>> character":37}},"n
>>>>> > ewText":")"}]}}]}}
>>>>> > +#      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=di
>>>>> > ff
>>>>> > ============================================================
>>>>> ==================
>>>>> > --- 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":{"pro
>>>>> cessId":123,"rootP
>>>>> > ath":"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":{"ur
>>>>> > i":"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/rangeFormatti
>>>>> ng","params":{"tex
>>>>> > tDocument":{"uri":"file:///foo.c"},"range":{"start":{"line":
>>>>> 1,"character":4},"
>>>>> > end":{"line":1,"character":12}},"options":{"tabSize":4,"inse
>>>>> rtSpaces":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/rangeFormatti
>>>>> ng","params":{"tex
>>>>> > tDocument":{"uri":"file:///foo.c"},"range":{"start":{"line":
>>>>> 1,"character":2},"
>>>>> > end":{"line":1,"character":12}},"options":{"tabSize":4,"inse
>>>>> rtSpaces":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":{"textDocu
>>>>> > ment":{"uri":"file:///foo.c"},"options":{"tabSize":4,"insert
>>>>> Spaces":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":{"textDocu
>>>>> > ment":{"uri":"file:///foo.c"},"options":{"tabSize":4,"insert
>>>>> Spaces":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/onTypeFormatt
>>>>> ing","params":{"te
>>>>> > xtDocument":{"uri":"file:///foo.c"},"position":{"line":3,"ch
>>>>> aracter":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/c
>>>>> langd/initialize-params-invalid.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-invali
>>>>> d.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":{"pro
>>>>> cessId":"","rootUr
>>>>> > i":"file:///path/to/workspace","capabilities":{},"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":{"pro
>>>>> cessId":123,"rootU
>>>>> > ri":"file:///path/to/workspace","capabilities":{},"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&r
>>>>> 2=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":{"pro
>>>>> cessId":123,"rootP
>>>>> > ath":"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":{"ur
>>>>> > i":"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":{"textDocu
>>>>> > ment":{"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","f
>>>>> ilterText":"a","in
>>>>> > sertText":"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":{"textDocu
>>>>> > ment":{"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","f
>>>>> ilterText":"a","in
>>>>> > sertText":"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":{"textDocu
>>>>> > ment":{"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","f
>>>>> ilterText":"a","in
>>>>> > sertText":"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":{"textDocu
>>>>> > ment":{"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/signatureHelp
>>>>> ","params":{"textD
>>>>> > ocument":{"uri":"file:///main.cpp"},"position":{"line":8,"ch
>>>>> aracter":9}}}
>>>>> > -# CHECK:
>>>>> > {"jsonrpc":"2.0","id":1,"result":{"activeSignature":0,"activ
>>>>> eParameter":0,"sig
>>>>> > natures":[
>>>>> > +# CHECK:
>>>>> > {"id":1,"jsonrpc":"2.0","result":{"activeParameter":0,"activ
>>>>> eSignature":0,"sig
>>>>> > natures":[
>>>>> >  # 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/signatureHelp
>>>>> ","params":{"textD
>>>>> > ocument":{"uri":"file:///main.cpp"},"position":{"line":8,"ch
>>>>> aracter":9}}}
>>>>> > -# CHECK:
>>>>> > {"jsonrpc":"2.0","id":2,"result":{"activeSignature":0,"activ
>>>>> eParameter":0,"sig
>>>>> > natures":[
>>>>> > +# CHECK:
>>>>> > {"id":2,"jsonrpc":"2.0","result":{"activeParameter":0,"activ
>>>>> eSignature":0,"sig
>>>>> > natures":[
>>>>> >  # 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/signatureHelp
>>>>> ","params":{"textD
>>>>> > ocument":{"uri":"file:///doesnotexist.cpp"},"position":{"lin
>>>>> e":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/c
>>>>> langd/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/jumpInTheAirL
>>>>> ikeYouJustDontCare
>>>>> > ","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=31
>>>>> 7485&r2=317486&vie
>>>>> > w=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
>>>>>
>>>>
>>>>
>>>
>>>
>>> --
>>> Regards,
>>> Ilya Biryukov
>>>
>>
>>
>


-- 
Regards,
Ilya Biryukov
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20171108/6a477837/attachment-0001.html>


More information about the cfe-commits mailing list