clang-tools 24.0.0git
CodeCompletionStringsTests.cpp
Go to the documentation of this file.
1//===-- CodeCompletionStringsTests.cpp --------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "Config.h"
11#include "TestTU.h"
12#include "clang/Sema/CodeCompleteConsumer.h"
13#include "gmock/gmock.h"
14#include "gtest/gtest.h"
15
16namespace clang {
17namespace clangd {
18namespace {
19
20class CompletionStringTest : public ::testing::Test {
21public:
22 CompletionStringTest()
23 : Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
24 CCTUInfo(Allocator), Builder(*Allocator, CCTUInfo) {}
25
26protected:
27 void computeSignature(const CodeCompletionString &CCS,
28 CodeCompletionResult::ResultKind ResultKind =
29 CodeCompletionResult::ResultKind::RK_Declaration,
30 bool IncludeFunctionArguments = true) {
31 Signature.clear();
32 Snippet.clear();
33 getSignature(CCS, &Signature, &Snippet, ResultKind,
34 /*CursorKind=*/CXCursorKind::CXCursor_NotImplemented,
35 /*IncludeFunctionArguments=*/IncludeFunctionArguments,
36 /*RequiredQualifiers=*/nullptr);
37 }
38
39 std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
40 CodeCompletionTUInfo CCTUInfo;
41 CodeCompletionBuilder Builder;
42 std::string Signature;
43 std::string Snippet;
44};
45
46TEST_F(CompletionStringTest, ReturnType) {
47 Builder.AddResultTypeChunk("result");
48 Builder.AddResultTypeChunk("redundant result no no");
49 EXPECT_EQ(getReturnType(*Builder.TakeString()), "result");
50}
51
52TEST_F(CompletionStringTest, Documentation) {
53 Builder.addBriefComment("This is ignored");
54 EXPECT_EQ(formatDocumentation(*Builder.TakeString(), "Is this brief?"),
55 "Is this brief?");
56}
57
58TEST_F(CompletionStringTest, DocumentationWithAnnotation) {
59 Builder.addBriefComment("This is ignored");
60 Builder.AddAnnotation("Ano");
61 EXPECT_EQ(formatDocumentation(*Builder.TakeString(), "Is this brief?"),
62 "Annotation: Ano\n\nIs this brief?");
63}
64
65TEST_F(CompletionStringTest, GetDeclCommentBadUTF8) {
66 // <ff> is not a valid byte here, should be replaced by encoded <U+FFFD>.
67 auto TU = TestTU::withCode("/*x\xffy*/ struct X;");
68 auto AST = TU.build();
69 EXPECT_EQ("x\xef\xbf\xbdy",
70 getDeclComment(AST.getASTContext(), findDecl(AST, "X")));
71}
72
73TEST_F(CompletionStringTest, GetDeclCommentForParam) {
74 auto TU =
75 TestTU::withCode("/** @param a this is param a */\nvoid func(int a);");
76 auto AST = TU.build();
77 Config Cfg;
79 WithContextValue WithCfg(Config::Key, std::move(Cfg));
80 const auto &FD = llvm::cast<FunctionDecl>(findDecl(AST, "func"));
81 EXPECT_EQ(FD.getNumParams(), 1UL);
82 EXPECT_EQ("this is param a",
83 getDeclComment(AST.getASTContext(), *FD.parameters()[0]));
84}
85
86TEST_F(CompletionStringTest, GetDeclCommentForMultipleParams) {
87 auto TU = TestTU::withCode("/** @param a this is param a\n * @param b this "
88 "is param b\n */\nvoid func(int a, int b);");
89 auto AST = TU.build();
90 Config Cfg;
92 WithContextValue WithCfg(Config::Key, std::move(Cfg));
93 const auto &FD = llvm::cast<FunctionDecl>(findDecl(AST, "func"));
94 EXPECT_EQ(FD.getNumParams(), 2UL);
95 EXPECT_EQ("this is param a",
96 getDeclComment(AST.getASTContext(), *FD.parameters()[0]));
97 EXPECT_EQ("this is param b",
98 getDeclComment(AST.getASTContext(), *FD.parameters()[1]));
99}
100
101TEST_F(CompletionStringTest, GetDeclCommentForUndocumentedParam) {
102 auto TU =
103 TestTU::withCode("/** @param c this is param c */\nvoid func(int a);");
104 auto AST = TU.build();
105 Config Cfg;
107 WithContextValue WithCfg(Config::Key, std::move(Cfg));
108 const auto &FD = llvm::cast<FunctionDecl>(findDecl(AST, "func"));
109 EXPECT_EQ(FD.getNumParams(), 1UL);
110 EXPECT_EQ("", getDeclComment(AST.getASTContext(), *FD.parameters()[0]));
111}
112
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();
117 Config Cfg;
119 WithContextValue WithCfg(Config::Key, std::move(Cfg));
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",
123 getDeclComment(AST.getASTContext(), *FD.parameters()[0]));
124}
125
126TEST_F(CompletionStringTest, MultipleAnnotations) {
127 Builder.AddAnnotation("Ano1");
128 Builder.AddAnnotation("Ano2");
129 Builder.AddAnnotation("Ano3");
130
131 EXPECT_EQ(formatDocumentation(*Builder.TakeString(), ""),
132 "Annotations: Ano1 Ano2 Ano3\n");
133}
134
135TEST_F(CompletionStringTest, EmptySignature) {
136 Builder.AddTypedTextChunk("X");
137 Builder.AddResultTypeChunk("result no no");
138 computeSignature(*Builder.TakeString());
139 EXPECT_EQ(Signature, "");
140 EXPECT_EQ(Snippet, "");
141}
142
143TEST_F(CompletionStringTest, Function) {
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);
152
153 auto *CCS = Builder.TakeString();
154 computeSignature(*CCS);
155 EXPECT_EQ(Signature, "(p1, p2)");
156 EXPECT_EQ(Snippet, "(${1:p1}, ${2:p2})");
157 EXPECT_EQ(formatDocumentation(*CCS, "Foo's comment"), "Foo's comment");
158}
159
160TEST_F(CompletionStringTest, FunctionWithDefaultParams) {
161 // return_type foo(p1, p2 = 0, p3 = 0)
162 Builder.AddChunk(CodeCompletionString::CK_Comma);
163 Builder.AddTypedTextChunk("p3 = 0");
164 auto *DefaultParam2 = Builder.TakeString();
165
166 Builder.AddChunk(CodeCompletionString::CK_Comma);
167 Builder.AddTypedTextChunk("p2 = 0");
168 Builder.AddOptionalChunk(DefaultParam2);
169 auto *DefaultParam1 = Builder.TakeString();
170
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);
177
178 auto *CCS = Builder.TakeString();
179 computeSignature(*CCS);
180 EXPECT_EQ(Signature, "(p1, p2 = 0, p3 = 0)");
181 EXPECT_EQ(Snippet, "(${1:p1})");
182}
183
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);
189
190 computeSignature(*Builder.TakeString());
191 EXPECT_EQ(Signature, "($p}1\\)");
192 EXPECT_EQ(Snippet, "(${1:\\$p\\}1\\\\})");
193}
194
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();
205 };
206 computeSignature(MakeCCS());
207 EXPECT_EQ(Snippet, " ${1:name} = ${2:target};");
208
209 // When completing a pattern, the last placeholder holds the cursor position.
210 computeSignature(MakeCCS(),
211 /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Pattern);
212 EXPECT_EQ(Snippet, " ${1:name} = $0;");
213}
214
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);
227
228 computeSignature(
229 *Builder.TakeString(),
230 /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Declaration,
231 /*IncludeFunctionArguments=*/false);
232 // Arguments dropped from snippet, kept in signature.
233 EXPECT_EQ(Signature, "<typename T, int U>(arg1, arg2)");
234 EXPECT_EQ(Snippet, "<${1:typename T}, ${2:int U}>");
235}
236
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");
243 EXPECT_EQ(Snippet, "");
244}
245
246TEST_F(CompletionStringTest, ObjectiveCMethodNoArguments) {
247 Builder.AddResultTypeChunk("void");
248 Builder.AddTypedTextChunk("methodName");
249
250 auto *CCS = Builder.TakeString();
251 computeSignature(*CCS);
252 EXPECT_EQ(Signature, "");
253 EXPECT_EQ(Snippet, "");
254}
255
256TEST_F(CompletionStringTest, ObjectiveCMethodOneArgument) {
257 Builder.AddResultTypeChunk("void");
258 Builder.AddTypedTextChunk("methodWithArg:");
259 Builder.AddPlaceholderChunk("(type)");
260
261 auto *CCS = Builder.TakeString();
262 computeSignature(*CCS);
263 EXPECT_EQ(Signature, "(type)");
264 EXPECT_EQ(Snippet, "${1:(type)}");
265}
266
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)");
274
275 auto *CCS = Builder.TakeString();
276 computeSignature(*CCS);
277 EXPECT_EQ(Signature, "(type) bar:(type2)");
278 EXPECT_EQ(Snippet, "${1:(type)} bar:${2:(type2)}");
279}
280
281TEST_F(CompletionStringTest, ObjectiveCMethodTwoArgumentsFromMiddle) {
282 Builder.AddResultTypeChunk("int");
283 Builder.AddInformativeChunk("withFoo:");
284 Builder.AddTypedTextChunk("bar:");
285 Builder.AddPlaceholderChunk("(type2)");
286
287 auto *CCS = Builder.TakeString();
288 computeSignature(*CCS);
289 EXPECT_EQ(Signature, "(type2)");
290 EXPECT_EQ(Snippet, "${1:(type2)}");
291}
292
293} // namespace
294} // namespace clangd
295} // namespace clang
WithContextValue extends Context::current() with a single value.
Definition Context.h:200
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
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)
Definition TestTU.cpp:220
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.
Definition Config.h:45
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
Definition Config.h:49
@ Doxygen
Treat comments as doxygen.
Definition Config.h:218
struct clang::clangd::Config::@205014242342057164216030136313205137334246150047 Documentation
CommentFormatPolicy CommentFormat
Definition Config.h:222
static TestTU withCode(llvm::StringRef Code)
Definition TestTU.h:36