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
) {
31 getSignature(CCS
, &Signature
, &Snippet
, ResultKind
,
32 /*CursorKind=*/CXCursorKind::CXCursor_NotImplemented
,
33 /*RequiredQualifiers=*/nullptr);
36 std::shared_ptr
<clang::GlobalCodeCompletionAllocator
> Allocator
;
37 CodeCompletionTUInfo CCTUInfo
;
38 CodeCompletionBuilder Builder
;
39 std::string Signature
;
43 TEST_F(CompletionStringTest
, ReturnType
) {
44 Builder
.AddResultTypeChunk("result");
45 Builder
.AddResultTypeChunk("redundant result no no");
46 EXPECT_EQ(getReturnType(*Builder
.TakeString()), "result");
49 TEST_F(CompletionStringTest
, Documentation
) {
50 Builder
.addBriefComment("This is ignored");
51 EXPECT_EQ(formatDocumentation(*Builder
.TakeString(), "Is this brief?"),
55 TEST_F(CompletionStringTest
, DocumentationWithAnnotation
) {
56 Builder
.addBriefComment("This is ignored");
57 Builder
.AddAnnotation("Ano");
58 EXPECT_EQ(formatDocumentation(*Builder
.TakeString(), "Is this brief?"),
59 "Annotation: Ano\n\nIs this brief?");
62 TEST_F(CompletionStringTest
, GetDeclCommentBadUTF8
) {
63 // <ff> is not a valid byte here, should be replaced by encoded <U+FFFD>.
64 auto TU
= TestTU::withCode("/*x\xffy*/ struct X;");
65 auto AST
= TU
.build();
66 EXPECT_EQ("x\xef\xbf\xbdy",
67 getDeclComment(AST
.getASTContext(), findDecl(AST
, "X")));
70 TEST_F(CompletionStringTest
, MultipleAnnotations
) {
71 Builder
.AddAnnotation("Ano1");
72 Builder
.AddAnnotation("Ano2");
73 Builder
.AddAnnotation("Ano3");
75 EXPECT_EQ(formatDocumentation(*Builder
.TakeString(), ""),
76 "Annotations: Ano1 Ano2 Ano3\n");
79 TEST_F(CompletionStringTest
, EmptySignature
) {
80 Builder
.AddTypedTextChunk("X");
81 Builder
.AddResultTypeChunk("result no no");
82 computeSignature(*Builder
.TakeString());
83 EXPECT_EQ(Signature
, "");
84 EXPECT_EQ(Snippet
, "");
87 TEST_F(CompletionStringTest
, Function
) {
88 Builder
.AddResultTypeChunk("result no no");
89 Builder
.addBriefComment("This comment is ignored");
90 Builder
.AddTypedTextChunk("Foo");
91 Builder
.AddChunk(CodeCompletionString::CK_LeftParen
);
92 Builder
.AddPlaceholderChunk("p1");
93 Builder
.AddChunk(CodeCompletionString::CK_Comma
);
94 Builder
.AddPlaceholderChunk("p2");
95 Builder
.AddChunk(CodeCompletionString::CK_RightParen
);
97 auto *CCS
= Builder
.TakeString();
98 computeSignature(*CCS
);
99 EXPECT_EQ(Signature
, "(p1, p2)");
100 EXPECT_EQ(Snippet
, "(${1:p1}, ${2:p2})");
101 EXPECT_EQ(formatDocumentation(*CCS
, "Foo's comment"), "Foo's comment");
104 TEST_F(CompletionStringTest
, FunctionWithDefaultParams
) {
105 // return_type foo(p1, p2 = 0, p3 = 0)
106 Builder
.AddChunk(CodeCompletionString::CK_Comma
);
107 Builder
.AddTypedTextChunk("p3 = 0");
108 auto *DefaultParam2
= Builder
.TakeString();
110 Builder
.AddChunk(CodeCompletionString::CK_Comma
);
111 Builder
.AddTypedTextChunk("p2 = 0");
112 Builder
.AddOptionalChunk(DefaultParam2
);
113 auto *DefaultParam1
= Builder
.TakeString();
115 Builder
.AddResultTypeChunk("return_type");
116 Builder
.AddTypedTextChunk("Foo");
117 Builder
.AddChunk(CodeCompletionString::CK_LeftParen
);
118 Builder
.AddPlaceholderChunk("p1");
119 Builder
.AddOptionalChunk(DefaultParam1
);
120 Builder
.AddChunk(CodeCompletionString::CK_RightParen
);
122 auto *CCS
= Builder
.TakeString();
123 computeSignature(*CCS
);
124 EXPECT_EQ(Signature
, "(p1, p2 = 0, p3 = 0)");
125 EXPECT_EQ(Snippet
, "(${1:p1})");
128 TEST_F(CompletionStringTest
, EscapeSnippet
) {
129 Builder
.AddTypedTextChunk("Foo");
130 Builder
.AddChunk(CodeCompletionString::CK_LeftParen
);
131 Builder
.AddPlaceholderChunk("$p}1\\");
132 Builder
.AddChunk(CodeCompletionString::CK_RightParen
);
134 computeSignature(*Builder
.TakeString());
135 EXPECT_EQ(Signature
, "($p}1\\)");
136 EXPECT_EQ(Snippet
, "(${1:\\$p\\}1\\\\})");
139 TEST_F(CompletionStringTest
, SnippetsInPatterns
) {
140 auto MakeCCS
= [this]() -> const CodeCompletionString
& {
141 CodeCompletionBuilder
Builder(*Allocator
, CCTUInfo
);
142 Builder
.AddTypedTextChunk("namespace");
143 Builder
.AddChunk(CodeCompletionString::CK_HorizontalSpace
);
144 Builder
.AddPlaceholderChunk("name");
145 Builder
.AddChunk(CodeCompletionString::CK_Equal
);
146 Builder
.AddPlaceholderChunk("target");
147 Builder
.AddChunk(CodeCompletionString::CK_SemiColon
);
148 return *Builder
.TakeString();
150 computeSignature(MakeCCS());
151 EXPECT_EQ(Snippet
, " ${1:name} = ${2:target};");
153 // When completing a pattern, the last placeholder holds the cursor position.
154 computeSignature(MakeCCS(),
155 /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Pattern
);
156 EXPECT_EQ(Snippet
, " ${1:name} = $0;");
159 TEST_F(CompletionStringTest
, IgnoreInformativeQualifier
) {
160 Builder
.AddTypedTextChunk("X");
161 Builder
.AddInformativeChunk("info ok");
162 Builder
.AddInformativeChunk("info no no::");
163 computeSignature(*Builder
.TakeString());
164 EXPECT_EQ(Signature
, "info ok");
165 EXPECT_EQ(Snippet
, "");
168 TEST_F(CompletionStringTest
, ObjectiveCMethodNoArguments
) {
169 Builder
.AddResultTypeChunk("void");
170 Builder
.AddTypedTextChunk("methodName");
172 auto *CCS
= Builder
.TakeString();
173 computeSignature(*CCS
);
174 EXPECT_EQ(Signature
, "");
175 EXPECT_EQ(Snippet
, "");
178 TEST_F(CompletionStringTest
, ObjectiveCMethodOneArgument
) {
179 Builder
.AddResultTypeChunk("void");
180 Builder
.AddTypedTextChunk("methodWithArg:");
181 Builder
.AddPlaceholderChunk("(type)");
183 auto *CCS
= Builder
.TakeString();
184 computeSignature(*CCS
);
185 EXPECT_EQ(Signature
, "(type)");
186 EXPECT_EQ(Snippet
, "${1:(type)}");
189 TEST_F(CompletionStringTest
, ObjectiveCMethodTwoArgumentsFromBeginning
) {
190 Builder
.AddResultTypeChunk("int");
191 Builder
.AddTypedTextChunk("withFoo:");
192 Builder
.AddPlaceholderChunk("(type)");
193 Builder
.AddChunk(CodeCompletionString::CK_HorizontalSpace
);
194 Builder
.AddTypedTextChunk("bar:");
195 Builder
.AddPlaceholderChunk("(type2)");
197 auto *CCS
= Builder
.TakeString();
198 computeSignature(*CCS
);
199 EXPECT_EQ(Signature
, "(type) bar:(type2)");
200 EXPECT_EQ(Snippet
, "${1:(type)} bar:${2:(type2)}");
203 TEST_F(CompletionStringTest
, ObjectiveCMethodTwoArgumentsFromMiddle
) {
204 Builder
.AddResultTypeChunk("int");
205 Builder
.AddInformativeChunk("withFoo:");
206 Builder
.AddTypedTextChunk("bar:");
207 Builder
.AddPlaceholderChunk("(type2)");
209 auto *CCS
= Builder
.TakeString();
210 computeSignature(*CCS
);
211 EXPECT_EQ(Signature
, "(type2)");
212 EXPECT_EQ(Snippet
, "${1:(type2)}");
216 } // namespace clangd