blob: 2fd8588543aeeebf7982d783c7894817d15717b9 [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 McCallb536a2a2017-12-19 12:23:48 +000016#include "SourceCode.h"
Ilya Biryukovcd5eb002018-02-12 11:37:28 +000017#include "SyncAPI.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000018#include "TestFS.h"
Eric Liu6f648df2017-12-19 16:50:37 +000019#include "index/MemIndex.h"
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +000020#include "llvm/Support/Error.h"
Ilya Biryukov981a35d2018-05-28 12:11:37 +000021#include "llvm/Testing/Support/Error.h"
Sam McCallf6ae3232017-12-05 20:11:29 +000022#include "gmock/gmock.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000023#include "gtest/gtest.h"
24
25namespace clang {
26namespace clangd {
Sam McCallf6ae3232017-12-05 20:11:29 +000027
Sam McCall9aad25f2017-12-05 07:20:26 +000028namespace {
29using namespace llvm;
Sam McCallf6ae3232017-12-05 20:11:29 +000030using ::testing::AllOf;
31using ::testing::Contains;
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000032using ::testing::Each;
Sam McCallf6ae3232017-12-05 20:11:29 +000033using ::testing::ElementsAre;
Ilya Biryukov71028b82018-03-12 15:28:22 +000034using ::testing::Field;
Sam McCallf6ae3232017-12-05 20:11:29 +000035using ::testing::Not;
Sam McCall3d139c52018-01-12 18:30:08 +000036using ::testing::UnorderedElementsAre;
Sam McCall9aad25f2017-12-05 07:20:26 +000037
38class IgnoreDiagnostics : public DiagnosticsConsumer {
Ilya Biryukov71028b82018-03-12 15:28:22 +000039 void onDiagnosticsReady(PathRef File,
Sam McCalla7bb0cc2018-03-12 23:22:35 +000040 std::vector<Diag> Diagnostics) override {}
Sam McCall9aad25f2017-12-05 07:20:26 +000041};
42
Sam McCallf6ae3232017-12-05 20:11:29 +000043// GMock helpers for matching completion items.
44MATCHER_P(Named, Name, "") { return arg.insertText == Name; }
Sam McCall44fdcec22017-12-08 15:00:59 +000045MATCHER_P(Labeled, Label, "") { return arg.label == Label; }
46MATCHER_P(Kind, K, "") { return arg.kind == K; }
Eric Liu6f648df2017-12-19 16:50:37 +000047MATCHER_P(Filter, F, "") { return arg.filterText == F; }
Eric Liu76f6b442018-01-09 17:32:00 +000048MATCHER_P(Doc, D, "") { return arg.documentation == D; }
49MATCHER_P(Detail, D, "") { return arg.detail == D; }
Eric Liu63f419a2018-05-15 15:29:32 +000050MATCHER_P(InsertInclude, IncludeHeader, "") {
51 if (arg.additionalTextEdits.size() != 1)
52 return false;
53 const auto &Edit = arg.additionalTextEdits[0];
54 if (Edit.range.start != Edit.range.end)
55 return false;
56 SmallVector<StringRef, 2> Matches;
57 llvm::Regex RE(R"(#include[ ]*(["<][^">]*[">]))");
58 return RE.match(Edit.newText, &Matches) && Matches[1] == IncludeHeader;
59}
Sam McCall44fdcec22017-12-08 15:00:59 +000060MATCHER_P(PlainText, Text, "") {
61 return arg.insertTextFormat == clangd::InsertTextFormat::PlainText &&
62 arg.insertText == Text;
63}
64MATCHER_P(Snippet, Text, "") {
65 return arg.insertTextFormat == clangd::InsertTextFormat::Snippet &&
66 arg.insertText == Text;
67}
Sam McCall545a20d2018-01-19 14:34:02 +000068MATCHER(NameContainsFilter, "") {
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000069 if (arg.filterText.empty())
70 return true;
71 return llvm::StringRef(arg.insertText).contains(arg.filterText);
72}
Eric Liu63f419a2018-05-15 15:29:32 +000073MATCHER(HasAdditionalEdits, "") { return !arg.additionalTextEdits.empty(); }
74
Sam McCallf6ae3232017-12-05 20:11:29 +000075// Shorthand for Contains(Named(Name)).
76Matcher<const std::vector<CompletionItem> &> Has(std::string Name) {
77 return Contains(Named(std::move(Name)));
78}
Sam McCall44fdcec22017-12-08 15:00:59 +000079Matcher<const std::vector<CompletionItem> &> Has(std::string Name,
80 CompletionItemKind K) {
81 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000082}
Sam McCall44fdcec22017-12-08 15:00:59 +000083MATCHER(IsDocumented, "") { return !arg.documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000084
Sam McCalla15c2d62018-01-18 09:27:56 +000085std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
86 SymbolSlab::Builder Slab;
87 for (const auto &Sym : Symbols)
88 Slab.insert(Sym);
89 return MemIndex::build(std::move(Slab).build());
90}
91
Eric Liu63f419a2018-05-15 15:29:32 +000092CompletionList completions(ClangdServer &Server, StringRef Text,
Sam McCalla15c2d62018-01-18 09:27:56 +000093 std::vector<Symbol> IndexSymbols = {},
Sam McCallf6ae3232017-12-05 20:11:29 +000094 clangd::CodeCompleteOptions Opts = {}) {
Sam McCalla15c2d62018-01-18 09:27:56 +000095 std::unique_ptr<SymbolIndex> OverrideIndex;
96 if (!IndexSymbols.empty()) {
97 assert(!Opts.Index && "both Index and IndexSymbols given!");
98 OverrideIndex = memIndex(std::move(IndexSymbols));
99 Opts.Index = OverrideIndex.get();
100 }
101
Sam McCallc1568062018-02-16 09:41:43 +0000102 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000103 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000104 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000105 auto CompletionList =
106 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000107 // Sanity-check that filterText is valid.
Sam McCall545a20d2018-01-19 14:34:02 +0000108 EXPECT_THAT(CompletionList.items, Each(NameContainsFilter()));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000109 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +0000110}
111
Eric Liu63f419a2018-05-15 15:29:32 +0000112// Builds a server and runs code completion.
113// If IndexSymbols is non-empty, an index will be built and passed to opts.
114CompletionList completions(StringRef Text,
115 std::vector<Symbol> IndexSymbols = {},
116 clangd::CodeCompleteOptions Opts = {}) {
117 MockFSProvider FS;
118 MockCompilationDatabase CDB;
119 IgnoreDiagnostics DiagConsumer;
120 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
121 return completions(Server, Text, std::move(IndexSymbols), std::move(Opts));
122}
123
Sam McCall545a20d2018-01-19 14:34:02 +0000124std::string replace(StringRef Haystack, StringRef Needle, StringRef Repl) {
125 std::string Result;
126 raw_string_ostream OS(Result);
127 std::pair<StringRef, StringRef> Split;
128 for (Split = Haystack.split(Needle); !Split.second.empty();
129 Split = Split.first.split(Needle))
130 OS << Split.first << Repl;
131 Result += Split.first;
132 OS.flush();
133 return Result;
134}
135
Sam McCalla15c2d62018-01-18 09:27:56 +0000136// Helpers to produce fake index symbols for memIndex() or completions().
Sam McCall545a20d2018-01-19 14:34:02 +0000137// USRFormat is a regex replacement string for the unqualified part of the USR.
138Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000139 Symbol Sym;
Sam McCall545a20d2018-01-19 14:34:02 +0000140 std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
Sam McCalla15c2d62018-01-18 09:27:56 +0000141 size_t Pos = QName.rfind("::");
142 if (Pos == llvm::StringRef::npos) {
143 Sym.Name = QName;
144 Sym.Scope = "";
145 } else {
146 Sym.Name = QName.substr(Pos + 2);
Sam McCall8b2faee2018-01-19 22:18:21 +0000147 Sym.Scope = QName.substr(0, Pos + 2);
148 USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
Sam McCalla15c2d62018-01-18 09:27:56 +0000149 }
Sam McCall545a20d2018-01-19 14:34:02 +0000150 USR += Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
151 Sym.ID = SymbolID(USR);
Sam McCalla15c2d62018-01-18 09:27:56 +0000152 Sym.CompletionPlainInsertText = Sym.Name;
Sam McCall545a20d2018-01-19 14:34:02 +0000153 Sym.CompletionSnippetInsertText = Sym.Name;
Sam McCalla15c2d62018-01-18 09:27:56 +0000154 Sym.CompletionLabel = Sym.Name;
155 Sym.SymInfo.Kind = Kind;
156 return Sym;
157}
Sam McCall545a20d2018-01-19 14:34:02 +0000158Symbol func(StringRef Name) { // Assumes the function has no args.
159 return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
160}
161Symbol cls(StringRef Name) {
Eric Liu9b3cba72018-05-30 09:03:39 +0000162 return sym(Name, index::SymbolKind::Class, "@S@\\0");
Sam McCall545a20d2018-01-19 14:34:02 +0000163}
164Symbol var(StringRef Name) {
165 return sym(Name, index::SymbolKind::Variable, "@\\0");
166}
Sam McCalldc8abc42018-05-03 14:53:02 +0000167Symbol ns(StringRef Name) {
168 return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
169}
170Symbol withReferences(int N, Symbol S) {
171 S.References = N;
172 return S;
173}
Sam McCalla15c2d62018-01-18 09:27:56 +0000174
Sam McCallf6ae3232017-12-05 20:11:29 +0000175TEST(CompletionTest, Limit) {
176 clangd::CodeCompleteOptions Opts;
177 Opts.Limit = 2;
178 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000179struct ClassWithMembers {
180 int AAA();
181 int BBB();
182 int CCC();
183}
Sam McCallf6ae3232017-12-05 20:11:29 +0000184int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000185 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000186 /*IndexSymbols=*/{}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000187
188 EXPECT_TRUE(Results.isIncomplete);
Sam McCallf6ae3232017-12-05 20:11:29 +0000189 EXPECT_THAT(Results.items, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000190}
191
Sam McCallf6ae3232017-12-05 20:11:29 +0000192TEST(CompletionTest, Filter) {
193 std::string Body = R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000194 int Abracadabra;
195 int Alakazam;
196 struct S {
197 int FooBar;
198 int FooBaz;
199 int Qux;
200 };
201 )cpp";
Sam McCallf6ae3232017-12-05 20:11:29 +0000202 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").items,
203 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000204
Sam McCallf6ae3232017-12-05 20:11:29 +0000205 EXPECT_THAT(completions(Body + "int main() { S().FR^ }").items,
206 AllOf(Has("FooBar"), Not(Has("FooBaz")), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000207
Sam McCallf6ae3232017-12-05 20:11:29 +0000208 EXPECT_THAT(completions(Body + "int main() { S().opr^ }").items,
209 Has("operator="));
Sam McCall9aad25f2017-12-05 07:20:26 +0000210
Sam McCallf6ae3232017-12-05 20:11:29 +0000211 EXPECT_THAT(completions(Body + "int main() { aaa^ }").items,
212 AllOf(Has("Abracadabra"), Has("Alakazam")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000213
Sam McCallf6ae3232017-12-05 20:11:29 +0000214 EXPECT_THAT(completions(Body + "int main() { _a^ }").items,
215 AllOf(Has("static_cast"), Not(Has("Abracadabra"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000216}
217
Sam McCallf6ae3232017-12-05 20:11:29 +0000218void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000219 auto Results = completions(
220 R"cpp(
221 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000222
Sam McCall44fdcec22017-12-08 15:00:59 +0000223 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000224
Sam McCall44fdcec22017-12-08 15:00:59 +0000225 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000226
Sam McCall44fdcec22017-12-08 15:00:59 +0000227 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000228
Sam McCall44fdcec22017-12-08 15:00:59 +0000229 struct ClassWithMembers {
230 /// Doc for method.
231 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000232
Sam McCall44fdcec22017-12-08 15:00:59 +0000233 int field;
234 private:
235 int private_field;
236 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000237
Sam McCall44fdcec22017-12-08 15:00:59 +0000238 int test() {
239 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000240
Sam McCall44fdcec22017-12-08 15:00:59 +0000241 /// Doc for local_var.
242 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000243
Sam McCall44fdcec22017-12-08 15:00:59 +0000244 ClassWithMembers().^
245 }
246 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000247 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000248
Sam McCallf6ae3232017-12-05 20:11:29 +0000249 // Class members. The only items that must be present in after-dot
250 // completion.
Sam McCall44fdcec22017-12-08 15:00:59 +0000251 EXPECT_THAT(
252 Results.items,
253 AllOf(Has(Opts.EnableSnippets ? "method()" : "method"), Has("field")));
254 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.items,
255 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000256 // Global items.
Sam McCall545a20d2018-01-19 14:34:02 +0000257 EXPECT_THAT(
258 Results.items,
259 Not(AnyOf(Has("global_var"), Has("index_var"), Has("global_func"),
260 Has("global_func()"), Has("index_func"), Has("GlobalClass"),
261 Has("IndexClass"), Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000262 // There should be no code patterns (aka snippets) in after-dot
263 // completion. At least there aren't any we're aware of.
Sam McCall44fdcec22017-12-08 15:00:59 +0000264 EXPECT_THAT(Results.items, Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000265 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000266 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000267}
Sam McCall9aad25f2017-12-05 07:20:26 +0000268
Sam McCallf6ae3232017-12-05 20:11:29 +0000269void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000270 auto Results = completions(
271 R"cpp(
272 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000273
Sam McCall44fdcec22017-12-08 15:00:59 +0000274 int global_var;
275 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000276
Sam McCall44fdcec22017-12-08 15:00:59 +0000277 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000278
Sam McCall44fdcec22017-12-08 15:00:59 +0000279 struct ClassWithMembers {
280 /// Doc for method.
281 int method();
282 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000283
Sam McCall44fdcec22017-12-08 15:00:59 +0000284 int test() {
285 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000286
Sam McCall44fdcec22017-12-08 15:00:59 +0000287 /// Doc for local_var.
288 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000289
Sam McCall44fdcec22017-12-08 15:00:59 +0000290 ^
291 }
292 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000293 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000294
295 // Class members. Should never be present in global completions.
Sam McCall44fdcec22017-12-08 15:00:59 +0000296 EXPECT_THAT(Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000297 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
298 // Global items.
Sam McCalld8169a82018-01-18 15:31:30 +0000299 EXPECT_THAT(Results.items,
Sam McCall545a20d2018-01-19 14:34:02 +0000300 AllOf(Has("global_var"), Has("index_var"),
Sam McCalld8169a82018-01-18 15:31:30 +0000301 Has(Opts.EnableSnippets ? "global_func()" : "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 McCall44fdcec22017-12-08 15:00:59 +0000305 EXPECT_IFF(Opts.IncludeMacros, Results.items, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000306 // Local items. Must be present always.
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000307 EXPECT_THAT(Results.items,
308 AllOf(Has("local_var"), Has("LocalClass"),
309 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000310 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000311 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000312}
313
314TEST(CompletionTest, CompletionOptions) {
Sam McCall2c3849a2018-01-16 12:21:24 +0000315 auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
316 TestAfterDotCompletion(Opts);
317 TestGlobalScopeCompletion(Opts);
318 };
319 // We used to test every combination of options, but that got too slow (2^N).
320 auto Flags = {
Ilya Biryukov71028b82018-03-12 15:28:22 +0000321 &clangd::CodeCompleteOptions::IncludeMacros,
Ilya Biryukov43714502018-05-16 12:32:44 +0000322 &clangd::CodeCompleteOptions::IncludeComments,
Ilya Biryukov71028b82018-03-12 15:28:22 +0000323 &clangd::CodeCompleteOptions::EnableSnippets,
324 &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");
346 EXPECT_THAT(Internal.items,
347 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");
360 EXPECT_THAT(External.items,
361 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");
375 EXPECT_THAT(Results.items, HasSubsequence(Labeled("bar() const"),
376 Labeled("Foo::foo() const")));
377 EXPECT_THAT(Results.items, Not(Contains(Labeled("foo() const")))); // private
378}
379
380TEST(CompletionTest, Snippets) {
381 clangd::CodeCompleteOptions Opts;
382 Opts.EnableSnippets = true;
383 auto Results = completions(
384 R"cpp(
385 struct fake {
386 int a;
387 int f(int i, const float f) const;
388 };
389 int main() {
390 fake f;
391 f.^
392 }
393 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000394 /*IndexSymbols=*/{}, Opts);
Sam McCall44fdcec22017-12-08 15:00:59 +0000395 EXPECT_THAT(Results.items,
Eric Liu63696e12017-12-20 17:24:31 +0000396 HasSubsequence(Snippet("a"),
Sam McCall44fdcec22017-12-08 15:00:59 +0000397 Snippet("f(${1:int i}, ${2:const float f})")));
398}
399
400TEST(CompletionTest, Kinds) {
Sam McCall545a20d2018-01-19 14:34:02 +0000401 auto Results = completions(
402 R"cpp(
403 #define MACRO X
404 int variable;
405 struct Struct {};
406 int function();
407 int X = ^
408 )cpp",
409 {func("indexFunction"), var("indexVariable"), cls("indexClass")});
410 EXPECT_THAT(Results.items,
411 AllOf(Has("function", CompletionItemKind::Function),
412 Has("variable", CompletionItemKind::Variable),
413 Has("int", CompletionItemKind::Keyword),
414 Has("Struct", CompletionItemKind::Class),
415 Has("MACRO", CompletionItemKind::Text),
416 Has("indexFunction", CompletionItemKind::Function),
417 Has("indexVariable", CompletionItemKind::Variable),
418 Has("indexClass", CompletionItemKind::Class)));
Sam McCall44fdcec22017-12-08 15:00:59 +0000419
Sam McCall44fdcec22017-12-08 15:00:59 +0000420 Results = completions("nam^");
421 EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
422}
423
Sam McCall84652cc2018-01-12 16:16:09 +0000424TEST(CompletionTest, NoDuplicates) {
Sam McCall545a20d2018-01-19 14:34:02 +0000425 auto Results = completions(
426 R"cpp(
427 class Adapter {
Sam McCall545a20d2018-01-19 14:34:02 +0000428 };
Sam McCall84652cc2018-01-12 16:16:09 +0000429
Eric Liu9b3cba72018-05-30 09:03:39 +0000430 void f() {
Sam McCall545a20d2018-01-19 14:34:02 +0000431 Adapter^
432 }
433 )cpp",
434 {cls("Adapter")});
Sam McCall84652cc2018-01-12 16:16:09 +0000435
436 // Make sure there are no duplicate entries of 'Adapter'.
Sam McCalld2a95922018-01-22 21:05:00 +0000437 EXPECT_THAT(Results.items, ElementsAre(Named("Adapter")));
Sam McCall84652cc2018-01-12 16:16:09 +0000438}
439
Sam McCall545a20d2018-01-19 14:34:02 +0000440TEST(CompletionTest, ScopedNoIndex) {
441 auto Results = completions(
442 R"cpp(
443 namespace fake { int BigBang, Babble, Ball; };
444 int main() { fake::bb^ }
445 ")cpp");
Sam McCall84652cc2018-01-12 16:16:09 +0000446 // BigBang is a better match than Babble. Ball doesn't match at all.
Sam McCall545a20d2018-01-19 14:34:02 +0000447 EXPECT_THAT(Results.items, ElementsAre(Named("BigBang"), Named("Babble")));
Sam McCall84652cc2018-01-12 16:16:09 +0000448}
449
Sam McCall545a20d2018-01-19 14:34:02 +0000450TEST(CompletionTest, Scoped) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000451 auto Results = completions(
452 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000453 namespace fake { int Babble, Ball; };
454 int main() { fake::bb^ }
455 ")cpp",
456 {var("fake::BigBang")});
457 EXPECT_THAT(Results.items, ElementsAre(Named("BigBang"), Named("Babble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000458}
459
Sam McCall545a20d2018-01-19 14:34:02 +0000460TEST(CompletionTest, ScopedWithFilter) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000461 auto Results = completions(
462 R"cpp(
463 void f() { ns::x^ }
464 )cpp",
465 {cls("ns::XYZ"), func("ns::foo")});
466 EXPECT_THAT(Results.items,
467 UnorderedElementsAre(AllOf(Named("XYZ"), Filter("XYZ"))));
468}
469
Sam McCalldc8abc42018-05-03 14:53:02 +0000470TEST(CompletionTest, ReferencesAffectRanking) {
471 auto Results = completions("int main() { abs^ }", {ns("absl"), func("abs")});
472 EXPECT_THAT(Results.items, HasSubsequence(Named("abs"), Named("absl")));
473 Results = completions("int main() { abs^ }",
474 {withReferences(10000, ns("absl")), func("abs")});
475 EXPECT_THAT(Results.items, HasSubsequence(Named("absl"), Named("abs")));
476}
477
Sam McCall545a20d2018-01-19 14:34:02 +0000478TEST(CompletionTest, GlobalQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000479 auto Results = completions(
480 R"cpp(
481 void f() { ::^ }
482 )cpp",
483 {cls("XYZ")});
484 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
485 Has("f", CompletionItemKind::Function)));
486}
487
Sam McCall545a20d2018-01-19 14:34:02 +0000488TEST(CompletionTest, FullyQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000489 auto Results = completions(
490 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000491 namespace ns { void bar(); }
Sam McCalla15c2d62018-01-18 09:27:56 +0000492 void f() { ::ns::^ }
493 )cpp",
494 {cls("ns::XYZ")});
Sam McCall545a20d2018-01-19 14:34:02 +0000495 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
496 Has("bar", CompletionItemKind::Function)));
497}
498
499TEST(CompletionTest, SemaIndexMerge) {
500 auto Results = completions(
501 R"cpp(
502 namespace ns { int local; void both(); }
503 void f() { ::ns::^ }
504 )cpp",
505 {func("ns::both"), cls("ns::Index")});
506 // We get results from both index and sema, with no duplicates.
507 EXPECT_THAT(
508 Results.items,
509 UnorderedElementsAre(Named("local"), Named("Index"), Named("both")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000510}
511
Haojian Wu48b48652018-01-25 09:20:09 +0000512TEST(CompletionTest, SemaIndexMergeWithLimit) {
513 clangd::CodeCompleteOptions Opts;
514 Opts.Limit = 1;
515 auto Results = completions(
516 R"cpp(
517 namespace ns { int local; void both(); }
518 void f() { ::ns::^ }
519 )cpp",
520 {func("ns::both"), cls("ns::Index")}, Opts);
521 EXPECT_EQ(Results.items.size(), Opts.Limit);
522 EXPECT_TRUE(Results.isIncomplete);
523}
524
Eric Liu63f419a2018-05-15 15:29:32 +0000525TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
526 MockFSProvider FS;
527 MockCompilationDatabase CDB;
528 std::string Subdir = testPath("sub");
529 std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
530 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
531 std::string BarHeader = testPath("sub/bar.h");
532 FS.Files[BarHeader] = "";
533
534 IgnoreDiagnostics DiagConsumer;
535 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
536 Symbol::Details Scratch;
537 auto BarURI = URI::createFile(BarHeader).toString();
538 Symbol Sym = cls("ns::X");
539 Sym.CanonicalDeclaration.FileURI = BarURI;
540 Scratch.IncludeHeader = BarURI;
541 Sym.Detail = &Scratch;
542 // Shoten include path based on search dirctory and insert.
543 auto Results = completions(Server,
544 R"cpp(
545 int main() { ns::^ }
546 )cpp",
547 {Sym});
548 EXPECT_THAT(Results.items,
549 ElementsAre(AllOf(Named("X"), InsertInclude("\"bar.h\""))));
550 // Duplicate based on inclusions in preamble.
551 Results = completions(Server,
552 R"cpp(
553 #include "sub/bar.h" // not shortest, so should only match resolved.
554 int main() { ns::^ }
555 )cpp",
556 {Sym});
557 EXPECT_THAT(Results.items,
558 ElementsAre(AllOf(Named("X"), Not(HasAdditionalEdits()))));
559}
560
Eric Liu9b3cba72018-05-30 09:03:39 +0000561TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
562 MockFSProvider FS;
563 MockCompilationDatabase CDB;
564
565 IgnoreDiagnostics DiagConsumer;
566 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
567 Symbol::Details Scratch;
568 Symbol SymX = cls("ns::X");
569 Symbol SymY = cls("ns::Y");
570 std::string BarHeader = testPath("bar.h");
571 auto BarURI = URI::createFile(BarHeader).toString();
572 SymX.CanonicalDeclaration.FileURI = BarURI;
573 SymY.CanonicalDeclaration.FileURI = BarURI;
574 Scratch.IncludeHeader = "<bar>";
575 SymX.Detail = &Scratch;
576 SymY.Detail = &Scratch;
577 // Shoten include path based on search dirctory and insert.
578 auto Results = completions(Server,
579 R"cpp(
580 namespace ns {
581 class X;
582 class Y {}
583 }
584 int main() { ns::^ }
585 )cpp",
586 {SymX, SymY});
587 EXPECT_THAT(Results.items,
588 ElementsAre(AllOf(Named("X"), Not(HasAdditionalEdits())),
589 AllOf(Named("Y"), Not(HasAdditionalEdits()))));
590}
591
Sam McCalla15c2d62018-01-18 09:27:56 +0000592TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
593 MockFSProvider FS;
594 MockCompilationDatabase CDB;
595 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000596 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCalla15c2d62018-01-18 09:27:56 +0000597
Sam McCallc1568062018-02-16 09:41:43 +0000598 FS.Files[testPath("bar.h")] =
Sam McCalld5ea3e32018-01-24 17:53:32 +0000599 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
Sam McCallc1568062018-02-16 09:41:43 +0000600 auto File = testPath("foo.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000601 Annotations Test(R"cpp(
602 #include "bar.h"
603 namespace ns { int local; }
Sam McCalld5ea3e32018-01-24 17:53:32 +0000604 void f() { ns::^; }
605 void f() { ns::preamble().$2^; }
Sam McCalla15c2d62018-01-18 09:27:56 +0000606 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000607 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000608 clangd::CodeCompleteOptions Opts = {};
609
Sam McCalla15c2d62018-01-18 09:27:56 +0000610 auto I = memIndex({var("ns::index")});
611 Opts.Index = I.get();
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000612 auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalla15c2d62018-01-18 09:27:56 +0000613 EXPECT_THAT(WithIndex.items,
614 UnorderedElementsAre(Named("local"), Named("index")));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000615 auto ClassFromPreamble =
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000616 cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000617 EXPECT_THAT(ClassFromPreamble.items, Contains(Named("member")));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000618
619 Opts.Index = nullptr;
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000620 auto WithoutIndex =
621 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000622 EXPECT_THAT(WithoutIndex.items,
623 UnorderedElementsAre(Named("local"), Named("preamble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000624}
625
626TEST(CompletionTest, DynamicIndexMultiFile) {
627 MockFSProvider FS;
628 MockCompilationDatabase CDB;
629 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000630 auto Opts = ClangdServer::optsForTest();
631 Opts.BuildDynamicSymbolIndex = true;
632 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCalla15c2d62018-01-18 09:27:56 +0000633
Eric Liu709bde82018-02-19 18:48:44 +0000634 FS.Files[testPath("foo.h")] = R"cpp(
Sam McCalla15c2d62018-01-18 09:27:56 +0000635 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liu709bde82018-02-19 18:48:44 +0000636 )cpp";
Sam McCall7363a2f2018-03-05 17:28:54 +0000637 runAddDocument(Server, testPath("foo.cpp"), R"cpp(
Eric Liu709bde82018-02-19 18:48:44 +0000638 #include "foo.h"
Sam McCall0bb24cd2018-02-13 08:59:23 +0000639 )cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000640
Sam McCallc1568062018-02-16 09:41:43 +0000641 auto File = testPath("bar.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000642 Annotations Test(R"cpp(
643 namespace ns {
644 class XXX {};
645 /// Doooc
646 void fooooo() {}
647 }
648 void f() { ns::^ }
649 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000650 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000651
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000652 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
Sam McCalla15c2d62018-01-18 09:27:56 +0000653 // "XYZ" and "foo" are not included in the file being completed but are still
654 // visible through the index.
655 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
656 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
657 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
658 EXPECT_THAT(Results.items, Contains(AllOf(Named("fooooo"), Filter("fooooo"),
659 Kind(CompletionItemKind::Function),
660 Doc("Doooc"), Detail("void"))));
661}
662
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000663TEST(CompletionTest, Documentation) {
664 auto Results = completions(
665 R"cpp(
666 // Non-doxygen comment.
667 int foo();
668 /// Doxygen comment.
669 /// \param int a
670 int bar(int a);
671 /* Multi-line
672 block comment
673 */
674 int baz();
675
676 int x = ^
677 )cpp");
678 EXPECT_THAT(Results.items,
679 Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
680 EXPECT_THAT(
681 Results.items,
682 Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
683 EXPECT_THAT(Results.items,
684 Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
685}
686
Haojian Wu58d208d2018-01-25 09:44:06 +0000687TEST(CodeCompleteTest, DisableTypoCorrection) {
688 auto Results = completions(R"cpp(
689 namespace clang { int v; }
690 void f() { clangd::^
691 )cpp");
692 EXPECT_TRUE(Results.items.empty());
693}
694
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000695TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
696 auto Results = completions(R"cpp(
697 namespace clang { }
698 void f() {
699 clan^
700 }
701 )cpp");
702
703 EXPECT_THAT(Results.items, Contains(Labeled("clang")));
704 EXPECT_THAT(Results.items, Not(Contains(Labeled("clang::"))));
705}
706
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000707TEST(CompletionTest, BacktrackCrashes) {
708 // Sema calls code completion callbacks twice in these cases.
709 auto Results = completions(R"cpp(
710 namespace ns {
711 struct FooBarBaz {};
712 } // namespace ns
713
714 int foo(ns::FooBar^
715 )cpp");
716
717 EXPECT_THAT(Results.items, ElementsAre(Labeled("FooBarBaz")));
718
719 // Check we don't crash in that case too.
720 completions(R"cpp(
721 struct FooBarBaz {};
722 void test() {
723 if (FooBarBaz * x^) {}
724 }
725)cpp");
726}
727
Eric Liu42abe412018-05-24 11:20:19 +0000728TEST(CompletionTest, CompleteInMacroWithStringification) {
729 auto Results = completions(R"cpp(
730void f(const char *, int x);
731#define F(x) f(#x, x)
732
733namespace ns {
734int X;
735int Y;
736} // namespace ns
737
738int f(int input_num) {
739 F(ns::^)
740}
741)cpp");
742
743 EXPECT_THAT(Results.items,
744 UnorderedElementsAre(Named("X"), Named("Y")));
745}
746
747TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
748 auto Results = completions(R"cpp(
749void f(const char *, int x);
750#define F(x) f(#x, x)
751
752namespace ns {
753int X;
754
755int f(int input_num) {
756 F(^)
757}
758} // namespace ns
759)cpp");
760
761 EXPECT_THAT(Results.items, Contains(Named("X")));
762}
763
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000764TEST(CompletionTest, CompleteInExcludedPPBranch) {
765 auto Results = completions(R"cpp(
766 int bar(int param_in_bar) {
767 }
768
769 int foo(int param_in_foo) {
770#if 0
771 par^
772#endif
773 }
774)cpp");
775
776 EXPECT_THAT(Results.items, Contains(Labeled("param_in_foo")));
777 EXPECT_THAT(Results.items, Not(Contains(Labeled("param_in_bar"))));
778}
779
Sam McCall800d4372017-12-19 10:29:27 +0000780SignatureHelp signatures(StringRef Text) {
781 MockFSProvider FS;
782 MockCompilationDatabase CDB;
783 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000784 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCallc1568062018-02-16 09:41:43 +0000785 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000786 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000787 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000788 return cantFail(runSignatureHelp(Server, File, Test.point()));
Sam McCall800d4372017-12-19 10:29:27 +0000789}
790
791MATCHER_P(ParamsAre, P, "") {
792 if (P.size() != arg.parameters.size())
793 return false;
794 for (unsigned I = 0; I < P.size(); ++I)
795 if (P[I] != arg.parameters[I].label)
796 return false;
797 return true;
798}
799
800Matcher<SignatureInformation> Sig(std::string Label,
801 std::vector<std::string> Params) {
802 return AllOf(Labeled(Label), ParamsAre(Params));
803}
804
805TEST(SignatureHelpTest, Overloads) {
806 auto Results = signatures(R"cpp(
807 void foo(int x, int y);
808 void foo(int x, float y);
809 void foo(float x, int y);
810 void foo(float x, float y);
811 void bar(int x, int y = 0);
812 int main() { foo(^); }
813 )cpp");
814 EXPECT_THAT(Results.signatures,
815 UnorderedElementsAre(
816 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
817 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
818 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
819 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
820 // We always prefer the first signature.
821 EXPECT_EQ(0, Results.activeSignature);
822 EXPECT_EQ(0, Results.activeParameter);
823}
824
825TEST(SignatureHelpTest, DefaultArgs) {
826 auto Results = signatures(R"cpp(
827 void bar(int x, int y = 0);
828 void bar(float x = 0, int y = 42);
829 int main() { bar(^
830 )cpp");
831 EXPECT_THAT(Results.signatures,
832 UnorderedElementsAre(
833 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
834 Sig("bar(float x = 0, int y = 42) -> void",
835 {"float x = 0", "int y = 42"})));
836 EXPECT_EQ(0, Results.activeSignature);
837 EXPECT_EQ(0, Results.activeParameter);
838}
839
840TEST(SignatureHelpTest, ActiveArg) {
841 auto Results = signatures(R"cpp(
842 int baz(int a, int b, int c);
843 int main() { baz(baz(1,2,3), ^); }
844 )cpp");
845 EXPECT_THAT(Results.signatures,
846 ElementsAre(Sig("baz(int a, int b, int c) -> int",
847 {"int a", "int b", "int c"})));
848 EXPECT_EQ(0, Results.activeSignature);
849 EXPECT_EQ(1, Results.activeParameter);
850}
851
Haojian Wu061c73e2018-01-23 11:37:26 +0000852class IndexRequestCollector : public SymbolIndex {
853public:
854 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000855 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000856 llvm::function_ref<void(const Symbol &)> Callback) const override {
857 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000858 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000859 }
860
Eric Liu9ec459f2018-03-14 09:48:05 +0000861 void lookup(const LookupRequest &,
862 llvm::function_ref<void(const Symbol &)>) const override {}
863
Haojian Wu061c73e2018-01-23 11:37:26 +0000864 const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
865
866private:
867 mutable std::vector<FuzzyFindRequest> Requests;
868};
869
870std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
871 clangd::CodeCompleteOptions Opts;
872 IndexRequestCollector Requests;
873 Opts.Index = &Requests;
874 completions(Code, {}, Opts);
875 return Requests.allRequests();
876}
877
878TEST(CompletionTest, UnqualifiedIdQuery) {
879 auto Requests = captureIndexRequests(R"cpp(
880 namespace std {}
881 using namespace std;
882 namespace ns {
883 void f() {
884 vec^
885 }
886 }
887 )cpp");
888
889 EXPECT_THAT(Requests,
890 ElementsAre(Field(&FuzzyFindRequest::Scopes,
891 UnorderedElementsAre("", "ns::", "std::"))));
892}
893
894TEST(CompletionTest, ResolvedQualifiedIdQuery) {
895 auto Requests = captureIndexRequests(R"cpp(
896 namespace ns1 {}
897 namespace ns2 {} // ignore
898 namespace ns3 { namespace nns3 {} }
899 namespace foo {
900 using namespace ns1;
901 using namespace ns3::nns3;
902 }
903 namespace ns {
904 void f() {
905 foo::^
906 }
907 }
908 )cpp");
909
910 EXPECT_THAT(Requests,
911 ElementsAre(Field(
912 &FuzzyFindRequest::Scopes,
913 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
914}
915
916TEST(CompletionTest, UnresolvedQualifierIdQuery) {
917 auto Requests = captureIndexRequests(R"cpp(
918 namespace a {}
919 using namespace a;
920 namespace ns {
921 void f() {
922 bar::^
923 }
924 } // namespace ns
925 )cpp");
926
927 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
928 UnorderedElementsAre("bar::"))));
929}
930
931TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
932 auto Requests = captureIndexRequests(R"cpp(
933 namespace a {}
934 using namespace a;
935 namespace ns {
936 void f() {
937 ::a::bar::^
938 }
939 } // namespace ns
940 )cpp");
941
942 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
943 UnorderedElementsAre("a::bar::"))));
944}
945
946TEST(CompletionTest, EmptyQualifiedQuery) {
947 auto Requests = captureIndexRequests(R"cpp(
948 namespace ns {
949 void f() {
950 ^
951 }
952 } // namespace ns
953 )cpp");
954
955 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
956 UnorderedElementsAre("", "ns::"))));
957}
958
959TEST(CompletionTest, GlobalQualifiedQuery) {
960 auto Requests = captureIndexRequests(R"cpp(
961 namespace ns {
962 void f() {
963 ::^
964 }
965 } // namespace ns
966 )cpp");
967
968 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
969 UnorderedElementsAre(""))));
970}
971
Ilya Biryukova907ba42018-05-14 10:50:04 +0000972TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
973 auto Completions = completions(
974 R"cpp(
975 struct Foo {
976 int SomeNameOfField;
977 typedef int SomeNameOfTypedefField;
978 };
979
980 Foo::^)cpp",
981 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
982
983 EXPECT_THAT(Completions.items,
984 AllOf(Contains(Labeled("SomeNameOfField")),
985 Contains(Labeled("SomeNameOfTypedefField")),
986 Not(Contains(Labeled("SomeNameInTheIndex")))));
987}
988
989TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
990 {
991 auto Completions = completions(
992 R"cpp(
993 template <class T>
994 void foo() {
995 T::^
996 }
997 )cpp",
998 {func("::SomeNameInTheIndex")});
999
1000 EXPECT_THAT(Completions.items,
1001 Not(Contains(Labeled("SomeNameInTheIndex"))));
1002 }
1003
1004 {
1005 auto Completions = completions(
1006 R"cpp(
1007 template <class T>
1008 void foo() {
1009 T::template Y<int>::^
1010 }
1011 )cpp",
1012 {func("::SomeNameInTheIndex")});
1013
1014 EXPECT_THAT(Completions.items,
1015 Not(Contains(Labeled("SomeNameInTheIndex"))));
1016 }
1017
1018 {
1019 auto Completions = completions(
1020 R"cpp(
1021 template <class T>
1022 void foo() {
1023 T::foo::^
1024 }
1025 )cpp",
1026 {func("::SomeNameInTheIndex")});
1027
1028 EXPECT_THAT(Completions.items,
1029 Not(Contains(Labeled("SomeNameInTheIndex"))));
1030 }
1031}
1032
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001033TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001034 MockFSProvider FS;
1035 auto FooH = testPath("foo.h");
1036 auto FooCpp = testPath("foo.cpp");
1037 FS.Files[FooH] = R"cpp(
1038 // this is my documentation comment.
1039 int func();
1040 )cpp";
1041 FS.Files[FooCpp] = "";
1042
1043 MockCompilationDatabase CDB;
1044 IgnoreDiagnostics DiagConsumer;
1045 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1046
1047 Annotations Source(R"cpp(
1048 #include "foo.h"
1049 int func() {
1050 // This makes sure we have func from header in the AST.
1051 }
1052 int a = fun^
1053 )cpp");
1054 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1055 // We need to wait for preamble to build.
1056 ASSERT_TRUE(Server.blockUntilIdleForTest());
1057
1058 // Change the header file. Completion will reuse the old preamble!
1059 FS.Files[FooH] = R"cpp(
1060 int func();
1061 )cpp";
1062
1063 clangd::CodeCompleteOptions Opts;
1064 Opts.IncludeComments = true;
1065 CompletionList Completions =
1066 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1067 // We shouldn't crash. Unfortunately, current workaround is to not produce
1068 // comments for symbols from headers.
1069 EXPECT_THAT(Completions.items,
1070 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1071}
1072
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001073TEST(CompletionTest, CompleteOnInvalidLine) {
1074 auto FooCpp = testPath("foo.cpp");
1075
1076 MockCompilationDatabase CDB;
1077 IgnoreDiagnostics DiagConsumer;
1078 MockFSProvider FS;
1079 FS.Files[FooCpp] = "// empty file";
1080
1081 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1082 // Run completion outside the file range.
1083 Position Pos;
1084 Pos.line = 100;
1085 Pos.character = 0;
1086 EXPECT_THAT_EXPECTED(
1087 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1088 Failed());
1089}
1090
1091
Sam McCall9aad25f2017-12-05 07:20:26 +00001092} // namespace
1093} // namespace clangd
1094} // namespace clang