1 //===-- CodeCompletionStringsTests.cpp --------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "CodeCompletionStrings.h"
11 #include "clang/Sema/CodeCompleteConsumer.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
19 class CompletionStringTest
: public ::testing::Test
{
21 CompletionStringTest()
22 : Allocator(std::make_shared
<clang::GlobalCodeCompletionAllocator
>()),
23 CCTUInfo(Allocator
), Builder(*Allocator
, CCTUInfo
) {}
26 void computeSignature(const CodeCompletionString
&CCS
,
27 CodeCompletionResult::ResultKind ResultKind
=
28 CodeCompletionResult::ResultKind::RK_Declaration
,
29 bool IncludeFunctionArguments
= true) {
32 getSignature(CCS
, &Signature
, &Snippet
, ResultKind
,
33 /*CursorKind=*/CXCursorKind::CXCursor_NotImplemented
,
34 /*IncludeFunctionArguments=*/IncludeFunctionArguments
,
35 /*RequiredQualifiers=*/nullptr);
38 std::shared_ptr
<clang::GlobalCodeCompletionAllocator
> Allocator
;
39 CodeCompletionTUInfo CCTUInfo
;
40 CodeCompletionBuilder Builder
;
41 std::string Signature
;
45 TEST_F(CompletionStringTest
, ReturnType
) {
46 Builder
.AddResultTypeChunk("result");
47 Builder
.AddResultTypeChunk("redundant result no no");
48 EXPECT_EQ(getReturnType(*Builder
.TakeString()), "result");
51 TEST_F(CompletionStringTest
, Documentation
) {
52 Builder
.addBriefComment("This is ignored");
53 EXPECT_EQ(formatDocumentation(*Builder
.TakeString(), "Is this brief?"),
57 TEST_F(CompletionStringTest
, DocumentationWithAnnotation
) {
58 Builder
.addBriefComment("This is ignored");
59 Builder
.AddAnnotation("Ano");
60 EXPECT_EQ(formatDocumentation(*Builder
.TakeString(), "Is this brief?"),
61 "Annotation: Ano\n\nIs this brief?");
64 TEST_F(CompletionStringTest
, GetDeclCommentBadUTF8
) {
65 // <ff> is not a valid byte here, should be replaced by encoded <U+FFFD>.
66 auto TU
= TestTU::withCode("/*x\xffy*/ struct X;");
67 auto AST
= TU
.build();
68 EXPECT_EQ("x\xef\xbf\xbdy",
69 getDeclComment(AST
.getASTContext(), findDecl(AST
, "X")));
72 TEST_F(CompletionStringTest
, MultipleAnnotations
) {
73 Builder
.AddAnnotation("Ano1");
74 Builder
.AddAnnotation("Ano2");
75 Builder
.AddAnnotation("Ano3");
77 EXPECT_EQ(formatDocumentation(*Builder
.TakeString(), ""),
78 "Annotations: Ano1 Ano2 Ano3\n");
81 TEST_F(CompletionStringTest
, EmptySignature
) {
82 Builder
.AddTypedTextChunk("X");
83 Builder
.AddResultTypeChunk("result no no");
84 computeSignature(*Builder
.TakeString());
85 EXPECT_EQ(Signature
, "");
86 EXPECT_EQ(Snippet
, "");
89 TEST_F(CompletionStringTest
, Function
) {
90 Builder
.AddResultTypeChunk("result no no");
91 Builder
.addBriefComment("This comment is ignored");
92 Builder
.AddTypedTextChunk("Foo");
93 Builder
.AddChunk(CodeCompletionString::CK_LeftParen
);
94 Builder
.AddPlaceholderChunk("p1");
95 Builder
.AddChunk(CodeCompletionString::CK_Comma
);
96 Builder
.AddPlaceholderChunk("p2");
97 Builder
.AddChunk(CodeCompletionString::CK_RightParen
);
99 auto *CCS
= Builder
.TakeString();
100 computeSignature(*CCS
);
101 EXPECT_EQ(Signature
, "(p1, p2)");
102 EXPECT_EQ(Snippet
, "(${1:p1}, ${2:p2})");
103 EXPECT_EQ(formatDocumentation(*CCS
, "Foo's comment"), "Foo's comment");
106 TEST_F(CompletionStringTest
, FunctionWithDefaultParams
) {
107 // return_type foo(p1, p2 = 0, p3 = 0)
108 Builder
.AddChunk(CodeCompletionString::CK_Comma
);
109 Builder
.AddTypedTextChunk("p3 = 0");
110 auto *DefaultParam2
= Builder
.TakeString();
112 Builder
.AddChunk(CodeCompletionString::CK_Comma
);
113 Builder
.AddTypedTextChunk("p2 = 0");
114 Builder
.AddOptionalChunk(DefaultParam2
);
115 auto *DefaultParam1
= Builder
.TakeString();
117 Builder
.AddResultTypeChunk("return_type");
118 Builder
.AddTypedTextChunk("Foo");
119 Builder
.AddChunk(CodeCompletionString::CK_LeftParen
);
120 Builder
.AddPlaceholderChunk("p1");
121 Builder
.AddOptionalChunk(DefaultParam1
);
122 Builder
.AddChunk(CodeCompletionString::CK_RightParen
);
124 auto *CCS
= Builder
.TakeString();
125 computeSignature(*CCS
);
126 EXPECT_EQ(Signature
, "(p1, p2 = 0, p3 = 0)");
127 EXPECT_EQ(Snippet
, "(${1:p1})");
130 TEST_F(CompletionStringTest
, EscapeSnippet
) {
131 Builder
.AddTypedTextChunk("Foo");
132 Builder
.AddChunk(CodeCompletionString::CK_LeftParen
);
133 Builder
.AddPlaceholderChunk("$p}1\\");
134 Builder
.AddChunk(CodeCompletionString::CK_RightParen
);
136 computeSignature(*Builder
.TakeString());
137 EXPECT_EQ(Signature
, "($p}1\\)");
138 EXPECT_EQ(Snippet
, "(${1:\\$p\\}1\\\\})");
141 TEST_F(CompletionStringTest
, SnippetsInPatterns
) {
142 auto MakeCCS
= [this]() -> const CodeCompletionString
& {
143 CodeCompletionBuilder
Builder(*Allocator
, CCTUInfo
);
144 Builder
.AddTypedTextChunk("namespace");
145 Builder
.AddChunk(CodeCompletionString::CK_HorizontalSpace
);
146 Builder
.AddPlaceholderChunk("name");
147 Builder
.AddChunk(CodeCompletionString::CK_Equal
);
148 Builder
.AddPlaceholderChunk("target");
149 Builder
.AddChunk(CodeCompletionString::CK_SemiColon
);
150 return *Builder
.TakeString();
152 computeSignature(MakeCCS());
153 EXPECT_EQ(Snippet
, " ${1:name} = ${2:target};");
155 // When completing a pattern, the last placeholder holds the cursor position.
156 computeSignature(MakeCCS(),
157 /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Pattern
);
158 EXPECT_EQ(Snippet
, " ${1:name} = $0;");
161 TEST_F(CompletionStringTest
, DropFunctionArguments
) {
162 Builder
.AddTypedTextChunk("foo");
163 Builder
.AddChunk(CodeCompletionString::CK_LeftAngle
);
164 Builder
.AddPlaceholderChunk("typename T");
165 Builder
.AddChunk(CodeCompletionString::CK_Comma
);
166 Builder
.AddPlaceholderChunk("int U");
167 Builder
.AddChunk(CodeCompletionString::CK_RightAngle
);
168 Builder
.AddChunk(CodeCompletionString::CK_LeftParen
);
169 Builder
.AddPlaceholderChunk("arg1");
170 Builder
.AddChunk(CodeCompletionString::CK_Comma
);
171 Builder
.AddPlaceholderChunk("arg2");
172 Builder
.AddChunk(CodeCompletionString::CK_RightParen
);
175 *Builder
.TakeString(),
176 /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Declaration
,
177 /*IncludeFunctionArguments=*/false);
178 // Arguments dropped from snippet, kept in signature.
179 EXPECT_EQ(Signature
, "<typename T, int U>(arg1, arg2)");
180 EXPECT_EQ(Snippet
, "<${1:typename T}, ${2:int U}>");
183 TEST_F(CompletionStringTest
, IgnoreInformativeQualifier
) {
184 Builder
.AddTypedTextChunk("X");
185 Builder
.AddInformativeChunk("info ok");
186 Builder
.AddInformativeChunk("info no no::");
187 computeSignature(*Builder
.TakeString());
188 EXPECT_EQ(Signature
, "info ok");
189 EXPECT_EQ(Snippet
, "");
192 TEST_F(CompletionStringTest
, ObjectiveCMethodNoArguments
) {
193 Builder
.AddResultTypeChunk("void");
194 Builder
.AddTypedTextChunk("methodName");
196 auto *CCS
= Builder
.TakeString();
197 computeSignature(*CCS
);
198 EXPECT_EQ(Signature
, "");
199 EXPECT_EQ(Snippet
, "");
202 TEST_F(CompletionStringTest
, ObjectiveCMethodOneArgument
) {
203 Builder
.AddResultTypeChunk("void");
204 Builder
.AddTypedTextChunk("methodWithArg:");
205 Builder
.AddPlaceholderChunk("(type)");
207 auto *CCS
= Builder
.TakeString();
208 computeSignature(*CCS
);
209 EXPECT_EQ(Signature
, "(type)");
210 EXPECT_EQ(Snippet
, "${1:(type)}");
213 TEST_F(CompletionStringTest
, ObjectiveCMethodTwoArgumentsFromBeginning
) {
214 Builder
.AddResultTypeChunk("int");
215 Builder
.AddTypedTextChunk("withFoo:");
216 Builder
.AddPlaceholderChunk("(type)");
217 Builder
.AddChunk(CodeCompletionString::CK_HorizontalSpace
);
218 Builder
.AddTypedTextChunk("bar:");
219 Builder
.AddPlaceholderChunk("(type2)");
221 auto *CCS
= Builder
.TakeString();
222 computeSignature(*CCS
);
223 EXPECT_EQ(Signature
, "(type) bar:(type2)");
224 EXPECT_EQ(Snippet
, "${1:(type)} bar:${2:(type2)}");
227 TEST_F(CompletionStringTest
, ObjectiveCMethodTwoArgumentsFromMiddle
) {
228 Builder
.AddResultTypeChunk("int");
229 Builder
.AddInformativeChunk("withFoo:");
230 Builder
.AddTypedTextChunk("bar:");
231 Builder
.AddPlaceholderChunk("(type2)");
233 auto *CCS
= Builder
.TakeString();
234 computeSignature(*CCS
);
235 EXPECT_EQ(Signature
, "(type2)");
236 EXPECT_EQ(Snippet
, "${1:(type2)}");
240 } // namespace clangd