[clangd] Support offsets for parameters in signatureHelp
Summary: Added to LSP in version 3.14 Reviewers: hokein Reviewed By: hokein Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D62476 llvm-svn: 362481
This commit is contained in:
@@ -360,6 +360,7 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params,
|
||||
Params.capabilities.HierarchicalDocumentSymbol;
|
||||
SupportFileStatus = Params.initializationOptions.FileStatus;
|
||||
HoverContentFormat = Params.capabilities.HoverContentFormat;
|
||||
SupportsOffsetsInSignatureHelp = Params.capabilities.OffsetsInSignatureHelp;
|
||||
llvm::json::Object Result{
|
||||
{{"capabilities",
|
||||
llvm::json::Object{
|
||||
@@ -761,7 +762,22 @@ void ClangdLSPServer::onCompletion(const CompletionParams &Params,
|
||||
void ClangdLSPServer::onSignatureHelp(const TextDocumentPositionParams &Params,
|
||||
Callback<SignatureHelp> Reply) {
|
||||
Server->signatureHelp(Params.textDocument.uri.file(), Params.position,
|
||||
std::move(Reply));
|
||||
Bind(
|
||||
[this](decltype(Reply) Reply,
|
||||
llvm::Expected<SignatureHelp> Signature) {
|
||||
if (!Signature)
|
||||
return Reply(Signature.takeError());
|
||||
if (SupportsOffsetsInSignatureHelp)
|
||||
return Reply(std::move(*Signature));
|
||||
// Strip out the offsets from signature help for
|
||||
// clients that only support string labels.
|
||||
for (auto &Signature : Signature->signatures) {
|
||||
for (auto &Param : Signature.parameters)
|
||||
Param.labelOffsets.reset();
|
||||
}
|
||||
return Reply(std::move(*Signature));
|
||||
},
|
||||
std::move(Reply)));
|
||||
}
|
||||
|
||||
// Go to definition has a toggle function: if def and decl are distinct, then
|
||||
|
||||
@@ -156,8 +156,9 @@ private:
|
||||
bool SupportFileStatus = false;
|
||||
/// Which kind of markup should we use in textDocument/hover responses.
|
||||
MarkupKind HoverContentFormat = MarkupKind::PlainText;
|
||||
|
||||
/// Store of the current versions of the open documents.
|
||||
/// Whether the client supports offsets for parameter info labels.
|
||||
bool SupportsOffsetsInSignatureHelp = false;
|
||||
// Store of the current versions of the open documents.
|
||||
DraftStore DraftMgr;
|
||||
|
||||
// The CDB is created by the "initialize" LSP method.
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "FuzzyMatch.h"
|
||||
#include "Headers.h"
|
||||
#include "Logger.h"
|
||||
#include "Protocol.h"
|
||||
#include "Quality.h"
|
||||
#include "SourceCode.h"
|
||||
#include "TUScheduler.h"
|
||||
@@ -56,6 +57,7 @@
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
@@ -148,46 +150,6 @@ toCompletionItemKind(CodeCompletionResult::ResultKind ResKind,
|
||||
llvm_unreachable("Unhandled CodeCompletionResult::ResultKind.");
|
||||
}
|
||||
|
||||
/// Get the optional chunk as a string. This function is possibly recursive.
|
||||
///
|
||||
/// The parameter info for each parameter is appended to the Parameters.
|
||||
std::string getOptionalParameters(const CodeCompletionString &CCS,
|
||||
std::vector<ParameterInformation> &Parameters,
|
||||
SignatureQualitySignals &Signal) {
|
||||
std::string Result;
|
||||
for (const auto &Chunk : CCS) {
|
||||
switch (Chunk.Kind) {
|
||||
case CodeCompletionString::CK_Optional:
|
||||
assert(Chunk.Optional &&
|
||||
"Expected the optional code completion string to be non-null.");
|
||||
Result += getOptionalParameters(*Chunk.Optional, Parameters, Signal);
|
||||
break;
|
||||
case CodeCompletionString::CK_VerticalSpace:
|
||||
break;
|
||||
case CodeCompletionString::CK_Placeholder:
|
||||
// A string that acts as a placeholder for, e.g., a function call
|
||||
// argument.
|
||||
// Intentional fallthrough here.
|
||||
case CodeCompletionString::CK_CurrentParameter: {
|
||||
// A piece of text that describes the parameter that corresponds to
|
||||
// the code-completion location within a function call, message send,
|
||||
// macro invocation, etc.
|
||||
Result += Chunk.Text;
|
||||
ParameterInformation Info;
|
||||
Info.label = Chunk.Text;
|
||||
Parameters.push_back(std::move(Info));
|
||||
Signal.ContainsActiveParameter = true;
|
||||
Signal.NumberOfOptionalParameters++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Result += Chunk.Text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Identifier code completion result.
|
||||
struct RawIdentifier {
|
||||
llvm::StringRef Name;
|
||||
@@ -830,8 +792,7 @@ class SignatureHelpCollector final : public CodeCompleteConsumer {
|
||||
public:
|
||||
SignatureHelpCollector(const clang::CodeCompleteOptions &CodeCompleteOpts,
|
||||
const SymbolIndex *Index, SignatureHelp &SigHelp)
|
||||
: CodeCompleteConsumer(CodeCompleteOpts),
|
||||
SigHelp(SigHelp),
|
||||
: CodeCompleteConsumer(CodeCompleteOpts), SigHelp(SigHelp),
|
||||
Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
|
||||
CCTUInfo(Allocator), Index(Index) {}
|
||||
|
||||
@@ -944,6 +905,50 @@ public:
|
||||
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
|
||||
|
||||
private:
|
||||
void processParameterChunk(llvm::StringRef ChunkText,
|
||||
SignatureInformation &Signature,
|
||||
SignatureQualitySignals Signal) const {
|
||||
// (!) this is O(n), should still be fast compared to building ASTs.
|
||||
unsigned ParamStartOffset = lspLength(Signature.label);
|
||||
unsigned ParamEndOffset = ParamStartOffset + lspLength(ChunkText);
|
||||
// A piece of text that describes the parameter that corresponds to
|
||||
// the code-completion location within a function call, message send,
|
||||
// macro invocation, etc.
|
||||
Signature.label += ChunkText;
|
||||
ParameterInformation Info;
|
||||
Info.labelOffsets.emplace(ParamStartOffset, ParamEndOffset);
|
||||
// FIXME: only set 'labelOffsets' when all clients migrate out of it.
|
||||
Info.labelString = ChunkText;
|
||||
|
||||
Signature.parameters.push_back(std::move(Info));
|
||||
// FIXME: this should only be set on CK_CurrentParameter.
|
||||
Signal.ContainsActiveParameter = true;
|
||||
}
|
||||
|
||||
void processOptionalChunk(const CodeCompletionString &CCS,
|
||||
SignatureInformation &Signature,
|
||||
SignatureQualitySignals &Signal) const {
|
||||
for (const auto &Chunk : CCS) {
|
||||
switch (Chunk.Kind) {
|
||||
case CodeCompletionString::CK_Optional:
|
||||
assert(Chunk.Optional &&
|
||||
"Expected the optional code completion string to be non-null.");
|
||||
processOptionalChunk(*Chunk.Optional, Signature, Signal);
|
||||
break;
|
||||
case CodeCompletionString::CK_VerticalSpace:
|
||||
break;
|
||||
case CodeCompletionString::CK_CurrentParameter:
|
||||
case CodeCompletionString::CK_Placeholder:
|
||||
processParameterChunk(Chunk.Text, Signature, Signal);
|
||||
Signal.NumberOfOptionalParameters++;
|
||||
break;
|
||||
default:
|
||||
Signature.label += Chunk.Text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(ioeric): consider moving CodeCompletionString logic here to
|
||||
// CompletionString.h.
|
||||
ScoredSignature processOverloadCandidate(const OverloadCandidate &Candidate,
|
||||
@@ -964,28 +969,16 @@ private:
|
||||
assert(!ReturnType && "Unexpected CK_ResultType");
|
||||
ReturnType = Chunk.Text;
|
||||
break;
|
||||
case CodeCompletionString::CK_CurrentParameter:
|
||||
case CodeCompletionString::CK_Placeholder:
|
||||
// A string that acts as a placeholder for, e.g., a function call
|
||||
// argument.
|
||||
// Intentional fallthrough here.
|
||||
case CodeCompletionString::CK_CurrentParameter: {
|
||||
// A piece of text that describes the parameter that corresponds to
|
||||
// the code-completion location within a function call, message send,
|
||||
// macro invocation, etc.
|
||||
Signature.label += Chunk.Text;
|
||||
ParameterInformation Info;
|
||||
Info.label = Chunk.Text;
|
||||
Signature.parameters.push_back(std::move(Info));
|
||||
processParameterChunk(Chunk.Text, Signature, Signal);
|
||||
Signal.NumberOfParameters++;
|
||||
Signal.ContainsActiveParameter = true;
|
||||
break;
|
||||
}
|
||||
case CodeCompletionString::CK_Optional: {
|
||||
// The rest of the parameters are defaulted/optional.
|
||||
assert(Chunk.Optional &&
|
||||
"Expected the optional code completion string to be non-null.");
|
||||
Signature.label += getOptionalParameters(*Chunk.Optional,
|
||||
Signature.parameters, Signal);
|
||||
processOptionalChunk(*Chunk.Optional, Signature, Signal);
|
||||
break;
|
||||
}
|
||||
case CodeCompletionString::CK_VerticalSpace:
|
||||
@@ -1037,7 +1030,7 @@ void loadMainFilePreambleMacros(const Preprocessor &PP,
|
||||
PP.getIdentifierTable().getExternalIdentifierLookup();
|
||||
if (!PreambleIdentifiers || !PreambleMacros)
|
||||
return;
|
||||
for (const auto& MacroName : Preamble.MainFileMacros)
|
||||
for (const auto &MacroName : Preamble.MainFileMacros)
|
||||
if (auto *II = PreambleIdentifiers->get(MacroName))
|
||||
if (II->isOutOfDate())
|
||||
PreambleMacros->updateOutOfDateIdentifier(*II);
|
||||
@@ -1213,7 +1206,7 @@ class CodeCompleteFlow {
|
||||
int NSema = 0, NIndex = 0, NSemaAndIndex = 0, NIdent = 0;
|
||||
bool Incomplete = false; // Would more be available with a higher limit?
|
||||
CompletionPrefix HeuristicPrefix;
|
||||
llvm::Optional<FuzzyMatcher> Filter; // Initialized once Sema runs.
|
||||
llvm::Optional<FuzzyMatcher> Filter; // Initialized once Sema runs.
|
||||
Range ReplacedRange;
|
||||
std::vector<std::string> QueryScopes; // Initialized once Sema runs.
|
||||
// Initialized once QueryScopes is initialized, if there are scopes.
|
||||
@@ -1707,8 +1700,8 @@ clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
|
||||
return Result;
|
||||
}
|
||||
|
||||
CompletionPrefix
|
||||
guessCompletionPrefix(llvm::StringRef Content, unsigned Offset) {
|
||||
CompletionPrefix guessCompletionPrefix(llvm::StringRef Content,
|
||||
unsigned Offset) {
|
||||
assert(Offset <= Content.size());
|
||||
StringRef Rest = Content.take_front(Offset);
|
||||
CompletionPrefix Result;
|
||||
|
||||
@@ -314,6 +314,14 @@ bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto *Help = TextDocument->getObject("signatureHelp")) {
|
||||
if (auto *Info = Help->getObject("signatureInformation")) {
|
||||
if (auto *Parameter = Info->getObject("parameterInformation")) {
|
||||
if (auto OffsetSupport = Parameter->getBoolean("labelOffsetSupport"))
|
||||
R.OffsetsInSignatureHelp = *OffsetSupport;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto *Workspace = O->getObject("workspace")) {
|
||||
if (auto *Symbol = Workspace->getObject("symbol")) {
|
||||
@@ -824,8 +832,14 @@ llvm::json::Value toJSON(const CompletionList &L) {
|
||||
}
|
||||
|
||||
llvm::json::Value toJSON(const ParameterInformation &PI) {
|
||||
assert(!PI.label.empty() && "parameter information label is required");
|
||||
llvm::json::Object Result{{"label", PI.label}};
|
||||
assert(PI.labelOffsets.hasValue() ||
|
||||
!PI.labelString.empty() && "parameter information label is required");
|
||||
llvm::json::Object Result;
|
||||
if (PI.labelOffsets)
|
||||
Result["label"] =
|
||||
llvm::json::Array({PI.labelOffsets->first, PI.labelOffsets->second});
|
||||
else
|
||||
Result["label"] = PI.labelString;
|
||||
if (!PI.documentation.empty())
|
||||
Result["documentation"] = PI.documentation;
|
||||
return std::move(Result);
|
||||
|
||||
@@ -390,6 +390,9 @@ struct ClientCapabilities {
|
||||
/// Client supports hierarchical document symbols.
|
||||
bool HierarchicalDocumentSymbol = false;
|
||||
|
||||
/// Client supports processing label offsets instead of a simple label string.
|
||||
bool OffsetsInSignatureHelp = false;
|
||||
|
||||
/// The supported set of CompletionItemKinds for textDocument/completion.
|
||||
/// textDocument.completion.completionItemKind.valueSet
|
||||
llvm::Optional<CompletionItemKindBitset> CompletionItemKinds;
|
||||
@@ -979,8 +982,14 @@ llvm::json::Value toJSON(const CompletionList &);
|
||||
/// A single parameter of a particular signature.
|
||||
struct ParameterInformation {
|
||||
|
||||
/// The label of this parameter. Mandatory.
|
||||
std::string label;
|
||||
/// The label of this parameter. Ignored when labelOffsets is set.
|
||||
std::string labelString;
|
||||
|
||||
/// Inclusive start and exclusive end offsets withing the containing signature
|
||||
/// label.
|
||||
/// Offsets are computed by lspLength(), which counts UTF-16 code units by
|
||||
/// default but that can be overriden, see its documentation for details.
|
||||
llvm::Optional<std::pair<unsigned, unsigned>> labelOffsets;
|
||||
|
||||
/// The documentation of this parameter. Optional.
|
||||
std::string documentation;
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
|
||||
# Start a session.
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 0,
|
||||
"method": "initialize",
|
||||
"params": {
|
||||
"processId": 123,
|
||||
"rootPath": "clangd",
|
||||
"capabilities": {
|
||||
"textDocument": {
|
||||
"signatureHelp": {
|
||||
"signatureInformation": {
|
||||
"parameterInformation": {
|
||||
"labelOffsetSupport": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"trace": "off"
|
||||
}
|
||||
}
|
||||
---
|
||||
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"void x(int);\nint main(){\nx("}}}
|
||||
---
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/signatureHelp","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":2}}}
|
||||
# CHECK: "id": 1,
|
||||
# CHECK-NEXT: "jsonrpc": "2.0",
|
||||
# CHECK-NEXT: "result": {
|
||||
# CHECK-NEXT: "activeParameter": 0,
|
||||
# CHECK-NEXT: "activeSignature": 0,
|
||||
# CHECK-NEXT: "signatures": [
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "label": "x(int) -> void",
|
||||
# CHECK-NEXT: "parameters": [
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "label": [
|
||||
# CHECK-NEXT: 2,
|
||||
# CHECK-NEXT: 5
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
---
|
||||
{"jsonrpc":"2.0","id":100000,"method":"shutdown"}
|
||||
---
|
||||
{"jsonrpc":"2.0","method":"exit"}
|
||||
@@ -967,19 +967,37 @@ SignatureHelp signatures(llvm::StringRef Text,
|
||||
return signatures(Test.code(), Test.point(), std::move(IndexSymbols));
|
||||
}
|
||||
|
||||
struct ExpectedParameter {
|
||||
std::string Text;
|
||||
std::pair<unsigned, unsigned> Offsets;
|
||||
};
|
||||
MATCHER_P(ParamsAre, P, "") {
|
||||
if (P.size() != arg.parameters.size())
|
||||
return false;
|
||||
for (unsigned I = 0; I < P.size(); ++I)
|
||||
if (P[I] != arg.parameters[I].label)
|
||||
for (unsigned I = 0; I < P.size(); ++I) {
|
||||
if (P[I].Text != arg.parameters[I].labelString ||
|
||||
P[I].Offsets != arg.parameters[I].labelOffsets)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
MATCHER_P(SigDoc, Doc, "") { return arg.documentation == Doc; }
|
||||
|
||||
Matcher<SignatureInformation> Sig(std::string Label,
|
||||
std::vector<std::string> Params) {
|
||||
return AllOf(SigHelpLabeled(Label), ParamsAre(Params));
|
||||
/// \p AnnotatedLabel is a signature label with ranges marking parameters, e.g.
|
||||
/// foo([[int p1]], [[double p2]]) -> void
|
||||
Matcher<SignatureInformation> Sig(llvm::StringRef AnnotatedLabel) {
|
||||
llvm::Annotations A(AnnotatedLabel);
|
||||
std::string Label = A.code();
|
||||
std::vector<ExpectedParameter> Parameters;
|
||||
for (auto Range : A.ranges()) {
|
||||
Parameters.emplace_back();
|
||||
|
||||
ExpectedParameter &P = Parameters.back();
|
||||
P.Text = Label.substr(Range.Begin, Range.End - Range.Begin);
|
||||
P.Offsets.first = lspLength(llvm::StringRef(Label).substr(0, Range.Begin));
|
||||
P.Offsets.second = lspLength(llvm::StringRef(Label).substr(1, Range.End));
|
||||
}
|
||||
return AllOf(SigHelpLabeled(Label), ParamsAre(Parameters));
|
||||
}
|
||||
|
||||
TEST(SignatureHelpTest, Overloads) {
|
||||
@@ -992,11 +1010,10 @@ TEST(SignatureHelpTest, Overloads) {
|
||||
int main() { foo(^); }
|
||||
)cpp");
|
||||
EXPECT_THAT(Results.signatures,
|
||||
UnorderedElementsAre(
|
||||
Sig("foo(float x, float y) -> void", {"float x", "float y"}),
|
||||
Sig("foo(float x, int y) -> void", {"float x", "int y"}),
|
||||
Sig("foo(int x, float y) -> void", {"int x", "float y"}),
|
||||
Sig("foo(int x, int y) -> void", {"int x", "int y"})));
|
||||
UnorderedElementsAre(Sig("foo([[float x]], [[float y]]) -> void"),
|
||||
Sig("foo([[float x]], [[int y]]) -> void"),
|
||||
Sig("foo([[int x]], [[float y]]) -> void"),
|
||||
Sig("foo([[int x]], [[int y]]) -> void")));
|
||||
// We always prefer the first signature.
|
||||
EXPECT_EQ(0, Results.activeSignature);
|
||||
EXPECT_EQ(0, Results.activeParameter);
|
||||
@@ -1010,9 +1027,8 @@ TEST(SignatureHelpTest, DefaultArgs) {
|
||||
)cpp");
|
||||
EXPECT_THAT(Results.signatures,
|
||||
UnorderedElementsAre(
|
||||
Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
|
||||
Sig("bar(float x = 0, int y = 42) -> void",
|
||||
{"float x = 0", "int y = 42"})));
|
||||
Sig("bar([[int x]], [[int y = 0]]) -> void"),
|
||||
Sig("bar([[float x = 0]], [[int y = 42]]) -> void")));
|
||||
EXPECT_EQ(0, Results.activeSignature);
|
||||
EXPECT_EQ(0, Results.activeParameter);
|
||||
}
|
||||
@@ -1023,8 +1039,7 @@ TEST(SignatureHelpTest, ActiveArg) {
|
||||
int main() { baz(baz(1,2,3), ^); }
|
||||
)cpp");
|
||||
EXPECT_THAT(Results.signatures,
|
||||
ElementsAre(Sig("baz(int a, int b, int c) -> int",
|
||||
{"int a", "int b", "int c"})));
|
||||
ElementsAre(Sig("baz([[int a]], [[int b]], [[int c]]) -> int")));
|
||||
EXPECT_EQ(0, Results.activeSignature);
|
||||
EXPECT_EQ(1, Results.activeParameter);
|
||||
}
|
||||
@@ -1761,14 +1776,12 @@ TEST(SignatureHelpTest, OverloadsOrdering) {
|
||||
void foo(int x, int y = 0);
|
||||
int main() { foo(^); }
|
||||
)cpp");
|
||||
EXPECT_THAT(
|
||||
Results.signatures,
|
||||
ElementsAre(
|
||||
Sig("foo(int x) -> void", {"int x"}),
|
||||
Sig("foo(int x, int y = 0) -> void", {"int x", "int y = 0"}),
|
||||
Sig("foo(float x, int y) -> void", {"float x", "int y"}),
|
||||
Sig("foo(int x, float y) -> void", {"int x", "float y"}),
|
||||
Sig("foo(float x, float y) -> void", {"float x", "float y"})));
|
||||
EXPECT_THAT(Results.signatures,
|
||||
ElementsAre(Sig("foo([[int x]]) -> void"),
|
||||
Sig("foo([[int x]], [[int y = 0]]) -> void"),
|
||||
Sig("foo([[float x]], [[int y]]) -> void"),
|
||||
Sig("foo([[int x]], [[float y]]) -> void"),
|
||||
Sig("foo([[float x]], [[float y]]) -> void")));
|
||||
// We always prefer the first signature.
|
||||
EXPECT_EQ(0, Results.activeSignature);
|
||||
EXPECT_EQ(0, Results.activeParameter);
|
||||
@@ -1785,7 +1798,7 @@ TEST(SignatureHelpTest, InstantiatedSignatures) {
|
||||
)cpp";
|
||||
|
||||
EXPECT_THAT(signatures(Sig0).signatures,
|
||||
ElementsAre(Sig("foo(T, T, T) -> void", {"T", "T", "T"})));
|
||||
ElementsAre(Sig("foo([[T]], [[T]], [[T]]) -> void")));
|
||||
|
||||
StringRef Sig1 = R"cpp(
|
||||
template <class T>
|
||||
@@ -1796,7 +1809,7 @@ TEST(SignatureHelpTest, InstantiatedSignatures) {
|
||||
})cpp";
|
||||
|
||||
EXPECT_THAT(signatures(Sig1).signatures,
|
||||
ElementsAre(Sig("foo(T, T, T) -> void", {"T", "T", "T"})));
|
||||
ElementsAre(Sig("foo([[T]], [[T]], [[T]]) -> void")));
|
||||
|
||||
StringRef Sig2 = R"cpp(
|
||||
template <class ...T>
|
||||
@@ -1808,7 +1821,7 @@ TEST(SignatureHelpTest, InstantiatedSignatures) {
|
||||
)cpp";
|
||||
|
||||
EXPECT_THAT(signatures(Sig2).signatures,
|
||||
ElementsAre(Sig("foo(T...) -> void", {"T..."})));
|
||||
ElementsAre(Sig("foo([[T...]]) -> void")));
|
||||
|
||||
// It is debatable whether we should substitute the outer template parameter
|
||||
// ('T') in that case. Currently we don't substitute it in signature help, but
|
||||
@@ -1828,7 +1841,7 @@ TEST(SignatureHelpTest, InstantiatedSignatures) {
|
||||
)cpp";
|
||||
|
||||
EXPECT_THAT(signatures(Sig3).signatures,
|
||||
ElementsAre(Sig("foo(T, U) -> void", {"T", "U"})));
|
||||
ElementsAre(Sig("foo([[T]], [[U]]) -> void")));
|
||||
}
|
||||
|
||||
TEST(SignatureHelpTest, IndexDocumentation) {
|
||||
@@ -1849,8 +1862,8 @@ TEST(SignatureHelpTest, IndexDocumentation) {
|
||||
|
||||
EXPECT_THAT(
|
||||
signatures(Sig0, {Foo0}).signatures,
|
||||
ElementsAre(AllOf(Sig("foo() -> int", {}), SigDoc("Doc from the index")),
|
||||
AllOf(Sig("foo(double) -> int", {"double"}), SigDoc(""))));
|
||||
ElementsAre(AllOf(Sig("foo() -> int"), SigDoc("Doc from the index")),
|
||||
AllOf(Sig("foo([[double]]) -> int"), SigDoc(""))));
|
||||
|
||||
StringRef Sig1 = R"cpp(
|
||||
int foo();
|
||||
@@ -1866,11 +1879,10 @@ TEST(SignatureHelpTest, IndexDocumentation) {
|
||||
|
||||
EXPECT_THAT(
|
||||
signatures(Sig1, {Foo0, Foo1, Foo2}).signatures,
|
||||
ElementsAre(AllOf(Sig("foo() -> int", {}), SigDoc("Doc from the index")),
|
||||
AllOf(Sig("foo(int) -> int", {"int"}),
|
||||
SigDoc("Overriden doc from sema")),
|
||||
AllOf(Sig("foo(int, int) -> int", {"int", "int"}),
|
||||
SigDoc("Doc from sema"))));
|
||||
ElementsAre(
|
||||
AllOf(Sig("foo() -> int"), SigDoc("Doc from the index")),
|
||||
AllOf(Sig("foo([[int]]) -> int"), SigDoc("Overriden doc from sema")),
|
||||
AllOf(Sig("foo([[int]], [[int]]) -> int"), SigDoc("Doc from sema"))));
|
||||
}
|
||||
|
||||
TEST(SignatureHelpTest, DynamicIndexDocumentation) {
|
||||
@@ -1901,7 +1913,7 @@ TEST(SignatureHelpTest, DynamicIndexDocumentation) {
|
||||
EXPECT_THAT(
|
||||
llvm::cantFail(runSignatureHelp(Server, File, FileContent.point()))
|
||||
.signatures,
|
||||
ElementsAre(AllOf(Sig("foo() -> int", {}), SigDoc("Member doc"))));
|
||||
ElementsAre(AllOf(Sig("foo() -> int"), SigDoc("Member doc"))));
|
||||
}
|
||||
|
||||
TEST(CompletionTest, CompletionFunctionArgsDisabled) {
|
||||
@@ -2179,10 +2191,9 @@ TEST(SignatureHelpTest, InsideArgument) {
|
||||
void foo(int x, int y);
|
||||
int main() { foo(1+^); }
|
||||
)cpp");
|
||||
EXPECT_THAT(
|
||||
Results.signatures,
|
||||
ElementsAre(Sig("foo(int x) -> void", {"int x"}),
|
||||
Sig("foo(int x, int y) -> void", {"int x", "int y"})));
|
||||
EXPECT_THAT(Results.signatures,
|
||||
ElementsAre(Sig("foo([[int x]]) -> void"),
|
||||
Sig("foo([[int x]], [[int y]]) -> void")));
|
||||
EXPECT_EQ(0, Results.activeParameter);
|
||||
}
|
||||
{
|
||||
@@ -2191,10 +2202,9 @@ TEST(SignatureHelpTest, InsideArgument) {
|
||||
void foo(int x, int y);
|
||||
int main() { foo(1^); }
|
||||
)cpp");
|
||||
EXPECT_THAT(
|
||||
Results.signatures,
|
||||
ElementsAre(Sig("foo(int x) -> void", {"int x"}),
|
||||
Sig("foo(int x, int y) -> void", {"int x", "int y"})));
|
||||
EXPECT_THAT(Results.signatures,
|
||||
ElementsAre(Sig("foo([[int x]]) -> void"),
|
||||
Sig("foo([[int x]], [[int y]]) -> void")));
|
||||
EXPECT_EQ(0, Results.activeParameter);
|
||||
}
|
||||
{
|
||||
@@ -2203,10 +2213,9 @@ TEST(SignatureHelpTest, InsideArgument) {
|
||||
void foo(int x, int y);
|
||||
int main() { foo(1^0); }
|
||||
)cpp");
|
||||
EXPECT_THAT(
|
||||
Results.signatures,
|
||||
ElementsAre(Sig("foo(int x) -> void", {"int x"}),
|
||||
Sig("foo(int x, int y) -> void", {"int x", "int y"})));
|
||||
EXPECT_THAT(Results.signatures,
|
||||
ElementsAre(Sig("foo([[int x]]) -> void"),
|
||||
Sig("foo([[int x]], [[int y]]) -> void")));
|
||||
EXPECT_EQ(0, Results.activeParameter);
|
||||
}
|
||||
{
|
||||
@@ -2216,8 +2225,8 @@ TEST(SignatureHelpTest, InsideArgument) {
|
||||
int bar(int x, int y);
|
||||
int main() { bar(foo(2, 3^)); }
|
||||
)cpp");
|
||||
EXPECT_THAT(Results.signatures, ElementsAre(Sig("foo(int x, int y) -> void",
|
||||
{"int x", "int y"})));
|
||||
EXPECT_THAT(Results.signatures,
|
||||
ElementsAre(Sig("foo([[int x]], [[int y]]) -> void")));
|
||||
EXPECT_EQ(1, Results.activeParameter);
|
||||
}
|
||||
}
|
||||
@@ -2234,9 +2243,8 @@ TEST(SignatureHelpTest, ConstructorInitializeFields) {
|
||||
};
|
||||
)cpp");
|
||||
EXPECT_THAT(Results.signatures,
|
||||
UnorderedElementsAre(Sig("A(int)", {"int"}),
|
||||
Sig("A(A &&)", {"A &&"}),
|
||||
Sig("A(const A &)", {"const A &"})));
|
||||
UnorderedElementsAre(Sig("A([[int]])"), Sig("A([[A &&]])"),
|
||||
Sig("A([[const A &]])")));
|
||||
}
|
||||
{
|
||||
const auto Results = signatures(R"cpp(
|
||||
@@ -2253,9 +2261,8 @@ TEST(SignatureHelpTest, ConstructorInitializeFields) {
|
||||
};
|
||||
)cpp");
|
||||
EXPECT_THAT(Results.signatures,
|
||||
UnorderedElementsAre(Sig("A(int)", {"int"}),
|
||||
Sig("A(A &&)", {"A &&"}),
|
||||
Sig("A(const A &)", {"const A &"})));
|
||||
UnorderedElementsAre(Sig("A([[int]])"), Sig("A([[A &&]])"),
|
||||
Sig("A([[const A &]])")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user