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 "clang/Sema/CodeCompleteConsumer.h" 11 #include "gmock/gmock.h" 12 #include "gtest/gtest.h" 13 14 namespace clang { 15 namespace clangd { 16 namespace { 17 18 class CompletionStringTest : public ::testing::Test { 19 public: 20 CompletionStringTest() 21 : Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()), 22 CCTUInfo(Allocator), Builder(*Allocator, CCTUInfo) {} 23 24 protected: 25 void computeSignature(const CodeCompletionString &CCS, 26 bool CompletingPattern = false) { 27 Signature.clear(); 28 Snippet.clear(); 29 getSignature(CCS, &Signature, &Snippet, /*RequiredQualifier=*/nullptr, 30 CompletingPattern); 31 } 32 33 std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator; 34 CodeCompletionTUInfo CCTUInfo; 35 CodeCompletionBuilder Builder; 36 std::string Signature; 37 std::string Snippet; 38 }; 39 40 TEST_F(CompletionStringTest, ReturnType) { 41 Builder.AddResultTypeChunk("result"); 42 Builder.AddResultTypeChunk("redundant result no no"); 43 EXPECT_EQ(getReturnType(*Builder.TakeString()), "result"); 44 } 45 46 TEST_F(CompletionStringTest, Documentation) { 47 Builder.addBriefComment("This is ignored"); 48 EXPECT_EQ(formatDocumentation(*Builder.TakeString(), "Is this brief?"), 49 "Is this brief?"); 50 } 51 52 TEST_F(CompletionStringTest, DocumentationWithAnnotation) { 53 Builder.addBriefComment("This is ignored"); 54 Builder.AddAnnotation("Ano"); 55 EXPECT_EQ(formatDocumentation(*Builder.TakeString(), "Is this brief?"), 56 "Annotation: Ano\n\nIs this brief?"); 57 } 58 59 TEST_F(CompletionStringTest, MultipleAnnotations) { 60 Builder.AddAnnotation("Ano1"); 61 Builder.AddAnnotation("Ano2"); 62 Builder.AddAnnotation("Ano3"); 63 64 EXPECT_EQ(formatDocumentation(*Builder.TakeString(), ""), 65 "Annotations: Ano1 Ano2 Ano3\n"); 66 } 67 68 TEST_F(CompletionStringTest, EmptySignature) { 69 Builder.AddTypedTextChunk("X"); 70 Builder.AddResultTypeChunk("result no no"); 71 computeSignature(*Builder.TakeString()); 72 EXPECT_EQ(Signature, ""); 73 EXPECT_EQ(Snippet, ""); 74 } 75 76 TEST_F(CompletionStringTest, Function) { 77 Builder.AddResultTypeChunk("result no no"); 78 Builder.addBriefComment("This comment is ignored"); 79 Builder.AddTypedTextChunk("Foo"); 80 Builder.AddChunk(CodeCompletionString::CK_LeftParen); 81 Builder.AddPlaceholderChunk("p1"); 82 Builder.AddChunk(CodeCompletionString::CK_Comma); 83 Builder.AddPlaceholderChunk("p2"); 84 Builder.AddChunk(CodeCompletionString::CK_RightParen); 85 86 auto *CCS = Builder.TakeString(); 87 computeSignature(*CCS); 88 EXPECT_EQ(Signature, "(p1, p2)"); 89 EXPECT_EQ(Snippet, "(${1:p1}, ${2:p2})"); 90 EXPECT_EQ(formatDocumentation(*CCS, "Foo's comment"), "Foo's comment"); 91 } 92 93 TEST_F(CompletionStringTest, FunctionWithDefaultParams) { 94 // return_type foo(p1, p2 = 0, p3 = 0) 95 Builder.AddChunk(CodeCompletionString::CK_Comma); 96 Builder.AddTypedTextChunk("p3 = 0"); 97 auto *DefaultParam2 = Builder.TakeString(); 98 99 Builder.AddChunk(CodeCompletionString::CK_Comma); 100 Builder.AddTypedTextChunk("p2 = 0"); 101 Builder.AddOptionalChunk(DefaultParam2); 102 auto *DefaultParam1 = Builder.TakeString(); 103 104 Builder.AddResultTypeChunk("return_type"); 105 Builder.AddTypedTextChunk("Foo"); 106 Builder.AddChunk(CodeCompletionString::CK_LeftParen); 107 Builder.AddPlaceholderChunk("p1"); 108 Builder.AddOptionalChunk(DefaultParam1); 109 Builder.AddChunk(CodeCompletionString::CK_RightParen); 110 111 auto *CCS = Builder.TakeString(); 112 computeSignature(*CCS); 113 EXPECT_EQ(Signature, "(p1, p2 = 0, p3 = 0)"); 114 EXPECT_EQ(Snippet, "(${1:p1})"); 115 } 116 117 TEST_F(CompletionStringTest, EscapeSnippet) { 118 Builder.AddTypedTextChunk("Foo"); 119 Builder.AddChunk(CodeCompletionString::CK_LeftParen); 120 Builder.AddPlaceholderChunk("$p}1\\"); 121 Builder.AddChunk(CodeCompletionString::CK_RightParen); 122 123 computeSignature(*Builder.TakeString()); 124 EXPECT_EQ(Signature, "($p}1\\)"); 125 EXPECT_EQ(Snippet, "(${1:\\$p\\}1\\\\})"); 126 } 127 128 TEST_F(CompletionStringTest, SnippetsInPatterns) { 129 auto MakeCCS = [this]() -> const CodeCompletionString & { 130 CodeCompletionBuilder Builder(*Allocator, CCTUInfo); 131 Builder.AddTypedTextChunk("namespace"); 132 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); 133 Builder.AddPlaceholderChunk("name"); 134 Builder.AddChunk(CodeCompletionString::CK_Equal); 135 Builder.AddPlaceholderChunk("target"); 136 Builder.AddChunk(CodeCompletionString::CK_SemiColon); 137 return *Builder.TakeString(); 138 }; 139 computeSignature(MakeCCS(), /*CompletingPattern=*/false); 140 EXPECT_EQ(Snippet, " ${1:name} = ${2:target};"); 141 142 // When completing a pattern, the last placeholder holds the cursor position. 143 computeSignature(MakeCCS(), /*CompletingPattern=*/true); 144 EXPECT_EQ(Snippet, " ${1:name} = ${0:target};"); 145 } 146 147 TEST_F(CompletionStringTest, IgnoreInformativeQualifier) { 148 Builder.AddTypedTextChunk("X"); 149 Builder.AddInformativeChunk("info ok"); 150 Builder.AddInformativeChunk("info no no::"); 151 computeSignature(*Builder.TakeString()); 152 EXPECT_EQ(Signature, "info ok"); 153 EXPECT_EQ(Snippet, ""); 154 } 155 156 TEST_F(CompletionStringTest, ObjectiveCMethodNoArguments) { 157 Builder.AddResultTypeChunk("void"); 158 Builder.AddTypedTextChunk("methodName"); 159 160 auto *CCS = Builder.TakeString(); 161 computeSignature(*CCS); 162 EXPECT_EQ(Signature, ""); 163 EXPECT_EQ(Snippet, ""); 164 } 165 166 TEST_F(CompletionStringTest, ObjectiveCMethodOneArgument) { 167 Builder.AddResultTypeChunk("void"); 168 Builder.AddTypedTextChunk("methodWithArg:"); 169 Builder.AddPlaceholderChunk("(type)"); 170 171 auto *CCS = Builder.TakeString(); 172 computeSignature(*CCS); 173 EXPECT_EQ(Signature, "(type)"); 174 EXPECT_EQ(Snippet, "${1:(type)}"); 175 } 176 177 TEST_F(CompletionStringTest, ObjectiveCMethodTwoArgumentsFromBeginning) { 178 Builder.AddResultTypeChunk("int"); 179 Builder.AddTypedTextChunk("withFoo:"); 180 Builder.AddPlaceholderChunk("(type)"); 181 Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); 182 Builder.AddTypedTextChunk("bar:"); 183 Builder.AddPlaceholderChunk("(type2)"); 184 185 auto *CCS = Builder.TakeString(); 186 computeSignature(*CCS); 187 EXPECT_EQ(Signature, "(type) bar:(type2)"); 188 EXPECT_EQ(Snippet, "${1:(type)} bar:${2:(type2)}"); 189 } 190 191 TEST_F(CompletionStringTest, ObjectiveCMethodTwoArgumentsFromMiddle) { 192 Builder.AddResultTypeChunk("int"); 193 Builder.AddInformativeChunk("withFoo:"); 194 Builder.AddTypedTextChunk("bar:"); 195 Builder.AddPlaceholderChunk("(type2)"); 196 197 auto *CCS = Builder.TakeString(); 198 computeSignature(*CCS); 199 EXPECT_EQ(Signature, "(type2)"); 200 EXPECT_EQ(Snippet, "${1:(type2)}"); 201 } 202 203 } // namespace 204 } // namespace clangd 205 } // namespace clang 206