• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- CodeCompletionStringsTests.cpp --------------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CodeCompletionStrings.h"
10 #include "TestTU.h"
11 #include "clang/Sema/CodeCompleteConsumer.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14 
15 namespace clang {
16 namespace clangd {
17 namespace {
18 
19 class CompletionStringTest : public ::testing::Test {
20 public:
CompletionStringTest()21   CompletionStringTest()
22       : Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
23         CCTUInfo(Allocator), Builder(*Allocator, CCTUInfo) {}
24 
25 protected:
computeSignature(const CodeCompletionString & CCS,bool CompletingPattern=false)26   void computeSignature(const CodeCompletionString &CCS,
27                         bool CompletingPattern = false) {
28     Signature.clear();
29     Snippet.clear();
30     getSignature(CCS, &Signature, &Snippet, /*RequiredQualifier=*/nullptr,
31                  CompletingPattern);
32   }
33 
34   std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
35   CodeCompletionTUInfo CCTUInfo;
36   CodeCompletionBuilder Builder;
37   std::string Signature;
38   std::string Snippet;
39 };
40 
TEST_F(CompletionStringTest,ReturnType)41 TEST_F(CompletionStringTest, ReturnType) {
42   Builder.AddResultTypeChunk("result");
43   Builder.AddResultTypeChunk("redundant result no no");
44   EXPECT_EQ(getReturnType(*Builder.TakeString()), "result");
45 }
46 
TEST_F(CompletionStringTest,Documentation)47 TEST_F(CompletionStringTest, Documentation) {
48   Builder.addBriefComment("This is ignored");
49   EXPECT_EQ(formatDocumentation(*Builder.TakeString(), "Is this brief?"),
50             "Is this brief?");
51 }
52 
TEST_F(CompletionStringTest,DocumentationWithAnnotation)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?");
58 }
59 
TEST_F(CompletionStringTest,GetDeclCommentBadUTF8)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")));
66 }
67 
TEST_F(CompletionStringTest,MultipleAnnotations)68 TEST_F(CompletionStringTest, MultipleAnnotations) {
69   Builder.AddAnnotation("Ano1");
70   Builder.AddAnnotation("Ano2");
71   Builder.AddAnnotation("Ano3");
72 
73   EXPECT_EQ(formatDocumentation(*Builder.TakeString(), ""),
74             "Annotations: Ano1 Ano2 Ano3\n");
75 }
76 
TEST_F(CompletionStringTest,EmptySignature)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, "");
83 }
84 
TEST_F(CompletionStringTest,Function)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);
94 
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");
100 }
101 
TEST_F(CompletionStringTest,FunctionWithDefaultParams)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();
107 
108   Builder.AddChunk(CodeCompletionString::CK_Comma);
109   Builder.AddTypedTextChunk("p2 = 0");
110   Builder.AddOptionalChunk(DefaultParam2);
111   auto *DefaultParam1 = Builder.TakeString();
112 
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);
119 
120   auto *CCS = Builder.TakeString();
121   computeSignature(*CCS);
122   EXPECT_EQ(Signature, "(p1, p2 = 0, p3 = 0)");
123   EXPECT_EQ(Snippet, "(${1:p1})");
124 }
125 
TEST_F(CompletionStringTest,EscapeSnippet)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);
131 
132   computeSignature(*Builder.TakeString());
133   EXPECT_EQ(Signature, "($p}1\\)");
134   EXPECT_EQ(Snippet, "(${1:\\$p\\}1\\\\})");
135 }
136 
TEST_F(CompletionStringTest,SnippetsInPatterns)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();
147   };
148   computeSignature(MakeCCS(), /*CompletingPattern=*/false);
149   EXPECT_EQ(Snippet, " ${1:name} = ${2:target};");
150 
151   // When completing a pattern, the last placeholder holds the cursor position.
152   computeSignature(MakeCCS(), /*CompletingPattern=*/true);
153   EXPECT_EQ(Snippet, " ${1:name} = ${0:target};");
154 }
155 
TEST_F(CompletionStringTest,IgnoreInformativeQualifier)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, "");
163 }
164 
TEST_F(CompletionStringTest,ObjectiveCMethodNoArguments)165 TEST_F(CompletionStringTest, ObjectiveCMethodNoArguments) {
166   Builder.AddResultTypeChunk("void");
167   Builder.AddTypedTextChunk("methodName");
168 
169   auto *CCS = Builder.TakeString();
170   computeSignature(*CCS);
171   EXPECT_EQ(Signature, "");
172   EXPECT_EQ(Snippet, "");
173 }
174 
TEST_F(CompletionStringTest,ObjectiveCMethodOneArgument)175 TEST_F(CompletionStringTest, ObjectiveCMethodOneArgument) {
176   Builder.AddResultTypeChunk("void");
177   Builder.AddTypedTextChunk("methodWithArg:");
178   Builder.AddPlaceholderChunk("(type)");
179 
180   auto *CCS = Builder.TakeString();
181   computeSignature(*CCS);
182   EXPECT_EQ(Signature, "(type)");
183   EXPECT_EQ(Snippet, "${1:(type)}");
184 }
185 
TEST_F(CompletionStringTest,ObjectiveCMethodTwoArgumentsFromBeginning)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)");
193 
194   auto *CCS = Builder.TakeString();
195   computeSignature(*CCS);
196   EXPECT_EQ(Signature, "(type) bar:(type2)");
197   EXPECT_EQ(Snippet, "${1:(type)} bar:${2:(type2)}");
198 }
199 
TEST_F(CompletionStringTest,ObjectiveCMethodTwoArgumentsFromMiddle)200 TEST_F(CompletionStringTest, ObjectiveCMethodTwoArgumentsFromMiddle) {
201   Builder.AddResultTypeChunk("int");
202   Builder.AddInformativeChunk("withFoo:");
203   Builder.AddTypedTextChunk("bar:");
204   Builder.AddPlaceholderChunk("(type2)");
205 
206   auto *CCS = Builder.TakeString();
207   computeSignature(*CCS);
208   EXPECT_EQ(Signature, "(type2)");
209   EXPECT_EQ(Snippet, "${1:(type2)}");
210 }
211 
212 } // namespace
213 } // namespace clangd
214 } // namespace clang
215