xref: /llvm-project/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp (revision 23ef8bf9c0f338ee073c6c1b553c42e46d2f22ad)
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