<div dir="ltr">Sorry about these - I've finally understood what's going on.<div>It looks like the PS4 has a different default --std, which probably doesn't make sense for clangd. I'll override it.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Nov 15, 2017 at 7:49 PM, Robinson, Paul <span dir="ltr"><<a href="mailto:paul.robinson@sony.com" target="_blank">paul.robinson@sony.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Sam,<br>
It looks like llvm-clang-lld-x86_64-scei-<wbr>ps4-windows10pro-fast has been<br>
failing a couple of clangd tests ever since this went in.<br>
<br>
<a href="http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/13517" rel="noreferrer" target="_blank">http://lab.llvm.org:8011/<wbr>builders/llvm-clang-lld-x86_<wbr>64-scei-ps4-windows10pro-fast/<wbr>builds/13517</a><br>
<br>
Please fix or revert ASAP when bots go red.  Failures like this interfere<br>
with our CI process.<br>
<br>
Thanks,<br>
--paulr<br>
PS4 code owner<br>
<br>
<br>
> -----Original Message-----<br>
> From: cfe-commits [mailto:<a href="mailto:cfe-commits-bounces@lists.llvm.org">cfe-commits-bounces@<wbr>lists.llvm.org</a>] On Behalf Of<br>
> Sam McCall via cfe-commits<br>
> Sent: Wednesday, November 15, 2017 1:16 AM<br>
> To: <a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
> Subject: [clang-tools-extra] r318287 - [clangd] Support returning a<br>
> limited number of completion results.<br>
><br>
> Author: sammccall<br>
> Date: Wed Nov 15 01:16:29 2017<br>
> New Revision: 318287<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=318287&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=318287&view=rev</a><br>
> Log:<br>
> [clangd] Support returning a limited number of completion results.<br>
><br>
> Summary:<br>
> All results are scored, we only process CodeCompletionStrings for the<br>
> winners.<br>
> We now return CompletionList rather than CompletionItem[] (both are<br>
> valid).<br>
> sortText is now based on CodeCompletionResult::<wbr>orderedName (mostly the<br>
> same).<br>
><br>
> This is the first clangd-only completion option, so plumbing changed.<br>
> It requires a small clangd patch (exposing<br>
> CodeCompletionResult::<wbr>orderedName).<br>
><br>
> (This can't usefully be enabled yet: we don't support server-side<br>
> filtering)<br>
><br>
> Reviewers: ilya-biryukov<br>
><br>
> Subscribers: cfe-commits<br>
><br>
> Differential Revision: <a href="https://reviews.llvm.org/D39852" rel="noreferrer" target="_blank">https://reviews.llvm.org/<wbr>D39852</a><br>
><br>
> Modified:<br>
>     clang-tools-extra/trunk/<wbr>clangd/ClangdLSPServer.cpp<br>
>     clang-tools-extra/trunk/<wbr>clangd/ClangdServer.cpp<br>
>     clang-tools-extra/trunk/<wbr>clangd/ClangdServer.h<br>
>     clang-tools-extra/trunk/<wbr>clangd/ClangdUnit.cpp<br>
>     clang-tools-extra/trunk/<wbr>clangd/ClangdUnit.h<br>
>     clang-tools-extra/trunk/<wbr>clangd/Protocol.cpp<br>
>     clang-tools-extra/trunk/<wbr>clangd/Protocol.h<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/authority-less-uri.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/completion-items-kinds.<wbr>test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/completion-priorities.<wbr>test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/completion-qualifiers.<wbr>test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/completion-snippet.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/completion.test<br>
>     clang-tools-extra/trunk/test/<wbr>clangd/protocol.test<br>
>     clang-tools-extra/trunk/<wbr>unittests/clangd/ClangdTests.<wbr>cpp<br>
><br>
> Modified: clang-tools-extra/trunk/<wbr>clangd/ClangdLSPServer.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/clangd/<wbr>ClangdLSPServer.cpp?rev=<wbr>318287&r1=318286&r2=318287&<wbr>view<br>
> =diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/<wbr>clangd/ClangdLSPServer.cpp (original)<br>
> +++ clang-tools-extra/trunk/<wbr>clangd/ClangdLSPServer.cpp Wed Nov 15 01:16:29<br>
> 2017<br>
> @@ -195,15 +195,15 @@ void ClangdLSPServer::onCodeAction(<wbr>Ctx C<br>
>  }<br>
><br>
>  void ClangdLSPServer::onCompletion(<wbr>Ctx C, TextDocumentPositionParams<br>
> &Params) {<br>
> -  auto Items = Server<br>
> -                   .codeComplete(Params.<wbr>textDocument.uri.file,<br>
> -                                 Position{Params.position.line,<br>
> -                                          Params.position.character})<br>
> -                   .get() // FIXME(ibiryukov): This could be made async<br>
> if we<br>
> -                          // had an API that would allow to attach<br>
> callbacks to<br>
> -                          // futures returned by ClangdServer.<br>
> -                   .Value;<br>
> -  C.reply(json::ary(Items));<br>
> +  auto List = Server<br>
> +                  .codeComplete(<br>
> +                      Params.textDocument.uri.file,<br>
> +                      Position{Params.position.line,<br>
> Params.position.character})<br>
> +                  .get() // FIXME(ibiryukov): This could be made async if<br>
> we<br>
> +                         // had an API that would allow to attach<br>
> callbacks to<br>
> +                         // futures returned by ClangdServer.<br>
> +                  .Value;<br>
> +  C.reply(List);<br>
>  }<br>
><br>
>  void ClangdLSPServer::<wbr>onSignatureHelp(Ctx C,<br>
><br>
> Modified: clang-tools-extra/trunk/<wbr>clangd/ClangdServer.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/clangd/<wbr>ClangdServer.cpp?rev=318287&<wbr>r1=318286&r2=318287&view=di<br>
> ff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/<wbr>clangd/ClangdServer.cpp (original)<br>
> +++ clang-tools-extra/trunk/<wbr>clangd/ClangdServer.cpp Wed Nov 15 01:16:29<br>
> 2017<br>
> @@ -222,11 +222,11 @@ std::future<void> ClangdServer::forceRep<br>
>                                   std::move(TaggedFS));<br>
>  }<br>
><br>
> -std::future<Tagged<std::<wbr>vector<CompletionItem>>><br>
> +std::future<Tagged<<wbr>CompletionList>><br>
>  ClangdServer::codeComplete(<wbr>PathRef File, Position Pos,<br>
>                             llvm::Optional<StringRef> OverridenContents,<br>
>                             IntrusiveRefCntPtr<vfs::<wbr>FileSystem> *UsedFS) {<br>
> -  using ResultType = Tagged<std::vector<<wbr>CompletionItem>>;<br>
> +  using ResultType = Tagged<CompletionList>;<br>
><br>
>    std::promise<ResultType> ResultPromise;<br>
><br>
> @@ -242,11 +242,10 @@ ClangdServer::codeComplete(<wbr>PathRef File,<br>
>  }<br>
><br>
>  void ClangdServer::codeComplete(<br>
> -    UniqueFunction<void(Tagged<<wbr>std::vector<CompletionItem>>)> Callback,<br>
> -    PathRef File, Position Pos, llvm::Optional<StringRef><br>
> OverridenContents,<br>
> +    UniqueFunction<void(Tagged<<wbr>CompletionList>)> Callback, PathRef File,<br>
> +    Position Pos, llvm::Optional<StringRef> OverridenContents,<br>
>      IntrusiveRefCntPtr<vfs::<wbr>FileSystem> *UsedFS) {<br>
> -  using CallbackType =<br>
> -      UniqueFunction<void(Tagged<<wbr>std::vector<CompletionItem>>)><wbr>;<br>
> +  using CallbackType = UniqueFunction<void(Tagged<<wbr>CompletionList>)>;<br>
><br>
>    std::string Contents;<br>
>    if (OverridenContents) {<br>
> @@ -283,7 +282,7 @@ void ClangdServer::codeComplete(<br>
>          // FIXME(ibiryukov): even if Preamble is non-null, we may want to<br>
> check<br>
>          // both the old and the new version in case only one of them<br>
> matches.<br>
><br>
> -        std::vector<CompletionItem> Result = clangd::codeComplete(<br>
> +        CompletionList Result = clangd::codeComplete(<br>
>              File, Resources->getCompileCommand()<wbr>,<br>
>              Preamble ? &Preamble->Preamble : nullptr, Contents, Pos,<br>
>              TaggedFS.Value, PCHs, CodeCompleteOpts, Logger);<br>
><br>
> Modified: clang-tools-extra/trunk/<wbr>clangd/ClangdServer.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/clangd/<wbr>ClangdServer.h?rev=318287&r1=<wbr>318286&r2=318287&view=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/<wbr>clangd/ClangdServer.h (original)<br>
> +++ clang-tools-extra/trunk/<wbr>clangd/ClangdServer.h Wed Nov 15 01:16:29 2017<br>
> @@ -251,18 +251,17 @@ public:<br>
>    /// This method should only be called for currently tracked files.<br>
> However, it<br>
>    /// is safe to call removeDocument for \p File after this method<br>
> returns, even<br>
>    /// while returned future is not yet ready.<br>
> -  std::future<Tagged<std::<wbr>vector<CompletionItem>>><br>
> +  std::future<Tagged<<wbr>CompletionList>><br>
>    codeComplete(PathRef File, Position Pos,<br>
>                 llvm::Optional<StringRef> OverridenContents = llvm::None,<br>
>                 IntrusiveRefCntPtr<vfs::<wbr>FileSystem> *UsedFS = nullptr);<br>
><br>
>    /// A version of `codeComplete` that runs \p Callback on the processing<br>
> thread<br>
>    /// when codeComplete results become available.<br>
> -  void codeComplete(<br>
> -      UniqueFunction<void(Tagged<<wbr>std::vector<CompletionItem>>)> Callback,<br>
> -      PathRef File, Position Pos,<br>
> -      llvm::Optional<StringRef> OverridenContents = llvm::None,<br>
> -      IntrusiveRefCntPtr<vfs::<wbr>FileSystem> *UsedFS = nullptr);<br>
> +  void codeComplete(UniqueFunction<<wbr>void(Tagged<CompletionList>)><br>
> Callback,<br>
> +                    PathRef File, Position Pos,<br>
> +                    llvm::Optional<StringRef> OverridenContents =<br>
> llvm::None,<br>
> +                    IntrusiveRefCntPtr<vfs::<wbr>FileSystem> *UsedFS =<br>
> nullptr);<br>
><br>
>    /// Provide signature help for \p File at \p Pos. If \p<br>
> OverridenContents is<br>
>    /// not None, they will used only for signature help, i.e. no<br>
> diagnostics<br>
><br>
> Modified: clang-tools-extra/trunk/<wbr>clangd/ClangdUnit.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/clangd/ClangdUnit.<wbr>cpp?rev=318287&r1=318286&r2=<wbr>318287&view=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/<wbr>clangd/ClangdUnit.cpp (original)<br>
> +++ clang-tools-extra/trunk/<wbr>clangd/ClangdUnit.cpp Wed Nov 15 01:16:29 2017<br>
> @@ -368,28 +368,90 @@ std::string getDocumentation(const CodeC<br>
>    return Result;<br>
>  }<br>
><br>
> +/// A scored code completion result.<br>
> +/// It may be promoted to a CompletionItem if it's among the top-ranked<br>
> results.<br>
> +struct CompletionCandidate {<br>
> +  CompletionCandidate(<wbr>CodeCompletionResult &Result)<br>
> +      : Result(&Result), Score(score(Result)) {}<br>
> +<br>
> +  CodeCompletionResult *Result;<br>
> +  // Higher score is worse. FIXME: use a more natural scale!<br>
> +  int Score;<br>
> +<br>
> +  // Comparison reflects rank: better candidates are smaller.<br>
> +  bool operator<(const CompletionCandidate &C) const {<br>
> +    if (Score != C.Score)<br>
> +      return Score < C.Score;<br>
> +    return *Result < *C.Result;<br>
> +  }<br>
> +<br>
> +  std::string sortText() const {<br>
> +    // Fill in the sortText of the CompletionItem.<br>
> +    assert(Score <= 999999 && "Expecting score to have at most 6-<br>
> digits");<br>
> +    std::string S, NameStorage;<br>
> +    StringRef Name = Result->getOrderedName(<wbr>NameStorage);<br>
> +    llvm::raw_string_ostream(S)<br>
> +        << llvm::format("%06d%.*s", Score, Name.size(), Name.data());<br>
> +    return S;<br>
> +  }<br>
> +<br>
> +private:<br>
> +  static int score(const CodeCompletionResult &Result) {<br>
> +    int Score = Result.Priority;<br>
> +    // Fill in the sortText of the CompletionItem.<br>
> +    assert(Score <= 99999 && "Expecting code completion result "<br>
> +                             "priority to have at most 5-digits");<br>
> +<br>
> +    const int Penalty = 100000;<br>
> +    switch (static_cast<<wbr>CXAvailabilityKind>(Result.<wbr>Availability)) {<br>
> +    case CXAvailability_Available:<br>
> +      // No penalty.<br>
> +      break;<br>
> +    case CXAvailability_Deprecated:<br>
> +      Score += Penalty;<br>
> +      break;<br>
> +    case CXAvailability_NotAccessible:<br>
> +      Score += 2 * Penalty;<br>
> +      break;<br>
> +    case CXAvailability_NotAvailable:<br>
> +      Score += 3 * Penalty;<br>
> +      break;<br>
> +    }<br>
> +    return Score;<br>
> +  }<br>
> +};<br>
> +<br>
>  class CompletionItemsCollector : public CodeCompleteConsumer {<br>
>  public:<br>
> -  CompletionItemsCollector(const clang::CodeCompleteOptions<br>
> &CodeCompleteOpts,<br>
> -                           std::vector<CompletionItem> &Items)<br>
> -      : CodeCompleteConsumer(<wbr>CodeCompleteOpts, /*OutputIsBinary=*/false),<br>
> -        Items(Items),<br>
> +  CompletionItemsCollector(const clangd::CodeCompleteOptions<br>
> &CodeCompleteOpts,<br>
> +                           CompletionList &Items)<br>
> +      : CodeCompleteConsumer(<wbr>CodeCompleteOpts.<wbr>getClangCompleteOpts(),<br>
> +                             /*OutputIsBinary=*/false),<br>
> +        ClangdOpts(CodeCompleteOpts), Items(Items),<br>
><br>
> Allocator(std::make_shared<<wbr>clang::<wbr>GlobalCodeCompletionAllocator><wbr>()),<br>
>          CCTUInfo(Allocator) {}<br>
><br>
>    void ProcessCodeCompleteResults(<wbr>Sema &S, CodeCompletionContext Context,<br>
>                                    CodeCompletionResult *Results,<br>
>                                    unsigned NumResults) override final {<br>
> -    Items.reserve(NumResults);<br>
> +    std::priority_queue<<wbr>CompletionCandidate> Candidates;<br>
>      for (unsigned I = 0; I < NumResults; ++I) {<br>
> -      auto &Result = Results[I];<br>
> -      const auto *CCS = Result.<wbr>CreateCodeCompletionString(<br>
> +      Candidates.emplace(Results[I])<wbr>;<br>
> +      if (ClangdOpts.Limit && Candidates.size() > ClangdOpts.Limit) {<br>
> +        Candidates.pop();<br>
> +        Items.isIncomplete = true;<br>
> +      }<br>
> +    }<br>
> +    while (!Candidates.empty()) {<br>
> +      auto &Candidate = Candidates.top();<br>
> +      const auto *CCS = Candidate.Result-><wbr>CreateCodeCompletionString(<br>
>            S, Context, *Allocator, CCTUInfo,<br>
>            CodeCompleteOpts.<wbr>IncludeBriefComments);<br>
>        assert(CCS && "Expected the CodeCompletionString to be non-null");<br>
> -      Items.push_back(<wbr>ProcessCodeCompleteResult(<wbr>Result, *CCS));<br>
> +      Items.items.push_back(<wbr>ProcessCodeCompleteResult(<wbr>Candidate, *CCS));<br>
> +      Candidates.pop();<br>
>      }<br>
> -    std::sort(Items.begin(), Items.end());<br>
> +    std::reverse(Items.items.<wbr>begin(), Items.items.end());<br>
>    }<br>
><br>
>    GlobalCodeCompletionAllocator &getAllocator() override { return<br>
> *Allocator; }<br>
> @@ -398,7 +460,7 @@ public:<br>
><br>
>  private:<br>
>    CompletionItem<br>
> -  ProcessCodeCompleteResult(<wbr>const CodeCompletionResult &Result,<br>
> +  ProcessCodeCompleteResult(<wbr>const CompletionCandidate &Candidate,<br>
>                              const CodeCompletionString &CCS) const {<br>
><br>
>      // Adjust this to InsertTextFormat::Snippet iff we encounter a<br>
> @@ -407,15 +469,14 @@ private:<br>
>      Item.insertTextFormat = InsertTextFormat::PlainText;<br>
><br>
>      Item.documentation = getDocumentation(CCS);<br>
> +    Item.sortText = Candidate.sortText();<br>
><br>
>      // Fill in the label, detail, insertText and filterText fields of the<br>
>      // CompletionItem.<br>
>      ProcessChunks(CCS, Item);<br>
><br>
>      // Fill in the kind field of the CompletionItem.<br>
> -    Item.kind = getKind(Result.Kind, Result.CursorKind);<br>
> -<br>
> -    FillSortText(CCS, Item);<br>
> +    Item.kind = getKind(Candidate.Result-><wbr>Kind, Candidate.Result-<br>
> >CursorKind);<br>
><br>
>      return Item;<br>
>    }<br>
> @@ -423,42 +484,8 @@ private:<br>
>    virtual void ProcessChunks(const CodeCompletionString &CCS,<br>
>                               CompletionItem &Item) const = 0;<br>
><br>
> -  static int GetSortPriority(const CodeCompletionString &CCS) {<br>
> -    int Score = CCS.getPriority();<br>
> -    // Fill in the sortText of the CompletionItem.<br>
> -    assert(Score <= 99999 && "Expecting code completion result "<br>
> -                             "priority to have at most 5-digits");<br>
> -<br>
> -    const int Penalty = 100000;<br>
> -    switch (static_cast<<wbr>CXAvailabilityKind>(CCS.<wbr>getAvailability())) {<br>
> -    case CXAvailability_Available:<br>
> -      // No penalty.<br>
> -      break;<br>
> -    case CXAvailability_Deprecated:<br>
> -      Score += Penalty;<br>
> -      break;<br>
> -    case CXAvailability_NotAccessible:<br>
> -      Score += 2 * Penalty;<br>
> -      break;<br>
> -    case CXAvailability_NotAvailable:<br>
> -      Score += 3 * Penalty;<br>
> -      break;<br>
> -    }<br>
> -<br>
> -    return Score;<br>
> -  }<br>
> -<br>
> -  static void FillSortText(const CodeCompletionString &CCS,<br>
> -                           CompletionItem &Item) {<br>
> -    int Priority = GetSortPriority(CCS);<br>
> -    // Fill in the sortText of the CompletionItem.<br>
> -    assert(Priority <= 999999 &&<br>
> -           "Expecting sort priority to have at most 6-digits");<br>
> -    llvm::raw_string_ostream(Item.<wbr>sortText)<br>
> -        << llvm::format("%06d%s", Priority, Item.filterText.c_str());<br>
> -  }<br>
> -<br>
> -  std::vector<CompletionItem> &Items;<br>
> +  clangd::CodeCompleteOptions ClangdOpts;<br>
> +  CompletionList &Items;<br>
>    std::shared_ptr<clang::<wbr>GlobalCodeCompletionAllocator> Allocator;<br>
>    CodeCompletionTUInfo CCTUInfo;<br>
><br>
> @@ -474,8 +501,8 @@ class PlainTextCompletionItemsCollec<wbr>tor<br>
><br>
>  public:<br>
>    PlainTextCompletionItemsCollec<wbr>tor(<br>
> -      const clang::CodeCompleteOptions &CodeCompleteOpts,<br>
> -      std::vector<CompletionItem> &Items)<br>
> +      const clangd::CodeCompleteOptions &CodeCompleteOpts,<br>
> +      CompletionList &Items)<br>
>        : CompletionItemsCollector(<wbr>CodeCompleteOpts, Items) {}<br>
><br>
>  private:<br>
> @@ -511,8 +538,8 @@ class SnippetCompletionItemsCollecto<wbr>r fi<br>
><br>
>  public:<br>
>    SnippetCompletionItemsCollecto<wbr>r(<br>
> -      const clang::CodeCompleteOptions &CodeCompleteOpts,<br>
> -      std::vector<CompletionItem> &Items)<br>
> +      const clangd::CodeCompleteOptions &CodeCompleteOpts,<br>
> +      CompletionList &Items)<br>
>        : CompletionItemsCollector(<wbr>CodeCompleteOpts, Items) {}<br>
><br>
>  private:<br>
> @@ -795,7 +822,8 @@ clangd::CodeCompleteOptions::<wbr>CodeComplet<br>
>        IncludeMacros(IncludeMacros), IncludeGlobals(IncludeGlobals)<wbr>,<br>
>        IncludeBriefComments(<wbr>IncludeBriefComments) {}<br>
><br>
> -clang::CodeCompleteOptions<br>
> clangd::CodeCompleteOptions::<wbr>getClangCompleteOpts() {<br>
> +clang::CodeCompleteOptions<br>
> +clangd::CodeCompleteOptions::<wbr>getClangCompleteOpts() const {<br>
>    clang::CodeCompleteOptions Result;<br>
>    Result.IncludeCodePatterns = EnableSnippets && IncludeCodePatterns;<br>
>    Result.IncludeMacros = IncludeMacros;<br>
> @@ -805,25 +833,24 @@ clang::CodeCompleteOptions clangd::CodeC<br>
>    return Result;<br>
>  }<br>
><br>
> -std::vector<CompletionItem><br>
> +CompletionList<br>
>  clangd::codeComplete(PathRef FileName, const tooling::CompileCommand<br>
> &Command,<br>
>                       PrecompiledPreamble const *Preamble, StringRef<br>
> Contents,<br>
>                       Position Pos, IntrusiveRefCntPtr<vfs::<wbr>FileSystem><br>
> VFS,<br>
>                       std::shared_ptr<<wbr>PCHContainerOperations> PCHs,<br>
>                       clangd::CodeCompleteOptions Opts, clangd::Logger<br>
> &Logger) {<br>
> -  std::vector<CompletionItem> Results;<br>
> +  CompletionList Results;<br>
>    std::unique_ptr<<wbr>CodeCompleteConsumer> Consumer;<br>
> -  clang::CodeCompleteOptions ClangCompleteOpts =<br>
> Opts.getClangCompleteOpts();<br>
>    if (Opts.EnableSnippets) {<br>
> -    Consumer = llvm::make_unique<<wbr>SnippetCompletionItemsCollecto<wbr>r>(<br>
> -        ClangCompleteOpts, Results);<br>
> +    Consumer =<br>
> +        llvm::make_unique<<wbr>SnippetCompletionItemsCollecto<wbr>r>(Opts,<br>
> Results);<br>
>    } else {<br>
> -    Consumer = llvm::make_unique<<wbr>PlainTextCompletionItemsCollec<wbr>tor>(<br>
> -        ClangCompleteOpts, Results);<br>
> +    Consumer =<br>
> +        llvm::make_unique<<wbr>PlainTextCompletionItemsCollec<wbr>tor>(Opts,<br>
> Results);<br>
>    }<br>
> -  invokeCodeComplete(std::move(<wbr>Consumer), ClangCompleteOpts, FileName,<br>
> Command,<br>
> -                     Preamble, Contents, Pos, std::move(VFS),<br>
> std::move(PCHs),<br>
> -                     Logger);<br>
> +  invokeCodeComplete(std::move(<wbr>Consumer), Opts.getClangCompleteOpts(),<br>
> FileName,<br>
> +                     Command, Preamble, Contents, Pos, std::move(VFS),<br>
> +                     std::move(PCHs), Logger);<br>
>    return Results;<br>
>  }<br>
><br>
><br>
> Modified: clang-tools-extra/trunk/<wbr>clangd/ClangdUnit.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/clangd/ClangdUnit.<wbr>h?rev=318287&r1=318286&r2=<wbr>318287&view=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/<wbr>clangd/ClangdUnit.h (original)<br>
> +++ clang-tools-extra/trunk/<wbr>clangd/ClangdUnit.h Wed Nov 15 01:16:29 2017<br>
> @@ -263,7 +263,7 @@ struct CodeCompleteOptions {<br>
>                        bool IncludeBriefComments);<br>
><br>
>    /// Returns options that can be passed to clang's completion engine.<br>
> -  clang::CodeCompleteOptions getClangCompleteOpts();<br>
> +  clang::CodeCompleteOptions getClangCompleteOpts() const;<br>
><br>
>    /// When true, completion items will contain expandable code snippets<br>
> in<br>
>    /// completion (e.g.  `return ${1:expression}` or `foo(${1:int a},<br>
> ${2:int<br>
> @@ -285,10 +285,14 @@ struct CodeCompleteOptions {<br>
>    /// FIXME(ibiryukov): it looks like turning this option on<br>
> significantly slows<br>
>    /// down completion, investigate if it can be made faster.<br>
>    bool IncludeBriefComments = true;<br>
> +<br>
> +  /// Limit the number of results returned (0 means no limit).<br>
> +  /// If more results are available, we set CompletionList.isIncomplete.<br>
> +  size_t Limit = 0;<br>
>  };<br>
><br>
>  /// Get code completions at a specified \p Pos in \p FileName.<br>
> -std::vector<CompletionItem><br>
> +CompletionList<br>
>  codeComplete(PathRef FileName, const tooling::CompileCommand &Command,<br>
>               PrecompiledPreamble const *Preamble, StringRef Contents,<br>
>               Position Pos, IntrusiveRefCntPtr<vfs::<wbr>FileSystem> VFS,<br>
><br>
> Modified: clang-tools-extra/trunk/<wbr>clangd/Protocol.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/clangd/Protocol.<wbr>cpp?rev=318287&r1=318286&r2=<wbr>318287&view=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/<wbr>clangd/Protocol.cpp (original)<br>
> +++ clang-tools-extra/trunk/<wbr>clangd/Protocol.cpp Wed Nov 15 01:16:29 2017<br>
> @@ -1043,6 +1043,13 @@ bool clangd::operator<(const CompletionI<br>
>           (R.sortText.empty() ? R.label : R.sortText);<br>
>  }<br>
><br>
> +json::Expr CompletionList::unparse(const CompletionList &L) {<br>
> +  return json::obj{<br>
> +      {"isIncomplete", L.isIncomplete},<br>
> +      {"items", json::ary(L.items)},<br>
> +  };<br>
> +}<br>
> +<br>
>  json::Expr ParameterInformation::unparse(<wbr>const ParameterInformation &PI)<br>
> {<br>
>    assert(!PI.label.empty() && "parameter information label is required");<br>
>    json::obj Result{{"label", PI.label}};<br>
><br>
> Modified: clang-tools-extra/trunk/<wbr>clangd/Protocol.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/clangd/Protocol.h?<wbr>rev=318287&r1=318286&r2=<wbr>318287&view=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/<wbr>clangd/Protocol.h (original)<br>
> +++ clang-tools-extra/trunk/<wbr>clangd/Protocol.h Wed Nov 15 01:16:29 2017<br>
> @@ -547,6 +547,18 @@ struct CompletionItem {<br>
><br>
>  bool operator<(const CompletionItem &, const CompletionItem &);<br>
><br>
> +/// Represents a collection of completion items to be presented in the<br>
> editor.<br>
> +struct CompletionList {<br>
> +  /// The list is not complete. Further typing should result in<br>
> recomputing the<br>
> +  /// list.<br>
> +  bool isIncomplete = false;<br>
> +<br>
> +  /// The completion items.<br>
> +  std::vector<CompletionItem> items;<br>
> +<br>
> +  static json::Expr unparse(const CompletionList &);<br>
> +};<br>
> +<br>
>  /// A single parameter of a particular signature.<br>
>  struct ParameterInformation {<br>
><br>
><br>
> Modified: clang-tools-extra/trunk/test/<wbr>clangd/authority-less-uri.test<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/test/clangd/<wbr>authority-less-<br>
> uri.test?rev=318287&r1=318286&<wbr>r2=318287&view=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/test/<wbr>clangd/authority-less-uri.test (original)<br>
> +++ clang-tools-extra/trunk/test/<wbr>clangd/authority-less-uri.test Wed Nov 15<br>
> 01:16:29 2017<br>
> @@ -17,14 +17,17 @@ Content-Length: 146<br>
>  #<br>
>  #      CHECK:  "id": 1,<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> -#      CHECK:      "filterText": "fake",<br>
> -# CHECK-NEXT:      "insertText": "fake",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 7,<br>
> -# CHECK-NEXT:      "label": "fake::",<br>
> -# CHECK-NEXT:      "sortText": "000075fake"<br>
> -#      CHECK:  ]<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
> +#      CHECK:        "filterText": "fake",<br>
> +# CHECK-NEXT:        "insertText": "fake",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 7,<br>
> +# CHECK-NEXT:        "label": "fake::",<br>
> +# CHECK-NEXT:        "sortText": "000075fake"<br>
> +#      CHECK:    ]<br>
> +# CHECK-NEXT:  }<br>
>  Content-Length: 172<br>
><br>
><br>
> {"jsonrpc":"2.0","id":2,"<wbr>method":"textDocument/<wbr>completion","params":{"text<br>
> Document":{"uri":"file:///<wbr>main.cpp"},"uri":"file:///<wbr>main.cpp","position":{<br>
> "line":3,"character":5}}}<br>
> @@ -32,14 +35,17 @@ Content-Length: 172<br>
>  #<br>
>  #      CHECK:  "id": 2,<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> -#      CHECK:      "filterText": "fake",<br>
> -# CHECK-NEXT:      "insertText": "fake",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 7,<br>
> -# CHECK-NEXT:      "label": "fake::",<br>
> -# CHECK-NEXT:      "sortText": "000075fake"<br>
> -#      CHECK:  ]<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
> +#      CHECK:        "filterText": "fake",<br>
> +# CHECK-NEXT:        "insertText": "fake",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 7,<br>
> +# CHECK-NEXT:        "label": "fake::",<br>
> +# CHECK-NEXT:        "sortText": "000075fake"<br>
> +#      CHECK:    ]<br>
> +# CHECK-NEXT:  }<br>
>  Content-Length: 44<br>
><br>
>  {"jsonrpc":"2.0","id":3,"<wbr>method":"shutdown"}<br>
><br>
> Modified: clang-tools-extra/trunk/test/<wbr>clangd/completion-items-kinds.<wbr>test<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/test/clangd/<wbr>completion-items-<br>
> kinds.test?rev=318287&r1=<wbr>318286&r2=318287&view=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/test/<wbr>clangd/completion-items-kinds.<wbr>test<br>
> (original)<br>
> +++ clang-tools-extra/trunk/test/<wbr>clangd/completion-items-kinds.<wbr>test Wed<br>
> Nov 15 01:16:29 2017<br>
> @@ -11,7 +11,7 @@ Content-Length: 148<br>
><br>
><br>
> {"jsonrpc":"2.0","id":1,"<wbr>method":"textDocument/<wbr>completion","params":{"text<br>
> Document":{"uri":"file:///<wbr>main.cpp"},"position":{"line":<wbr>4,"character":7}}}<br>
>  Content-Length: 58<br>
> -# CHECK: {"id":1,"jsonrpc":"2.0","<wbr>result":[<br>
> +# CHECK: {"id":1,"jsonrpc":"2.0","<wbr>result":{"isIncomplete":false,<wbr>"items":<br>
>  #<br>
>  # Keyword<br>
>  # CHECK-DAG:<br>
> {"filterText":"int","<wbr>insertText":"int","<wbr>insertTextFormat":1,"kind":14,<wbr>"lab<br>
> el":"int","sortText":"<wbr>000050int"}<br>
> @@ -31,6 +31,6 @@ Content-Length: 58<br>
>  # Function<br>
>  # CHECK-DAG:<br>
> {"detail":"int","filterText":"<wbr>function","insertText":"<wbr>function()","insertT<br>
> extFormat":1,"kind":3,"label":<wbr>"function()","sortText":"<wbr>000012function"}<br>
>  #<br>
> -# CHECK-SAME: ]}<br>
> +# CHECK-SAME: ]}}<br>
><br>
>  {"jsonrpc":"2.0","id":3,"<wbr>method":"shutdown","params":<wbr>null}<br>
><br>
> Modified: clang-tools-extra/trunk/test/<wbr>clangd/completion-priorities.<wbr>test<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/test/clangd/<wbr>completion-<br>
> priorities.test?rev=318287&r1=<wbr>318286&r2=318287&view=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/test/<wbr>clangd/completion-priorities.<wbr>test<br>
> (original)<br>
> +++ clang-tools-extra/trunk/test/<wbr>clangd/completion-priorities.<wbr>test Wed Nov<br>
> 15 01:16:29 2017<br>
> @@ -15,69 +15,74 @@ Content-Length: 151<br>
><br>
> {"jsonrpc":"2.0","id":2,"<wbr>method":"textDocument/<wbr>completion","params":{"text<br>
> Document":{"uri":"file:///<wbr>main.cpp"},"position":{"line":<wbr>12,"character":8}}<br>
> }<br>
>  #      CHECK:  "id": 2,<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "void",<br>
> -# CHECK-NEXT:      "filterText": "priv",<br>
> -# CHECK-NEXT:      "insertText": "priv",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "priv()",<br>
> -# CHECK-NEXT:      "sortText": "000034priv"<br>
> -# CHECK-NEXT:    },<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "void",<br>
> -# CHECK-NEXT:      "filterText": "prot",<br>
> -# CHECK-NEXT:      "insertText": "prot",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "prot()",<br>
> -# CHECK-NEXT:      "sortText": "000034prot"<br>
> -# CHECK-NEXT:    },<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "void",<br>
> -# CHECK-NEXT:      "filterText": "pub",<br>
> -# CHECK-NEXT:      "insertText": "pub",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "pub()",<br>
> -# CHECK-NEXT:      "sortText": "000034pub"<br>
> -# CHECK-NEXT:    },<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "void",<br>
> +# CHECK-NEXT:        "filterText": "priv",<br>
> +# CHECK-NEXT:        "insertText": "priv",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "priv()",<br>
> +# CHECK-NEXT:        "sortText": "000034priv"<br>
> +# CHECK-NEXT:      },<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "void",<br>
> +# CHECK-NEXT:        "filterText": "prot",<br>
> +# CHECK-NEXT:        "insertText": "prot",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "prot()",<br>
> +# CHECK-NEXT:        "sortText": "000034prot"<br>
> +# CHECK-NEXT:      },<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "void",<br>
> +# CHECK-NEXT:        "filterText": "pub",<br>
> +# CHECK-NEXT:        "insertText": "pub",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "pub()",<br>
> +# CHECK-NEXT:        "sortText": "000034pub"<br>
> +# CHECK-NEXT:      },<br>
>  Content-Length: 151<br>
><br>
><br>
> {"jsonrpc":"2.0","id":3,"<wbr>method":"textDocument/<wbr>completion","params":{"text<br>
> Document":{"uri":"file:///<wbr>main.cpp"},"position":{"line":<wbr>17,"character":4}}<br>
> }<br>
>  #      CHECK:  "id": 3,<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "void",<br>
> -# CHECK-NEXT:      "filterText": "pub",<br>
> -# CHECK-NEXT:      "insertText": "pub",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "pub()",<br>
> -# CHECK-NEXT:      "sortText": "000034pub"<br>
> -# CHECK-NEXT:    },<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "void",<br>
> +# CHECK-NEXT:        "filterText": "pub",<br>
> +# CHECK-NEXT:        "insertText": "pub",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "pub()",<br>
> +# CHECK-NEXT:        "sortText": "000034pub"<br>
> +# CHECK-NEXT:      },<br>
>  # priv() and prot() are at the end of the list<br>
> -# CHECK-NEXT:    {<br>
> -#      CHECK:      "detail": "void",<br>
> -#      CHECK:      "filterText": "priv",<br>
> -# CHECK-NEXT:      "insertText": "priv",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "priv()",<br>
> -# CHECK-NEXT:      "sortText": "200034priv"<br>
> -# CHECK-NEXT:    },<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "void",<br>
> -# CHECK-NEXT:      "filterText": "prot",<br>
> -# CHECK-NEXT:      "insertText": "prot",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "prot()",<br>
> -# CHECK-NEXT:      "sortText": "200034prot"<br>
> -# CHECK-NEXT:    }<br>
> -# CHECK-NEXT:  ]<br>
> +# CHECK-NEXT:      {<br>
> +#      CHECK:        "detail": "void",<br>
> +#      CHECK:        "filterText": "priv",<br>
> +# CHECK-NEXT:        "insertText": "priv",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "priv()",<br>
> +# CHECK-NEXT:        "sortText": "200034priv"<br>
> +# CHECK-NEXT:      },<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "void",<br>
> +# CHECK-NEXT:        "filterText": "prot",<br>
> +# CHECK-NEXT:        "insertText": "prot",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "prot()",<br>
> +# CHECK-NEXT:        "sortText": "200034prot"<br>
> +# CHECK-NEXT:      }<br>
> +# CHECK-NEXT:    ]<br>
> +# CHECK-NEXT:  }<br>
>  Content-Length: 58<br>
><br>
>  {"jsonrpc":"2.0","id":4,"<wbr>method":"shutdown","params":<wbr>null}<br>
><br>
> Modified: clang-tools-extra/trunk/test/<wbr>clangd/completion-qualifiers.<wbr>test<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/test/clangd/<wbr>completion-<br>
> qualifiers.test?rev=318287&r1=<wbr>318286&r2=318287&view=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/test/<wbr>clangd/completion-qualifiers.<wbr>test<br>
> (original)<br>
> +++ clang-tools-extra/trunk/test/<wbr>clangd/completion-qualifiers.<wbr>test Wed Nov<br>
> 15 01:16:29 2017<br>
> @@ -10,37 +10,40 @@ Content-Length: 151<br>
><br>
> {"jsonrpc":"2.0","id":2,"<wbr>method":"textDocument/<wbr>completion","params":{"text<br>
> Document":{"uri":"file:///<wbr>main.cpp"},"position":{"line":<wbr>11,"character":8}}<br>
> }<br>
>  #      CHECK:  "id": 2,<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
>  # Eligible const functions are at the top of the list.<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "int",<br>
> -# CHECK-NEXT:      "filterText": "bar",<br>
> -# CHECK-NEXT:      "insertText": "bar",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "bar() const",<br>
> -# CHECK-NEXT:      "sortText": "000037bar"<br>
> -# CHECK-NEXT:    },<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "int",<br>
> -# CHECK-NEXT:      "filterText": "foo",<br>
> -# CHECK-NEXT:      "insertText": "foo",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "Foo::foo() const",<br>
> -# CHECK-NEXT:      "sortText": "000037foo"<br>
> -# CHECK-NEXT:    },<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "int",<br>
> +# CHECK-NEXT:        "filterText": "bar",<br>
> +# CHECK-NEXT:        "insertText": "bar",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "bar() const",<br>
> +# CHECK-NEXT:        "sortText": "000037bar"<br>
> +# CHECK-NEXT:      },<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "int",<br>
> +# CHECK-NEXT:        "filterText": "foo",<br>
> +# CHECK-NEXT:        "insertText": "foo",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "Foo::foo() const",<br>
> +# CHECK-NEXT:        "sortText": "000037foo"<br>
> +# CHECK-NEXT:      },<br>
>  # Ineligible non-const function is at the bottom of the list.<br>
> -# CHECK-NEXT:    {<br>
> -#      CHECK:      "detail": "int",<br>
> -#      CHECK:      "filterText": "foo",<br>
> -# CHECK-NEXT:      "insertText": "foo",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "foo() const",<br>
> -# CHECK-NEXT:      "sortText": "200035foo"<br>
> -# CHECK-NEXT:    }<br>
> -# CHECK-NEXT:  ]<br>
> +# CHECK-NEXT:      {<br>
> +#      CHECK:        "detail": "int",<br>
> +#      CHECK:        "filterText": "foo",<br>
> +# CHECK-NEXT:        "insertText": "foo",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "foo() const",<br>
> +# CHECK-NEXT:        "sortText": "200035foo"<br>
> +# CHECK-NEXT:      }<br>
> +# CHECK-NEXT:    ]<br>
> +# CHECK-NEXT:  }<br>
>  Content-Length: 44<br>
><br>
>  {"jsonrpc":"2.0","id":4,"<wbr>method":"shutdown"}<br>
><br>
> Modified: clang-tools-extra/trunk/test/<wbr>clangd/completion-snippet.test<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/test/clangd/<wbr>completion-<br>
> snippet.test?rev=318287&r1=<wbr>318286&r2=318287&view=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/test/<wbr>clangd/completion-snippet.test (original)<br>
> +++ clang-tools-extra/trunk/test/<wbr>clangd/completion-snippet.test Wed Nov 15<br>
> 01:16:29 2017<br>
> @@ -14,71 +14,74 @@ Content-Length: 148<br>
><br>
> {"jsonrpc":"2.0","id":1,"<wbr>method":"textDocument/<wbr>completion","params":{"text<br>
> Document":{"uri":"file:///<wbr>main.cpp"},"position":{"line":<wbr>3,"character":5}}}<br>
>  #      CHECK:  "id": 1,<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "int",<br>
> -# CHECK-NEXT:      "filterText": "a",<br>
> -# CHECK-NEXT:      "insertText": "a",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 5,<br>
> -# CHECK-NEXT:      "label": "a",<br>
> -# CHECK-NEXT:      "sortText": "000035a"<br>
> -# CHECK-NEXT:    },<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "int",<br>
> -# CHECK-NEXT:      "filterText": "bb",<br>
> -# CHECK-NEXT:      "insertText": "bb",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 5,<br>
> -# CHECK-NEXT:      "label": "bb",<br>
> -# CHECK-NEXT:      "sortText": "000035bb"<br>
> -# CHECK-NEXT:    },<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "int",<br>
> -# CHECK-NEXT:      "filterText": "ccc",<br>
> -# CHECK-NEXT:      "insertText": "ccc",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 5,<br>
> -# CHECK-NEXT:      "label": "ccc",<br>
> -# CHECK-NEXT:      "sortText": "000035ccc"<br>
> -# CHECK-NEXT:    },<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "int",<br>
> -# CHECK-NEXT:      "filterText": "f",<br>
> -# CHECK-NEXT:      "insertText": "f(${1:int i}, ${2:const float f})",<br>
> -# CHECK-NEXT:      "insertTextFormat": 2,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "f(int i, const float f) const",<br>
> -# CHECK-NEXT:      "sortText": "000035f"<br>
> -# CHECK-NEXT:    },<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "filterText": "fake",<br>
> -# CHECK-NEXT:      "insertText": "fake::",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 7,<br>
> -# CHECK-NEXT:      "label": "fake::",<br>
> -# CHECK-NEXT:      "sortText": "000075fake"<br>
> -# CHECK-NEXT:    },<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "fake &",<br>
> -# CHECK-NEXT:      "filterText": "operator=",<br>
> -# CHECK-NEXT:      "insertText": "operator=(${1:const fake &})",<br>
> -# CHECK-NEXT:      "insertTextFormat": 2,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "operator=(const fake &)",<br>
> -# CHECK-NEXT:      "sortText": "000079operator="<br>
> -# CHECK-NEXT:    },<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "int",<br>
> +# CHECK-NEXT:        "filterText": "a",<br>
> +# CHECK-NEXT:        "insertText": "a",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 5,<br>
> +# CHECK-NEXT:        "label": "a",<br>
> +# CHECK-NEXT:        "sortText": "000035a"<br>
> +# CHECK-NEXT:      },<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "int",<br>
> +# CHECK-NEXT:        "filterText": "bb",<br>
> +# CHECK-NEXT:        "insertText": "bb",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 5,<br>
> +# CHECK-NEXT:        "label": "bb",<br>
> +# CHECK-NEXT:        "sortText": "000035bb"<br>
> +# CHECK-NEXT:      },<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "int",<br>
> +# CHECK-NEXT:        "filterText": "ccc",<br>
> +# CHECK-NEXT:        "insertText": "ccc",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 5,<br>
> +# CHECK-NEXT:        "label": "ccc",<br>
> +# CHECK-NEXT:        "sortText": "000035ccc"<br>
> +# CHECK-NEXT:      },<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "int",<br>
> +# CHECK-NEXT:        "filterText": "f",<br>
> +# CHECK-NEXT:        "insertText": "f(${1:int i}, ${2:const float f})",<br>
> +# CHECK-NEXT:        "insertTextFormat": 2,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "f(int i, const float f) const",<br>
> +# CHECK-NEXT:        "sortText": "000035f"<br>
> +# CHECK-NEXT:      },<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "filterText": "fake",<br>
> +# CHECK-NEXT:        "insertText": "fake::",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 7,<br>
> +# CHECK-NEXT:        "label": "fake::",<br>
> +# CHECK-NEXT:        "sortText": "000075fake"<br>
> +# CHECK-NEXT:      },<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "fake &",<br>
> +# CHECK-NEXT:        "filterText": "operator=",<br>
> +# CHECK-NEXT:        "insertText": "operator=(${1:const fake &})",<br>
> +# CHECK-NEXT:        "insertTextFormat": 2,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "operator=(const fake &)",<br>
> +# CHECK-NEXT:        "sortText": "000079operator="<br>
> +# CHECK-NEXT:      },<br>
>  # FIXME: Why do some buildbots show an extra operator==(fake&&) here?<br>
> -#      CHECK:    {<br>
> -#      CHECK:      "detail": "void",<br>
> -# CHECK-NEXT:      "filterText": "~fake",<br>
> -# CHECK-NEXT:      "insertText": "~fake()",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 4,<br>
> -# CHECK-NEXT:      "label": "~fake()",<br>
> -# CHECK-NEXT:      "sortText": "000079~fake"<br>
> -# CHECK-NEXT:    }<br>
> -# CHECK-NEXT:  ]<br>
> +#      CHECK:      {<br>
> +#      CHECK:        "detail": "void",<br>
> +# CHECK-NEXT:        "filterText": "~fake",<br>
> +# CHECK-NEXT:        "insertText": "~fake()",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 4,<br>
> +# CHECK-NEXT:        "label": "~fake()",<br>
> +# CHECK-NEXT:        "sortText": "000079~fake"<br>
> +# CHECK-NEXT:      }<br>
> +# CHECK-NEXT:    ]<br>
> +# CHECK-NEXT:  }<br>
>  # Update the source file and check for completions again.<br>
>  Content-Length: 226<br>
><br>
> @@ -89,16 +92,18 @@ Content-Length: 148<br>
><br>
> {"jsonrpc":"2.0","id":3,"<wbr>method":"textDocument/<wbr>completion","params":{"text<br>
> Document":{"uri":"file:///<wbr>main.cpp"},"position":{"line":<wbr>3,"character":5}}}<br>
>  #      CHECK:  "id": 3,<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> -# CHECK-NEXT:    {<br>
> -# CHECK-NEXT:      "detail": "int (*)(int, int)",<br>
> -# CHECK-NEXT:      "filterText": "func",<br>
> -# CHECK-NEXT:      "insertText": "func()",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 2,<br>
> -# CHECK-NEXT:      "label": "func()",<br>
> -# CHECK-NEXT:      "sortText": "000034func"<br>
> -# CHECK-NEXT:    },<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
> +# CHECK-NEXT:      {<br>
> +# CHECK-NEXT:        "detail": "int (*)(int, int)",<br>
> +# CHECK-NEXT:        "filterText": "func",<br>
> +# CHECK-NEXT:        "insertText": "func()",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 2,<br>
> +# CHECK-NEXT:        "label": "func()",<br>
> +# CHECK-NEXT:        "sortText": "000034func"<br>
> +# CHECK-NEXT:      },<br>
>  Content-Length: 44<br>
><br>
>  {"jsonrpc":"2.0","id":4,"<wbr>method":"shutdown"}<br>
><br>
> Modified: clang-tools-extra/trunk/test/<wbr>clangd/completion.test<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/test/clangd/<wbr>completion.test?rev=318287&r1=<wbr>318286&r2=318287&vie<br>
> w=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/test/<wbr>clangd/completion.test (original)<br>
> +++ clang-tools-extra/trunk/test/<wbr>clangd/completion.test Wed Nov 15<br>
> 01:16:29 2017<br>
> @@ -14,7 +14,9 @@ Content-Length: 148<br>
><br>
> {"jsonrpc":"2.0","id":1,"<wbr>method":"textDocument/<wbr>completion","params":{"text<br>
> Document":{"uri":"file:///<wbr>main.cpp"},"position":{"line":<wbr>3,"character":5}}}<br>
>  #      CHECK:  "id": 1<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
>  # CHECK-NEXT:    {<br>
>  # CHECK-NEXT:      "detail": "int",<br>
>  # CHECK-NEXT:      "filterText": "a",<br>
> @@ -84,7 +86,9 @@ Content-Length: 148<br>
><br>
> {"jsonrpc":"2.0","id":2,"<wbr>method":"textDocument/<wbr>completion","params":{"text<br>
> Document":{"uri":"file:///<wbr>main.cpp"},"position":{"line":<wbr>3,"character":5}}}<br>
>  #      CHECK:  "id": 2<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
>  # CHECK-NEXT:    {<br>
>  # CHECK-NEXT:      "detail": "int",<br>
>  # CHECK-NEXT:      "filterText": "a",<br>
> @@ -158,7 +162,9 @@ Content-Length: 148<br>
><br>
> {"jsonrpc":"2.0","id":3,"<wbr>method":"textDocument/<wbr>completion","params":{"text<br>
> Document":{"uri":"file:///<wbr>main.cpp"},"position":{"line":<wbr>3,"character":5}}}<br>
>  #      CHECK:    "id": 3,<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
>  # CHECK-NEXT:    {<br>
>  # CHECK-NEXT:      "detail": "int (*)(int, int)",<br>
>  # CHECK-NEXT:      "filterText": "func",<br>
><br>
> Modified: clang-tools-extra/trunk/test/<wbr>clangd/protocol.test<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/test/clangd/<wbr>protocol.test?rev=318287&r1=<wbr>318286&r2=318287&view=<br>
> diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/test/<wbr>clangd/protocol.test (original)<br>
> +++ clang-tools-extra/trunk/test/<wbr>clangd/protocol.test Wed Nov 15 01:16:29<br>
> 2017<br>
> @@ -31,14 +31,17 @@ Content-Length: 146<br>
>  #<br>
>  #      CHECK:  "id": 1,<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> -#      CHECK:      "filterText": "fake",<br>
> -# CHECK-NEXT:      "insertText": "fake",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 7,<br>
> -# CHECK-NEXT:      "label": "fake::",<br>
> -# CHECK-NEXT:      "sortText": "000075fake"<br>
> -#      CHECK:  ]<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
> +#      CHECK:        "filterText": "fake",<br>
> +# CHECK-NEXT:        "insertText": "fake",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 7,<br>
> +# CHECK-NEXT:        "label": "fake::",<br>
> +# CHECK-NEXT:        "sortText": "000075fake"<br>
> +#      CHECK:    ]<br>
> +# CHECK-NEXT:  }<br>
><br>
>  X-Test: Testing<br>
>  Content-Type: application/vscode-jsonrpc; charset-utf-8<br>
> @@ -57,14 +60,17 @@ Content-Length: 146<br>
>  #<br>
>  #      CHECK:  "id": 3,<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> -#      CHECK:      "filterText": "fake",<br>
> -# CHECK-NEXT:      "insertText": "fake",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 7,<br>
> -# CHECK-NEXT:      "label": "fake::",<br>
> -# CHECK-NEXT:      "sortText": "000075fake"<br>
> -#      CHECK:  ]<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
> +#      CHECK:        "filterText": "fake",<br>
> +# CHECK-NEXT:        "insertText": "fake",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 7,<br>
> +# CHECK-NEXT:        "label": "fake::",<br>
> +# CHECK-NEXT:        "sortText": "000075fake"<br>
> +#      CHECK:    ]<br>
> +# CHECK-NEXT:  }<br>
>  # STDERR: Warning: Duplicate Content-Length header received. The previous<br>
> value for this message (10) was ignored.<br>
><br>
>  Content-Type: application/vscode-jsonrpc; charset-utf-8<br>
> @@ -83,14 +89,17 @@ Content-Length: 146<br>
>  #<br>
>  #      CHECK:  "id": 5,<br>
>  # CHECK-NEXT:  "jsonrpc": "2.0",<br>
> -# CHECK-NEXT:  "result": [<br>
> -#      CHECK:      "filterText": "fake",<br>
> -# CHECK-NEXT:      "insertText": "fake",<br>
> -# CHECK-NEXT:      "insertTextFormat": 1,<br>
> -# CHECK-NEXT:      "kind": 7,<br>
> -# CHECK-NEXT:      "label": "fake::",<br>
> -# CHECK-NEXT:      "sortText": "000075fake"<br>
> -#      CHECK:  ]<br>
> +# CHECK-NEXT:  "result": {<br>
> +# CHECK-NEXT:    "isIncomplete": false,<br>
> +# CHECK-NEXT:    "items": [<br>
> +#      CHECK:        "filterText": "fake",<br>
> +# CHECK-NEXT:        "insertText": "fake",<br>
> +# CHECK-NEXT:        "insertTextFormat": 1,<br>
> +# CHECK-NEXT:        "kind": 7,<br>
> +# CHECK-NEXT:        "label": "fake::",<br>
> +# CHECK-NEXT:        "sortText": "000075fake"<br>
> +#      CHECK:    ]<br>
> +# CHECK-NEXT:  }<br>
>  Content-Length: 1024<br>
><br>
><br>
> {"jsonrpc":"2.0","id":5,"<wbr>method":"textDocument/<wbr>completion","params":{"text<br>
> Document":{"uri":"file:/main.<wbr>cpp"},"position":{"line":3,"<wbr>character":5}}}<br>
><br>
> Modified: clang-tools-extra/trunk/<wbr>unittests/clangd/ClangdTests.<wbr>cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/clang-tools-</a><br>
> extra/trunk/unittests/clangd/<wbr>ClangdTests.cpp?rev=318287&r1=<wbr>318286&r2=31828<br>
> 7&view=diff<br>
> ==============================<wbr>==============================<wbr>==============<br>
> ====<br>
> --- clang-tools-extra/trunk/<wbr>unittests/clangd/ClangdTests.<wbr>cpp (original)<br>
> +++ clang-tools-extra/trunk/<wbr>unittests/clangd/ClangdTests.<wbr>cpp Wed Nov 15<br>
> 01:16:29 2017<br>
> @@ -619,16 +619,15 @@ struct bar { T x; };<br>
>  class ClangdCompletionTest : public ClangdVFSTest {<br>
>  protected:<br>
>    template <class Predicate><br>
> -  bool ContainsItemPred(std::vector<<wbr>CompletionItem> const &Items,<br>
> -                        Predicate Pred) {<br>
> -    for (const auto &Item : Items) {<br>
> +  bool ContainsItemPred(<wbr>CompletionList const &Items, Predicate Pred) {<br>
> +    for (const auto &Item : Items.items) {<br>
>        if (Pred(Item))<br>
>          return true;<br>
>      }<br>
>      return false;<br>
>    }<br>
><br>
> -  bool ContainsItem(std::vector<<wbr>CompletionItem> const &Items, StringRef<br>
> Name) {<br>
> +  bool ContainsItem(CompletionList const &Items, StringRef Name) {<br>
>      return ContainsItemPred(Items, [Name](clangd::CompletionItem Item) {<br>
>        return Item.insertText == Name;<br>
>      });<br>
> @@ -694,6 +693,44 @@ int b =   ;<br>
>    }<br>
>  }<br>
><br>
> +TEST_F(ClangdCompletionTest, Limit) {<br>
> +  MockFSProvider FS;<br>
> +  MockCompilationDatabase CDB(/*AddFreestandingFlag=*/<wbr>true);<br>
> +  CDB.ExtraClangFlags.push_back(<wbr>"-xc++");<br>
> +  ErrorCheckingDiagConsumer DiagConsumer;<br>
> +  clangd::CodeCompleteOptions Opts;<br>
> +  Opts.Limit = 2;<br>
> +  ClangdServer Server(CDB, DiagConsumer, FS,<br>
> getDefaultAsyncThreadsCount(),<br>
> +                      Opts, EmptyLogger::getInstance());<br>
> +<br>
> +  auto FooCpp = getVirtualTestFilePath("foo.<wbr>cpp");<br>
> +  FS.Files[FooCpp] = "";<br>
> +  FS.ExpectedFile = FooCpp;<br>
> +  StringWithPos Completion = parseTextMarker(R"cpp(<br>
> +struct ClassWithMembers {<br>
> +  int AAA();<br>
> +  int BBB();<br>
> +  int CCC();<br>
> +}<br>
> +int main() { ClassWithMembers().{complete} }<br>
> +      )cpp",<br>
> +                                             "complete");<br>
> +  Server.addDocument(FooCpp, Completion.Text);<br>
> +<br>
> +  /// For after-dot completion we must always get consistent results.<br>
> +  auto Results = Server<br>
> +                     .codeComplete(FooCpp, Completion.MarkerPos,<br>
> +                                   StringRef(Completion.Text))<br>
> +                     .get()<br>
> +                     .Value;<br>
> +<br>
> +  EXPECT_TRUE(Results.<wbr>isIncomplete);<br>
> +  EXPECT_EQ(Opts.Limit, Results.items.size());<br>
> +  EXPECT_TRUE(ContainsItem(<wbr>Results, "AAA"));<br>
> +  EXPECT_TRUE(ContainsItem(<wbr>Results, "BBB"));<br>
> +  EXPECT_FALSE(ContainsItem(<wbr>Results, "CCC"));<br>
> +}<br>
> +<br>
>  TEST_F(ClangdCompletionTest, CompletionOptions) {<br>
>    MockFSProvider FS;<br>
>    ErrorCheckingDiagConsumer DiagConsumer;<br>
><br>
><br>
> ______________________________<wbr>_________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>