blob: 284149a5e05f2a3852dad770721e8139ead4dd22 [file] [log] [blame]
Sam McCall9aad25f2017-12-05 07:20:26 +00001//===-- CodeCompleteTests.cpp -----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Eric Liu6f648df2017-12-19 16:50:37 +00009
Sam McCall328cbdb2017-12-20 16:06:05 +000010#include "Annotations.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000011#include "ClangdServer.h"
Sam McCall328cbdb2017-12-20 16:06:05 +000012#include "CodeComplete.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000013#include "Compiler.h"
Ilya Biryukov5a85b8e2017-12-13 12:53:16 +000014#include "Matchers.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000015#include "Protocol.h"
Sam McCalle746a2b2018-07-02 11:13:16 +000016#include "Quality.h"
Sam McCallb536a2a2017-12-19 12:23:48 +000017#include "SourceCode.h"
Ilya Biryukovcd5eb002018-02-12 11:37:28 +000018#include "SyncAPI.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000019#include "TestFS.h"
Eric Liu6f648df2017-12-19 16:50:37 +000020#include "index/MemIndex.h"
Eric Liu5d2a8072018-07-23 10:56:37 +000021#include "clang/Sema/CodeCompleteConsumer.h"
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +000022#include "llvm/Support/Error.h"
Ilya Biryukov981a35d2018-05-28 12:11:37 +000023#include "llvm/Testing/Support/Error.h"
Sam McCallf6ae3232017-12-05 20:11:29 +000024#include "gmock/gmock.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000025#include "gtest/gtest.h"
26
27namespace clang {
28namespace clangd {
Sam McCallf6ae3232017-12-05 20:11:29 +000029
Sam McCall9aad25f2017-12-05 07:20:26 +000030namespace {
31using namespace llvm;
Sam McCallf6ae3232017-12-05 20:11:29 +000032using ::testing::AllOf;
33using ::testing::Contains;
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000034using ::testing::Each;
Sam McCallf6ae3232017-12-05 20:11:29 +000035using ::testing::ElementsAre;
Ilya Biryukov71028b82018-03-12 15:28:22 +000036using ::testing::Field;
Sam McCallc18c2802018-06-15 11:06:29 +000037using ::testing::HasSubstr;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +000038using ::testing::IsEmpty;
Sam McCallf6ae3232017-12-05 20:11:29 +000039using ::testing::Not;
Sam McCall3d139c52018-01-12 18:30:08 +000040using ::testing::UnorderedElementsAre;
Sam McCall9aad25f2017-12-05 07:20:26 +000041
42class IgnoreDiagnostics : public DiagnosticsConsumer {
Ilya Biryukov71028b82018-03-12 15:28:22 +000043 void onDiagnosticsReady(PathRef File,
Sam McCalla7bb0cc2018-03-12 23:22:35 +000044 std::vector<Diag> Diagnostics) override {}
Sam McCall9aad25f2017-12-05 07:20:26 +000045};
46
Sam McCallf6ae3232017-12-05 20:11:29 +000047// GMock helpers for matching completion items.
Sam McCalle746a2b2018-07-02 11:13:16 +000048MATCHER_P(Named, Name, "") { return arg.Name == Name; }
49MATCHER_P(Scope, S, "") { return arg.Scope == S; }
50MATCHER_P(Qualifier, Q, "") { return arg.RequiredQualifier == Q; }
Eric Liu8f3678d2018-06-15 13:34:18 +000051MATCHER_P(Labeled, Label, "") {
Sam McCalle746a2b2018-07-02 11:13:16 +000052 return arg.RequiredQualifier + arg.Name + arg.Signature == Label;
Eric Liu8f3678d2018-06-15 13:34:18 +000053}
54MATCHER_P(SigHelpLabeled, Label, "") { return arg.label == Label; }
Sam McCalle746a2b2018-07-02 11:13:16 +000055MATCHER_P(Kind, K, "") { return arg.Kind == K; }
56MATCHER_P(Doc, D, "") { return arg.Documentation == D; }
57MATCHER_P(ReturnType, D, "") { return arg.ReturnType == D; }
Eric Liu63f419a2018-05-15 15:29:32 +000058MATCHER_P(InsertInclude, IncludeHeader, "") {
Sam McCalle746a2b2018-07-02 11:13:16 +000059 return arg.Header == IncludeHeader && bool(arg.HeaderInsertion);
Eric Liu63f419a2018-05-15 15:29:32 +000060}
Sam McCalle746a2b2018-07-02 11:13:16 +000061MATCHER(InsertInclude, "") { return bool(arg.HeaderInsertion); }
62MATCHER_P(SnippetSuffix, Text, "") { return arg.SnippetSuffix == Text; }
Sam McCall2161ec72018-07-05 06:20:41 +000063MATCHER_P(Origin, OriginSet, "") { return arg.Origin == OriginSet; }
Eric Liu63f419a2018-05-15 15:29:32 +000064
Sam McCallf6ae3232017-12-05 20:11:29 +000065// Shorthand for Contains(Named(Name)).
Sam McCalle746a2b2018-07-02 11:13:16 +000066Matcher<const std::vector<CodeCompletion> &> Has(std::string Name) {
Sam McCallf6ae3232017-12-05 20:11:29 +000067 return Contains(Named(std::move(Name)));
68}
Sam McCalle746a2b2018-07-02 11:13:16 +000069Matcher<const std::vector<CodeCompletion> &> Has(std::string Name,
Sam McCall44fdcec22017-12-08 15:00:59 +000070 CompletionItemKind K) {
71 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000072}
Sam McCalle746a2b2018-07-02 11:13:16 +000073MATCHER(IsDocumented, "") { return !arg.Documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000074
Sam McCalla15c2d62018-01-18 09:27:56 +000075std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
76 SymbolSlab::Builder Slab;
77 for (const auto &Sym : Symbols)
78 Slab.insert(Sym);
Haojian Wue8064b62018-08-31 19:53:37 +000079 return MemIndex::build(std::move(Slab).build(),
80 SymbolOccurrenceSlab::createEmpty());
Sam McCalla15c2d62018-01-18 09:27:56 +000081}
82
Kadir Cetinkaya2f84d912018-08-08 08:59:29 +000083CodeCompleteResult completions(ClangdServer &Server, StringRef TestCode,
84 Position point,
85 std::vector<Symbol> IndexSymbols = {},
86 clangd::CodeCompleteOptions Opts = {}) {
87 std::unique_ptr<SymbolIndex> OverrideIndex;
88 if (!IndexSymbols.empty()) {
89 assert(!Opts.Index && "both Index and IndexSymbols given!");
90 OverrideIndex = memIndex(std::move(IndexSymbols));
91 Opts.Index = OverrideIndex.get();
92 }
93
94 auto File = testPath("foo.cpp");
95 runAddDocument(Server, File, TestCode);
96 auto CompletionList = cantFail(runCodeComplete(Server, File, point, Opts));
97 return CompletionList;
98}
99
Sam McCalle746a2b2018-07-02 11:13:16 +0000100CodeCompleteResult completions(ClangdServer &Server, StringRef Text,
101 std::vector<Symbol> IndexSymbols = {},
102 clangd::CodeCompleteOptions Opts = {}) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000103 std::unique_ptr<SymbolIndex> OverrideIndex;
104 if (!IndexSymbols.empty()) {
105 assert(!Opts.Index && "both Index and IndexSymbols given!");
106 OverrideIndex = memIndex(std::move(IndexSymbols));
107 Opts.Index = OverrideIndex.get();
108 }
109
Sam McCallc1568062018-02-16 09:41:43 +0000110 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000111 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000112 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000113 auto CompletionList =
114 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000115 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +0000116}
117
Eric Liu63f419a2018-05-15 15:29:32 +0000118// Builds a server and runs code completion.
119// If IndexSymbols is non-empty, an index will be built and passed to opts.
Sam McCalle746a2b2018-07-02 11:13:16 +0000120CodeCompleteResult completions(StringRef Text,
121 std::vector<Symbol> IndexSymbols = {},
122 clangd::CodeCompleteOptions Opts = {}) {
Eric Liu63f419a2018-05-15 15:29:32 +0000123 MockFSProvider FS;
124 MockCompilationDatabase CDB;
125 IgnoreDiagnostics DiagConsumer;
126 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
127 return completions(Server, Text, std::move(IndexSymbols), std::move(Opts));
128}
129
Sam McCall545a20d2018-01-19 14:34:02 +0000130std::string replace(StringRef Haystack, StringRef Needle, StringRef Repl) {
131 std::string Result;
132 raw_string_ostream OS(Result);
133 std::pair<StringRef, StringRef> Split;
134 for (Split = Haystack.split(Needle); !Split.second.empty();
135 Split = Split.first.split(Needle))
136 OS << Split.first << Repl;
137 Result += Split.first;
138 OS.flush();
139 return Result;
140}
141
Sam McCalla15c2d62018-01-18 09:27:56 +0000142// Helpers to produce fake index symbols for memIndex() or completions().
Sam McCall545a20d2018-01-19 14:34:02 +0000143// USRFormat is a regex replacement string for the unqualified part of the USR.
144Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000145 Symbol Sym;
Sam McCall545a20d2018-01-19 14:34:02 +0000146 std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
Sam McCalla15c2d62018-01-18 09:27:56 +0000147 size_t Pos = QName.rfind("::");
148 if (Pos == llvm::StringRef::npos) {
149 Sym.Name = QName;
150 Sym.Scope = "";
151 } else {
152 Sym.Name = QName.substr(Pos + 2);
Sam McCall8b2faee2018-01-19 22:18:21 +0000153 Sym.Scope = QName.substr(0, Pos + 2);
154 USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
Sam McCalla15c2d62018-01-18 09:27:56 +0000155 }
Sam McCall545a20d2018-01-19 14:34:02 +0000156 USR += Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
157 Sym.ID = SymbolID(USR);
Sam McCalla15c2d62018-01-18 09:27:56 +0000158 Sym.SymInfo.Kind = Kind;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000159 Sym.IsIndexedForCodeCompletion = true;
Sam McCall2161ec72018-07-05 06:20:41 +0000160 Sym.Origin = SymbolOrigin::Static;
Sam McCalla15c2d62018-01-18 09:27:56 +0000161 return Sym;
162}
Sam McCall545a20d2018-01-19 14:34:02 +0000163Symbol func(StringRef Name) { // Assumes the function has no args.
164 return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
165}
166Symbol cls(StringRef Name) {
Eric Liu9b3cba72018-05-30 09:03:39 +0000167 return sym(Name, index::SymbolKind::Class, "@S@\\0");
Sam McCall545a20d2018-01-19 14:34:02 +0000168}
169Symbol var(StringRef Name) {
170 return sym(Name, index::SymbolKind::Variable, "@\\0");
171}
Sam McCalldc8abc42018-05-03 14:53:02 +0000172Symbol ns(StringRef Name) {
173 return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
174}
175Symbol withReferences(int N, Symbol S) {
176 S.References = N;
177 return S;
178}
Sam McCalla15c2d62018-01-18 09:27:56 +0000179
Sam McCallf6ae3232017-12-05 20:11:29 +0000180TEST(CompletionTest, Limit) {
181 clangd::CodeCompleteOptions Opts;
182 Opts.Limit = 2;
183 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000184struct ClassWithMembers {
185 int AAA();
186 int BBB();
187 int CCC();
188}
Sam McCallf6ae3232017-12-05 20:11:29 +0000189int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000190 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000191 /*IndexSymbols=*/{}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000192
Sam McCalle746a2b2018-07-02 11:13:16 +0000193 EXPECT_TRUE(Results.HasMore);
194 EXPECT_THAT(Results.Completions, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000195}
196
Sam McCallf6ae3232017-12-05 20:11:29 +0000197TEST(CompletionTest, Filter) {
198 std::string Body = R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000199 #define MotorCar
200 int Car;
Sam McCall9aad25f2017-12-05 07:20:26 +0000201 struct S {
202 int FooBar;
203 int FooBaz;
204 int Qux;
205 };
206 )cpp";
Sam McCall8b2dcc12018-06-14 13:50:30 +0000207
208 // Only items matching the fuzzy query are returned.
Sam McCalle746a2b2018-07-02 11:13:16 +0000209 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").Completions,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000210 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000211
Sam McCall8b2dcc12018-06-14 13:50:30 +0000212 // Macros require prefix match.
Sam McCalle746a2b2018-07-02 11:13:16 +0000213 EXPECT_THAT(completions(Body + "int main() { C^ }").Completions,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000214 AllOf(Has("Car"), Not(Has("MotorCar"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000215}
216
Sam McCallf6ae3232017-12-05 20:11:29 +0000217void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000218 auto Results = completions(
219 R"cpp(
220 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000221
Sam McCall44fdcec22017-12-08 15:00:59 +0000222 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000223
Sam McCall44fdcec22017-12-08 15:00:59 +0000224 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000225
Sam McCall44fdcec22017-12-08 15:00:59 +0000226 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000227
Sam McCall44fdcec22017-12-08 15:00:59 +0000228 struct ClassWithMembers {
229 /// Doc for method.
230 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000231
Sam McCall44fdcec22017-12-08 15:00:59 +0000232 int field;
233 private:
234 int private_field;
235 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000236
Sam McCall44fdcec22017-12-08 15:00:59 +0000237 int test() {
238 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000239
Sam McCall44fdcec22017-12-08 15:00:59 +0000240 /// Doc for local_var.
241 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000242
Sam McCall44fdcec22017-12-08 15:00:59 +0000243 ClassWithMembers().^
244 }
245 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000246 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000247
Sam McCallf6ae3232017-12-05 20:11:29 +0000248 // Class members. The only items that must be present in after-dot
249 // completion.
Sam McCalle746a2b2018-07-02 11:13:16 +0000250 EXPECT_THAT(Results.Completions,
251 AllOf(Has("method"), Has("field"), Not(Has("ClassWithMembers")),
Sam McCall4caa8512018-06-07 12:49:17 +0000252 Not(Has("operator=")), Not(Has("~ClassWithMembers"))));
Sam McCalle746a2b2018-07-02 11:13:16 +0000253 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000254 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000255 // Global items.
Sam McCall545a20d2018-01-19 14:34:02 +0000256 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +0000257 Results.Completions,
Sam McCall545a20d2018-01-19 14:34:02 +0000258 Not(AnyOf(Has("global_var"), Has("index_var"), Has("global_func"),
259 Has("global_func()"), Has("index_func"), Has("GlobalClass"),
260 Has("IndexClass"), Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000261 // There should be no code patterns (aka snippets) in after-dot
262 // completion. At least there aren't any we're aware of.
Sam McCalle746a2b2018-07-02 11:13:16 +0000263 EXPECT_THAT(Results.Completions,
264 Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000265 // Check documentation.
Sam McCalle746a2b2018-07-02 11:13:16 +0000266 EXPECT_IFF(Opts.IncludeComments, Results.Completions,
267 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000268}
Sam McCall9aad25f2017-12-05 07:20:26 +0000269
Sam McCallf6ae3232017-12-05 20:11:29 +0000270void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000271 auto Results = completions(
272 R"cpp(
273 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000274
Sam McCall44fdcec22017-12-08 15:00:59 +0000275 int global_var;
276 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000277
Sam McCall44fdcec22017-12-08 15:00:59 +0000278 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000279
Sam McCall44fdcec22017-12-08 15:00:59 +0000280 struct ClassWithMembers {
281 /// Doc for method.
282 int method();
283 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000284
Sam McCall44fdcec22017-12-08 15:00:59 +0000285 int test() {
286 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000287
Sam McCall44fdcec22017-12-08 15:00:59 +0000288 /// Doc for local_var.
289 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000290
Sam McCall44fdcec22017-12-08 15:00:59 +0000291 ^
292 }
293 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000294 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000295
296 // Class members. Should never be present in global completions.
Sam McCalle746a2b2018-07-02 11:13:16 +0000297 EXPECT_THAT(Results.Completions,
Sam McCallf6ae3232017-12-05 20:11:29 +0000298 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
299 // Global items.
Sam McCalle746a2b2018-07-02 11:13:16 +0000300 EXPECT_THAT(Results.Completions,
301 AllOf(Has("global_var"), Has("index_var"), Has("global_func"),
Sam McCall545a20d2018-01-19 14:34:02 +0000302 Has("index_func" /* our fake symbol doesn't include () */),
303 Has("GlobalClass"), Has("IndexClass")));
Sam McCallf6ae3232017-12-05 20:11:29 +0000304 // A macro.
Sam McCalle746a2b2018-07-02 11:13:16 +0000305 EXPECT_IFF(Opts.IncludeMacros, Results.Completions, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000306 // Local items. Must be present always.
Sam McCalle746a2b2018-07-02 11:13:16 +0000307 EXPECT_THAT(Results.Completions,
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000308 AllOf(Has("local_var"), Has("LocalClass"),
309 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000310 // Check documentation.
Sam McCalle746a2b2018-07-02 11:13:16 +0000311 EXPECT_IFF(Opts.IncludeComments, Results.Completions,
312 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000313}
314
315TEST(CompletionTest, CompletionOptions) {
Sam McCall2c3849a2018-01-16 12:21:24 +0000316 auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
317 TestAfterDotCompletion(Opts);
318 TestGlobalScopeCompletion(Opts);
319 };
320 // We used to test every combination of options, but that got too slow (2^N).
321 auto Flags = {
Ilya Biryukov71028b82018-03-12 15:28:22 +0000322 &clangd::CodeCompleteOptions::IncludeMacros,
Ilya Biryukov43714502018-05-16 12:32:44 +0000323 &clangd::CodeCompleteOptions::IncludeComments,
Ilya Biryukov71028b82018-03-12 15:28:22 +0000324 &clangd::CodeCompleteOptions::IncludeCodePatterns,
325 &clangd::CodeCompleteOptions::IncludeIneligibleResults,
Sam McCall2c3849a2018-01-16 12:21:24 +0000326 };
327 // Test default options.
328 Test({});
329 // Test with one flag flipped.
330 for (auto &F : Flags) {
331 clangd::CodeCompleteOptions O;
332 O.*F ^= true;
333 Test(O);
Sam McCall9aad25f2017-12-05 07:20:26 +0000334 }
335}
336
Sam McCall44fdcec22017-12-08 15:00:59 +0000337TEST(CompletionTest, Priorities) {
338 auto Internal = completions(R"cpp(
339 class Foo {
340 public: void pub();
341 protected: void prot();
342 private: void priv();
343 };
344 void Foo::pub() { this->^ }
345 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000346 EXPECT_THAT(Internal.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000347 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
348
349 auto External = completions(R"cpp(
350 class Foo {
351 public: void pub();
352 protected: void prot();
353 private: void priv();
354 };
355 void test() {
356 Foo F;
357 F.^
358 }
359 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000360 EXPECT_THAT(External.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000361 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
362}
363
364TEST(CompletionTest, Qualifiers) {
365 auto Results = completions(R"cpp(
366 class Foo {
367 public: int foo() const;
368 int bar() const;
369 };
370 class Bar : public Foo {
371 int foo() const;
372 };
373 void test() { Bar().^ }
374 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000375 EXPECT_THAT(Results.Completions,
376 HasSubsequence(AllOf(Qualifier(""), Named("bar")),
377 AllOf(Qualifier("Foo::"), Named("foo"))));
378 EXPECT_THAT(Results.Completions,
379 Not(Contains(AllOf(Qualifier(""), Named("foo"))))); // private
Sam McCall44fdcec22017-12-08 15:00:59 +0000380}
381
Sam McCall4caa8512018-06-07 12:49:17 +0000382TEST(CompletionTest, InjectedTypename) {
383 // These are suppressed when accessed as a member...
Sam McCalle746a2b2018-07-02 11:13:16 +0000384 EXPECT_THAT(completions("struct X{}; void foo(){ X().^ }").Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000385 Not(Has("X")));
Sam McCalle746a2b2018-07-02 11:13:16 +0000386 EXPECT_THAT(completions("struct X{ void foo(){ this->^ } };").Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000387 Not(Has("X")));
388 // ...but accessible in other, more useful cases.
Sam McCalle746a2b2018-07-02 11:13:16 +0000389 EXPECT_THAT(completions("struct X{ void foo(){ ^ } };").Completions,
390 Has("X"));
391 EXPECT_THAT(
392 completions("struct Y{}; struct X:Y{ void foo(){ ^ } };").Completions,
393 Has("Y"));
Sam McCall4caa8512018-06-07 12:49:17 +0000394 EXPECT_THAT(
395 completions(
396 "template<class> struct Y{}; struct X:Y<int>{ void foo(){ ^ } };")
Sam McCalle746a2b2018-07-02 11:13:16 +0000397 .Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000398 Has("Y"));
399 // This case is marginal (`using X::X` is useful), we allow it for now.
Sam McCalle746a2b2018-07-02 11:13:16 +0000400 EXPECT_THAT(completions("struct X{}; void foo(){ X::^ }").Completions,
401 Has("X"));
Sam McCall4caa8512018-06-07 12:49:17 +0000402}
403
Sam McCall44fdcec22017-12-08 15:00:59 +0000404TEST(CompletionTest, Snippets) {
405 clangd::CodeCompleteOptions Opts;
Sam McCall44fdcec22017-12-08 15:00:59 +0000406 auto Results = completions(
407 R"cpp(
408 struct fake {
409 int a;
410 int f(int i, const float f) const;
411 };
412 int main() {
413 fake f;
414 f.^
415 }
416 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000417 /*IndexSymbols=*/{}, Opts);
Sam McCalle746a2b2018-07-02 11:13:16 +0000418 EXPECT_THAT(
419 Results.Completions,
420 HasSubsequence(Named("a"),
421 SnippetSuffix("(${1:int i}, ${2:const float f})")));
Sam McCall44fdcec22017-12-08 15:00:59 +0000422}
423
424TEST(CompletionTest, Kinds) {
Sam McCall545a20d2018-01-19 14:34:02 +0000425 auto Results = completions(
426 R"cpp(
427 #define MACRO X
428 int variable;
429 struct Struct {};
430 int function();
431 int X = ^
432 )cpp",
433 {func("indexFunction"), var("indexVariable"), cls("indexClass")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000434 EXPECT_THAT(Results.Completions,
Sam McCall545a20d2018-01-19 14:34:02 +0000435 AllOf(Has("function", CompletionItemKind::Function),
436 Has("variable", CompletionItemKind::Variable),
437 Has("int", CompletionItemKind::Keyword),
438 Has("Struct", CompletionItemKind::Class),
439 Has("MACRO", CompletionItemKind::Text),
440 Has("indexFunction", CompletionItemKind::Function),
441 Has("indexVariable", CompletionItemKind::Variable),
442 Has("indexClass", CompletionItemKind::Class)));
Sam McCall44fdcec22017-12-08 15:00:59 +0000443
Sam McCall44fdcec22017-12-08 15:00:59 +0000444 Results = completions("nam^");
Sam McCalle746a2b2018-07-02 11:13:16 +0000445 EXPECT_THAT(Results.Completions,
446 Has("namespace", CompletionItemKind::Snippet));
Sam McCall44fdcec22017-12-08 15:00:59 +0000447}
448
Sam McCall84652cc2018-01-12 16:16:09 +0000449TEST(CompletionTest, NoDuplicates) {
Sam McCall545a20d2018-01-19 14:34:02 +0000450 auto Results = completions(
451 R"cpp(
452 class Adapter {
Sam McCall545a20d2018-01-19 14:34:02 +0000453 };
Sam McCall84652cc2018-01-12 16:16:09 +0000454
Eric Liu9b3cba72018-05-30 09:03:39 +0000455 void f() {
Sam McCall545a20d2018-01-19 14:34:02 +0000456 Adapter^
457 }
458 )cpp",
459 {cls("Adapter")});
Sam McCall84652cc2018-01-12 16:16:09 +0000460
461 // Make sure there are no duplicate entries of 'Adapter'.
Sam McCalle746a2b2018-07-02 11:13:16 +0000462 EXPECT_THAT(Results.Completions, ElementsAre(Named("Adapter")));
Sam McCall84652cc2018-01-12 16:16:09 +0000463}
464
Sam McCall545a20d2018-01-19 14:34:02 +0000465TEST(CompletionTest, ScopedNoIndex) {
466 auto Results = completions(
467 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000468 namespace fake { int BigBang, Babble, Box; };
469 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000470 ")cpp");
Sam McCall8b2dcc12018-06-14 13:50:30 +0000471 // Babble is a better match than BigBang. Box doesn't match at all.
Sam McCalle746a2b2018-07-02 11:13:16 +0000472 EXPECT_THAT(Results.Completions,
473 ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCall84652cc2018-01-12 16:16:09 +0000474}
475
Sam McCall545a20d2018-01-19 14:34:02 +0000476TEST(CompletionTest, Scoped) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000477 auto Results = completions(
478 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000479 namespace fake { int Babble, Box; };
480 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000481 ")cpp",
482 {var("fake::BigBang")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000483 EXPECT_THAT(Results.Completions,
484 ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000485}
486
Sam McCall545a20d2018-01-19 14:34:02 +0000487TEST(CompletionTest, ScopedWithFilter) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000488 auto Results = completions(
489 R"cpp(
490 void f() { ns::x^ }
491 )cpp",
492 {cls("ns::XYZ"), func("ns::foo")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000493 EXPECT_THAT(Results.Completions, UnorderedElementsAre(Named("XYZ")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000494}
495
Sam McCalldc8abc42018-05-03 14:53:02 +0000496TEST(CompletionTest, ReferencesAffectRanking) {
Eric Liu84bd5db2018-07-25 11:26:35 +0000497 auto Results = completions("int main() { abs^ }", {ns("absl"), func("absb")});
498 EXPECT_THAT(Results.Completions, HasSubsequence(Named("absb"), Named("absl")));
Sam McCalldc8abc42018-05-03 14:53:02 +0000499 Results = completions("int main() { abs^ }",
Eric Liu84bd5db2018-07-25 11:26:35 +0000500 {withReferences(10000, ns("absl")), func("absb")});
501 EXPECT_THAT(Results.Completions,
502 HasSubsequence(Named("absl"), Named("absb")));
Sam McCalldc8abc42018-05-03 14:53:02 +0000503}
504
Sam McCall545a20d2018-01-19 14:34:02 +0000505TEST(CompletionTest, GlobalQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000506 auto Results = completions(
507 R"cpp(
508 void f() { ::^ }
509 )cpp",
510 {cls("XYZ")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000511 EXPECT_THAT(Results.Completions,
512 AllOf(Has("XYZ", CompletionItemKind::Class),
513 Has("f", CompletionItemKind::Function)));
Sam McCalla15c2d62018-01-18 09:27:56 +0000514}
515
Sam McCall545a20d2018-01-19 14:34:02 +0000516TEST(CompletionTest, FullyQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000517 auto Results = completions(
518 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000519 namespace ns { void bar(); }
Sam McCalla15c2d62018-01-18 09:27:56 +0000520 void f() { ::ns::^ }
521 )cpp",
522 {cls("ns::XYZ")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000523 EXPECT_THAT(Results.Completions,
524 AllOf(Has("XYZ", CompletionItemKind::Class),
525 Has("bar", CompletionItemKind::Function)));
Sam McCall545a20d2018-01-19 14:34:02 +0000526}
527
528TEST(CompletionTest, SemaIndexMerge) {
529 auto Results = completions(
530 R"cpp(
531 namespace ns { int local; void both(); }
532 void f() { ::ns::^ }
533 )cpp",
534 {func("ns::both"), cls("ns::Index")});
535 // We get results from both index and sema, with no duplicates.
Sam McCall2161ec72018-07-05 06:20:41 +0000536 EXPECT_THAT(Results.Completions,
537 UnorderedElementsAre(
538 AllOf(Named("local"), Origin(SymbolOrigin::AST)),
539 AllOf(Named("Index"), Origin(SymbolOrigin::Static)),
540 AllOf(Named("both"),
541 Origin(SymbolOrigin::AST | SymbolOrigin::Static))));
Sam McCalla15c2d62018-01-18 09:27:56 +0000542}
543
Haojian Wu48b48652018-01-25 09:20:09 +0000544TEST(CompletionTest, SemaIndexMergeWithLimit) {
545 clangd::CodeCompleteOptions Opts;
546 Opts.Limit = 1;
547 auto Results = completions(
548 R"cpp(
549 namespace ns { int local; void both(); }
550 void f() { ::ns::^ }
551 )cpp",
552 {func("ns::both"), cls("ns::Index")}, Opts);
Sam McCalle746a2b2018-07-02 11:13:16 +0000553 EXPECT_EQ(Results.Completions.size(), Opts.Limit);
554 EXPECT_TRUE(Results.HasMore);
Haojian Wu48b48652018-01-25 09:20:09 +0000555}
556
Eric Liu63f419a2018-05-15 15:29:32 +0000557TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
558 MockFSProvider FS;
559 MockCompilationDatabase CDB;
560 std::string Subdir = testPath("sub");
561 std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
562 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
563 std::string BarHeader = testPath("sub/bar.h");
564 FS.Files[BarHeader] = "";
565
566 IgnoreDiagnostics DiagConsumer;
567 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Eric Liu63f419a2018-05-15 15:29:32 +0000568 auto BarURI = URI::createFile(BarHeader).toString();
569 Symbol Sym = cls("ns::X");
570 Sym.CanonicalDeclaration.FileURI = BarURI;
Sam McCall2e5700f2018-08-31 13:55:01 +0000571 Sym.IncludeHeader = BarURI;
Eric Liu63f419a2018-05-15 15:29:32 +0000572 // Shoten include path based on search dirctory and insert.
573 auto Results = completions(Server,
574 R"cpp(
575 int main() { ns::^ }
576 )cpp",
577 {Sym});
Sam McCalle746a2b2018-07-02 11:13:16 +0000578 EXPECT_THAT(Results.Completions,
579 ElementsAre(AllOf(Named("X"), InsertInclude("\"bar.h\""))));
Eric Liu63f419a2018-05-15 15:29:32 +0000580 // Duplicate based on inclusions in preamble.
581 Results = completions(Server,
582 R"cpp(
583 #include "sub/bar.h" // not shortest, so should only match resolved.
584 int main() { ns::^ }
585 )cpp",
586 {Sym});
Sam McCalle746a2b2018-07-02 11:13:16 +0000587 EXPECT_THAT(Results.Completions, ElementsAre(AllOf(Named("X"), Labeled("X"),
588 Not(InsertInclude()))));
Eric Liu63f419a2018-05-15 15:29:32 +0000589}
590
Eric Liu9b3cba72018-05-30 09:03:39 +0000591TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
592 MockFSProvider FS;
593 MockCompilationDatabase CDB;
594
595 IgnoreDiagnostics DiagConsumer;
596 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Eric Liu9b3cba72018-05-30 09:03:39 +0000597 Symbol SymX = cls("ns::X");
598 Symbol SymY = cls("ns::Y");
599 std::string BarHeader = testPath("bar.h");
600 auto BarURI = URI::createFile(BarHeader).toString();
601 SymX.CanonicalDeclaration.FileURI = BarURI;
602 SymY.CanonicalDeclaration.FileURI = BarURI;
Sam McCall2e5700f2018-08-31 13:55:01 +0000603 SymX.IncludeHeader = "<bar>";
604 SymY.IncludeHeader = "<bar>";
Eric Liu9b3cba72018-05-30 09:03:39 +0000605 // Shoten include path based on search dirctory and insert.
606 auto Results = completions(Server,
607 R"cpp(
608 namespace ns {
609 class X;
610 class Y {}
611 }
612 int main() { ns::^ }
613 )cpp",
614 {SymX, SymY});
Sam McCalle746a2b2018-07-02 11:13:16 +0000615 EXPECT_THAT(Results.Completions,
616 ElementsAre(AllOf(Named("X"), Not(InsertInclude())),
617 AllOf(Named("Y"), Not(InsertInclude()))));
Eric Liu9b3cba72018-05-30 09:03:39 +0000618}
619
Sam McCalla15c2d62018-01-18 09:27:56 +0000620TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
621 MockFSProvider FS;
622 MockCompilationDatabase CDB;
623 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000624 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCalla15c2d62018-01-18 09:27:56 +0000625
Sam McCallc1568062018-02-16 09:41:43 +0000626 FS.Files[testPath("bar.h")] =
Sam McCalld5ea3e32018-01-24 17:53:32 +0000627 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
Sam McCallc1568062018-02-16 09:41:43 +0000628 auto File = testPath("foo.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000629 Annotations Test(R"cpp(
630 #include "bar.h"
631 namespace ns { int local; }
Sam McCalld5ea3e32018-01-24 17:53:32 +0000632 void f() { ns::^; }
633 void f() { ns::preamble().$2^; }
Sam McCalla15c2d62018-01-18 09:27:56 +0000634 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000635 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000636 clangd::CodeCompleteOptions Opts = {};
637
Sam McCalla15c2d62018-01-18 09:27:56 +0000638 auto I = memIndex({var("ns::index")});
639 Opts.Index = I.get();
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000640 auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000641 EXPECT_THAT(WithIndex.Completions,
Sam McCalla15c2d62018-01-18 09:27:56 +0000642 UnorderedElementsAre(Named("local"), Named("index")));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000643 auto ClassFromPreamble =
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000644 cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000645 EXPECT_THAT(ClassFromPreamble.Completions, Contains(Named("member")));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000646
647 Opts.Index = nullptr;
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000648 auto WithoutIndex =
649 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000650 EXPECT_THAT(WithoutIndex.Completions,
Sam McCall0bb24cd2018-02-13 08:59:23 +0000651 UnorderedElementsAre(Named("local"), Named("preamble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000652}
653
654TEST(CompletionTest, DynamicIndexMultiFile) {
655 MockFSProvider FS;
656 MockCompilationDatabase CDB;
657 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000658 auto Opts = ClangdServer::optsForTest();
659 Opts.BuildDynamicSymbolIndex = true;
660 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCalla15c2d62018-01-18 09:27:56 +0000661
Eric Liu709bde82018-02-19 18:48:44 +0000662 FS.Files[testPath("foo.h")] = R"cpp(
Sam McCalla15c2d62018-01-18 09:27:56 +0000663 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liu709bde82018-02-19 18:48:44 +0000664 )cpp";
Sam McCall7363a2f2018-03-05 17:28:54 +0000665 runAddDocument(Server, testPath("foo.cpp"), R"cpp(
Eric Liu709bde82018-02-19 18:48:44 +0000666 #include "foo.h"
Sam McCall0bb24cd2018-02-13 08:59:23 +0000667 )cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000668
Sam McCallc1568062018-02-16 09:41:43 +0000669 auto File = testPath("bar.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000670 Annotations Test(R"cpp(
671 namespace ns {
672 class XXX {};
673 /// Doooc
674 void fooooo() {}
675 }
676 void f() { ns::^ }
677 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000678 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000679
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000680 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
Sam McCalla15c2d62018-01-18 09:27:56 +0000681 // "XYZ" and "foo" are not included in the file being completed but are still
682 // visible through the index.
Sam McCalle746a2b2018-07-02 11:13:16 +0000683 EXPECT_THAT(Results.Completions, Has("XYZ", CompletionItemKind::Class));
684 EXPECT_THAT(Results.Completions, Has("foo", CompletionItemKind::Function));
685 EXPECT_THAT(Results.Completions, Has("XXX", CompletionItemKind::Class));
686 EXPECT_THAT(Results.Completions,
687 Contains((Named("fooooo"), Kind(CompletionItemKind::Function),
688 Doc("Doooc"), ReturnType("void"))));
Sam McCalla15c2d62018-01-18 09:27:56 +0000689}
690
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000691TEST(CompletionTest, Documentation) {
692 auto Results = completions(
693 R"cpp(
694 // Non-doxygen comment.
695 int foo();
696 /// Doxygen comment.
697 /// \param int a
698 int bar(int a);
699 /* Multi-line
700 block comment
701 */
702 int baz();
703
704 int x = ^
705 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000706 EXPECT_THAT(Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000707 Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
708 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +0000709 Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000710 Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
Sam McCalle746a2b2018-07-02 11:13:16 +0000711 EXPECT_THAT(Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000712 Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
713}
714
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000715TEST(CompletionTest, GlobalCompletionFiltering) {
716
717 Symbol Class = cls("XYZ");
718 Class.IsIndexedForCodeCompletion = false;
719 Symbol Func = func("XYZ::foooo");
720 Func.IsIndexedForCodeCompletion = false;
721
722 auto Results = completions(R"(// void f() {
723 XYZ::foooo^
724 })",
725 {Class, Func});
Sam McCalle746a2b2018-07-02 11:13:16 +0000726 EXPECT_THAT(Results.Completions, IsEmpty());
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000727}
728
Haojian Wu58d208d2018-01-25 09:44:06 +0000729TEST(CodeCompleteTest, DisableTypoCorrection) {
730 auto Results = completions(R"cpp(
731 namespace clang { int v; }
732 void f() { clangd::^
733 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000734 EXPECT_TRUE(Results.Completions.empty());
Haojian Wu58d208d2018-01-25 09:44:06 +0000735}
736
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000737TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
738 auto Results = completions(R"cpp(
739 namespace clang { }
740 void f() {
741 clan^
742 }
743 )cpp");
744
Sam McCalle746a2b2018-07-02 11:13:16 +0000745 EXPECT_THAT(Results.Completions, Contains(Labeled("clang")));
746 EXPECT_THAT(Results.Completions, Not(Contains(Labeled("clang::"))));
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000747}
748
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000749TEST(CompletionTest, BacktrackCrashes) {
750 // Sema calls code completion callbacks twice in these cases.
751 auto Results = completions(R"cpp(
752 namespace ns {
753 struct FooBarBaz {};
754 } // namespace ns
755
756 int foo(ns::FooBar^
757 )cpp");
758
Sam McCalle746a2b2018-07-02 11:13:16 +0000759 EXPECT_THAT(Results.Completions, ElementsAre(Labeled("FooBarBaz")));
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000760
761 // Check we don't crash in that case too.
762 completions(R"cpp(
763 struct FooBarBaz {};
764 void test() {
765 if (FooBarBaz * x^) {}
766 }
767)cpp");
768}
769
Eric Liu42abe412018-05-24 11:20:19 +0000770TEST(CompletionTest, CompleteInMacroWithStringification) {
771 auto Results = completions(R"cpp(
772void f(const char *, int x);
773#define F(x) f(#x, x)
774
775namespace ns {
776int X;
777int Y;
778} // namespace ns
779
780int f(int input_num) {
781 F(ns::^)
782}
783)cpp");
784
Sam McCalle746a2b2018-07-02 11:13:16 +0000785 EXPECT_THAT(Results.Completions,
Eric Liu42abe412018-05-24 11:20:19 +0000786 UnorderedElementsAre(Named("X"), Named("Y")));
787}
788
789TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
790 auto Results = completions(R"cpp(
791void f(const char *, int x);
792#define F(x) f(#x, x)
793
794namespace ns {
795int X;
796
797int f(int input_num) {
798 F(^)
799}
800} // namespace ns
801)cpp");
802
Sam McCalle746a2b2018-07-02 11:13:16 +0000803 EXPECT_THAT(Results.Completions, Contains(Named("X")));
Eric Liu42abe412018-05-24 11:20:19 +0000804}
805
Eric Liu485074f2018-07-11 13:15:31 +0000806TEST(CompletionTest, IgnoreCompleteInExcludedPPBranchWithRecoveryContext) {
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000807 auto Results = completions(R"cpp(
808 int bar(int param_in_bar) {
809 }
810
811 int foo(int param_in_foo) {
812#if 0
Eric Liu485074f2018-07-11 13:15:31 +0000813 // In recorvery mode, "param_in_foo" will also be suggested among many other
814 // unrelated symbols; however, this is really a special case where this works.
815 // If the #if block is outside of the function, "param_in_foo" is still
816 // suggested, but "bar" and "foo" are missing. So the recovery mode doesn't
817 // really provide useful results in excluded branches.
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000818 par^
819#endif
820 }
821)cpp");
822
Eric Liu485074f2018-07-11 13:15:31 +0000823 EXPECT_TRUE(Results.Completions.empty());
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000824}
Ilya Biryukov43c292c2018-08-30 13:14:31 +0000825SignatureHelp signatures(StringRef Text, Position Point,
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +0000826 std::vector<Symbol> IndexSymbols = {}) {
827 std::unique_ptr<SymbolIndex> Index;
828 if (!IndexSymbols.empty())
829 Index = memIndex(IndexSymbols);
830
Sam McCall800d4372017-12-19 10:29:27 +0000831 MockFSProvider FS;
832 MockCompilationDatabase CDB;
833 IgnoreDiagnostics DiagConsumer;
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +0000834 ClangdServer::Options Opts = ClangdServer::optsForTest();
835 Opts.StaticIndex = Index.get();
836
837 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCallc1568062018-02-16 09:41:43 +0000838 auto File = testPath("foo.cpp");
Ilya Biryukov43c292c2018-08-30 13:14:31 +0000839 runAddDocument(Server, File, Text);
840 return cantFail(runSignatureHelp(Server, File, Point));
841}
842
843SignatureHelp signatures(StringRef Text,
844 std::vector<Symbol> IndexSymbols = {}) {
Sam McCall328cbdb2017-12-20 16:06:05 +0000845 Annotations Test(Text);
Ilya Biryukov43c292c2018-08-30 13:14:31 +0000846 return signatures(Test.code(), Test.point(), std::move(IndexSymbols));
Sam McCall800d4372017-12-19 10:29:27 +0000847}
848
849MATCHER_P(ParamsAre, P, "") {
850 if (P.size() != arg.parameters.size())
851 return false;
852 for (unsigned I = 0; I < P.size(); ++I)
853 if (P[I] != arg.parameters[I].label)
854 return false;
855 return true;
856}
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +0000857MATCHER_P(SigDoc, Doc, "") { return arg.documentation == Doc; }
Sam McCall800d4372017-12-19 10:29:27 +0000858
859Matcher<SignatureInformation> Sig(std::string Label,
860 std::vector<std::string> Params) {
Eric Liu8f3678d2018-06-15 13:34:18 +0000861 return AllOf(SigHelpLabeled(Label), ParamsAre(Params));
Sam McCall800d4372017-12-19 10:29:27 +0000862}
863
864TEST(SignatureHelpTest, Overloads) {
865 auto Results = signatures(R"cpp(
866 void foo(int x, int y);
867 void foo(int x, float y);
868 void foo(float x, int y);
869 void foo(float x, float y);
870 void bar(int x, int y = 0);
871 int main() { foo(^); }
872 )cpp");
873 EXPECT_THAT(Results.signatures,
874 UnorderedElementsAre(
875 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
876 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
877 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
878 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
879 // We always prefer the first signature.
880 EXPECT_EQ(0, Results.activeSignature);
881 EXPECT_EQ(0, Results.activeParameter);
882}
883
884TEST(SignatureHelpTest, DefaultArgs) {
885 auto Results = signatures(R"cpp(
886 void bar(int x, int y = 0);
887 void bar(float x = 0, int y = 42);
888 int main() { bar(^
889 )cpp");
890 EXPECT_THAT(Results.signatures,
891 UnorderedElementsAre(
892 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
893 Sig("bar(float x = 0, int y = 42) -> void",
894 {"float x = 0", "int y = 42"})));
895 EXPECT_EQ(0, Results.activeSignature);
896 EXPECT_EQ(0, Results.activeParameter);
897}
898
899TEST(SignatureHelpTest, ActiveArg) {
900 auto Results = signatures(R"cpp(
901 int baz(int a, int b, int c);
902 int main() { baz(baz(1,2,3), ^); }
903 )cpp");
904 EXPECT_THAT(Results.signatures,
905 ElementsAre(Sig("baz(int a, int b, int c) -> int",
906 {"int a", "int b", "int c"})));
907 EXPECT_EQ(0, Results.activeSignature);
908 EXPECT_EQ(1, Results.activeParameter);
909}
910
Ilya Biryukov43c292c2018-08-30 13:14:31 +0000911TEST(SignatureHelpTest, OpeningParen) {
912 llvm::StringLiteral Tests[] = {// Recursive function call.
913 R"cpp(
914 int foo(int a, int b, int c);
915 int main() {
916 foo(foo $p^( foo(10, 10, 10), ^ )));
917 })cpp",
918 // Functional type cast.
919 R"cpp(
920 struct Foo {
921 Foo(int a, int b, int c);
922 };
923 int main() {
924 Foo $p^( 10, ^ );
925 })cpp",
926 // New expression.
927 R"cpp(
928 struct Foo {
929 Foo(int a, int b, int c);
930 };
931 int main() {
932 new Foo $p^( 10, ^ );
933 })cpp",
934 // Macro expansion.
935 R"cpp(
936 int foo(int a, int b, int c);
937 #define FOO foo(
938
939 int main() {
940 // Macro expansions.
941 $p^FOO 10, ^ );
942 })cpp",
943 // Macro arguments.
944 R"cpp(
945 int foo(int a, int b, int c);
946 int main() {
947 #define ID(X) X
948 ID(foo $p^( foo(10), ^ ))
949 })cpp"};
950
951 for (auto Test : Tests) {
952 Annotations Code(Test);
953 EXPECT_EQ(signatures(Code.code(), Code.point()).argListStart,
954 Code.point("p"))
955 << "Test source:" << Test;
956 }
957}
958
Haojian Wu061c73e2018-01-23 11:37:26 +0000959class IndexRequestCollector : public SymbolIndex {
960public:
961 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000962 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000963 llvm::function_ref<void(const Symbol &)> Callback) const override {
964 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000965 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000966 }
967
Eric Liu9ec459f2018-03-14 09:48:05 +0000968 void lookup(const LookupRequest &,
969 llvm::function_ref<void(const Symbol &)>) const override {}
970
Haojian Wu65ac3212018-08-06 13:14:32 +0000971 void findOccurrences(const OccurrencesRequest &Req,
972 llvm::function_ref<void(const SymbolOccurrence &)>
973 Callback) const override {}
974
Kirill Bobyrevfc890012018-08-24 09:12:54 +0000975 // This is incorrect, but IndexRequestCollector is not an actual index and it
976 // isn't used in production code.
977 size_t estimateMemoryUsage() const override { return 0; }
978
Eric Liu25d74e92018-08-24 11:23:56 +0000979 const std::vector<FuzzyFindRequest> consumeRequests() const {
980 auto Reqs = std::move(Requests);
981 Requests = {};
982 return Reqs;
983 }
Haojian Wu061c73e2018-01-23 11:37:26 +0000984
985private:
986 mutable std::vector<FuzzyFindRequest> Requests;
987};
988
989std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
990 clangd::CodeCompleteOptions Opts;
991 IndexRequestCollector Requests;
992 Opts.Index = &Requests;
993 completions(Code, {}, Opts);
Eric Liu25d74e92018-08-24 11:23:56 +0000994 return Requests.consumeRequests();
Haojian Wu061c73e2018-01-23 11:37:26 +0000995}
996
997TEST(CompletionTest, UnqualifiedIdQuery) {
998 auto Requests = captureIndexRequests(R"cpp(
999 namespace std {}
1000 using namespace std;
1001 namespace ns {
1002 void f() {
1003 vec^
1004 }
1005 }
1006 )cpp");
1007
1008 EXPECT_THAT(Requests,
1009 ElementsAre(Field(&FuzzyFindRequest::Scopes,
1010 UnorderedElementsAre("", "ns::", "std::"))));
1011}
1012
1013TEST(CompletionTest, ResolvedQualifiedIdQuery) {
1014 auto Requests = captureIndexRequests(R"cpp(
1015 namespace ns1 {}
1016 namespace ns2 {} // ignore
1017 namespace ns3 { namespace nns3 {} }
1018 namespace foo {
1019 using namespace ns1;
1020 using namespace ns3::nns3;
1021 }
1022 namespace ns {
1023 void f() {
1024 foo::^
1025 }
1026 }
1027 )cpp");
1028
1029 EXPECT_THAT(Requests,
1030 ElementsAre(Field(
1031 &FuzzyFindRequest::Scopes,
1032 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
1033}
1034
1035TEST(CompletionTest, UnresolvedQualifierIdQuery) {
1036 auto Requests = captureIndexRequests(R"cpp(
1037 namespace a {}
1038 using namespace a;
1039 namespace ns {
1040 void f() {
1041 bar::^
1042 }
1043 } // namespace ns
1044 )cpp");
1045
1046 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1047 UnorderedElementsAre("bar::"))));
1048}
1049
1050TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
1051 auto Requests = captureIndexRequests(R"cpp(
1052 namespace a {}
1053 using namespace a;
1054 namespace ns {
1055 void f() {
1056 ::a::bar::^
1057 }
1058 } // namespace ns
1059 )cpp");
1060
1061 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1062 UnorderedElementsAre("a::bar::"))));
1063}
1064
1065TEST(CompletionTest, EmptyQualifiedQuery) {
1066 auto Requests = captureIndexRequests(R"cpp(
1067 namespace ns {
1068 void f() {
1069 ^
1070 }
1071 } // namespace ns
1072 )cpp");
1073
1074 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1075 UnorderedElementsAre("", "ns::"))));
1076}
1077
1078TEST(CompletionTest, GlobalQualifiedQuery) {
1079 auto Requests = captureIndexRequests(R"cpp(
1080 namespace ns {
1081 void f() {
1082 ::^
1083 }
1084 } // namespace ns
1085 )cpp");
1086
1087 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1088 UnorderedElementsAre(""))));
1089}
1090
Ilya Biryukova907ba42018-05-14 10:50:04 +00001091TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
1092 auto Completions = completions(
1093 R"cpp(
1094 struct Foo {
1095 int SomeNameOfField;
1096 typedef int SomeNameOfTypedefField;
1097 };
1098
1099 Foo::^)cpp",
1100 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
1101
Sam McCalle746a2b2018-07-02 11:13:16 +00001102 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001103 AllOf(Contains(Labeled("SomeNameOfField")),
1104 Contains(Labeled("SomeNameOfTypedefField")),
1105 Not(Contains(Labeled("SomeNameInTheIndex")))));
1106}
1107
1108TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
1109 {
1110 auto Completions = completions(
1111 R"cpp(
1112 template <class T>
1113 void foo() {
1114 T::^
1115 }
1116 )cpp",
1117 {func("::SomeNameInTheIndex")});
1118
Sam McCalle746a2b2018-07-02 11:13:16 +00001119 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001120 Not(Contains(Labeled("SomeNameInTheIndex"))));
1121 }
1122
1123 {
1124 auto Completions = completions(
1125 R"cpp(
1126 template <class T>
1127 void foo() {
1128 T::template Y<int>::^
1129 }
1130 )cpp",
1131 {func("::SomeNameInTheIndex")});
1132
Sam McCalle746a2b2018-07-02 11:13:16 +00001133 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001134 Not(Contains(Labeled("SomeNameInTheIndex"))));
1135 }
1136
1137 {
1138 auto Completions = completions(
1139 R"cpp(
1140 template <class T>
1141 void foo() {
1142 T::foo::^
1143 }
1144 )cpp",
1145 {func("::SomeNameInTheIndex")});
1146
Sam McCalle746a2b2018-07-02 11:13:16 +00001147 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001148 Not(Contains(Labeled("SomeNameInTheIndex"))));
1149 }
1150}
1151
Sam McCallc18c2802018-06-15 11:06:29 +00001152TEST(CompletionTest, OverloadBundling) {
1153 clangd::CodeCompleteOptions Opts;
1154 Opts.BundleOverloads = true;
1155
1156 std::string Context = R"cpp(
1157 struct X {
1158 // Overload with int
1159 int a(int);
1160 // Overload with bool
1161 int a(bool);
1162 int b(float);
1163 };
1164 int GFuncC(int);
1165 int GFuncD(int);
1166 )cpp";
1167
1168 // Member completions are bundled.
Sam McCalle746a2b2018-07-02 11:13:16 +00001169 EXPECT_THAT(completions(Context + "int y = X().^", {}, Opts).Completions,
Sam McCallc18c2802018-06-15 11:06:29 +00001170 UnorderedElementsAre(Labeled("a(…)"), Labeled("b(float)")));
1171
1172 // Non-member completions are bundled, including index+sema.
1173 Symbol NoArgsGFunc = func("GFuncC");
1174 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001175 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
Sam McCallc18c2802018-06-15 11:06:29 +00001176 UnorderedElementsAre(Labeled("GFuncC(…)"), Labeled("GFuncD(int)")));
1177
1178 // Differences in header-to-insert suppress bundling.
Sam McCallc18c2802018-06-15 11:06:29 +00001179 std::string DeclFile = URI::createFile(testPath("foo")).toString();
1180 NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile;
Sam McCall2e5700f2018-08-31 13:55:01 +00001181 NoArgsGFunc.IncludeHeader = "<foo>";
Sam McCallc18c2802018-06-15 11:06:29 +00001182 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001183 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
1184 UnorderedElementsAre(AllOf(Named("GFuncC"), InsertInclude("<foo>")),
1185 Labeled("GFuncC(int)"), Labeled("GFuncD(int)")));
Sam McCallc18c2802018-06-15 11:06:29 +00001186
1187 // Examine a bundled completion in detail.
Sam McCalle746a2b2018-07-02 11:13:16 +00001188 auto A =
1189 completions(Context + "int y = X().a^", {}, Opts).Completions.front();
1190 EXPECT_EQ(A.Name, "a");
1191 EXPECT_EQ(A.Signature, "(…)");
1192 EXPECT_EQ(A.BundleSize, 2u);
1193 EXPECT_EQ(A.Kind, CompletionItemKind::Method);
1194 EXPECT_EQ(A.ReturnType, "int"); // All overloads return int.
Sam McCallc18c2802018-06-15 11:06:29 +00001195 // For now we just return one of the doc strings arbitrarily.
Sam McCalle746a2b2018-07-02 11:13:16 +00001196 EXPECT_THAT(A.Documentation, AnyOf(HasSubstr("Overload with int"),
Sam McCallc18c2802018-06-15 11:06:29 +00001197 HasSubstr("Overload with bool")));
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001198 EXPECT_EQ(A.SnippetSuffix, "($0)");
Sam McCallc18c2802018-06-15 11:06:29 +00001199}
1200
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001201TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001202 MockFSProvider FS;
1203 auto FooH = testPath("foo.h");
1204 auto FooCpp = testPath("foo.cpp");
1205 FS.Files[FooH] = R"cpp(
1206 // this is my documentation comment.
1207 int func();
1208 )cpp";
1209 FS.Files[FooCpp] = "";
1210
1211 MockCompilationDatabase CDB;
1212 IgnoreDiagnostics DiagConsumer;
1213 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1214
1215 Annotations Source(R"cpp(
1216 #include "foo.h"
1217 int func() {
1218 // This makes sure we have func from header in the AST.
1219 }
1220 int a = fun^
1221 )cpp");
1222 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1223 // We need to wait for preamble to build.
1224 ASSERT_TRUE(Server.blockUntilIdleForTest());
1225
1226 // Change the header file. Completion will reuse the old preamble!
1227 FS.Files[FooH] = R"cpp(
1228 int func();
1229 )cpp";
1230
1231 clangd::CodeCompleteOptions Opts;
1232 Opts.IncludeComments = true;
Sam McCalle746a2b2018-07-02 11:13:16 +00001233 CodeCompleteResult Completions =
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001234 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1235 // We shouldn't crash. Unfortunately, current workaround is to not produce
1236 // comments for symbols from headers.
Sam McCalle746a2b2018-07-02 11:13:16 +00001237 EXPECT_THAT(Completions.Completions,
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001238 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1239}
1240
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001241TEST(CompletionTest, NonDocComments) {
1242 MockFSProvider FS;
1243 auto FooCpp = testPath("foo.cpp");
1244 FS.Files[FooCpp] = "";
1245
1246 MockCompilationDatabase CDB;
1247 IgnoreDiagnostics DiagConsumer;
1248 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1249
1250 Annotations Source(R"cpp(
Ilya Biryukovda8dd8b2018-06-27 09:47:20 +00001251 // We ignore namespace comments, for rationale see CodeCompletionStrings.h.
1252 namespace comments_ns {
1253 }
1254
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001255 // ------------------
1256 int comments_foo();
1257
1258 // A comment and a decl are separated by newlines.
1259 // Therefore, the comment shouldn't show up as doc comment.
1260
1261 int comments_bar();
1262
1263 // this comment should be in the results.
1264 int comments_baz();
1265
1266
1267 template <class T>
1268 struct Struct {
1269 int comments_qux();
1270 int comments_quux();
1271 };
1272
1273
1274 // This comment should not be there.
1275
1276 template <class T>
1277 int Struct<T>::comments_qux() {
1278 }
1279
1280 // This comment **should** be in results.
1281 template <class T>
1282 int Struct<T>::comments_quux() {
1283 int a = comments^;
1284 }
1285 )cpp");
Reid Kleckner80274b12018-06-18 18:55:10 +00001286 // FIXME: Auto-completion in a template requires disabling delayed template
1287 // parsing.
1288 CDB.ExtraClangFlags.push_back("-fno-delayed-template-parsing");
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001289 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
Sam McCalle746a2b2018-07-02 11:13:16 +00001290 CodeCompleteResult Completions = cantFail(runCodeComplete(
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001291 Server, FooCpp, Source.point(), clangd::CodeCompleteOptions()));
1292
1293 // We should not get any of those comments in completion.
1294 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001295 Completions.Completions,
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001296 UnorderedElementsAre(AllOf(Not(IsDocumented()), Named("comments_foo")),
1297 AllOf(IsDocumented(), Named("comments_baz")),
1298 AllOf(IsDocumented(), Named("comments_quux")),
Ilya Biryukovda8dd8b2018-06-27 09:47:20 +00001299 AllOf(Not(IsDocumented()), Named("comments_ns")),
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001300 // FIXME(ibiryukov): the following items should have
1301 // empty documentation, since they are separated from
1302 // a comment with an empty line. Unfortunately, I
1303 // couldn't make Sema tests pass if we ignore those.
1304 AllOf(IsDocumented(), Named("comments_bar")),
1305 AllOf(IsDocumented(), Named("comments_qux"))));
1306}
1307
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001308TEST(CompletionTest, CompleteOnInvalidLine) {
1309 auto FooCpp = testPath("foo.cpp");
1310
1311 MockCompilationDatabase CDB;
1312 IgnoreDiagnostics DiagConsumer;
1313 MockFSProvider FS;
1314 FS.Files[FooCpp] = "// empty file";
1315
1316 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1317 // Run completion outside the file range.
1318 Position Pos;
1319 Pos.line = 100;
1320 Pos.character = 0;
1321 EXPECT_THAT_EXPECTED(
1322 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1323 Failed());
1324}
1325
Eric Liu7ad16962018-06-22 10:46:59 +00001326TEST(CompletionTest, QualifiedNames) {
1327 auto Results = completions(
1328 R"cpp(
1329 namespace ns { int local; void both(); }
1330 void f() { ::ns::^ }
1331 )cpp",
1332 {func("ns::both"), cls("ns::Index")});
1333 // We get results from both index and sema, with no duplicates.
Sam McCalle746a2b2018-07-02 11:13:16 +00001334 EXPECT_THAT(
1335 Results.Completions,
1336 UnorderedElementsAre(Scope("ns::"), Scope("ns::"), Scope("ns::")));
1337}
1338
1339TEST(CompletionTest, Render) {
1340 CodeCompletion C;
1341 C.Name = "x";
1342 C.Signature = "(bool) const";
1343 C.SnippetSuffix = "(${0:bool})";
1344 C.ReturnType = "int";
1345 C.RequiredQualifier = "Foo::";
1346 C.Scope = "ns::Foo::";
1347 C.Documentation = "This is x().";
1348 C.Header = "\"foo.h\"";
1349 C.Kind = CompletionItemKind::Method;
1350 C.Score.Total = 1.0;
Sam McCall4e5742a2018-07-06 11:50:49 +00001351 C.Origin = SymbolOrigin::AST | SymbolOrigin::Static;
Sam McCalle746a2b2018-07-02 11:13:16 +00001352
1353 CodeCompleteOptions Opts;
1354 Opts.IncludeIndicator.Insert = "^";
1355 Opts.IncludeIndicator.NoInsert = "";
1356 Opts.EnableSnippets = false;
1357
1358 auto R = C.render(Opts);
1359 EXPECT_EQ(R.label, "Foo::x(bool) const");
1360 EXPECT_EQ(R.insertText, "Foo::x");
1361 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText);
1362 EXPECT_EQ(R.filterText, "x");
1363 EXPECT_EQ(R.detail, "int\n\"foo.h\"");
1364 EXPECT_EQ(R.documentation, "This is x().");
1365 EXPECT_THAT(R.additionalTextEdits, IsEmpty());
Sam McCalle746a2b2018-07-02 11:13:16 +00001366 EXPECT_EQ(R.sortText, sortText(1.0, "x"));
1367
1368 Opts.EnableSnippets = true;
1369 R = C.render(Opts);
1370 EXPECT_EQ(R.insertText, "Foo::x(${0:bool})");
1371 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet);
1372
1373 C.HeaderInsertion.emplace();
1374 R = C.render(Opts);
1375 EXPECT_EQ(R.label, "^Foo::x(bool) const");
1376 EXPECT_THAT(R.additionalTextEdits, Not(IsEmpty()));
1377
Sam McCall2161ec72018-07-05 06:20:41 +00001378 Opts.ShowOrigins = true;
1379 R = C.render(Opts);
1380 EXPECT_EQ(R.label, "^[AS]Foo::x(bool) const");
1381
Sam McCalle746a2b2018-07-02 11:13:16 +00001382 C.BundleSize = 2;
1383 R = C.render(Opts);
1384 EXPECT_EQ(R.detail, "[2 overloads]\n\"foo.h\"");
Eric Liu7ad16962018-06-22 10:46:59 +00001385}
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001386
Eric Liu485074f2018-07-11 13:15:31 +00001387TEST(CompletionTest, IgnoreRecoveryResults) {
1388 auto Results = completions(
1389 R"cpp(
1390 namespace ns { int NotRecovered() { return 0; } }
1391 void f() {
1392 // Sema enters recovery mode first and then normal mode.
1393 if (auto x = ns::NotRecover^)
1394 }
1395 )cpp");
1396 EXPECT_THAT(Results.Completions, UnorderedElementsAre(Named("NotRecovered")));
1397}
1398
Eric Liuf433c2d2018-07-18 15:31:14 +00001399TEST(CompletionTest, ScopeOfClassFieldInConstructorInitializer) {
1400 auto Results = completions(
1401 R"cpp(
1402 namespace ns {
1403 class X { public: X(); int x_; };
1404 X::X() : x_^(0) {}
1405 }
1406 )cpp");
1407 EXPECT_THAT(Results.Completions,
1408 UnorderedElementsAre(AllOf(Scope("ns::X::"), Named("x_"))));
1409}
1410
Eric Liu5d2a8072018-07-23 10:56:37 +00001411TEST(CompletionTest, CodeCompletionContext) {
1412 auto Results = completions(
1413 R"cpp(
1414 namespace ns {
1415 class X { public: X(); int x_; };
1416 void f() {
1417 X x;
1418 x.^;
1419 }
1420 }
1421 )cpp");
1422
1423 EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess);
1424}
1425
Kadir Cetinkaya2f84d912018-08-08 08:59:29 +00001426TEST(CompletionTest, FixItForArrowToDot) {
1427 MockFSProvider FS;
1428 MockCompilationDatabase CDB;
1429 IgnoreDiagnostics DiagConsumer;
1430 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1431
1432 CodeCompleteOptions Opts;
1433 Opts.IncludeFixIts = true;
1434 Annotations TestCode(
1435 R"cpp(
1436 class Auxilary {
1437 public:
1438 void AuxFunction();
1439 };
1440 class ClassWithPtr {
1441 public:
1442 void MemberFunction();
1443 Auxilary* operator->() const;
1444 Auxilary* Aux;
1445 };
1446 void f() {
1447 ClassWithPtr x;
1448 x[[->]]^;
1449 }
1450 )cpp");
1451 auto Results =
1452 completions(Server, TestCode.code(), TestCode.point(), {}, Opts);
1453 EXPECT_EQ(Results.Completions.size(), 3u);
1454
1455 TextEdit ReplacementEdit;
1456 ReplacementEdit.range = TestCode.range();
1457 ReplacementEdit.newText = ".";
1458 for (const auto &C : Results.Completions) {
1459 EXPECT_TRUE(C.FixIts.size() == 1u || C.Name == "AuxFunction");
Haojian Wu1793bc92018-08-10 08:34:16 +00001460 if (!C.FixIts.empty()) {
Kadir Cetinkaya2f84d912018-08-08 08:59:29 +00001461 EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit));
Haojian Wu1793bc92018-08-10 08:34:16 +00001462 }
Kadir Cetinkaya2f84d912018-08-08 08:59:29 +00001463 }
1464}
1465
1466TEST(CompletionTest, FixItForDotToArrow) {
1467 MockFSProvider FS;
1468 MockCompilationDatabase CDB;
1469 IgnoreDiagnostics DiagConsumer;
1470 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1471
1472 CodeCompleteOptions Opts;
1473 Opts.IncludeFixIts = true;
1474 Annotations TestCode(
1475 R"cpp(
1476 class Auxilary {
1477 public:
1478 void AuxFunction();
1479 };
1480 class ClassWithPtr {
1481 public:
1482 void MemberFunction();
1483 Auxilary* operator->() const;
1484 Auxilary* Aux;
1485 };
1486 void f() {
1487 ClassWithPtr x;
1488 x[[.]]^;
1489 }
1490 )cpp");
1491 auto Results =
1492 completions(Server, TestCode.code(), TestCode.point(), {}, Opts);
1493 EXPECT_EQ(Results.Completions.size(), 3u);
1494
1495 TextEdit ReplacementEdit;
1496 ReplacementEdit.range = TestCode.range();
1497 ReplacementEdit.newText = "->";
1498 for (const auto &C : Results.Completions) {
1499 EXPECT_TRUE(C.FixIts.empty() || C.Name == "AuxFunction");
1500 if (!C.FixIts.empty()) {
1501 EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit));
1502 }
1503 }
1504}
1505
Kadir Cetinkayaa9c9d002018-08-13 08:23:01 +00001506TEST(CompletionTest, RenderWithFixItMerged) {
1507 TextEdit FixIt;
1508 FixIt.range.end.character = 5;
1509 FixIt.newText = "->";
1510
1511 CodeCompletion C;
1512 C.Name = "x";
1513 C.RequiredQualifier = "Foo::";
1514 C.FixIts = {FixIt};
1515 C.CompletionTokenRange.start.character = 5;
1516
1517 CodeCompleteOptions Opts;
1518 Opts.IncludeFixIts = true;
1519
1520 auto R = C.render(Opts);
1521 EXPECT_TRUE(R.textEdit);
1522 EXPECT_EQ(R.textEdit->newText, "->Foo::x");
1523 EXPECT_TRUE(R.additionalTextEdits.empty());
1524}
1525
1526TEST(CompletionTest, RenderWithFixItNonMerged) {
1527 TextEdit FixIt;
1528 FixIt.range.end.character = 4;
1529 FixIt.newText = "->";
1530
1531 CodeCompletion C;
1532 C.Name = "x";
1533 C.RequiredQualifier = "Foo::";
1534 C.FixIts = {FixIt};
1535 C.CompletionTokenRange.start.character = 5;
1536
1537 CodeCompleteOptions Opts;
1538 Opts.IncludeFixIts = true;
1539
1540 auto R = C.render(Opts);
1541 EXPECT_TRUE(R.textEdit);
1542 EXPECT_EQ(R.textEdit->newText, "Foo::x");
1543 EXPECT_THAT(R.additionalTextEdits, UnorderedElementsAre(FixIt));
1544}
1545
1546TEST(CompletionTest, CompletionTokenRange) {
1547 MockFSProvider FS;
1548 MockCompilationDatabase CDB;
1549 IgnoreDiagnostics DiagConsumer;
1550 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1551
1552 constexpr const char *TestCodes[] = {
1553 R"cpp(
1554 class Auxilary {
1555 public:
1556 void AuxFunction();
1557 };
1558 void f() {
1559 Auxilary x;
1560 x.[[Aux]]^;
1561 }
1562 )cpp",
1563 R"cpp(
1564 class Auxilary {
1565 public:
1566 void AuxFunction();
1567 };
1568 void f() {
1569 Auxilary x;
1570 x.[[]]^;
1571 }
1572 )cpp"};
1573 for (const auto &Text : TestCodes) {
1574 Annotations TestCode(Text);
1575 auto Results = completions(Server, TestCode.code(), TestCode.point());
1576
1577 EXPECT_EQ(Results.Completions.size(), 1u);
1578 EXPECT_THAT(Results.Completions.front().CompletionTokenRange, TestCode.range());
1579 }
1580}
1581
Kadir Cetinkayae486e372018-08-13 08:40:05 +00001582TEST(SignatureHelpTest, OverloadsOrdering) {
1583 const auto Results = signatures(R"cpp(
1584 void foo(int x);
1585 void foo(int x, float y);
1586 void foo(float x, int y);
1587 void foo(float x, float y);
1588 void foo(int x, int y = 0);
1589 int main() { foo(^); }
1590 )cpp");
1591 EXPECT_THAT(
1592 Results.signatures,
1593 ElementsAre(
1594 Sig("foo(int x) -> void", {"int x"}),
1595 Sig("foo(int x, int y = 0) -> void", {"int x", "int y = 0"}),
1596 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
1597 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
1598 Sig("foo(float x, float y) -> void", {"float x", "float y"})));
1599 // We always prefer the first signature.
1600 EXPECT_EQ(0, Results.activeSignature);
1601 EXPECT_EQ(0, Results.activeParameter);
1602}
1603
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001604TEST(SignatureHelpTest, InstantiatedSignatures) {
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001605 StringRef Sig0 = R"cpp(
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001606 template <class T>
1607 void foo(T, T, T);
1608
1609 int main() {
1610 foo<int>(^);
1611 }
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001612 )cpp";
1613
1614 EXPECT_THAT(signatures(Sig0).signatures,
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001615 ElementsAre(Sig("foo(T, T, T) -> void", {"T", "T", "T"})));
1616
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001617 StringRef Sig1 = R"cpp(
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001618 template <class T>
1619 void foo(T, T, T);
1620
1621 int main() {
1622 foo(10, ^);
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001623 })cpp";
1624
1625 EXPECT_THAT(signatures(Sig1).signatures,
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001626 ElementsAre(Sig("foo(T, T, T) -> void", {"T", "T", "T"})));
1627
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001628 StringRef Sig2 = R"cpp(
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001629 template <class ...T>
1630 void foo(T...);
1631
1632 int main() {
1633 foo<int>(^);
1634 }
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001635 )cpp";
1636
1637 EXPECT_THAT(signatures(Sig2).signatures,
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001638 ElementsAre(Sig("foo(T...) -> void", {"T..."})));
1639
1640 // It is debatable whether we should substitute the outer template parameter
1641 // ('T') in that case. Currently we don't substitute it in signature help, but
1642 // do substitute in code complete.
1643 // FIXME: make code complete and signature help consistent, figure out which
1644 // way is better.
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001645 StringRef Sig3 = R"cpp(
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001646 template <class T>
1647 struct X {
1648 template <class U>
1649 void foo(T, U);
1650 };
1651
1652 int main() {
1653 X<int>().foo<double>(^)
1654 }
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001655 )cpp";
1656
1657 EXPECT_THAT(signatures(Sig3).signatures,
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001658 ElementsAre(Sig("foo(T, U) -> void", {"T", "U"})));
1659}
1660
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001661TEST(SignatureHelpTest, IndexDocumentation) {
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001662 Symbol Foo0 = sym("foo", index::SymbolKind::Function, "@F@\\0#");
Sam McCall2e5700f2018-08-31 13:55:01 +00001663 Foo0.Documentation = "Doc from the index";
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001664 Symbol Foo1 = sym("foo", index::SymbolKind::Function, "@F@\\0#I#");
Sam McCall2e5700f2018-08-31 13:55:01 +00001665 Foo1.Documentation = "Doc from the index";
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001666 Symbol Foo2 = sym("foo", index::SymbolKind::Function, "@F@\\0#I#I#");
1667
Simon Pilgrim24d34922018-08-17 10:40:05 +00001668 StringRef Sig0 = R"cpp(
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001669 int foo();
1670 int foo(double);
1671
1672 void test() {
1673 foo(^);
1674 }
Simon Pilgrim24d34922018-08-17 10:40:05 +00001675 )cpp";
1676
1677 EXPECT_THAT(
1678 signatures(Sig0, {Foo0}).signatures,
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001679 ElementsAre(AllOf(Sig("foo() -> int", {}), SigDoc("Doc from the index")),
1680 AllOf(Sig("foo(double) -> int", {"double"}), SigDoc(""))));
1681
Simon Pilgrim24d34922018-08-17 10:40:05 +00001682 StringRef Sig1 = R"cpp(
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001683 int foo();
1684 // Overriden doc from sema
1685 int foo(int);
1686 // Doc from sema
1687 int foo(int, int);
1688
1689 void test() {
1690 foo(^);
1691 }
Simon Pilgrim24d34922018-08-17 10:40:05 +00001692 )cpp";
1693
1694 EXPECT_THAT(
1695 signatures(Sig1, {Foo0, Foo1, Foo2}).signatures,
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001696 ElementsAre(AllOf(Sig("foo() -> int", {}), SigDoc("Doc from the index")),
1697 AllOf(Sig("foo(int) -> int", {"int"}),
1698 SigDoc("Overriden doc from sema")),
1699 AllOf(Sig("foo(int, int) -> int", {"int", "int"}),
1700 SigDoc("Doc from sema"))));
1701}
1702
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001703TEST(CompletionTest, CompletionFunctionArgsDisabled) {
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001704 CodeCompleteOptions Opts;
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001705 Opts.EnableSnippets = true;
1706 Opts.EnableFunctionArgSnippets = false;
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001707 const std::string Header =
1708 R"cpp(
1709 void xfoo();
1710 void xfoo(int x, int y);
1711 void xbar();
1712 void f() {
1713 )cpp";
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001714 {
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001715 auto Results = completions(Header + "\nxfo^", {}, Opts);
1716 EXPECT_THAT(
1717 Results.Completions,
1718 UnorderedElementsAre(AllOf(Named("xfoo"), SnippetSuffix("()")),
1719 AllOf(Named("xfoo"), SnippetSuffix("($0)"))));
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001720 }
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001721 {
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001722 auto Results = completions(Header + "\nxba^", {}, Opts);
1723 EXPECT_THAT(Results.Completions, UnorderedElementsAre(AllOf(
1724 Named("xbar"), SnippetSuffix("()"))));
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001725 }
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001726 {
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001727 Opts.BundleOverloads = true;
1728 auto Results = completions(Header + "\nxfo^", {}, Opts);
1729 EXPECT_THAT(
1730 Results.Completions,
1731 UnorderedElementsAre(AllOf(Named("xfoo"), SnippetSuffix("($0)"))));
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001732 }
1733}
1734
Kadir Cetinkayaf8b85a32018-08-23 13:14:50 +00001735TEST(CompletionTest, SuggestOverrides) {
1736 constexpr const char *const Text(R"cpp(
1737 class A {
1738 public:
1739 virtual void vfunc(bool param);
1740 virtual void vfunc(bool param, int p);
1741 void func(bool param);
1742 };
1743 class B : public A {
1744 virtual void ttt(bool param) const;
1745 void vfunc(bool param, int p) override;
1746 };
1747 class C : public B {
1748 public:
1749 void vfunc(bool param) override;
1750 ^
1751 };
1752 )cpp");
1753 const auto Results = completions(Text);
1754 EXPECT_THAT(Results.Completions,
1755 AllOf(Contains(Labeled("void vfunc(bool param, int p) override")),
1756 Contains(Labeled("void ttt(bool param) const override")),
1757 Not(Contains(Labeled("void vfunc(bool param) override")))));
1758}
1759
Eric Liu25d74e92018-08-24 11:23:56 +00001760TEST(SpeculateCompletionFilter, Filters) {
1761 Annotations F(R"cpp($bof^
1762 $bol^
1763 ab$ab^
1764 x.ab$dot^
1765 x.$dotempty^
1766 x::ab$scoped^
1767 x::$scopedempty^
1768
1769 )cpp");
1770 auto speculate = [&](StringRef PointName) {
1771 auto Filter = speculateCompletionFilter(F.code(), F.point(PointName));
1772 assert(Filter);
1773 return *Filter;
1774 };
1775 EXPECT_EQ(speculate("bof"), "");
1776 EXPECT_EQ(speculate("bol"), "");
1777 EXPECT_EQ(speculate("ab"), "ab");
1778 EXPECT_EQ(speculate("dot"), "ab");
1779 EXPECT_EQ(speculate("dotempty"), "");
1780 EXPECT_EQ(speculate("scoped"), "ab");
1781 EXPECT_EQ(speculate("scopedempty"), "");
1782}
1783
1784TEST(CompletionTest, EnableSpeculativeIndexRequest) {
1785 MockFSProvider FS;
1786 MockCompilationDatabase CDB;
1787 IgnoreDiagnostics DiagConsumer;
1788 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1789
1790 auto File = testPath("foo.cpp");
1791 Annotations Test(R"cpp(
1792 namespace ns1 { int abc; }
1793 namespace ns2 { int abc; }
1794 void f() { ns1::ab$1^; ns1::ab$2^; }
1795 void f() { ns2::ab$3^; }
1796 )cpp");
1797 runAddDocument(Server, File, Test.code());
1798 clangd::CodeCompleteOptions Opts = {};
1799
1800 IndexRequestCollector Requests;
1801 Opts.Index = &Requests;
1802 Opts.SpeculativeIndexRequest = true;
1803
1804 auto CompleteAtPoint = [&](StringRef P) {
1805 cantFail(runCodeComplete(Server, File, Test.point(P), Opts));
1806 // Sleep for a while to make sure asynchronous call (if applicable) is also
1807 // triggered before callback is invoked.
1808 std::this_thread::sleep_for(std::chrono::milliseconds(100));
1809 };
1810
1811 CompleteAtPoint("1");
1812 auto Reqs1 = Requests.consumeRequests();
1813 ASSERT_EQ(Reqs1.size(), 1u);
1814 EXPECT_THAT(Reqs1[0].Scopes, UnorderedElementsAre("ns1::"));
1815
1816 CompleteAtPoint("2");
1817 auto Reqs2 = Requests.consumeRequests();
1818 // Speculation succeeded. Used speculative index result.
1819 ASSERT_EQ(Reqs2.size(), 1u);
1820 EXPECT_EQ(Reqs2[0], Reqs1[0]);
1821
1822 CompleteAtPoint("3");
1823 // Speculation failed. Sent speculative index request and the new index
1824 // request after sema.
1825 auto Reqs3 = Requests.consumeRequests();
1826 ASSERT_EQ(Reqs3.size(), 2u);
1827}
1828
Sam McCall9aad25f2017-12-05 07:20:26 +00001829} // namespace
1830} // namespace clangd
1831} // namespace clang