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 bool CompletingPattern
= false) {
30 getSignature(CCS
, &Signature
, &Snippet
, /*RequiredQualifier=*/nullptr,
34 std::shared_ptr
<clang::GlobalCodeCompletionAllocator
> Allocator
;
35 CodeCompletionTUInfo CCTUInfo
;
36 CodeCompletionBuilder Builder
;
37 std::string Signature
;
41 TEST_F(CompletionStringTest
, ReturnType
) {
42 Builder
.AddResultTypeChunk("result");
43 Builder
.AddResultTypeChunk("redundant result no no");
44 EXPECT_EQ(getReturnType(*Builder
.TakeString()), "result");
47 TEST_F(CompletionStringTest
, Documentation
) {
48 Builder
.addBriefComment("This is ignored");
49 EXPECT_EQ(formatDocumentation(*Builder
.TakeString(), "Is this brief?"),
53 TEST_F(CompletionStringTest
, DocumentationWithAnnotation
) {
54 Builder
.addBriefComment("This is ignored");
55 Builder
.AddAnnotation("Ano");
56 EXPECT_EQ(formatDocumentation(*Builder
.TakeString(), "Is this brief?"),
57 "Annotation: Ano\n\nIs this brief?");
60 TEST_F(CompletionStringTest
, GetDeclCommentBadUTF8
) {
61 // <ff> is not a valid byte here, should be replaced by encoded <U+FFFD>.
62 auto TU
= TestTU::withCode("/*x\xffy*/ struct X;");
63 auto AST
= TU
.build();
64 EXPECT_EQ("x\xef\xbf\xbdy",
65 getDeclComment(AST
.getASTContext(), findDecl(AST
, "X")));
68 TEST_F(CompletionStringTest
, MultipleAnnotations
) {
69 Builder
.AddAnnotation("Ano1");
70 Builder
.AddAnnotation("Ano2");
71 Builder
.AddAnnotation("Ano3");
73 EXPECT_EQ(formatDocumentation(*Builder
.TakeString(), ""),
74 "Annotations: Ano1 Ano2 Ano3\n");
77 TEST_F(CompletionStringTest
, EmptySignature
) {
78 Builder
.AddTypedTextChunk("X");
79 Builder
.AddResultTypeChunk("result no no");
80 computeSignature(*Builder
.TakeString());
81 EXPECT_EQ(Signature
, "");
82 EXPECT_EQ(Snippet
, "");
85 TEST_F(CompletionStringTest
, Function
) {
86 Builder
.AddResultTypeChunk("result no no");
87 Builder
.addBriefComment("This comment is ignored");
88 Builder
.AddTypedTextChunk("Foo");
89 Builder
.AddChunk(CodeCompletionString::CK_LeftParen
);
90 Builder
.AddPlaceholderChunk("p1");
91 Builder
.AddChunk(CodeCompletionString::CK_Comma
);
92 Builder
.AddPlaceholderChunk("p2");
93 Builder
.AddChunk(CodeCompletionString::CK_RightParen
);
95 auto *CCS
= Builder
.TakeString();
96 computeSignature(*CCS
);
97 EXPECT_EQ(Signature
, "(p1, p2)");
98 EXPECT_EQ(Snippet
, "(${1:p1}, ${2:p2})");
99 EXPECT_EQ(formatDocumentation(*CCS
, "Foo's comment"), "Foo's comment");
102 TEST_F(CompletionStringTest
, FunctionWithDefaultParams
) {
103 // return_type foo(p1, p2 = 0, p3 = 0)
104 Builder
.AddChunk(CodeCompletionString::CK_Comma
);
105 Builder
.AddTypedTextChunk("p3 = 0");
106 auto *DefaultParam2
= Builder
.TakeString();
108 Builder
.AddChunk(CodeCompletionString::CK_Comma
);
109 Builder
.AddTypedTextChunk("p2 = 0");
110 Builder
.AddOptionalChunk(DefaultParam2
);
111 auto *DefaultParam1
= Builder
.TakeString();
113 Builder
.AddResultTypeChunk("return_type");
114 Builder
.AddTypedTextChunk("Foo");
115 Builder
.AddChunk(CodeCompletionString::CK_LeftParen
);
116 Builder
.AddPlaceholderChunk("p1");
117 Builder
.AddOptionalChunk(DefaultParam1
);
118 Builder
.AddChunk(CodeCompletionString::CK_RightParen
);
120 auto *CCS
= Builder
.TakeString();
121 computeSignature(*CCS
);
122 EXPECT_EQ(Signature
, "(p1, p2 = 0, p3 = 0)");
123 EXPECT_EQ(Snippet
, "(${1:p1})");
126 TEST_F(CompletionStringTest
, EscapeSnippet
) {
127 Builder
.AddTypedTextChunk("Foo");
128 Builder
.AddChunk(CodeCompletionString::CK_LeftParen
);
129 Builder
.AddPlaceholderChunk("$p}1\\");
130 Builder
.AddChunk(CodeCompletionString::CK_RightParen
);
132 computeSignature(*Builder
.TakeString());
133 EXPECT_EQ(Signature
, "($p}1\\)");
134 EXPECT_EQ(Snippet
, "(${1:\\$p\\}1\\\\})");
137 TEST_F(CompletionStringTest
, SnippetsInPatterns
) {
138 auto MakeCCS
= [this]() -> const CodeCompletionString
& {
139 CodeCompletionBuilder
Builder(*Allocator
, CCTUInfo
);
140 Builder
.AddTypedTextChunk("namespace");
141 Builder
.AddChunk(CodeCompletionString::CK_HorizontalSpace
);
142 Builder
.AddPlaceholderChunk("name");
143 Builder
.AddChunk(CodeCompletionString::CK_Equal
);
144 Builder
.AddPlaceholderChunk("target");
145 Builder
.AddChunk(CodeCompletionString::CK_SemiColon
);
146 return *Builder
.TakeString();
148 computeSignature(MakeCCS(), /*CompletingPattern=*/false);
149 EXPECT_EQ(Snippet
, " ${1:name} = ${2:target};");
151 // When completing a pattern, the last placeholder holds the cursor position.
152 computeSignature(MakeCCS(), /*CompletingPattern=*/true);
153 EXPECT_EQ(Snippet
, " ${1:name} = $0;");
156 TEST_F(CompletionStringTest
, IgnoreInformativeQualifier
) {
157 Builder
.AddTypedTextChunk("X");
158 Builder
.AddInformativeChunk("info ok");
159 Builder
.AddInformativeChunk("info no no::");
160 computeSignature(*Builder
.TakeString());
161 EXPECT_EQ(Signature
, "info ok");
162 EXPECT_EQ(Snippet
, "");
165 TEST_F(CompletionStringTest
, ObjectiveCMethodNoArguments
) {
166 Builder
.AddResultTypeChunk("void");
167 Builder
.AddTypedTextChunk("methodName");
169 auto *CCS
= Builder
.TakeString();
170 computeSignature(*CCS
);
171 EXPECT_EQ(Signature
, "");
172 EXPECT_EQ(Snippet
, "");
175 TEST_F(CompletionStringTest
, ObjectiveCMethodOneArgument
) {
176 Builder
.AddResultTypeChunk("void");
177 Builder
.AddTypedTextChunk("methodWithArg:");
178 Builder
.AddPlaceholderChunk("(type)");
180 auto *CCS
= Builder
.TakeString();
181 computeSignature(*CCS
);
182 EXPECT_EQ(Signature
, "(type)");
183 EXPECT_EQ(Snippet
, "${1:(type)}");
186 TEST_F(CompletionStringTest
, ObjectiveCMethodTwoArgumentsFromBeginning
) {
187 Builder
.AddResultTypeChunk("int");
188 Builder
.AddTypedTextChunk("withFoo:");
189 Builder
.AddPlaceholderChunk("(type)");
190 Builder
.AddChunk(CodeCompletionString::CK_HorizontalSpace
);
191 Builder
.AddTypedTextChunk("bar:");
192 Builder
.AddPlaceholderChunk("(type2)");
194 auto *CCS
= Builder
.TakeString();
195 computeSignature(*CCS
);
196 EXPECT_EQ(Signature
, "(type) bar:(type2)");
197 EXPECT_EQ(Snippet
, "${1:(type)} bar:${2:(type2)}");
200 TEST_F(CompletionStringTest
, ObjectiveCMethodTwoArgumentsFromMiddle
) {
201 Builder
.AddResultTypeChunk("int");
202 Builder
.AddInformativeChunk("withFoo:");
203 Builder
.AddTypedTextChunk("bar:");
204 Builder
.AddPlaceholderChunk("(type2)");
206 auto *CCS
= Builder
.TakeString();
207 computeSignature(*CCS
);
208 EXPECT_EQ(Signature
, "(type2)");
209 EXPECT_EQ(Snippet
, "${1:(type2)}");
213 } // namespace clangd