[clang-tools-extra] r318287 - [clangd] Support returning a limited number of completion results.

Robinson, Paul via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 15 10:49:21 PST 2017


Hi Sam,
It looks like llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast has been
failing a couple of clangd tests ever since this went in.

http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/13517

Please fix or revert ASAP when bots go red.  Failures like this interfere
with our CI process.

Thanks,
--paulr
PS4 code owner


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


More information about the cfe-commits mailing list