1b804eef0SSam McCall //===-- CodeCompletionStringsTests.cpp --------------------------*- C++ -*-===//
2b804eef0SSam McCall //
3b804eef0SSam McCall // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b804eef0SSam McCall // See https://llvm.org/LICENSE.txt for license information.
5b804eef0SSam McCall // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b804eef0SSam McCall //
7b804eef0SSam McCall //===----------------------------------------------------------------------===//
8b804eef0SSam McCall
9b804eef0SSam McCall #include "CodeCompletionStrings.h"
10216af81cSSam McCall #include "TestTU.h"
11b804eef0SSam McCall #include "clang/Sema/CodeCompleteConsumer.h"
12b804eef0SSam McCall #include "gmock/gmock.h"
13b804eef0SSam McCall #include "gtest/gtest.h"
14b804eef0SSam McCall
15b804eef0SSam McCall namespace clang {
16b804eef0SSam McCall namespace clangd {
17b804eef0SSam McCall namespace {
18b804eef0SSam McCall
19b804eef0SSam McCall class CompletionStringTest : public ::testing::Test {
20b804eef0SSam McCall public:
CompletionStringTest()21b804eef0SSam McCall CompletionStringTest()
22b804eef0SSam McCall : Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
23b804eef0SSam McCall CCTUInfo(Allocator), Builder(*Allocator, CCTUInfo) {}
24b804eef0SSam McCall
25b804eef0SSam McCall protected:
computeSignature(const CodeCompletionString & CCS,CodeCompletionResult::ResultKind ResultKind=CodeCompletionResult::ResultKind::RK_Declaration,bool IncludeFunctionArguments=true)268534675cSIlya Biryukov void computeSignature(const CodeCompletionString &CCS,
27138adb09SYounan Zhang CodeCompletionResult::ResultKind ResultKind =
28*23ef8bf9SYounan Zhang CodeCompletionResult::ResultKind::RK_Declaration,
29*23ef8bf9SYounan Zhang bool IncludeFunctionArguments = true) {
30b804eef0SSam McCall Signature.clear();
31b804eef0SSam McCall Snippet.clear();
32138adb09SYounan Zhang getSignature(CCS, &Signature, &Snippet, ResultKind,
33138adb09SYounan Zhang /*CursorKind=*/CXCursorKind::CXCursor_NotImplemented,
34*23ef8bf9SYounan Zhang /*IncludeFunctionArguments=*/IncludeFunctionArguments,
35138adb09SYounan Zhang /*RequiredQualifiers=*/nullptr);
36b804eef0SSam McCall }
37b804eef0SSam McCall
38b804eef0SSam McCall std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
39b804eef0SSam McCall CodeCompletionTUInfo CCTUInfo;
40b804eef0SSam McCall CodeCompletionBuilder Builder;
41b804eef0SSam McCall std::string Signature;
42b804eef0SSam McCall std::string Snippet;
43b804eef0SSam McCall };
44b804eef0SSam McCall
TEST_F(CompletionStringTest,ReturnType)45b804eef0SSam McCall TEST_F(CompletionStringTest, ReturnType) {
46b804eef0SSam McCall Builder.AddResultTypeChunk("result");
47b804eef0SSam McCall Builder.AddResultTypeChunk("redundant result no no");
48b804eef0SSam McCall EXPECT_EQ(getReturnType(*Builder.TakeString()), "result");
49b804eef0SSam McCall }
50b804eef0SSam McCall
TEST_F(CompletionStringTest,Documentation)51b804eef0SSam McCall TEST_F(CompletionStringTest, Documentation) {
52b804eef0SSam McCall Builder.addBriefComment("This is ignored");
53b804eef0SSam McCall EXPECT_EQ(formatDocumentation(*Builder.TakeString(), "Is this brief?"),
54b804eef0SSam McCall "Is this brief?");
55b804eef0SSam McCall }
56b804eef0SSam McCall
TEST_F(CompletionStringTest,DocumentationWithAnnotation)57b804eef0SSam McCall TEST_F(CompletionStringTest, DocumentationWithAnnotation) {
58b804eef0SSam McCall Builder.addBriefComment("This is ignored");
59b804eef0SSam McCall Builder.AddAnnotation("Ano");
60b804eef0SSam McCall EXPECT_EQ(formatDocumentation(*Builder.TakeString(), "Is this brief?"),
61b804eef0SSam McCall "Annotation: Ano\n\nIs this brief?");
62b804eef0SSam McCall }
63b804eef0SSam McCall
TEST_F(CompletionStringTest,GetDeclCommentBadUTF8)64216af81cSSam McCall TEST_F(CompletionStringTest, GetDeclCommentBadUTF8) {
65216af81cSSam McCall // <ff> is not a valid byte here, should be replaced by encoded <U+FFFD>.
66216af81cSSam McCall auto TU = TestTU::withCode("/*x\xffy*/ struct X;");
67216af81cSSam McCall auto AST = TU.build();
68216af81cSSam McCall EXPECT_EQ("x\xef\xbf\xbdy",
69216af81cSSam McCall getDeclComment(AST.getASTContext(), findDecl(AST, "X")));
70216af81cSSam McCall }
71216af81cSSam McCall
TEST_F(CompletionStringTest,MultipleAnnotations)72b804eef0SSam McCall TEST_F(CompletionStringTest, MultipleAnnotations) {
73b804eef0SSam McCall Builder.AddAnnotation("Ano1");
74b804eef0SSam McCall Builder.AddAnnotation("Ano2");
75b804eef0SSam McCall Builder.AddAnnotation("Ano3");
76b804eef0SSam McCall
77b804eef0SSam McCall EXPECT_EQ(formatDocumentation(*Builder.TakeString(), ""),
78b804eef0SSam McCall "Annotations: Ano1 Ano2 Ano3\n");
79b804eef0SSam McCall }
80b804eef0SSam McCall
TEST_F(CompletionStringTest,EmptySignature)81b804eef0SSam McCall TEST_F(CompletionStringTest, EmptySignature) {
82b804eef0SSam McCall Builder.AddTypedTextChunk("X");
83b804eef0SSam McCall Builder.AddResultTypeChunk("result no no");
84b804eef0SSam McCall computeSignature(*Builder.TakeString());
85b804eef0SSam McCall EXPECT_EQ(Signature, "");
86b804eef0SSam McCall EXPECT_EQ(Snippet, "");
87b804eef0SSam McCall }
88b804eef0SSam McCall
TEST_F(CompletionStringTest,Function)89b804eef0SSam McCall TEST_F(CompletionStringTest, Function) {
90b804eef0SSam McCall Builder.AddResultTypeChunk("result no no");
91b804eef0SSam McCall Builder.addBriefComment("This comment is ignored");
92b804eef0SSam McCall Builder.AddTypedTextChunk("Foo");
93b804eef0SSam McCall Builder.AddChunk(CodeCompletionString::CK_LeftParen);
94b804eef0SSam McCall Builder.AddPlaceholderChunk("p1");
95b804eef0SSam McCall Builder.AddChunk(CodeCompletionString::CK_Comma);
96b804eef0SSam McCall Builder.AddPlaceholderChunk("p2");
97b804eef0SSam McCall Builder.AddChunk(CodeCompletionString::CK_RightParen);
98b804eef0SSam McCall
99b804eef0SSam McCall auto *CCS = Builder.TakeString();
100b804eef0SSam McCall computeSignature(*CCS);
101b804eef0SSam McCall EXPECT_EQ(Signature, "(p1, p2)");
102b804eef0SSam McCall EXPECT_EQ(Snippet, "(${1:p1}, ${2:p2})");
103b804eef0SSam McCall EXPECT_EQ(formatDocumentation(*CCS, "Foo's comment"), "Foo's comment");
104b804eef0SSam McCall }
105b804eef0SSam McCall
TEST_F(CompletionStringTest,FunctionWithDefaultParams)1060e8dd4a8SSam McCall TEST_F(CompletionStringTest, FunctionWithDefaultParams) {
1070e8dd4a8SSam McCall // return_type foo(p1, p2 = 0, p3 = 0)
1080e8dd4a8SSam McCall Builder.AddChunk(CodeCompletionString::CK_Comma);
1090e8dd4a8SSam McCall Builder.AddTypedTextChunk("p3 = 0");
1100e8dd4a8SSam McCall auto *DefaultParam2 = Builder.TakeString();
1110e8dd4a8SSam McCall
1120e8dd4a8SSam McCall Builder.AddChunk(CodeCompletionString::CK_Comma);
1130e8dd4a8SSam McCall Builder.AddTypedTextChunk("p2 = 0");
1140e8dd4a8SSam McCall Builder.AddOptionalChunk(DefaultParam2);
1150e8dd4a8SSam McCall auto *DefaultParam1 = Builder.TakeString();
1160e8dd4a8SSam McCall
1170e8dd4a8SSam McCall Builder.AddResultTypeChunk("return_type");
1180e8dd4a8SSam McCall Builder.AddTypedTextChunk("Foo");
1190e8dd4a8SSam McCall Builder.AddChunk(CodeCompletionString::CK_LeftParen);
1200e8dd4a8SSam McCall Builder.AddPlaceholderChunk("p1");
1210e8dd4a8SSam McCall Builder.AddOptionalChunk(DefaultParam1);
1220e8dd4a8SSam McCall Builder.AddChunk(CodeCompletionString::CK_RightParen);
1230e8dd4a8SSam McCall
1240e8dd4a8SSam McCall auto *CCS = Builder.TakeString();
1250e8dd4a8SSam McCall computeSignature(*CCS);
1260e8dd4a8SSam McCall EXPECT_EQ(Signature, "(p1, p2 = 0, p3 = 0)");
1270e8dd4a8SSam McCall EXPECT_EQ(Snippet, "(${1:p1})");
1280e8dd4a8SSam McCall }
1290e8dd4a8SSam McCall
TEST_F(CompletionStringTest,EscapeSnippet)130b804eef0SSam McCall TEST_F(CompletionStringTest, EscapeSnippet) {
131b804eef0SSam McCall Builder.AddTypedTextChunk("Foo");
132b804eef0SSam McCall Builder.AddChunk(CodeCompletionString::CK_LeftParen);
133b804eef0SSam McCall Builder.AddPlaceholderChunk("$p}1\\");
134b804eef0SSam McCall Builder.AddChunk(CodeCompletionString::CK_RightParen);
135b804eef0SSam McCall
136b804eef0SSam McCall computeSignature(*Builder.TakeString());
137b804eef0SSam McCall EXPECT_EQ(Signature, "($p}1\\)");
138b804eef0SSam McCall EXPECT_EQ(Snippet, "(${1:\\$p\\}1\\\\})");
139b804eef0SSam McCall }
140b804eef0SSam McCall
TEST_F(CompletionStringTest,SnippetsInPatterns)1418534675cSIlya Biryukov TEST_F(CompletionStringTest, SnippetsInPatterns) {
1428534675cSIlya Biryukov auto MakeCCS = [this]() -> const CodeCompletionString & {
1438534675cSIlya Biryukov CodeCompletionBuilder Builder(*Allocator, CCTUInfo);
1448534675cSIlya Biryukov Builder.AddTypedTextChunk("namespace");
1458534675cSIlya Biryukov Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
1468534675cSIlya Biryukov Builder.AddPlaceholderChunk("name");
1478534675cSIlya Biryukov Builder.AddChunk(CodeCompletionString::CK_Equal);
1488534675cSIlya Biryukov Builder.AddPlaceholderChunk("target");
1498534675cSIlya Biryukov Builder.AddChunk(CodeCompletionString::CK_SemiColon);
1508534675cSIlya Biryukov return *Builder.TakeString();
1518534675cSIlya Biryukov };
152138adb09SYounan Zhang computeSignature(MakeCCS());
1538534675cSIlya Biryukov EXPECT_EQ(Snippet, " ${1:name} = ${2:target};");
1548534675cSIlya Biryukov
1558534675cSIlya Biryukov // When completing a pattern, the last placeholder holds the cursor position.
156138adb09SYounan Zhang computeSignature(MakeCCS(),
157138adb09SYounan Zhang /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Pattern);
1582eba08fdSNathan Ridge EXPECT_EQ(Snippet, " ${1:name} = $0;");
1598534675cSIlya Biryukov }
1608534675cSIlya Biryukov
TEST_F(CompletionStringTest,DropFunctionArguments)161*23ef8bf9SYounan Zhang TEST_F(CompletionStringTest, DropFunctionArguments) {
162*23ef8bf9SYounan Zhang Builder.AddTypedTextChunk("foo");
163*23ef8bf9SYounan Zhang Builder.AddChunk(CodeCompletionString::CK_LeftAngle);
164*23ef8bf9SYounan Zhang Builder.AddPlaceholderChunk("typename T");
165*23ef8bf9SYounan Zhang Builder.AddChunk(CodeCompletionString::CK_Comma);
166*23ef8bf9SYounan Zhang Builder.AddPlaceholderChunk("int U");
167*23ef8bf9SYounan Zhang Builder.AddChunk(CodeCompletionString::CK_RightAngle);
168*23ef8bf9SYounan Zhang Builder.AddChunk(CodeCompletionString::CK_LeftParen);
169*23ef8bf9SYounan Zhang Builder.AddPlaceholderChunk("arg1");
170*23ef8bf9SYounan Zhang Builder.AddChunk(CodeCompletionString::CK_Comma);
171*23ef8bf9SYounan Zhang Builder.AddPlaceholderChunk("arg2");
172*23ef8bf9SYounan Zhang Builder.AddChunk(CodeCompletionString::CK_RightParen);
173*23ef8bf9SYounan Zhang
174*23ef8bf9SYounan Zhang computeSignature(
175*23ef8bf9SYounan Zhang *Builder.TakeString(),
176*23ef8bf9SYounan Zhang /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Declaration,
177*23ef8bf9SYounan Zhang /*IncludeFunctionArguments=*/false);
178*23ef8bf9SYounan Zhang // Arguments dropped from snippet, kept in signature.
179*23ef8bf9SYounan Zhang EXPECT_EQ(Signature, "<typename T, int U>(arg1, arg2)");
180*23ef8bf9SYounan Zhang EXPECT_EQ(Snippet, "<${1:typename T}, ${2:int U}>");
181*23ef8bf9SYounan Zhang }
182*23ef8bf9SYounan Zhang
TEST_F(CompletionStringTest,IgnoreInformativeQualifier)183b804eef0SSam McCall TEST_F(CompletionStringTest, IgnoreInformativeQualifier) {
184b804eef0SSam McCall Builder.AddTypedTextChunk("X");
185b804eef0SSam McCall Builder.AddInformativeChunk("info ok");
186b804eef0SSam McCall Builder.AddInformativeChunk("info no no::");
187b804eef0SSam McCall computeSignature(*Builder.TakeString());
188b804eef0SSam McCall EXPECT_EQ(Signature, "info ok");
189b804eef0SSam McCall EXPECT_EQ(Snippet, "");
190b804eef0SSam McCall }
191b804eef0SSam McCall
TEST_F(CompletionStringTest,ObjectiveCMethodNoArguments)192b804eef0SSam McCall TEST_F(CompletionStringTest, ObjectiveCMethodNoArguments) {
193b804eef0SSam McCall Builder.AddResultTypeChunk("void");
194b804eef0SSam McCall Builder.AddTypedTextChunk("methodName");
195b804eef0SSam McCall
196b804eef0SSam McCall auto *CCS = Builder.TakeString();
197b804eef0SSam McCall computeSignature(*CCS);
198b804eef0SSam McCall EXPECT_EQ(Signature, "");
199b804eef0SSam McCall EXPECT_EQ(Snippet, "");
200b804eef0SSam McCall }
201b804eef0SSam McCall
TEST_F(CompletionStringTest,ObjectiveCMethodOneArgument)202b804eef0SSam McCall TEST_F(CompletionStringTest, ObjectiveCMethodOneArgument) {
203b804eef0SSam McCall Builder.AddResultTypeChunk("void");
204b804eef0SSam McCall Builder.AddTypedTextChunk("methodWithArg:");
205b804eef0SSam McCall Builder.AddPlaceholderChunk("(type)");
206b804eef0SSam McCall
207b804eef0SSam McCall auto *CCS = Builder.TakeString();
208b804eef0SSam McCall computeSignature(*CCS);
209b804eef0SSam McCall EXPECT_EQ(Signature, "(type)");
210b804eef0SSam McCall EXPECT_EQ(Snippet, "${1:(type)}");
211b804eef0SSam McCall }
212b804eef0SSam McCall
TEST_F(CompletionStringTest,ObjectiveCMethodTwoArgumentsFromBeginning)213b804eef0SSam McCall TEST_F(CompletionStringTest, ObjectiveCMethodTwoArgumentsFromBeginning) {
214b804eef0SSam McCall Builder.AddResultTypeChunk("int");
215b804eef0SSam McCall Builder.AddTypedTextChunk("withFoo:");
216b804eef0SSam McCall Builder.AddPlaceholderChunk("(type)");
217b804eef0SSam McCall Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
218b804eef0SSam McCall Builder.AddTypedTextChunk("bar:");
219b804eef0SSam McCall Builder.AddPlaceholderChunk("(type2)");
220b804eef0SSam McCall
221b804eef0SSam McCall auto *CCS = Builder.TakeString();
222b804eef0SSam McCall computeSignature(*CCS);
223b804eef0SSam McCall EXPECT_EQ(Signature, "(type) bar:(type2)");
224b804eef0SSam McCall EXPECT_EQ(Snippet, "${1:(type)} bar:${2:(type2)}");
225b804eef0SSam McCall }
226b804eef0SSam McCall
TEST_F(CompletionStringTest,ObjectiveCMethodTwoArgumentsFromMiddle)227b804eef0SSam McCall TEST_F(CompletionStringTest, ObjectiveCMethodTwoArgumentsFromMiddle) {
228b804eef0SSam McCall Builder.AddResultTypeChunk("int");
229b804eef0SSam McCall Builder.AddInformativeChunk("withFoo:");
230b804eef0SSam McCall Builder.AddTypedTextChunk("bar:");
231b804eef0SSam McCall Builder.AddPlaceholderChunk("(type2)");
232b804eef0SSam McCall
233b804eef0SSam McCall auto *CCS = Builder.TakeString();
234b804eef0SSam McCall computeSignature(*CCS);
235b804eef0SSam McCall EXPECT_EQ(Signature, "(type2)");
236b804eef0SSam McCall EXPECT_EQ(Snippet, "${1:(type2)}");
237b804eef0SSam McCall }
238b804eef0SSam McCall
239b804eef0SSam McCall } // namespace
240b804eef0SSam McCall } // namespace clangd
241b804eef0SSam McCall } // namespace clang
242