12#include "clang/Sema/CodeCompleteConsumer.h"
13#include "gmock/gmock.h"
14#include "gtest/gtest.h"
20class CompletionStringTest :
public ::testing::Test {
22 CompletionStringTest()
23 : Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
24 CCTUInfo(Allocator), Builder(*Allocator, CCTUInfo) {}
27 void computeSignature(
const CodeCompletionString &CCS,
28 CodeCompletionResult::ResultKind ResultKind =
29 CodeCompletionResult::ResultKind::RK_Declaration,
30 bool IncludeFunctionArguments =
true) {
34 CXCursorKind::CXCursor_NotImplemented,
35 IncludeFunctionArguments,
39 std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
40 CodeCompletionTUInfo CCTUInfo;
41 CodeCompletionBuilder Builder;
42 std::string Signature;
46TEST_F(CompletionStringTest, ReturnType) {
47 Builder.AddResultTypeChunk(
"result");
48 Builder.AddResultTypeChunk(
"redundant result no no");
52TEST_F(CompletionStringTest, Documentation) {
53 Builder.addBriefComment(
"This is ignored");
58TEST_F(CompletionStringTest, DocumentationWithAnnotation) {
59 Builder.addBriefComment(
"This is ignored");
60 Builder.AddAnnotation(
"Ano");
62 "Annotation: Ano\n\nIs this brief?");
65TEST_F(CompletionStringTest, GetDeclCommentBadUTF8) {
68 auto AST = TU.build();
69 EXPECT_EQ(
"x\xef\xbf\xbdy",
73TEST_F(CompletionStringTest, GetDeclCommentForParam) {
76 auto AST = TU.build();
80 const auto &FD = llvm::cast<FunctionDecl>(
findDecl(
AST,
"func"));
81 EXPECT_EQ(FD.getNumParams(), 1UL);
82 EXPECT_EQ(
"this is param a",
86TEST_F(CompletionStringTest, GetDeclCommentForMultipleParams) {
88 "is param b\n */\nvoid func(int a, int b);");
89 auto AST = TU.build();
93 const auto &FD = llvm::cast<FunctionDecl>(
findDecl(
AST,
"func"));
94 EXPECT_EQ(FD.getNumParams(), 2UL);
95 EXPECT_EQ(
"this is param a",
97 EXPECT_EQ(
"this is param b",
101TEST_F(CompletionStringTest, GetDeclCommentForUndocumentedParam) {
104 auto AST = TU.build();
108 const auto &FD = llvm::cast<FunctionDecl>(
findDecl(
AST,
"func"));
109 EXPECT_EQ(FD.getNumParams(), 1UL);
113TEST_F(CompletionStringTest, GetDeclCommentForParamWithUnknownDoxygenCommand) {
114 auto TU =
TestTU::withCode(
"/** @param a this is param a and an\n * @unknown "
115 "command\n */\nvoid func(int a);");
116 auto AST = TU.build();
120 const auto &FD = llvm::cast<FunctionDecl>(
findDecl(
AST,
"func"));
121 EXPECT_EQ(FD.getNumParams(), 1UL);
122 EXPECT_EQ(
"this is param a and an\n@unknown command",
126TEST_F(CompletionStringTest, MultipleAnnotations) {
127 Builder.AddAnnotation(
"Ano1");
128 Builder.AddAnnotation(
"Ano2");
129 Builder.AddAnnotation(
"Ano3");
132 "Annotations: Ano1 Ano2 Ano3\n");
135TEST_F(CompletionStringTest, EmptySignature) {
136 Builder.AddTypedTextChunk(
"X");
137 Builder.AddResultTypeChunk(
"result no no");
138 computeSignature(*Builder.TakeString());
139 EXPECT_EQ(Signature,
"");
144 Builder.AddResultTypeChunk(
"result no no");
145 Builder.addBriefComment(
"This comment is ignored");
146 Builder.AddTypedTextChunk(
"Foo");
147 Builder.AddChunk(CodeCompletionString::CK_LeftParen);
148 Builder.AddPlaceholderChunk(
"p1");
149 Builder.AddChunk(CodeCompletionString::CK_Comma);
150 Builder.AddPlaceholderChunk(
"p2");
151 Builder.AddChunk(CodeCompletionString::CK_RightParen);
153 auto *CCS = Builder.TakeString();
154 computeSignature(*CCS);
155 EXPECT_EQ(Signature,
"(p1, p2)");
156 EXPECT_EQ(
Snippet,
"(${1:p1}, ${2:p2})");
160TEST_F(CompletionStringTest, FunctionWithDefaultParams) {
162 Builder.AddChunk(CodeCompletionString::CK_Comma);
163 Builder.AddTypedTextChunk(
"p3 = 0");
164 auto *DefaultParam2 = Builder.TakeString();
166 Builder.AddChunk(CodeCompletionString::CK_Comma);
167 Builder.AddTypedTextChunk(
"p2 = 0");
168 Builder.AddOptionalChunk(DefaultParam2);
169 auto *DefaultParam1 = Builder.TakeString();
171 Builder.AddResultTypeChunk(
"return_type");
172 Builder.AddTypedTextChunk(
"Foo");
173 Builder.AddChunk(CodeCompletionString::CK_LeftParen);
174 Builder.AddPlaceholderChunk(
"p1");
175 Builder.AddOptionalChunk(DefaultParam1);
176 Builder.AddChunk(CodeCompletionString::CK_RightParen);
178 auto *CCS = Builder.TakeString();
179 computeSignature(*CCS);
180 EXPECT_EQ(Signature,
"(p1, p2 = 0, p3 = 0)");
181 EXPECT_EQ(
Snippet,
"(${1:p1})");
184TEST_F(CompletionStringTest, EscapeSnippet) {
185 Builder.AddTypedTextChunk(
"Foo");
186 Builder.AddChunk(CodeCompletionString::CK_LeftParen);
187 Builder.AddPlaceholderChunk(
"$p}1\\");
188 Builder.AddChunk(CodeCompletionString::CK_RightParen);
190 computeSignature(*Builder.TakeString());
191 EXPECT_EQ(Signature,
"($p}1\\)");
192 EXPECT_EQ(
Snippet,
"(${1:\\$p\\}1\\\\})");
195TEST_F(CompletionStringTest, SnippetsInPatterns) {
196 auto MakeCCS = [
this]() ->
const CodeCompletionString & {
197 CodeCompletionBuilder Builder(*Allocator, CCTUInfo);
198 Builder.AddTypedTextChunk(
"namespace");
199 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
200 Builder.AddPlaceholderChunk(
"name");
201 Builder.AddChunk(CodeCompletionString::CK_Equal);
202 Builder.AddPlaceholderChunk(
"target");
203 Builder.AddChunk(CodeCompletionString::CK_SemiColon);
204 return *Builder.TakeString();
206 computeSignature(MakeCCS());
207 EXPECT_EQ(
Snippet,
" ${1:name} = ${2:target};");
210 computeSignature(MakeCCS(),
211 CodeCompletionResult::ResultKind::RK_Pattern);
212 EXPECT_EQ(
Snippet,
" ${1:name} = $0;");
215TEST_F(CompletionStringTest, DropFunctionArguments) {
216 Builder.AddTypedTextChunk(
"foo");
217 Builder.AddChunk(CodeCompletionString::CK_LeftAngle);
218 Builder.AddPlaceholderChunk(
"typename T");
219 Builder.AddChunk(CodeCompletionString::CK_Comma);
220 Builder.AddPlaceholderChunk(
"int U");
221 Builder.AddChunk(CodeCompletionString::CK_RightAngle);
222 Builder.AddChunk(CodeCompletionString::CK_LeftParen);
223 Builder.AddPlaceholderChunk(
"arg1");
224 Builder.AddChunk(CodeCompletionString::CK_Comma);
225 Builder.AddPlaceholderChunk(
"arg2");
226 Builder.AddChunk(CodeCompletionString::CK_RightParen);
229 *Builder.TakeString(),
230 CodeCompletionResult::ResultKind::RK_Declaration,
233 EXPECT_EQ(Signature,
"<typename T, int U>(arg1, arg2)");
234 EXPECT_EQ(
Snippet,
"<${1:typename T}, ${2:int U}>");
237TEST_F(CompletionStringTest, IgnoreInformativeQualifier) {
238 Builder.AddTypedTextChunk(
"X");
239 Builder.AddInformativeChunk(
"info ok");
240 Builder.AddInformativeChunk(
"info no no::");
241 computeSignature(*Builder.TakeString());
242 EXPECT_EQ(Signature,
"info ok");
246TEST_F(CompletionStringTest, ObjectiveCMethodNoArguments) {
247 Builder.AddResultTypeChunk(
"void");
248 Builder.AddTypedTextChunk(
"methodName");
250 auto *CCS = Builder.TakeString();
251 computeSignature(*CCS);
252 EXPECT_EQ(Signature,
"");
256TEST_F(CompletionStringTest, ObjectiveCMethodOneArgument) {
257 Builder.AddResultTypeChunk(
"void");
258 Builder.AddTypedTextChunk(
"methodWithArg:");
259 Builder.AddPlaceholderChunk(
"(type)");
261 auto *CCS = Builder.TakeString();
262 computeSignature(*CCS);
263 EXPECT_EQ(Signature,
"(type)");
264 EXPECT_EQ(
Snippet,
"${1:(type)}");
267TEST_F(CompletionStringTest, ObjectiveCMethodTwoArgumentsFromBeginning) {
268 Builder.AddResultTypeChunk(
"int");
269 Builder.AddTypedTextChunk(
"withFoo:");
270 Builder.AddPlaceholderChunk(
"(type)");
271 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
272 Builder.AddTypedTextChunk(
"bar:");
273 Builder.AddPlaceholderChunk(
"(type2)");
275 auto *CCS = Builder.TakeString();
276 computeSignature(*CCS);
277 EXPECT_EQ(Signature,
"(type) bar:(type2)");
278 EXPECT_EQ(
Snippet,
"${1:(type)} bar:${2:(type2)}");
281TEST_F(CompletionStringTest, ObjectiveCMethodTwoArgumentsFromMiddle) {
282 Builder.AddResultTypeChunk(
"int");
283 Builder.AddInformativeChunk(
"withFoo:");
284 Builder.AddTypedTextChunk(
"bar:");
285 Builder.AddPlaceholderChunk(
"(type2)");
287 auto *CCS = Builder.TakeString();
288 computeSignature(*CCS);
289 EXPECT_EQ(Signature,
"(type2)");
290 EXPECT_EQ(
Snippet,
"${1:(type2)}");
WithContextValue extends Context::current() with a single value.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
std::string formatDocumentation(const CodeCompletionString &CCS, llvm::StringRef DocComment)
Assembles formatted documentation for a completion result.
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl)
Similar to getDocComment, but returns the comment for a NamedDecl.
std::string getReturnType(const CodeCompletionString &CCS)
Gets detail to be used as the detail field in an LSP completion item.
void getSignature(const CodeCompletionString &CCS, std::string *Signature, std::string *Snippet, CodeCompletionResult::ResultKind ResultKind, CXCursorKind CursorKind, bool IncludeFunctionArguments, std::string *RequiredQualifiers)
Formats the signature for an item, as a display string and snippet.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Settings that express user/project preferences and control clangd behavior.
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
@ Doxygen
Treat comments as doxygen.
struct clang::clangd::Config::@205014242342057164216030136313205137334246150047 Documentation
CommentFormatPolicy CommentFormat
static TestTU withCode(llvm::StringRef Code)