242 lines · cpp
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-exception6//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 15namespace clang {16namespace clangd {17namespace {18 19class CompletionStringTest : public ::testing::Test {20public:21 CompletionStringTest()22 : Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),23 CCTUInfo(Allocator), Builder(*Allocator, CCTUInfo) {}24 25protected:26 void computeSignature(const CodeCompletionString &CCS,27 CodeCompletionResult::ResultKind ResultKind =28 CodeCompletionResult::ResultKind::RK_Declaration,29 bool IncludeFunctionArguments = true) {30 Signature.clear();31 Snippet.clear();32 getSignature(CCS, &Signature, &Snippet, ResultKind,33 /*CursorKind=*/CXCursorKind::CXCursor_NotImplemented,34 /*IncludeFunctionArguments=*/IncludeFunctionArguments,35 /*RequiredQualifiers=*/nullptr);36 }37 38 std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;39 CodeCompletionTUInfo CCTUInfo;40 CodeCompletionBuilder Builder;41 std::string Signature;42 std::string Snippet;43};44 45TEST_F(CompletionStringTest, ReturnType) {46 Builder.AddResultTypeChunk("result");47 Builder.AddResultTypeChunk("redundant result no no");48 EXPECT_EQ(getReturnType(*Builder.TakeString()), "result");49}50 51TEST_F(CompletionStringTest, Documentation) {52 Builder.addBriefComment("This is ignored");53 EXPECT_EQ(formatDocumentation(*Builder.TakeString(), "Is this brief?"),54 "Is this brief?");55}56 57TEST_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?");62}63 64TEST_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")));70}71 72TEST_F(CompletionStringTest, MultipleAnnotations) {73 Builder.AddAnnotation("Ano1");74 Builder.AddAnnotation("Ano2");75 Builder.AddAnnotation("Ano3");76 77 EXPECT_EQ(formatDocumentation(*Builder.TakeString(), ""),78 "Annotations: Ano1 Ano2 Ano3\n");79}80 81TEST_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, "");87}88 89TEST_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);98 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");104}105 106TEST_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();111 112 Builder.AddChunk(CodeCompletionString::CK_Comma);113 Builder.AddTypedTextChunk("p2 = 0");114 Builder.AddOptionalChunk(DefaultParam2);115 auto *DefaultParam1 = Builder.TakeString();116 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);123 124 auto *CCS = Builder.TakeString();125 computeSignature(*CCS);126 EXPECT_EQ(Signature, "(p1, p2 = 0, p3 = 0)");127 EXPECT_EQ(Snippet, "(${1:p1})");128}129 130TEST_F(CompletionStringTest, EscapeSnippet) {131 Builder.AddTypedTextChunk("Foo");132 Builder.AddChunk(CodeCompletionString::CK_LeftParen);133 Builder.AddPlaceholderChunk("$p}1\\");134 Builder.AddChunk(CodeCompletionString::CK_RightParen);135 136 computeSignature(*Builder.TakeString());137 EXPECT_EQ(Signature, "($p}1\\)");138 EXPECT_EQ(Snippet, "(${1:\\$p\\}1\\\\})");139}140 141TEST_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();151 };152 computeSignature(MakeCCS());153 EXPECT_EQ(Snippet, " ${1:name} = ${2:target};");154 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;");159}160 161TEST_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);173 174 computeSignature(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}>");181}182 183TEST_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, "");190}191 192TEST_F(CompletionStringTest, ObjectiveCMethodNoArguments) {193 Builder.AddResultTypeChunk("void");194 Builder.AddTypedTextChunk("methodName");195 196 auto *CCS = Builder.TakeString();197 computeSignature(*CCS);198 EXPECT_EQ(Signature, "");199 EXPECT_EQ(Snippet, "");200}201 202TEST_F(CompletionStringTest, ObjectiveCMethodOneArgument) {203 Builder.AddResultTypeChunk("void");204 Builder.AddTypedTextChunk("methodWithArg:");205 Builder.AddPlaceholderChunk("(type)");206 207 auto *CCS = Builder.TakeString();208 computeSignature(*CCS);209 EXPECT_EQ(Signature, "(type)");210 EXPECT_EQ(Snippet, "${1:(type)}");211}212 213TEST_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)");220 221 auto *CCS = Builder.TakeString();222 computeSignature(*CCS);223 EXPECT_EQ(Signature, "(type) bar:(type2)");224 EXPECT_EQ(Snippet, "${1:(type)} bar:${2:(type2)}");225}226 227TEST_F(CompletionStringTest, ObjectiveCMethodTwoArgumentsFromMiddle) {228 Builder.AddResultTypeChunk("int");229 Builder.AddInformativeChunk("withFoo:");230 Builder.AddTypedTextChunk("bar:");231 Builder.AddPlaceholderChunk("(type2)");232 233 auto *CCS = Builder.TakeString();234 computeSignature(*CCS);235 EXPECT_EQ(Signature, "(type2)");236 EXPECT_EQ(Snippet, "${1:(type2)}");237}238 239} // namespace240} // namespace clangd241} // namespace clang242