forked from OSchip/llvm-project
[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 llvm-svn: 318287
This commit is contained in:
parent
1102a861f5
commit
a40371bcb6
|
@ -195,15 +195,15 @@ void ClangdLSPServer::onCodeAction(Ctx C, CodeActionParams &Params) {
|
|||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -222,11 +222,11 @@ std::future<void> ClangdServer::forceReparse(PathRef File) {
|
|||
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, Position Pos,
|
|||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -368,69 +368,42 @@ std::string getDocumentation(const CodeCompletionString &CCS) {
|
|||
return Result;
|
||||
}
|
||||
|
||||
class CompletionItemsCollector : public CodeCompleteConsumer {
|
||||
public:
|
||||
CompletionItemsCollector(const clang::CodeCompleteOptions &CodeCompleteOpts,
|
||||
std::vector<CompletionItem> &Items)
|
||||
: CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
|
||||
Items(Items),
|
||||
Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
|
||||
CCTUInfo(Allocator) {}
|
||||
/// 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)) {}
|
||||
|
||||
void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
|
||||
CodeCompletionResult *Results,
|
||||
unsigned NumResults) override final {
|
||||
Items.reserve(NumResults);
|
||||
for (unsigned I = 0; I < NumResults; ++I) {
|
||||
auto &Result = Results[I];
|
||||
const auto *CCS = Result.CreateCodeCompletionString(
|
||||
S, Context, *Allocator, CCTUInfo,
|
||||
CodeCompleteOpts.IncludeBriefComments);
|
||||
assert(CCS && "Expected the CodeCompletionString to be non-null");
|
||||
Items.push_back(ProcessCodeCompleteResult(Result, *CCS));
|
||||
}
|
||||
std::sort(Items.begin(), Items.end());
|
||||
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;
|
||||
}
|
||||
|
||||
GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
|
||||
|
||||
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
|
||||
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:
|
||||
CompletionItem
|
||||
ProcessCodeCompleteResult(const CodeCompletionResult &Result,
|
||||
const CodeCompletionString &CCS) const {
|
||||
|
||||
// Adjust this to InsertTextFormat::Snippet iff we encounter a
|
||||
// CK_Placeholder chunk in SnippetCompletionItemsCollector.
|
||||
CompletionItem Item;
|
||||
Item.insertTextFormat = InsertTextFormat::PlainText;
|
||||
|
||||
Item.documentation = getDocumentation(CCS);
|
||||
|
||||
// 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);
|
||||
|
||||
return Item;
|
||||
}
|
||||
|
||||
virtual void ProcessChunks(const CodeCompletionString &CCS,
|
||||
CompletionItem &Item) const = 0;
|
||||
|
||||
static int GetSortPriority(const CodeCompletionString &CCS) {
|
||||
int Score = CCS.getPriority();
|
||||
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>(CCS.getAvailability())) {
|
||||
switch (static_cast<CXAvailabilityKind>(Result.Availability)) {
|
||||
case CXAvailability_Available:
|
||||
// No penalty.
|
||||
break;
|
||||
|
@ -444,21 +417,75 @@ private:
|
|||
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());
|
||||
class CompletionItemsCollector : public CodeCompleteConsumer {
|
||||
public:
|
||||
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 {
|
||||
std::priority_queue<CompletionCandidate> Candidates;
|
||||
for (unsigned I = 0; I < NumResults; ++I) {
|
||||
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.items.push_back(ProcessCodeCompleteResult(Candidate, *CCS));
|
||||
Candidates.pop();
|
||||
}
|
||||
std::reverse(Items.items.begin(), Items.items.end());
|
||||
}
|
||||
|
||||
std::vector<CompletionItem> &Items;
|
||||
GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
|
||||
|
||||
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
|
||||
|
||||
private:
|
||||
CompletionItem
|
||||
ProcessCodeCompleteResult(const CompletionCandidate &Candidate,
|
||||
const CodeCompletionString &CCS) const {
|
||||
|
||||
// Adjust this to InsertTextFormat::Snippet iff we encounter a
|
||||
// CK_Placeholder chunk in SnippetCompletionItemsCollector.
|
||||
CompletionItem Item;
|
||||
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(Candidate.Result->Kind, Candidate.Result->CursorKind);
|
||||
|
||||
return Item;
|
||||
}
|
||||
|
||||
virtual void ProcessChunks(const CodeCompletionString &CCS,
|
||||
CompletionItem &Item) const = 0;
|
||||
|
||||
clangd::CodeCompleteOptions ClangdOpts;
|
||||
CompletionList &Items;
|
||||
std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
|
||||
CodeCompletionTUInfo CCTUInfo;
|
||||
|
||||
|
@ -474,8 +501,8 @@ class PlainTextCompletionItemsCollector final
|
|||
|
||||
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 final : public CompletionItemsCollector {
|
|||
|
||||
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::CodeCompleteOptions(bool EnableSnippets,
|
|||
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::CodeCompleteOptions::getClangCompleteOpts() {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1043,6 +1043,13 @@ bool clangd::operator<(const CompletionItem &L, const CompletionItem &R) {
|
|||
(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}};
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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":{"textDocument":{"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"}
|
||||
|
|
|
@ -11,7 +11,7 @@ Content-Length: 148
|
|||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":7}}}
|
||||
Content-Length: 58
|
||||
# CHECK: {"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,"label":"int","sortText":"000050int"}
|
||||
|
@ -31,6 +31,6 @@ Content-Length: 58
|
|||
# Function
|
||||
# CHECK-DAG: {"detail":"int","filterText":"function","insertText":"function()","insertTextFormat":1,"kind":3,"label":"function()","sortText":"000012function"}
|
||||
#
|
||||
# CHECK-SAME: ]}
|
||||
# CHECK-SAME: ]}}
|
||||
|
||||
{"jsonrpc":"2.0","id":3,"method":"shutdown","params":null}
|
||||
|
|
|
@ -15,69 +15,74 @@ Content-Length: 151
|
|||
{"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"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":{"textDocument":{"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}
|
||||
|
|
|
@ -10,37 +10,40 @@ Content-Length: 151
|
|||
{"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"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"}
|
||||
|
|
|
@ -14,71 +14,74 @@ Content-Length: 148
|
|||
{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"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":{"textDocument":{"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"}
|
||||
|
|
|
@ -14,7 +14,9 @@ Content-Length: 148
|
|||
{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"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":{"textDocument":{"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":{"textDocument":{"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",
|
||||
|
|
|
@ -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":{"textDocument":{"uri":"file:/main.cpp"},"position":{"line":3,"character":5}}}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue