blob: 315050f79a8e2fdb56f4e0bd4346309255ba5533 [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 Liu83f63e42018-09-03 10:18:21 +000058MATCHER_P(HasInclude, IncludeHeader, "") {
59 return !arg.Includes.empty() && arg.Includes[0].Header == IncludeHeader;
Eric Liu63f419a2018-05-15 15:29:32 +000060}
Eric Liu83f63e42018-09-03 10:18:21 +000061MATCHER_P(InsertInclude, IncludeHeader, "") {
62 return !arg.Includes.empty() && arg.Includes[0].Header == IncludeHeader &&
63 bool(arg.Includes[0].Insertion);
64}
65MATCHER(InsertInclude, "") {
66 return !arg.Includes.empty() && bool(arg.Includes[0].Insertion);
67}
Sam McCalle746a2b2018-07-02 11:13:16 +000068MATCHER_P(SnippetSuffix, Text, "") { return arg.SnippetSuffix == Text; }
Sam McCall2161ec72018-07-05 06:20:41 +000069MATCHER_P(Origin, OriginSet, "") { return arg.Origin == OriginSet; }
Eric Liu63f419a2018-05-15 15:29:32 +000070
Sam McCallf6ae3232017-12-05 20:11:29 +000071// Shorthand for Contains(Named(Name)).
Sam McCalle746a2b2018-07-02 11:13:16 +000072Matcher<const std::vector<CodeCompletion> &> Has(std::string Name) {
Sam McCallf6ae3232017-12-05 20:11:29 +000073 return Contains(Named(std::move(Name)));
74}
Sam McCalle746a2b2018-07-02 11:13:16 +000075Matcher<const std::vector<CodeCompletion> &> Has(std::string Name,
Sam McCall44fdcec22017-12-08 15:00:59 +000076 CompletionItemKind K) {
77 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000078}
Sam McCalle746a2b2018-07-02 11:13:16 +000079MATCHER(IsDocumented, "") { return !arg.Documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000080
Sam McCalla15c2d62018-01-18 09:27:56 +000081std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
82 SymbolSlab::Builder Slab;
83 for (const auto &Sym : Symbols)
84 Slab.insert(Sym);
Sam McCallb0138312018-09-04 14:39:56 +000085 return MemIndex::build(std::move(Slab).build(), RefSlab());
Sam McCalla15c2d62018-01-18 09:27:56 +000086}
87
Kadir Cetinkaya2f84d912018-08-08 08:59:29 +000088CodeCompleteResult completions(ClangdServer &Server, StringRef TestCode,
89 Position point,
90 std::vector<Symbol> IndexSymbols = {},
91 clangd::CodeCompleteOptions Opts = {}) {
92 std::unique_ptr<SymbolIndex> OverrideIndex;
93 if (!IndexSymbols.empty()) {
94 assert(!Opts.Index && "both Index and IndexSymbols given!");
95 OverrideIndex = memIndex(std::move(IndexSymbols));
96 Opts.Index = OverrideIndex.get();
97 }
98
99 auto File = testPath("foo.cpp");
100 runAddDocument(Server, File, TestCode);
101 auto CompletionList = cantFail(runCodeComplete(Server, File, point, Opts));
102 return CompletionList;
103}
104
Sam McCalle746a2b2018-07-02 11:13:16 +0000105CodeCompleteResult completions(ClangdServer &Server, StringRef Text,
106 std::vector<Symbol> IndexSymbols = {},
107 clangd::CodeCompleteOptions Opts = {}) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000108 std::unique_ptr<SymbolIndex> OverrideIndex;
109 if (!IndexSymbols.empty()) {
110 assert(!Opts.Index && "both Index and IndexSymbols given!");
111 OverrideIndex = memIndex(std::move(IndexSymbols));
112 Opts.Index = OverrideIndex.get();
113 }
114
Sam McCallc1568062018-02-16 09:41:43 +0000115 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000116 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000117 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000118 auto CompletionList =
119 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000120 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +0000121}
122
Eric Liu63f419a2018-05-15 15:29:32 +0000123// Builds a server and runs code completion.
124// If IndexSymbols is non-empty, an index will be built and passed to opts.
Sam McCalle746a2b2018-07-02 11:13:16 +0000125CodeCompleteResult completions(StringRef Text,
126 std::vector<Symbol> IndexSymbols = {},
127 clangd::CodeCompleteOptions Opts = {}) {
Eric Liu63f419a2018-05-15 15:29:32 +0000128 MockFSProvider FS;
129 MockCompilationDatabase CDB;
130 IgnoreDiagnostics DiagConsumer;
131 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
132 return completions(Server, Text, std::move(IndexSymbols), std::move(Opts));
133}
134
Sam McCall545a20d2018-01-19 14:34:02 +0000135std::string replace(StringRef Haystack, StringRef Needle, StringRef Repl) {
136 std::string Result;
137 raw_string_ostream OS(Result);
138 std::pair<StringRef, StringRef> Split;
139 for (Split = Haystack.split(Needle); !Split.second.empty();
140 Split = Split.first.split(Needle))
141 OS << Split.first << Repl;
142 Result += Split.first;
143 OS.flush();
144 return Result;
145}
146
Sam McCalla15c2d62018-01-18 09:27:56 +0000147// Helpers to produce fake index symbols for memIndex() or completions().
Sam McCall545a20d2018-01-19 14:34:02 +0000148// USRFormat is a regex replacement string for the unqualified part of the USR.
149Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000150 Symbol Sym;
Sam McCall545a20d2018-01-19 14:34:02 +0000151 std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
Sam McCalla15c2d62018-01-18 09:27:56 +0000152 size_t Pos = QName.rfind("::");
153 if (Pos == llvm::StringRef::npos) {
154 Sym.Name = QName;
155 Sym.Scope = "";
156 } else {
157 Sym.Name = QName.substr(Pos + 2);
Sam McCall8b2faee2018-01-19 22:18:21 +0000158 Sym.Scope = QName.substr(0, Pos + 2);
159 USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
Sam McCalla15c2d62018-01-18 09:27:56 +0000160 }
Sam McCall545a20d2018-01-19 14:34:02 +0000161 USR += Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
162 Sym.ID = SymbolID(USR);
Sam McCalla15c2d62018-01-18 09:27:56 +0000163 Sym.SymInfo.Kind = Kind;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000164 Sym.IsIndexedForCodeCompletion = true;
Sam McCall2161ec72018-07-05 06:20:41 +0000165 Sym.Origin = SymbolOrigin::Static;
Sam McCalla15c2d62018-01-18 09:27:56 +0000166 return Sym;
167}
Sam McCall545a20d2018-01-19 14:34:02 +0000168Symbol func(StringRef Name) { // Assumes the function has no args.
169 return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
170}
171Symbol cls(StringRef Name) {
Eric Liu9b3cba72018-05-30 09:03:39 +0000172 return sym(Name, index::SymbolKind::Class, "@S@\\0");
Sam McCall545a20d2018-01-19 14:34:02 +0000173}
174Symbol var(StringRef Name) {
175 return sym(Name, index::SymbolKind::Variable, "@\\0");
176}
Sam McCalldc8abc42018-05-03 14:53:02 +0000177Symbol ns(StringRef Name) {
178 return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
179}
180Symbol withReferences(int N, Symbol S) {
181 S.References = N;
182 return S;
183}
Sam McCalla15c2d62018-01-18 09:27:56 +0000184
Sam McCallf6ae3232017-12-05 20:11:29 +0000185TEST(CompletionTest, Limit) {
186 clangd::CodeCompleteOptions Opts;
187 Opts.Limit = 2;
188 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000189struct ClassWithMembers {
190 int AAA();
191 int BBB();
192 int CCC();
193}
Sam McCallf6ae3232017-12-05 20:11:29 +0000194int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000195 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000196 /*IndexSymbols=*/{}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000197
Sam McCalle746a2b2018-07-02 11:13:16 +0000198 EXPECT_TRUE(Results.HasMore);
199 EXPECT_THAT(Results.Completions, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000200}
201
Sam McCallf6ae3232017-12-05 20:11:29 +0000202TEST(CompletionTest, Filter) {
203 std::string Body = R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000204 #define MotorCar
205 int Car;
Sam McCall9aad25f2017-12-05 07:20:26 +0000206 struct S {
207 int FooBar;
208 int FooBaz;
209 int Qux;
210 };
211 )cpp";
Sam McCall8b2dcc12018-06-14 13:50:30 +0000212
213 // Only items matching the fuzzy query are returned.
Sam McCalle746a2b2018-07-02 11:13:16 +0000214 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").Completions,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000215 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000216
Sam McCall8b2dcc12018-06-14 13:50:30 +0000217 // Macros require prefix match.
Sam McCalle746a2b2018-07-02 11:13:16 +0000218 EXPECT_THAT(completions(Body + "int main() { C^ }").Completions,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000219 AllOf(Has("Car"), Not(Has("MotorCar"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000220}
221
Sam McCallf6ae3232017-12-05 20:11:29 +0000222void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000223 auto Results = completions(
224 R"cpp(
225 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000226
Sam McCall44fdcec22017-12-08 15:00:59 +0000227 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000228
Sam McCall44fdcec22017-12-08 15:00:59 +0000229 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000230
Sam McCall44fdcec22017-12-08 15:00:59 +0000231 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000232
Sam McCall44fdcec22017-12-08 15:00:59 +0000233 struct ClassWithMembers {
234 /// Doc for method.
235 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000236
Sam McCall44fdcec22017-12-08 15:00:59 +0000237 int field;
238 private:
239 int private_field;
240 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000241
Sam McCall44fdcec22017-12-08 15:00:59 +0000242 int test() {
243 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000244
Sam McCall44fdcec22017-12-08 15:00:59 +0000245 /// Doc for local_var.
246 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000247
Sam McCall44fdcec22017-12-08 15:00:59 +0000248 ClassWithMembers().^
249 }
250 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000251 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000252
Sam McCallf6ae3232017-12-05 20:11:29 +0000253 // Class members. The only items that must be present in after-dot
254 // completion.
Sam McCalle746a2b2018-07-02 11:13:16 +0000255 EXPECT_THAT(Results.Completions,
256 AllOf(Has("method"), Has("field"), Not(Has("ClassWithMembers")),
Sam McCall4caa8512018-06-07 12:49:17 +0000257 Not(Has("operator=")), Not(Has("~ClassWithMembers"))));
Sam McCalle746a2b2018-07-02 11:13:16 +0000258 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000259 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000260 // Global items.
Sam McCall545a20d2018-01-19 14:34:02 +0000261 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +0000262 Results.Completions,
Sam McCall545a20d2018-01-19 14:34:02 +0000263 Not(AnyOf(Has("global_var"), Has("index_var"), Has("global_func"),
264 Has("global_func()"), Has("index_func"), Has("GlobalClass"),
265 Has("IndexClass"), Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000266 // There should be no code patterns (aka snippets) in after-dot
267 // completion. At least there aren't any we're aware of.
Sam McCalle746a2b2018-07-02 11:13:16 +0000268 EXPECT_THAT(Results.Completions,
269 Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000270 // Check documentation.
Sam McCalle746a2b2018-07-02 11:13:16 +0000271 EXPECT_IFF(Opts.IncludeComments, Results.Completions,
272 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000273}
Sam McCall9aad25f2017-12-05 07:20:26 +0000274
Sam McCallf6ae3232017-12-05 20:11:29 +0000275void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000276 auto Results = completions(
277 R"cpp(
278 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000279
Sam McCall44fdcec22017-12-08 15:00:59 +0000280 int global_var;
281 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000282
Sam McCall44fdcec22017-12-08 15:00:59 +0000283 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000284
Sam McCall44fdcec22017-12-08 15:00:59 +0000285 struct ClassWithMembers {
286 /// Doc for method.
287 int method();
288 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000289
Sam McCall44fdcec22017-12-08 15:00:59 +0000290 int test() {
291 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000292
Sam McCall44fdcec22017-12-08 15:00:59 +0000293 /// Doc for local_var.
294 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000295
Sam McCall44fdcec22017-12-08 15:00:59 +0000296 ^
297 }
298 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000299 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000300
301 // Class members. Should never be present in global completions.
Sam McCalle746a2b2018-07-02 11:13:16 +0000302 EXPECT_THAT(Results.Completions,
Sam McCallf6ae3232017-12-05 20:11:29 +0000303 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
304 // Global items.
Sam McCalle746a2b2018-07-02 11:13:16 +0000305 EXPECT_THAT(Results.Completions,
306 AllOf(Has("global_var"), Has("index_var"), Has("global_func"),
Sam McCall545a20d2018-01-19 14:34:02 +0000307 Has("index_func" /* our fake symbol doesn't include () */),
308 Has("GlobalClass"), Has("IndexClass")));
Sam McCallf6ae3232017-12-05 20:11:29 +0000309 // A macro.
Sam McCalle746a2b2018-07-02 11:13:16 +0000310 EXPECT_IFF(Opts.IncludeMacros, Results.Completions, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000311 // Local items. Must be present always.
Sam McCalle746a2b2018-07-02 11:13:16 +0000312 EXPECT_THAT(Results.Completions,
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000313 AllOf(Has("local_var"), Has("LocalClass"),
314 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000315 // Check documentation.
Sam McCalle746a2b2018-07-02 11:13:16 +0000316 EXPECT_IFF(Opts.IncludeComments, Results.Completions,
317 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000318}
319
320TEST(CompletionTest, CompletionOptions) {
Sam McCall2c3849a2018-01-16 12:21:24 +0000321 auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
322 TestAfterDotCompletion(Opts);
323 TestGlobalScopeCompletion(Opts);
324 };
325 // We used to test every combination of options, but that got too slow (2^N).
326 auto Flags = {
Ilya Biryukov71028b82018-03-12 15:28:22 +0000327 &clangd::CodeCompleteOptions::IncludeMacros,
Ilya Biryukov43714502018-05-16 12:32:44 +0000328 &clangd::CodeCompleteOptions::IncludeComments,
Ilya Biryukov71028b82018-03-12 15:28:22 +0000329 &clangd::CodeCompleteOptions::IncludeCodePatterns,
330 &clangd::CodeCompleteOptions::IncludeIneligibleResults,
Sam McCall2c3849a2018-01-16 12:21:24 +0000331 };
332 // Test default options.
333 Test({});
334 // Test with one flag flipped.
335 for (auto &F : Flags) {
336 clangd::CodeCompleteOptions O;
337 O.*F ^= true;
338 Test(O);
Sam McCall9aad25f2017-12-05 07:20:26 +0000339 }
340}
341
Sam McCall44fdcec22017-12-08 15:00:59 +0000342TEST(CompletionTest, Priorities) {
343 auto Internal = completions(R"cpp(
344 class Foo {
345 public: void pub();
346 protected: void prot();
347 private: void priv();
348 };
349 void Foo::pub() { this->^ }
350 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000351 EXPECT_THAT(Internal.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000352 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
353
354 auto External = completions(R"cpp(
355 class Foo {
356 public: void pub();
357 protected: void prot();
358 private: void priv();
359 };
360 void test() {
361 Foo F;
362 F.^
363 }
364 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000365 EXPECT_THAT(External.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000366 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
367}
368
369TEST(CompletionTest, Qualifiers) {
370 auto Results = completions(R"cpp(
371 class Foo {
372 public: int foo() const;
373 int bar() const;
374 };
375 class Bar : public Foo {
376 int foo() const;
377 };
378 void test() { Bar().^ }
379 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000380 EXPECT_THAT(Results.Completions,
381 HasSubsequence(AllOf(Qualifier(""), Named("bar")),
382 AllOf(Qualifier("Foo::"), Named("foo"))));
383 EXPECT_THAT(Results.Completions,
384 Not(Contains(AllOf(Qualifier(""), Named("foo"))))); // private
Sam McCall44fdcec22017-12-08 15:00:59 +0000385}
386
Sam McCall4caa8512018-06-07 12:49:17 +0000387TEST(CompletionTest, InjectedTypename) {
388 // These are suppressed when accessed as a member...
Sam McCalle746a2b2018-07-02 11:13:16 +0000389 EXPECT_THAT(completions("struct X{}; void foo(){ X().^ }").Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000390 Not(Has("X")));
Sam McCalle746a2b2018-07-02 11:13:16 +0000391 EXPECT_THAT(completions("struct X{ void foo(){ this->^ } };").Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000392 Not(Has("X")));
393 // ...but accessible in other, more useful cases.
Sam McCalle746a2b2018-07-02 11:13:16 +0000394 EXPECT_THAT(completions("struct X{ void foo(){ ^ } };").Completions,
395 Has("X"));
396 EXPECT_THAT(
397 completions("struct Y{}; struct X:Y{ void foo(){ ^ } };").Completions,
398 Has("Y"));
Sam McCall4caa8512018-06-07 12:49:17 +0000399 EXPECT_THAT(
400 completions(
401 "template<class> struct Y{}; struct X:Y<int>{ void foo(){ ^ } };")
Sam McCalle746a2b2018-07-02 11:13:16 +0000402 .Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000403 Has("Y"));
404 // This case is marginal (`using X::X` is useful), we allow it for now.
Sam McCalle746a2b2018-07-02 11:13:16 +0000405 EXPECT_THAT(completions("struct X{}; void foo(){ X::^ }").Completions,
406 Has("X"));
Sam McCall4caa8512018-06-07 12:49:17 +0000407}
408
Sam McCall44fdcec22017-12-08 15:00:59 +0000409TEST(CompletionTest, Snippets) {
410 clangd::CodeCompleteOptions Opts;
Sam McCall44fdcec22017-12-08 15:00:59 +0000411 auto Results = completions(
412 R"cpp(
413 struct fake {
414 int a;
415 int f(int i, const float f) const;
416 };
417 int main() {
418 fake f;
419 f.^
420 }
421 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000422 /*IndexSymbols=*/{}, Opts);
Sam McCalle746a2b2018-07-02 11:13:16 +0000423 EXPECT_THAT(
424 Results.Completions,
425 HasSubsequence(Named("a"),
426 SnippetSuffix("(${1:int i}, ${2:const float f})")));
Sam McCall44fdcec22017-12-08 15:00:59 +0000427}
428
429TEST(CompletionTest, Kinds) {
Sam McCall545a20d2018-01-19 14:34:02 +0000430 auto Results = completions(
431 R"cpp(
432 #define MACRO X
433 int variable;
434 struct Struct {};
435 int function();
436 int X = ^
437 )cpp",
438 {func("indexFunction"), var("indexVariable"), cls("indexClass")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000439 EXPECT_THAT(Results.Completions,
Sam McCall545a20d2018-01-19 14:34:02 +0000440 AllOf(Has("function", CompletionItemKind::Function),
441 Has("variable", CompletionItemKind::Variable),
442 Has("int", CompletionItemKind::Keyword),
443 Has("Struct", CompletionItemKind::Class),
444 Has("MACRO", CompletionItemKind::Text),
445 Has("indexFunction", CompletionItemKind::Function),
446 Has("indexVariable", CompletionItemKind::Variable),
447 Has("indexClass", CompletionItemKind::Class)));
Sam McCall44fdcec22017-12-08 15:00:59 +0000448
Sam McCall44fdcec22017-12-08 15:00:59 +0000449 Results = completions("nam^");
Sam McCalle746a2b2018-07-02 11:13:16 +0000450 EXPECT_THAT(Results.Completions,
451 Has("namespace", CompletionItemKind::Snippet));
Sam McCall44fdcec22017-12-08 15:00:59 +0000452}
453
Sam McCall84652cc2018-01-12 16:16:09 +0000454TEST(CompletionTest, NoDuplicates) {
Sam McCall545a20d2018-01-19 14:34:02 +0000455 auto Results = completions(
456 R"cpp(
457 class Adapter {
Sam McCall545a20d2018-01-19 14:34:02 +0000458 };
Sam McCall84652cc2018-01-12 16:16:09 +0000459
Eric Liu9b3cba72018-05-30 09:03:39 +0000460 void f() {
Sam McCall545a20d2018-01-19 14:34:02 +0000461 Adapter^
462 }
463 )cpp",
464 {cls("Adapter")});
Sam McCall84652cc2018-01-12 16:16:09 +0000465
466 // Make sure there are no duplicate entries of 'Adapter'.
Sam McCalle746a2b2018-07-02 11:13:16 +0000467 EXPECT_THAT(Results.Completions, ElementsAre(Named("Adapter")));
Sam McCall84652cc2018-01-12 16:16:09 +0000468}
469
Sam McCall545a20d2018-01-19 14:34:02 +0000470TEST(CompletionTest, ScopedNoIndex) {
471 auto Results = completions(
472 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000473 namespace fake { int BigBang, Babble, Box; };
474 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000475 ")cpp");
Sam McCall8b2dcc12018-06-14 13:50:30 +0000476 // Babble is a better match than BigBang. Box doesn't match at all.
Sam McCalle746a2b2018-07-02 11:13:16 +0000477 EXPECT_THAT(Results.Completions,
478 ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCall84652cc2018-01-12 16:16:09 +0000479}
480
Sam McCall545a20d2018-01-19 14:34:02 +0000481TEST(CompletionTest, Scoped) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000482 auto Results = completions(
483 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000484 namespace fake { int Babble, Box; };
485 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000486 ")cpp",
487 {var("fake::BigBang")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000488 EXPECT_THAT(Results.Completions,
489 ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000490}
491
Sam McCall545a20d2018-01-19 14:34:02 +0000492TEST(CompletionTest, ScopedWithFilter) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000493 auto Results = completions(
494 R"cpp(
495 void f() { ns::x^ }
496 )cpp",
497 {cls("ns::XYZ"), func("ns::foo")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000498 EXPECT_THAT(Results.Completions, UnorderedElementsAre(Named("XYZ")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000499}
500
Sam McCalldc8abc42018-05-03 14:53:02 +0000501TEST(CompletionTest, ReferencesAffectRanking) {
Eric Liu84bd5db2018-07-25 11:26:35 +0000502 auto Results = completions("int main() { abs^ }", {ns("absl"), func("absb")});
503 EXPECT_THAT(Results.Completions, HasSubsequence(Named("absb"), Named("absl")));
Sam McCalldc8abc42018-05-03 14:53:02 +0000504 Results = completions("int main() { abs^ }",
Eric Liu84bd5db2018-07-25 11:26:35 +0000505 {withReferences(10000, ns("absl")), func("absb")});
506 EXPECT_THAT(Results.Completions,
507 HasSubsequence(Named("absl"), Named("absb")));
Sam McCalldc8abc42018-05-03 14:53:02 +0000508}
509
Sam McCall545a20d2018-01-19 14:34:02 +0000510TEST(CompletionTest, GlobalQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000511 auto Results = completions(
512 R"cpp(
513 void f() { ::^ }
514 )cpp",
515 {cls("XYZ")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000516 EXPECT_THAT(Results.Completions,
517 AllOf(Has("XYZ", CompletionItemKind::Class),
518 Has("f", CompletionItemKind::Function)));
Sam McCalla15c2d62018-01-18 09:27:56 +0000519}
520
Sam McCall545a20d2018-01-19 14:34:02 +0000521TEST(CompletionTest, FullyQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000522 auto Results = completions(
523 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000524 namespace ns { void bar(); }
Sam McCalla15c2d62018-01-18 09:27:56 +0000525 void f() { ::ns::^ }
526 )cpp",
527 {cls("ns::XYZ")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000528 EXPECT_THAT(Results.Completions,
529 AllOf(Has("XYZ", CompletionItemKind::Class),
530 Has("bar", CompletionItemKind::Function)));
Sam McCall545a20d2018-01-19 14:34:02 +0000531}
532
533TEST(CompletionTest, SemaIndexMerge) {
534 auto Results = completions(
535 R"cpp(
536 namespace ns { int local; void both(); }
537 void f() { ::ns::^ }
538 )cpp",
539 {func("ns::both"), cls("ns::Index")});
540 // We get results from both index and sema, with no duplicates.
Sam McCall2161ec72018-07-05 06:20:41 +0000541 EXPECT_THAT(Results.Completions,
542 UnorderedElementsAre(
543 AllOf(Named("local"), Origin(SymbolOrigin::AST)),
544 AllOf(Named("Index"), Origin(SymbolOrigin::Static)),
545 AllOf(Named("both"),
546 Origin(SymbolOrigin::AST | SymbolOrigin::Static))));
Sam McCalla15c2d62018-01-18 09:27:56 +0000547}
548
Haojian Wu48b48652018-01-25 09:20:09 +0000549TEST(CompletionTest, SemaIndexMergeWithLimit) {
550 clangd::CodeCompleteOptions Opts;
551 Opts.Limit = 1;
552 auto Results = completions(
553 R"cpp(
554 namespace ns { int local; void both(); }
555 void f() { ::ns::^ }
556 )cpp",
557 {func("ns::both"), cls("ns::Index")}, Opts);
Sam McCalle746a2b2018-07-02 11:13:16 +0000558 EXPECT_EQ(Results.Completions.size(), Opts.Limit);
559 EXPECT_TRUE(Results.HasMore);
Haojian Wu48b48652018-01-25 09:20:09 +0000560}
561
Eric Liu63f419a2018-05-15 15:29:32 +0000562TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
563 MockFSProvider FS;
564 MockCompilationDatabase CDB;
565 std::string Subdir = testPath("sub");
566 std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
567 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
568 std::string BarHeader = testPath("sub/bar.h");
569 FS.Files[BarHeader] = "";
570
571 IgnoreDiagnostics DiagConsumer;
572 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Eric Liu63f419a2018-05-15 15:29:32 +0000573 auto BarURI = URI::createFile(BarHeader).toString();
574 Symbol Sym = cls("ns::X");
575 Sym.CanonicalDeclaration.FileURI = BarURI;
Eric Liu83f63e42018-09-03 10:18:21 +0000576 Sym.IncludeHeaders.emplace_back(BarURI, 1);
Eric Liu63f419a2018-05-15 15:29:32 +0000577 // Shoten include path based on search dirctory and insert.
578 auto Results = completions(Server,
579 R"cpp(
580 int main() { ns::^ }
581 )cpp",
582 {Sym});
Sam McCalle746a2b2018-07-02 11:13:16 +0000583 EXPECT_THAT(Results.Completions,
584 ElementsAre(AllOf(Named("X"), InsertInclude("\"bar.h\""))));
Eric Liu63f419a2018-05-15 15:29:32 +0000585 // Duplicate based on inclusions in preamble.
586 Results = completions(Server,
587 R"cpp(
588 #include "sub/bar.h" // not shortest, so should only match resolved.
589 int main() { ns::^ }
590 )cpp",
591 {Sym});
Sam McCalle746a2b2018-07-02 11:13:16 +0000592 EXPECT_THAT(Results.Completions, ElementsAre(AllOf(Named("X"), Labeled("X"),
593 Not(InsertInclude()))));
Eric Liu63f419a2018-05-15 15:29:32 +0000594}
595
Eric Liu9b3cba72018-05-30 09:03:39 +0000596TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
597 MockFSProvider FS;
598 MockCompilationDatabase CDB;
599
600 IgnoreDiagnostics DiagConsumer;
601 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Eric Liu9b3cba72018-05-30 09:03:39 +0000602 Symbol SymX = cls("ns::X");
603 Symbol SymY = cls("ns::Y");
604 std::string BarHeader = testPath("bar.h");
605 auto BarURI = URI::createFile(BarHeader).toString();
606 SymX.CanonicalDeclaration.FileURI = BarURI;
607 SymY.CanonicalDeclaration.FileURI = BarURI;
Eric Liu83f63e42018-09-03 10:18:21 +0000608 SymX.IncludeHeaders.emplace_back("<bar>", 1);
609 SymY.IncludeHeaders.emplace_back("<bar>", 1);
Eric Liu9b3cba72018-05-30 09:03:39 +0000610 // Shoten include path based on search dirctory and insert.
611 auto Results = completions(Server,
612 R"cpp(
613 namespace ns {
614 class X;
615 class Y {}
616 }
617 int main() { ns::^ }
618 )cpp",
619 {SymX, SymY});
Sam McCalle746a2b2018-07-02 11:13:16 +0000620 EXPECT_THAT(Results.Completions,
621 ElementsAre(AllOf(Named("X"), Not(InsertInclude())),
622 AllOf(Named("Y"), Not(InsertInclude()))));
Eric Liu9b3cba72018-05-30 09:03:39 +0000623}
624
Sam McCalla15c2d62018-01-18 09:27:56 +0000625TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
626 MockFSProvider FS;
627 MockCompilationDatabase CDB;
628 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000629 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCalla15c2d62018-01-18 09:27:56 +0000630
Sam McCallc1568062018-02-16 09:41:43 +0000631 FS.Files[testPath("bar.h")] =
Sam McCalld5ea3e32018-01-24 17:53:32 +0000632 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
Sam McCallc1568062018-02-16 09:41:43 +0000633 auto File = testPath("foo.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000634 Annotations Test(R"cpp(
635 #include "bar.h"
636 namespace ns { int local; }
Sam McCalld5ea3e32018-01-24 17:53:32 +0000637 void f() { ns::^; }
638 void f() { ns::preamble().$2^; }
Sam McCalla15c2d62018-01-18 09:27:56 +0000639 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000640 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000641 clangd::CodeCompleteOptions Opts = {};
642
Sam McCalla15c2d62018-01-18 09:27:56 +0000643 auto I = memIndex({var("ns::index")});
644 Opts.Index = I.get();
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000645 auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000646 EXPECT_THAT(WithIndex.Completions,
Sam McCalla15c2d62018-01-18 09:27:56 +0000647 UnorderedElementsAre(Named("local"), Named("index")));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000648 auto ClassFromPreamble =
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000649 cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000650 EXPECT_THAT(ClassFromPreamble.Completions, Contains(Named("member")));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000651
652 Opts.Index = nullptr;
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000653 auto WithoutIndex =
654 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000655 EXPECT_THAT(WithoutIndex.Completions,
Sam McCall0bb24cd2018-02-13 08:59:23 +0000656 UnorderedElementsAre(Named("local"), Named("preamble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000657}
658
659TEST(CompletionTest, DynamicIndexMultiFile) {
660 MockFSProvider FS;
661 MockCompilationDatabase CDB;
662 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000663 auto Opts = ClangdServer::optsForTest();
664 Opts.BuildDynamicSymbolIndex = true;
665 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCalla15c2d62018-01-18 09:27:56 +0000666
Eric Liu709bde82018-02-19 18:48:44 +0000667 FS.Files[testPath("foo.h")] = R"cpp(
Sam McCalla15c2d62018-01-18 09:27:56 +0000668 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liu709bde82018-02-19 18:48:44 +0000669 )cpp";
Sam McCall7363a2f2018-03-05 17:28:54 +0000670 runAddDocument(Server, testPath("foo.cpp"), R"cpp(
Eric Liu709bde82018-02-19 18:48:44 +0000671 #include "foo.h"
Sam McCall0bb24cd2018-02-13 08:59:23 +0000672 )cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000673
Sam McCallc1568062018-02-16 09:41:43 +0000674 auto File = testPath("bar.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000675 Annotations Test(R"cpp(
676 namespace ns {
677 class XXX {};
678 /// Doooc
679 void fooooo() {}
680 }
681 void f() { ns::^ }
682 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000683 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000684
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000685 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
Sam McCalla15c2d62018-01-18 09:27:56 +0000686 // "XYZ" and "foo" are not included in the file being completed but are still
687 // visible through the index.
Sam McCalle746a2b2018-07-02 11:13:16 +0000688 EXPECT_THAT(Results.Completions, Has("XYZ", CompletionItemKind::Class));
689 EXPECT_THAT(Results.Completions, Has("foo", CompletionItemKind::Function));
690 EXPECT_THAT(Results.Completions, Has("XXX", CompletionItemKind::Class));
691 EXPECT_THAT(Results.Completions,
692 Contains((Named("fooooo"), Kind(CompletionItemKind::Function),
693 Doc("Doooc"), ReturnType("void"))));
Sam McCalla15c2d62018-01-18 09:27:56 +0000694}
695
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000696TEST(CompletionTest, Documentation) {
697 auto Results = completions(
698 R"cpp(
699 // Non-doxygen comment.
700 int foo();
701 /// Doxygen comment.
702 /// \param int a
703 int bar(int a);
704 /* Multi-line
705 block comment
706 */
707 int baz();
708
709 int x = ^
710 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000711 EXPECT_THAT(Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000712 Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
713 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +0000714 Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000715 Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
Sam McCalle746a2b2018-07-02 11:13:16 +0000716 EXPECT_THAT(Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000717 Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
718}
719
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000720TEST(CompletionTest, GlobalCompletionFiltering) {
721
722 Symbol Class = cls("XYZ");
723 Class.IsIndexedForCodeCompletion = false;
724 Symbol Func = func("XYZ::foooo");
725 Func.IsIndexedForCodeCompletion = false;
726
727 auto Results = completions(R"(// void f() {
728 XYZ::foooo^
729 })",
730 {Class, Func});
Sam McCalle746a2b2018-07-02 11:13:16 +0000731 EXPECT_THAT(Results.Completions, IsEmpty());
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000732}
733
Haojian Wu58d208d2018-01-25 09:44:06 +0000734TEST(CodeCompleteTest, DisableTypoCorrection) {
735 auto Results = completions(R"cpp(
736 namespace clang { int v; }
737 void f() { clangd::^
738 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000739 EXPECT_TRUE(Results.Completions.empty());
Haojian Wu58d208d2018-01-25 09:44:06 +0000740}
741
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000742TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
743 auto Results = completions(R"cpp(
744 namespace clang { }
745 void f() {
746 clan^
747 }
748 )cpp");
749
Sam McCalle746a2b2018-07-02 11:13:16 +0000750 EXPECT_THAT(Results.Completions, Contains(Labeled("clang")));
751 EXPECT_THAT(Results.Completions, Not(Contains(Labeled("clang::"))));
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000752}
753
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000754TEST(CompletionTest, BacktrackCrashes) {
755 // Sema calls code completion callbacks twice in these cases.
756 auto Results = completions(R"cpp(
757 namespace ns {
758 struct FooBarBaz {};
759 } // namespace ns
760
761 int foo(ns::FooBar^
762 )cpp");
763
Sam McCalle746a2b2018-07-02 11:13:16 +0000764 EXPECT_THAT(Results.Completions, ElementsAre(Labeled("FooBarBaz")));
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000765
766 // Check we don't crash in that case too.
767 completions(R"cpp(
768 struct FooBarBaz {};
769 void test() {
770 if (FooBarBaz * x^) {}
771 }
772)cpp");
773}
774
Eric Liu42abe412018-05-24 11:20:19 +0000775TEST(CompletionTest, CompleteInMacroWithStringification) {
776 auto Results = completions(R"cpp(
777void f(const char *, int x);
778#define F(x) f(#x, x)
779
780namespace ns {
781int X;
782int Y;
783} // namespace ns
784
785int f(int input_num) {
786 F(ns::^)
787}
788)cpp");
789
Sam McCalle746a2b2018-07-02 11:13:16 +0000790 EXPECT_THAT(Results.Completions,
Eric Liu42abe412018-05-24 11:20:19 +0000791 UnorderedElementsAre(Named("X"), Named("Y")));
792}
793
794TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
795 auto Results = completions(R"cpp(
796void f(const char *, int x);
797#define F(x) f(#x, x)
798
799namespace ns {
800int X;
801
802int f(int input_num) {
803 F(^)
804}
805} // namespace ns
806)cpp");
807
Sam McCalle746a2b2018-07-02 11:13:16 +0000808 EXPECT_THAT(Results.Completions, Contains(Named("X")));
Eric Liu42abe412018-05-24 11:20:19 +0000809}
810
Eric Liu485074f2018-07-11 13:15:31 +0000811TEST(CompletionTest, IgnoreCompleteInExcludedPPBranchWithRecoveryContext) {
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000812 auto Results = completions(R"cpp(
813 int bar(int param_in_bar) {
814 }
815
816 int foo(int param_in_foo) {
817#if 0
Eric Liu485074f2018-07-11 13:15:31 +0000818 // In recorvery mode, "param_in_foo" will also be suggested among many other
819 // unrelated symbols; however, this is really a special case where this works.
820 // If the #if block is outside of the function, "param_in_foo" is still
821 // suggested, but "bar" and "foo" are missing. So the recovery mode doesn't
822 // really provide useful results in excluded branches.
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000823 par^
824#endif
825 }
826)cpp");
827
Eric Liu485074f2018-07-11 13:15:31 +0000828 EXPECT_TRUE(Results.Completions.empty());
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000829}
Ilya Biryukov43c292c2018-08-30 13:14:31 +0000830SignatureHelp signatures(StringRef Text, Position Point,
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +0000831 std::vector<Symbol> IndexSymbols = {}) {
832 std::unique_ptr<SymbolIndex> Index;
833 if (!IndexSymbols.empty())
834 Index = memIndex(IndexSymbols);
835
Sam McCall800d4372017-12-19 10:29:27 +0000836 MockFSProvider FS;
837 MockCompilationDatabase CDB;
838 IgnoreDiagnostics DiagConsumer;
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +0000839 ClangdServer::Options Opts = ClangdServer::optsForTest();
840 Opts.StaticIndex = Index.get();
841
842 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCallc1568062018-02-16 09:41:43 +0000843 auto File = testPath("foo.cpp");
Ilya Biryukov43c292c2018-08-30 13:14:31 +0000844 runAddDocument(Server, File, Text);
845 return cantFail(runSignatureHelp(Server, File, Point));
846}
847
848SignatureHelp signatures(StringRef Text,
849 std::vector<Symbol> IndexSymbols = {}) {
Sam McCall328cbdb2017-12-20 16:06:05 +0000850 Annotations Test(Text);
Ilya Biryukov43c292c2018-08-30 13:14:31 +0000851 return signatures(Test.code(), Test.point(), std::move(IndexSymbols));
Sam McCall800d4372017-12-19 10:29:27 +0000852}
853
854MATCHER_P(ParamsAre, P, "") {
855 if (P.size() != arg.parameters.size())
856 return false;
857 for (unsigned I = 0; I < P.size(); ++I)
858 if (P[I] != arg.parameters[I].label)
859 return false;
860 return true;
861}
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +0000862MATCHER_P(SigDoc, Doc, "") { return arg.documentation == Doc; }
Sam McCall800d4372017-12-19 10:29:27 +0000863
864Matcher<SignatureInformation> Sig(std::string Label,
865 std::vector<std::string> Params) {
Eric Liu8f3678d2018-06-15 13:34:18 +0000866 return AllOf(SigHelpLabeled(Label), ParamsAre(Params));
Sam McCall800d4372017-12-19 10:29:27 +0000867}
868
869TEST(SignatureHelpTest, Overloads) {
870 auto Results = signatures(R"cpp(
871 void foo(int x, int y);
872 void foo(int x, float y);
873 void foo(float x, int y);
874 void foo(float x, float y);
875 void bar(int x, int y = 0);
876 int main() { foo(^); }
877 )cpp");
878 EXPECT_THAT(Results.signatures,
879 UnorderedElementsAre(
880 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
881 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
882 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
883 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
884 // We always prefer the first signature.
885 EXPECT_EQ(0, Results.activeSignature);
886 EXPECT_EQ(0, Results.activeParameter);
887}
888
889TEST(SignatureHelpTest, DefaultArgs) {
890 auto Results = signatures(R"cpp(
891 void bar(int x, int y = 0);
892 void bar(float x = 0, int y = 42);
893 int main() { bar(^
894 )cpp");
895 EXPECT_THAT(Results.signatures,
896 UnorderedElementsAre(
897 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
898 Sig("bar(float x = 0, int y = 42) -> void",
899 {"float x = 0", "int y = 42"})));
900 EXPECT_EQ(0, Results.activeSignature);
901 EXPECT_EQ(0, Results.activeParameter);
902}
903
904TEST(SignatureHelpTest, ActiveArg) {
905 auto Results = signatures(R"cpp(
906 int baz(int a, int b, int c);
907 int main() { baz(baz(1,2,3), ^); }
908 )cpp");
909 EXPECT_THAT(Results.signatures,
910 ElementsAre(Sig("baz(int a, int b, int c) -> int",
911 {"int a", "int b", "int c"})));
912 EXPECT_EQ(0, Results.activeSignature);
913 EXPECT_EQ(1, Results.activeParameter);
914}
915
Ilya Biryukov43c292c2018-08-30 13:14:31 +0000916TEST(SignatureHelpTest, OpeningParen) {
917 llvm::StringLiteral Tests[] = {// Recursive function call.
918 R"cpp(
919 int foo(int a, int b, int c);
920 int main() {
921 foo(foo $p^( foo(10, 10, 10), ^ )));
922 })cpp",
923 // Functional type cast.
924 R"cpp(
925 struct Foo {
926 Foo(int a, int b, int c);
927 };
928 int main() {
929 Foo $p^( 10, ^ );
930 })cpp",
931 // New expression.
932 R"cpp(
933 struct Foo {
934 Foo(int a, int b, int c);
935 };
936 int main() {
937 new Foo $p^( 10, ^ );
938 })cpp",
939 // Macro expansion.
940 R"cpp(
941 int foo(int a, int b, int c);
942 #define FOO foo(
943
944 int main() {
945 // Macro expansions.
946 $p^FOO 10, ^ );
947 })cpp",
948 // Macro arguments.
949 R"cpp(
950 int foo(int a, int b, int c);
951 int main() {
952 #define ID(X) X
953 ID(foo $p^( foo(10), ^ ))
954 })cpp"};
955
956 for (auto Test : Tests) {
957 Annotations Code(Test);
958 EXPECT_EQ(signatures(Code.code(), Code.point()).argListStart,
959 Code.point("p"))
960 << "Test source:" << Test;
961 }
962}
963
Haojian Wu061c73e2018-01-23 11:37:26 +0000964class IndexRequestCollector : public SymbolIndex {
965public:
966 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000967 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000968 llvm::function_ref<void(const Symbol &)> Callback) const override {
Ilya Biryukov5c4d6e62018-09-06 11:04:56 +0000969 std::lock_guard<std::mutex> Lock(Mut);
Haojian Wu061c73e2018-01-23 11:37:26 +0000970 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000971 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000972 }
973
Eric Liu9ec459f2018-03-14 09:48:05 +0000974 void lookup(const LookupRequest &,
975 llvm::function_ref<void(const Symbol &)>) const override {}
976
Sam McCallb0138312018-09-04 14:39:56 +0000977 void refs(const RefsRequest &,
978 llvm::function_ref<void(const Ref &)>) const override {}
Haojian Wu65ac3212018-08-06 13:14:32 +0000979
Kirill Bobyrevfc890012018-08-24 09:12:54 +0000980 // This is incorrect, but IndexRequestCollector is not an actual index and it
981 // isn't used in production code.
982 size_t estimateMemoryUsage() const override { return 0; }
983
Eric Liu25d74e92018-08-24 11:23:56 +0000984 const std::vector<FuzzyFindRequest> consumeRequests() const {
Ilya Biryukov5c4d6e62018-09-06 11:04:56 +0000985 std::lock_guard<std::mutex> Lock(Mut);
Eric Liu25d74e92018-08-24 11:23:56 +0000986 auto Reqs = std::move(Requests);
987 Requests = {};
988 return Reqs;
989 }
Haojian Wu061c73e2018-01-23 11:37:26 +0000990
991private:
Ilya Biryukov5c4d6e62018-09-06 11:04:56 +0000992 // We need a mutex to handle async fuzzy find requests.
993 mutable std::mutex Mut;
Haojian Wu061c73e2018-01-23 11:37:26 +0000994 mutable std::vector<FuzzyFindRequest> Requests;
995};
996
997std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
998 clangd::CodeCompleteOptions Opts;
999 IndexRequestCollector Requests;
1000 Opts.Index = &Requests;
1001 completions(Code, {}, Opts);
Eric Liu25d74e92018-08-24 11:23:56 +00001002 return Requests.consumeRequests();
Haojian Wu061c73e2018-01-23 11:37:26 +00001003}
1004
1005TEST(CompletionTest, UnqualifiedIdQuery) {
1006 auto Requests = captureIndexRequests(R"cpp(
1007 namespace std {}
1008 using namespace std;
1009 namespace ns {
1010 void f() {
1011 vec^
1012 }
1013 }
1014 )cpp");
1015
1016 EXPECT_THAT(Requests,
1017 ElementsAre(Field(&FuzzyFindRequest::Scopes,
1018 UnorderedElementsAre("", "ns::", "std::"))));
1019}
1020
1021TEST(CompletionTest, ResolvedQualifiedIdQuery) {
1022 auto Requests = captureIndexRequests(R"cpp(
1023 namespace ns1 {}
1024 namespace ns2 {} // ignore
1025 namespace ns3 { namespace nns3 {} }
1026 namespace foo {
1027 using namespace ns1;
1028 using namespace ns3::nns3;
1029 }
1030 namespace ns {
1031 void f() {
1032 foo::^
1033 }
1034 }
1035 )cpp");
1036
1037 EXPECT_THAT(Requests,
1038 ElementsAre(Field(
1039 &FuzzyFindRequest::Scopes,
1040 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
1041}
1042
1043TEST(CompletionTest, UnresolvedQualifierIdQuery) {
1044 auto Requests = captureIndexRequests(R"cpp(
1045 namespace a {}
1046 using namespace a;
1047 namespace ns {
1048 void f() {
1049 bar::^
1050 }
1051 } // namespace ns
1052 )cpp");
1053
1054 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1055 UnorderedElementsAre("bar::"))));
1056}
1057
1058TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
1059 auto Requests = captureIndexRequests(R"cpp(
1060 namespace a {}
1061 using namespace a;
1062 namespace ns {
1063 void f() {
1064 ::a::bar::^
1065 }
1066 } // namespace ns
1067 )cpp");
1068
1069 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1070 UnorderedElementsAre("a::bar::"))));
1071}
1072
1073TEST(CompletionTest, EmptyQualifiedQuery) {
1074 auto Requests = captureIndexRequests(R"cpp(
1075 namespace ns {
1076 void f() {
1077 ^
1078 }
1079 } // namespace ns
1080 )cpp");
1081
1082 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1083 UnorderedElementsAre("", "ns::"))));
1084}
1085
1086TEST(CompletionTest, GlobalQualifiedQuery) {
1087 auto Requests = captureIndexRequests(R"cpp(
1088 namespace ns {
1089 void f() {
1090 ::^
1091 }
1092 } // namespace ns
1093 )cpp");
1094
1095 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1096 UnorderedElementsAre(""))));
1097}
1098
Ilya Biryukova907ba42018-05-14 10:50:04 +00001099TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
1100 auto Completions = completions(
1101 R"cpp(
1102 struct Foo {
1103 int SomeNameOfField;
1104 typedef int SomeNameOfTypedefField;
1105 };
1106
1107 Foo::^)cpp",
1108 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
1109
Sam McCalle746a2b2018-07-02 11:13:16 +00001110 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001111 AllOf(Contains(Labeled("SomeNameOfField")),
1112 Contains(Labeled("SomeNameOfTypedefField")),
1113 Not(Contains(Labeled("SomeNameInTheIndex")))));
1114}
1115
1116TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
1117 {
1118 auto Completions = completions(
1119 R"cpp(
1120 template <class T>
1121 void foo() {
1122 T::^
1123 }
1124 )cpp",
1125 {func("::SomeNameInTheIndex")});
1126
Sam McCalle746a2b2018-07-02 11:13:16 +00001127 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001128 Not(Contains(Labeled("SomeNameInTheIndex"))));
1129 }
1130
1131 {
1132 auto Completions = completions(
1133 R"cpp(
1134 template <class T>
1135 void foo() {
1136 T::template Y<int>::^
1137 }
1138 )cpp",
1139 {func("::SomeNameInTheIndex")});
1140
Sam McCalle746a2b2018-07-02 11:13:16 +00001141 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001142 Not(Contains(Labeled("SomeNameInTheIndex"))));
1143 }
1144
1145 {
1146 auto Completions = completions(
1147 R"cpp(
1148 template <class T>
1149 void foo() {
1150 T::foo::^
1151 }
1152 )cpp",
1153 {func("::SomeNameInTheIndex")});
1154
Sam McCalle746a2b2018-07-02 11:13:16 +00001155 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001156 Not(Contains(Labeled("SomeNameInTheIndex"))));
1157 }
1158}
1159
Sam McCallc18c2802018-06-15 11:06:29 +00001160TEST(CompletionTest, OverloadBundling) {
1161 clangd::CodeCompleteOptions Opts;
1162 Opts.BundleOverloads = true;
1163
1164 std::string Context = R"cpp(
1165 struct X {
1166 // Overload with int
1167 int a(int);
1168 // Overload with bool
1169 int a(bool);
1170 int b(float);
1171 };
1172 int GFuncC(int);
1173 int GFuncD(int);
1174 )cpp";
1175
1176 // Member completions are bundled.
Sam McCalle746a2b2018-07-02 11:13:16 +00001177 EXPECT_THAT(completions(Context + "int y = X().^", {}, Opts).Completions,
Sam McCallc18c2802018-06-15 11:06:29 +00001178 UnorderedElementsAre(Labeled("a(…)"), Labeled("b(float)")));
1179
1180 // Non-member completions are bundled, including index+sema.
1181 Symbol NoArgsGFunc = func("GFuncC");
1182 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001183 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
Sam McCallc18c2802018-06-15 11:06:29 +00001184 UnorderedElementsAre(Labeled("GFuncC(…)"), Labeled("GFuncD(int)")));
1185
1186 // Differences in header-to-insert suppress bundling.
Sam McCallc18c2802018-06-15 11:06:29 +00001187 std::string DeclFile = URI::createFile(testPath("foo")).toString();
1188 NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile;
Eric Liu83f63e42018-09-03 10:18:21 +00001189 NoArgsGFunc.IncludeHeaders.emplace_back("<foo>", 1);
Sam McCallc18c2802018-06-15 11:06:29 +00001190 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001191 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
1192 UnorderedElementsAre(AllOf(Named("GFuncC"), InsertInclude("<foo>")),
1193 Labeled("GFuncC(int)"), Labeled("GFuncD(int)")));
Sam McCallc18c2802018-06-15 11:06:29 +00001194
1195 // Examine a bundled completion in detail.
Sam McCalle746a2b2018-07-02 11:13:16 +00001196 auto A =
1197 completions(Context + "int y = X().a^", {}, Opts).Completions.front();
1198 EXPECT_EQ(A.Name, "a");
1199 EXPECT_EQ(A.Signature, "(…)");
1200 EXPECT_EQ(A.BundleSize, 2u);
1201 EXPECT_EQ(A.Kind, CompletionItemKind::Method);
1202 EXPECT_EQ(A.ReturnType, "int"); // All overloads return int.
Sam McCallc18c2802018-06-15 11:06:29 +00001203 // For now we just return one of the doc strings arbitrarily.
Sam McCalle746a2b2018-07-02 11:13:16 +00001204 EXPECT_THAT(A.Documentation, AnyOf(HasSubstr("Overload with int"),
Sam McCallc18c2802018-06-15 11:06:29 +00001205 HasSubstr("Overload with bool")));
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001206 EXPECT_EQ(A.SnippetSuffix, "($0)");
Sam McCallc18c2802018-06-15 11:06:29 +00001207}
1208
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001209TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001210 MockFSProvider FS;
1211 auto FooH = testPath("foo.h");
1212 auto FooCpp = testPath("foo.cpp");
1213 FS.Files[FooH] = R"cpp(
1214 // this is my documentation comment.
1215 int func();
1216 )cpp";
1217 FS.Files[FooCpp] = "";
1218
1219 MockCompilationDatabase CDB;
1220 IgnoreDiagnostics DiagConsumer;
1221 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1222
1223 Annotations Source(R"cpp(
1224 #include "foo.h"
1225 int func() {
1226 // This makes sure we have func from header in the AST.
1227 }
1228 int a = fun^
1229 )cpp");
1230 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1231 // We need to wait for preamble to build.
1232 ASSERT_TRUE(Server.blockUntilIdleForTest());
1233
1234 // Change the header file. Completion will reuse the old preamble!
1235 FS.Files[FooH] = R"cpp(
1236 int func();
1237 )cpp";
1238
1239 clangd::CodeCompleteOptions Opts;
1240 Opts.IncludeComments = true;
Sam McCalle746a2b2018-07-02 11:13:16 +00001241 CodeCompleteResult Completions =
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001242 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1243 // We shouldn't crash. Unfortunately, current workaround is to not produce
1244 // comments for symbols from headers.
Sam McCalle746a2b2018-07-02 11:13:16 +00001245 EXPECT_THAT(Completions.Completions,
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001246 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1247}
1248
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001249TEST(CompletionTest, NonDocComments) {
1250 MockFSProvider FS;
1251 auto FooCpp = testPath("foo.cpp");
1252 FS.Files[FooCpp] = "";
1253
1254 MockCompilationDatabase CDB;
1255 IgnoreDiagnostics DiagConsumer;
1256 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1257
1258 Annotations Source(R"cpp(
Ilya Biryukovda8dd8b2018-06-27 09:47:20 +00001259 // We ignore namespace comments, for rationale see CodeCompletionStrings.h.
1260 namespace comments_ns {
1261 }
1262
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001263 // ------------------
1264 int comments_foo();
1265
1266 // A comment and a decl are separated by newlines.
1267 // Therefore, the comment shouldn't show up as doc comment.
1268
1269 int comments_bar();
1270
1271 // this comment should be in the results.
1272 int comments_baz();
1273
1274
1275 template <class T>
1276 struct Struct {
1277 int comments_qux();
1278 int comments_quux();
1279 };
1280
1281
1282 // This comment should not be there.
1283
1284 template <class T>
1285 int Struct<T>::comments_qux() {
1286 }
1287
1288 // This comment **should** be in results.
1289 template <class T>
1290 int Struct<T>::comments_quux() {
1291 int a = comments^;
1292 }
1293 )cpp");
Reid Kleckner80274b12018-06-18 18:55:10 +00001294 // FIXME: Auto-completion in a template requires disabling delayed template
1295 // parsing.
1296 CDB.ExtraClangFlags.push_back("-fno-delayed-template-parsing");
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001297 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
Sam McCalle746a2b2018-07-02 11:13:16 +00001298 CodeCompleteResult Completions = cantFail(runCodeComplete(
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001299 Server, FooCpp, Source.point(), clangd::CodeCompleteOptions()));
1300
1301 // We should not get any of those comments in completion.
1302 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001303 Completions.Completions,
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001304 UnorderedElementsAre(AllOf(Not(IsDocumented()), Named("comments_foo")),
1305 AllOf(IsDocumented(), Named("comments_baz")),
1306 AllOf(IsDocumented(), Named("comments_quux")),
Ilya Biryukovda8dd8b2018-06-27 09:47:20 +00001307 AllOf(Not(IsDocumented()), Named("comments_ns")),
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001308 // FIXME(ibiryukov): the following items should have
1309 // empty documentation, since they are separated from
1310 // a comment with an empty line. Unfortunately, I
1311 // couldn't make Sema tests pass if we ignore those.
1312 AllOf(IsDocumented(), Named("comments_bar")),
1313 AllOf(IsDocumented(), Named("comments_qux"))));
1314}
1315
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001316TEST(CompletionTest, CompleteOnInvalidLine) {
1317 auto FooCpp = testPath("foo.cpp");
1318
1319 MockCompilationDatabase CDB;
1320 IgnoreDiagnostics DiagConsumer;
1321 MockFSProvider FS;
1322 FS.Files[FooCpp] = "// empty file";
1323
1324 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1325 // Run completion outside the file range.
1326 Position Pos;
1327 Pos.line = 100;
1328 Pos.character = 0;
1329 EXPECT_THAT_EXPECTED(
1330 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1331 Failed());
1332}
1333
Eric Liu7ad16962018-06-22 10:46:59 +00001334TEST(CompletionTest, QualifiedNames) {
1335 auto Results = completions(
1336 R"cpp(
1337 namespace ns { int local; void both(); }
1338 void f() { ::ns::^ }
1339 )cpp",
1340 {func("ns::both"), cls("ns::Index")});
1341 // We get results from both index and sema, with no duplicates.
Sam McCalle746a2b2018-07-02 11:13:16 +00001342 EXPECT_THAT(
1343 Results.Completions,
1344 UnorderedElementsAre(Scope("ns::"), Scope("ns::"), Scope("ns::")));
1345}
1346
1347TEST(CompletionTest, Render) {
1348 CodeCompletion C;
1349 C.Name = "x";
1350 C.Signature = "(bool) const";
1351 C.SnippetSuffix = "(${0:bool})";
1352 C.ReturnType = "int";
1353 C.RequiredQualifier = "Foo::";
1354 C.Scope = "ns::Foo::";
1355 C.Documentation = "This is x().";
Eric Liu83f63e42018-09-03 10:18:21 +00001356 C.Includes.emplace_back();
1357 auto &Include = C.Includes.back();
1358 Include.Header = "\"foo.h\"";
Sam McCalle746a2b2018-07-02 11:13:16 +00001359 C.Kind = CompletionItemKind::Method;
1360 C.Score.Total = 1.0;
Sam McCall4e5742a2018-07-06 11:50:49 +00001361 C.Origin = SymbolOrigin::AST | SymbolOrigin::Static;
Sam McCalle746a2b2018-07-02 11:13:16 +00001362
1363 CodeCompleteOptions Opts;
1364 Opts.IncludeIndicator.Insert = "^";
1365 Opts.IncludeIndicator.NoInsert = "";
1366 Opts.EnableSnippets = false;
1367
1368 auto R = C.render(Opts);
1369 EXPECT_EQ(R.label, "Foo::x(bool) const");
1370 EXPECT_EQ(R.insertText, "Foo::x");
1371 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText);
1372 EXPECT_EQ(R.filterText, "x");
1373 EXPECT_EQ(R.detail, "int\n\"foo.h\"");
1374 EXPECT_EQ(R.documentation, "This is x().");
1375 EXPECT_THAT(R.additionalTextEdits, IsEmpty());
Sam McCalle746a2b2018-07-02 11:13:16 +00001376 EXPECT_EQ(R.sortText, sortText(1.0, "x"));
1377
1378 Opts.EnableSnippets = true;
1379 R = C.render(Opts);
1380 EXPECT_EQ(R.insertText, "Foo::x(${0:bool})");
1381 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet);
1382
Eric Liu83f63e42018-09-03 10:18:21 +00001383 Include.Insertion.emplace();
Sam McCalle746a2b2018-07-02 11:13:16 +00001384 R = C.render(Opts);
1385 EXPECT_EQ(R.label, "^Foo::x(bool) const");
1386 EXPECT_THAT(R.additionalTextEdits, Not(IsEmpty()));
1387
Sam McCall2161ec72018-07-05 06:20:41 +00001388 Opts.ShowOrigins = true;
1389 R = C.render(Opts);
1390 EXPECT_EQ(R.label, "^[AS]Foo::x(bool) const");
1391
Sam McCalle746a2b2018-07-02 11:13:16 +00001392 C.BundleSize = 2;
1393 R = C.render(Opts);
1394 EXPECT_EQ(R.detail, "[2 overloads]\n\"foo.h\"");
Eric Liu7ad16962018-06-22 10:46:59 +00001395}
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001396
Eric Liu485074f2018-07-11 13:15:31 +00001397TEST(CompletionTest, IgnoreRecoveryResults) {
1398 auto Results = completions(
1399 R"cpp(
1400 namespace ns { int NotRecovered() { return 0; } }
1401 void f() {
1402 // Sema enters recovery mode first and then normal mode.
1403 if (auto x = ns::NotRecover^)
1404 }
1405 )cpp");
1406 EXPECT_THAT(Results.Completions, UnorderedElementsAre(Named("NotRecovered")));
1407}
1408
Eric Liuf433c2d2018-07-18 15:31:14 +00001409TEST(CompletionTest, ScopeOfClassFieldInConstructorInitializer) {
1410 auto Results = completions(
1411 R"cpp(
1412 namespace ns {
1413 class X { public: X(); int x_; };
1414 X::X() : x_^(0) {}
1415 }
1416 )cpp");
1417 EXPECT_THAT(Results.Completions,
1418 UnorderedElementsAre(AllOf(Scope("ns::X::"), Named("x_"))));
1419}
1420
Eric Liu5d2a8072018-07-23 10:56:37 +00001421TEST(CompletionTest, CodeCompletionContext) {
1422 auto Results = completions(
1423 R"cpp(
1424 namespace ns {
1425 class X { public: X(); int x_; };
1426 void f() {
1427 X x;
1428 x.^;
1429 }
1430 }
1431 )cpp");
1432
1433 EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess);
1434}
1435
Kadir Cetinkaya2f84d912018-08-08 08:59:29 +00001436TEST(CompletionTest, FixItForArrowToDot) {
1437 MockFSProvider FS;
1438 MockCompilationDatabase CDB;
1439 IgnoreDiagnostics DiagConsumer;
1440 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1441
1442 CodeCompleteOptions Opts;
1443 Opts.IncludeFixIts = true;
1444 Annotations TestCode(
1445 R"cpp(
1446 class Auxilary {
1447 public:
1448 void AuxFunction();
1449 };
1450 class ClassWithPtr {
1451 public:
1452 void MemberFunction();
1453 Auxilary* operator->() const;
1454 Auxilary* Aux;
1455 };
1456 void f() {
1457 ClassWithPtr x;
1458 x[[->]]^;
1459 }
1460 )cpp");
1461 auto Results =
1462 completions(Server, TestCode.code(), TestCode.point(), {}, Opts);
1463 EXPECT_EQ(Results.Completions.size(), 3u);
1464
1465 TextEdit ReplacementEdit;
1466 ReplacementEdit.range = TestCode.range();
1467 ReplacementEdit.newText = ".";
1468 for (const auto &C : Results.Completions) {
1469 EXPECT_TRUE(C.FixIts.size() == 1u || C.Name == "AuxFunction");
Haojian Wu1793bc92018-08-10 08:34:16 +00001470 if (!C.FixIts.empty()) {
Kadir Cetinkaya2f84d912018-08-08 08:59:29 +00001471 EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit));
Haojian Wu1793bc92018-08-10 08:34:16 +00001472 }
Kadir Cetinkaya2f84d912018-08-08 08:59:29 +00001473 }
1474}
1475
1476TEST(CompletionTest, FixItForDotToArrow) {
1477 MockFSProvider FS;
1478 MockCompilationDatabase CDB;
1479 IgnoreDiagnostics DiagConsumer;
1480 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1481
1482 CodeCompleteOptions Opts;
1483 Opts.IncludeFixIts = true;
1484 Annotations TestCode(
1485 R"cpp(
1486 class Auxilary {
1487 public:
1488 void AuxFunction();
1489 };
1490 class ClassWithPtr {
1491 public:
1492 void MemberFunction();
1493 Auxilary* operator->() const;
1494 Auxilary* Aux;
1495 };
1496 void f() {
1497 ClassWithPtr x;
1498 x[[.]]^;
1499 }
1500 )cpp");
1501 auto Results =
1502 completions(Server, TestCode.code(), TestCode.point(), {}, Opts);
1503 EXPECT_EQ(Results.Completions.size(), 3u);
1504
1505 TextEdit ReplacementEdit;
1506 ReplacementEdit.range = TestCode.range();
1507 ReplacementEdit.newText = "->";
1508 for (const auto &C : Results.Completions) {
1509 EXPECT_TRUE(C.FixIts.empty() || C.Name == "AuxFunction");
1510 if (!C.FixIts.empty()) {
1511 EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit));
1512 }
1513 }
1514}
1515
Kadir Cetinkayaa9c9d002018-08-13 08:23:01 +00001516TEST(CompletionTest, RenderWithFixItMerged) {
1517 TextEdit FixIt;
1518 FixIt.range.end.character = 5;
1519 FixIt.newText = "->";
1520
1521 CodeCompletion C;
1522 C.Name = "x";
1523 C.RequiredQualifier = "Foo::";
1524 C.FixIts = {FixIt};
1525 C.CompletionTokenRange.start.character = 5;
1526
1527 CodeCompleteOptions Opts;
1528 Opts.IncludeFixIts = true;
1529
1530 auto R = C.render(Opts);
1531 EXPECT_TRUE(R.textEdit);
1532 EXPECT_EQ(R.textEdit->newText, "->Foo::x");
1533 EXPECT_TRUE(R.additionalTextEdits.empty());
1534}
1535
1536TEST(CompletionTest, RenderWithFixItNonMerged) {
1537 TextEdit FixIt;
1538 FixIt.range.end.character = 4;
1539 FixIt.newText = "->";
1540
1541 CodeCompletion C;
1542 C.Name = "x";
1543 C.RequiredQualifier = "Foo::";
1544 C.FixIts = {FixIt};
1545 C.CompletionTokenRange.start.character = 5;
1546
1547 CodeCompleteOptions Opts;
1548 Opts.IncludeFixIts = true;
1549
1550 auto R = C.render(Opts);
1551 EXPECT_TRUE(R.textEdit);
1552 EXPECT_EQ(R.textEdit->newText, "Foo::x");
1553 EXPECT_THAT(R.additionalTextEdits, UnorderedElementsAre(FixIt));
1554}
1555
1556TEST(CompletionTest, CompletionTokenRange) {
1557 MockFSProvider FS;
1558 MockCompilationDatabase CDB;
1559 IgnoreDiagnostics DiagConsumer;
1560 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1561
1562 constexpr const char *TestCodes[] = {
1563 R"cpp(
1564 class Auxilary {
1565 public:
1566 void AuxFunction();
1567 };
1568 void f() {
1569 Auxilary x;
1570 x.[[Aux]]^;
1571 }
1572 )cpp",
1573 R"cpp(
1574 class Auxilary {
1575 public:
1576 void AuxFunction();
1577 };
1578 void f() {
1579 Auxilary x;
1580 x.[[]]^;
1581 }
1582 )cpp"};
1583 for (const auto &Text : TestCodes) {
1584 Annotations TestCode(Text);
1585 auto Results = completions(Server, TestCode.code(), TestCode.point());
1586
1587 EXPECT_EQ(Results.Completions.size(), 1u);
1588 EXPECT_THAT(Results.Completions.front().CompletionTokenRange, TestCode.range());
1589 }
1590}
1591
Kadir Cetinkayae486e372018-08-13 08:40:05 +00001592TEST(SignatureHelpTest, OverloadsOrdering) {
1593 const auto Results = signatures(R"cpp(
1594 void foo(int x);
1595 void foo(int x, float y);
1596 void foo(float x, int y);
1597 void foo(float x, float y);
1598 void foo(int x, int y = 0);
1599 int main() { foo(^); }
1600 )cpp");
1601 EXPECT_THAT(
1602 Results.signatures,
1603 ElementsAre(
1604 Sig("foo(int x) -> void", {"int x"}),
1605 Sig("foo(int x, int y = 0) -> void", {"int x", "int y = 0"}),
1606 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
1607 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
1608 Sig("foo(float x, float y) -> void", {"float x", "float y"})));
1609 // We always prefer the first signature.
1610 EXPECT_EQ(0, Results.activeSignature);
1611 EXPECT_EQ(0, Results.activeParameter);
1612}
1613
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001614TEST(SignatureHelpTest, InstantiatedSignatures) {
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001615 StringRef Sig0 = R"cpp(
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001616 template <class T>
1617 void foo(T, T, T);
1618
1619 int main() {
1620 foo<int>(^);
1621 }
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001622 )cpp";
1623
1624 EXPECT_THAT(signatures(Sig0).signatures,
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001625 ElementsAre(Sig("foo(T, T, T) -> void", {"T", "T", "T"})));
1626
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001627 StringRef Sig1 = R"cpp(
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001628 template <class T>
1629 void foo(T, T, T);
1630
1631 int main() {
1632 foo(10, ^);
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001633 })cpp";
1634
1635 EXPECT_THAT(signatures(Sig1).signatures,
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001636 ElementsAre(Sig("foo(T, T, T) -> void", {"T", "T", "T"})));
1637
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001638 StringRef Sig2 = R"cpp(
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001639 template <class ...T>
1640 void foo(T...);
1641
1642 int main() {
1643 foo<int>(^);
1644 }
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001645 )cpp";
1646
1647 EXPECT_THAT(signatures(Sig2).signatures,
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001648 ElementsAre(Sig("foo(T...) -> void", {"T..."})));
1649
1650 // It is debatable whether we should substitute the outer template parameter
1651 // ('T') in that case. Currently we don't substitute it in signature help, but
1652 // do substitute in code complete.
1653 // FIXME: make code complete and signature help consistent, figure out which
1654 // way is better.
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001655 StringRef Sig3 = R"cpp(
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001656 template <class T>
1657 struct X {
1658 template <class U>
1659 void foo(T, U);
1660 };
1661
1662 int main() {
1663 X<int>().foo<double>(^)
1664 }
Simon Pilgrim83552ee2018-08-16 11:41:19 +00001665 )cpp";
1666
1667 EXPECT_THAT(signatures(Sig3).signatures,
Ilya Biryukov8fd44bb2018-08-14 09:36:32 +00001668 ElementsAre(Sig("foo(T, U) -> void", {"T", "U"})));
1669}
1670
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001671TEST(SignatureHelpTest, IndexDocumentation) {
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001672 Symbol Foo0 = sym("foo", index::SymbolKind::Function, "@F@\\0#");
Sam McCall2e5700f2018-08-31 13:55:01 +00001673 Foo0.Documentation = "Doc from the index";
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001674 Symbol Foo1 = sym("foo", index::SymbolKind::Function, "@F@\\0#I#");
Sam McCall2e5700f2018-08-31 13:55:01 +00001675 Foo1.Documentation = "Doc from the index";
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001676 Symbol Foo2 = sym("foo", index::SymbolKind::Function, "@F@\\0#I#I#");
1677
Simon Pilgrim24d34922018-08-17 10:40:05 +00001678 StringRef Sig0 = R"cpp(
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001679 int foo();
1680 int foo(double);
1681
1682 void test() {
1683 foo(^);
1684 }
Simon Pilgrim24d34922018-08-17 10:40:05 +00001685 )cpp";
1686
1687 EXPECT_THAT(
1688 signatures(Sig0, {Foo0}).signatures,
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001689 ElementsAre(AllOf(Sig("foo() -> int", {}), SigDoc("Doc from the index")),
1690 AllOf(Sig("foo(double) -> int", {"double"}), SigDoc(""))));
1691
Simon Pilgrim24d34922018-08-17 10:40:05 +00001692 StringRef Sig1 = R"cpp(
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001693 int foo();
1694 // Overriden doc from sema
1695 int foo(int);
1696 // Doc from sema
1697 int foo(int, int);
1698
1699 void test() {
1700 foo(^);
1701 }
Simon Pilgrim24d34922018-08-17 10:40:05 +00001702 )cpp";
1703
1704 EXPECT_THAT(
1705 signatures(Sig1, {Foo0, Foo1, Foo2}).signatures,
Ilya Biryukov8a0f76b2018-08-17 09:32:30 +00001706 ElementsAre(AllOf(Sig("foo() -> int", {}), SigDoc("Doc from the index")),
1707 AllOf(Sig("foo(int) -> int", {"int"}),
1708 SigDoc("Overriden doc from sema")),
1709 AllOf(Sig("foo(int, int) -> int", {"int", "int"}),
1710 SigDoc("Doc from sema"))));
1711}
1712
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001713TEST(CompletionTest, CompletionFunctionArgsDisabled) {
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001714 CodeCompleteOptions Opts;
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001715 Opts.EnableSnippets = true;
1716 Opts.EnableFunctionArgSnippets = false;
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001717 const std::string Header =
1718 R"cpp(
1719 void xfoo();
1720 void xfoo(int x, int y);
1721 void xbar();
1722 void f() {
1723 )cpp";
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001724 {
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001725 auto Results = completions(Header + "\nxfo^", {}, Opts);
1726 EXPECT_THAT(
1727 Results.Completions,
1728 UnorderedElementsAre(AllOf(Named("xfoo"), SnippetSuffix("()")),
1729 AllOf(Named("xfoo"), SnippetSuffix("($0)"))));
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001730 }
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001731 {
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001732 auto Results = completions(Header + "\nxba^", {}, Opts);
1733 EXPECT_THAT(Results.Completions, UnorderedElementsAre(AllOf(
1734 Named("xbar"), SnippetSuffix("()"))));
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001735 }
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001736 {
Kadir Cetinkaya516fcda2018-08-23 12:19:39 +00001737 Opts.BundleOverloads = true;
1738 auto Results = completions(Header + "\nxfo^", {}, Opts);
1739 EXPECT_THAT(
1740 Results.Completions,
1741 UnorderedElementsAre(AllOf(Named("xfoo"), SnippetSuffix("($0)"))));
Kadir Cetinkaya6c9f15c2018-08-17 15:42:54 +00001742 }
1743}
1744
Kadir Cetinkayaf8b85a32018-08-23 13:14:50 +00001745TEST(CompletionTest, SuggestOverrides) {
1746 constexpr const char *const Text(R"cpp(
1747 class A {
1748 public:
1749 virtual void vfunc(bool param);
1750 virtual void vfunc(bool param, int p);
1751 void func(bool param);
1752 };
1753 class B : public A {
1754 virtual void ttt(bool param) const;
1755 void vfunc(bool param, int p) override;
1756 };
1757 class C : public B {
1758 public:
1759 void vfunc(bool param) override;
1760 ^
1761 };
1762 )cpp");
1763 const auto Results = completions(Text);
1764 EXPECT_THAT(Results.Completions,
1765 AllOf(Contains(Labeled("void vfunc(bool param, int p) override")),
1766 Contains(Labeled("void ttt(bool param) const override")),
1767 Not(Contains(Labeled("void vfunc(bool param) override")))));
1768}
1769
Ilya Biryukov5a79d1e2018-09-03 15:25:27 +00001770TEST(CompletionTest, OverridesNonIdentName) {
1771 // Check the completions call does not crash.
1772 completions(R"cpp(
1773 struct Base {
1774 virtual ~Base() = 0;
1775 virtual operator int() = 0;
1776 virtual Base& operator+(Base&) = 0;
1777 };
1778
1779 struct Derived : Base {
1780 ^
1781 };
1782 )cpp");
1783}
1784
Eric Liu25d74e92018-08-24 11:23:56 +00001785TEST(SpeculateCompletionFilter, Filters) {
1786 Annotations F(R"cpp($bof^
1787 $bol^
1788 ab$ab^
1789 x.ab$dot^
1790 x.$dotempty^
1791 x::ab$scoped^
1792 x::$scopedempty^
1793
1794 )cpp");
1795 auto speculate = [&](StringRef PointName) {
1796 auto Filter = speculateCompletionFilter(F.code(), F.point(PointName));
1797 assert(Filter);
1798 return *Filter;
1799 };
1800 EXPECT_EQ(speculate("bof"), "");
1801 EXPECT_EQ(speculate("bol"), "");
1802 EXPECT_EQ(speculate("ab"), "ab");
1803 EXPECT_EQ(speculate("dot"), "ab");
1804 EXPECT_EQ(speculate("dotempty"), "");
1805 EXPECT_EQ(speculate("scoped"), "ab");
1806 EXPECT_EQ(speculate("scopedempty"), "");
1807}
1808
1809TEST(CompletionTest, EnableSpeculativeIndexRequest) {
1810 MockFSProvider FS;
1811 MockCompilationDatabase CDB;
1812 IgnoreDiagnostics DiagConsumer;
1813 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1814
1815 auto File = testPath("foo.cpp");
1816 Annotations Test(R"cpp(
1817 namespace ns1 { int abc; }
1818 namespace ns2 { int abc; }
1819 void f() { ns1::ab$1^; ns1::ab$2^; }
1820 void f() { ns2::ab$3^; }
1821 )cpp");
1822 runAddDocument(Server, File, Test.code());
1823 clangd::CodeCompleteOptions Opts = {};
1824
1825 IndexRequestCollector Requests;
1826 Opts.Index = &Requests;
1827 Opts.SpeculativeIndexRequest = true;
1828
1829 auto CompleteAtPoint = [&](StringRef P) {
1830 cantFail(runCodeComplete(Server, File, Test.point(P), Opts));
1831 // Sleep for a while to make sure asynchronous call (if applicable) is also
1832 // triggered before callback is invoked.
1833 std::this_thread::sleep_for(std::chrono::milliseconds(100));
1834 };
1835
1836 CompleteAtPoint("1");
1837 auto Reqs1 = Requests.consumeRequests();
1838 ASSERT_EQ(Reqs1.size(), 1u);
1839 EXPECT_THAT(Reqs1[0].Scopes, UnorderedElementsAre("ns1::"));
1840
1841 CompleteAtPoint("2");
1842 auto Reqs2 = Requests.consumeRequests();
1843 // Speculation succeeded. Used speculative index result.
1844 ASSERT_EQ(Reqs2.size(), 1u);
1845 EXPECT_EQ(Reqs2[0], Reqs1[0]);
1846
1847 CompleteAtPoint("3");
1848 // Speculation failed. Sent speculative index request and the new index
1849 // request after sema.
1850 auto Reqs3 = Requests.consumeRequests();
1851 ASSERT_EQ(Reqs3.size(), 2u);
1852}
1853
Eric Liu83f63e42018-09-03 10:18:21 +00001854TEST(CompletionTest, InsertTheMostPopularHeader) {
1855 std::string DeclFile = URI::createFile(testPath("foo")).toString();
1856 Symbol sym = func("Func");
1857 sym.CanonicalDeclaration.FileURI = DeclFile;
1858 sym.IncludeHeaders.emplace_back("\"foo.h\"", 2);
1859 sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000);
1860
1861 auto Results = completions("Fun^", {sym}).Completions;
1862 assert(!Results.empty());
1863 EXPECT_THAT(Results[0], AllOf(Named("Func"), InsertInclude("\"bar.h\"")));
1864 EXPECT_EQ(Results[0].Includes.size(), 2u);
1865}
1866
1867TEST(CompletionTest, NoInsertIncludeIfOnePresent) {
1868 MockFSProvider FS;
1869 MockCompilationDatabase CDB;
1870
1871 std::string FooHeader = testPath("foo.h");
1872 FS.Files[FooHeader] = "";
1873
1874 IgnoreDiagnostics DiagConsumer;
1875 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1876
1877 std::string DeclFile = URI::createFile(testPath("foo")).toString();
1878 Symbol sym = func("Func");
1879 sym.CanonicalDeclaration.FileURI = DeclFile;
1880 sym.IncludeHeaders.emplace_back("\"foo.h\"", 2);
1881 sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000);
1882
1883 EXPECT_THAT(
1884 completions(Server, "#include \"foo.h\"\nFun^", {sym}).Completions,
1885 UnorderedElementsAre(
1886 AllOf(Named("Func"), HasInclude("\"foo.h\""), Not(InsertInclude()))));
1887}
1888
Eric Liud25f1212018-09-06 09:59:37 +00001889TEST(CompletionTest, MergeMacrosFromIndexAndSema) {
1890 Symbol Sym;
1891 Sym.Name = "Clangd_Macro_Test";
1892 Sym.ID = SymbolID("c:foo.cpp@8@macro@Clangd_Macro_Test");
1893 Sym.SymInfo.Kind = index::SymbolKind::Macro;
1894 Sym.IsIndexedForCodeCompletion = true;
1895 EXPECT_THAT(completions("#define Clangd_Macro_Test\nClangd_Macro_T^", {Sym})
1896 .Completions,
1897 UnorderedElementsAre(Named("Clangd_Macro_Test")));
1898}
1899
Sam McCall9aad25f2017-12-05 07:20:26 +00001900} // namespace
1901} // namespace clangd
1902} // namespace clang