blob: 22653e7c10bd7a7d053e83a92925b69196fa796c [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;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +000035using ::testing::IsEmpty;
Sam McCallf6ae3232017-12-05 20:11:29 +000036using ::testing::Not;
Sam McCall3d139c52018-01-12 18:30:08 +000037using ::testing::UnorderedElementsAre;
Sam McCall9aad25f2017-12-05 07:20:26 +000038
39class IgnoreDiagnostics : public DiagnosticsConsumer {
Ilya Biryukov71028b82018-03-12 15:28:22 +000040 void onDiagnosticsReady(PathRef File,
Sam McCalla7bb0cc2018-03-12 23:22:35 +000041 std::vector<Diag> Diagnostics) override {}
Sam McCall9aad25f2017-12-05 07:20:26 +000042};
43
Sam McCallf6ae3232017-12-05 20:11:29 +000044// GMock helpers for matching completion items.
45MATCHER_P(Named, Name, "") { return arg.insertText == Name; }
Sam McCall44fdcec22017-12-08 15:00:59 +000046MATCHER_P(Labeled, Label, "") { return arg.label == Label; }
47MATCHER_P(Kind, K, "") { return arg.kind == K; }
Eric Liu6f648df2017-12-19 16:50:37 +000048MATCHER_P(Filter, F, "") { return arg.filterText == F; }
Eric Liu76f6b442018-01-09 17:32:00 +000049MATCHER_P(Doc, D, "") { return arg.documentation == D; }
50MATCHER_P(Detail, D, "") { return arg.detail == D; }
Eric Liu63f419a2018-05-15 15:29:32 +000051MATCHER_P(InsertInclude, IncludeHeader, "") {
52 if (arg.additionalTextEdits.size() != 1)
53 return false;
54 const auto &Edit = arg.additionalTextEdits[0];
55 if (Edit.range.start != Edit.range.end)
56 return false;
57 SmallVector<StringRef, 2> Matches;
58 llvm::Regex RE(R"(#include[ ]*(["<][^">]*[">]))");
59 return RE.match(Edit.newText, &Matches) && Matches[1] == IncludeHeader;
60}
Sam McCall44fdcec22017-12-08 15:00:59 +000061MATCHER_P(PlainText, Text, "") {
62 return arg.insertTextFormat == clangd::InsertTextFormat::PlainText &&
63 arg.insertText == Text;
64}
65MATCHER_P(Snippet, Text, "") {
66 return arg.insertTextFormat == clangd::InsertTextFormat::Snippet &&
67 arg.insertText == Text;
68}
Sam McCall545a20d2018-01-19 14:34:02 +000069MATCHER(NameContainsFilter, "") {
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000070 if (arg.filterText.empty())
71 return true;
72 return llvm::StringRef(arg.insertText).contains(arg.filterText);
73}
Eric Liu63f419a2018-05-15 15:29:32 +000074MATCHER(HasAdditionalEdits, "") { return !arg.additionalTextEdits.empty(); }
75
Sam McCallf6ae3232017-12-05 20:11:29 +000076// Shorthand for Contains(Named(Name)).
77Matcher<const std::vector<CompletionItem> &> Has(std::string Name) {
78 return Contains(Named(std::move(Name)));
79}
Sam McCall44fdcec22017-12-08 15:00:59 +000080Matcher<const std::vector<CompletionItem> &> Has(std::string Name,
81 CompletionItemKind K) {
82 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000083}
Sam McCall44fdcec22017-12-08 15:00:59 +000084MATCHER(IsDocumented, "") { return !arg.documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000085
Sam McCalla15c2d62018-01-18 09:27:56 +000086std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
87 SymbolSlab::Builder Slab;
88 for (const auto &Sym : Symbols)
89 Slab.insert(Sym);
90 return MemIndex::build(std::move(Slab).build());
91}
92
Eric Liu63f419a2018-05-15 15:29:32 +000093CompletionList completions(ClangdServer &Server, StringRef Text,
Sam McCalla15c2d62018-01-18 09:27:56 +000094 std::vector<Symbol> IndexSymbols = {},
Sam McCallf6ae3232017-12-05 20:11:29 +000095 clangd::CodeCompleteOptions Opts = {}) {
Sam McCalla15c2d62018-01-18 09:27:56 +000096 std::unique_ptr<SymbolIndex> OverrideIndex;
97 if (!IndexSymbols.empty()) {
98 assert(!Opts.Index && "both Index and IndexSymbols given!");
99 OverrideIndex = memIndex(std::move(IndexSymbols));
100 Opts.Index = OverrideIndex.get();
101 }
102
Sam McCallc1568062018-02-16 09:41:43 +0000103 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000104 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000105 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000106 auto CompletionList =
107 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000108 // Sanity-check that filterText is valid.
Sam McCall545a20d2018-01-19 14:34:02 +0000109 EXPECT_THAT(CompletionList.items, Each(NameContainsFilter()));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000110 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +0000111}
112
Eric Liu63f419a2018-05-15 15:29:32 +0000113// Builds a server and runs code completion.
114// If IndexSymbols is non-empty, an index will be built and passed to opts.
115CompletionList completions(StringRef Text,
116 std::vector<Symbol> IndexSymbols = {},
117 clangd::CodeCompleteOptions Opts = {}) {
118 MockFSProvider FS;
119 MockCompilationDatabase CDB;
120 IgnoreDiagnostics DiagConsumer;
121 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
122 return completions(Server, Text, std::move(IndexSymbols), std::move(Opts));
123}
124
Sam McCall545a20d2018-01-19 14:34:02 +0000125std::string replace(StringRef Haystack, StringRef Needle, StringRef Repl) {
126 std::string Result;
127 raw_string_ostream OS(Result);
128 std::pair<StringRef, StringRef> Split;
129 for (Split = Haystack.split(Needle); !Split.second.empty();
130 Split = Split.first.split(Needle))
131 OS << Split.first << Repl;
132 Result += Split.first;
133 OS.flush();
134 return Result;
135}
136
Sam McCalla15c2d62018-01-18 09:27:56 +0000137// Helpers to produce fake index symbols for memIndex() or completions().
Sam McCall545a20d2018-01-19 14:34:02 +0000138// USRFormat is a regex replacement string for the unqualified part of the USR.
139Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000140 Symbol Sym;
Sam McCall545a20d2018-01-19 14:34:02 +0000141 std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
Sam McCalla15c2d62018-01-18 09:27:56 +0000142 size_t Pos = QName.rfind("::");
143 if (Pos == llvm::StringRef::npos) {
144 Sym.Name = QName;
145 Sym.Scope = "";
146 } else {
147 Sym.Name = QName.substr(Pos + 2);
Sam McCall8b2faee2018-01-19 22:18:21 +0000148 Sym.Scope = QName.substr(0, Pos + 2);
149 USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
Sam McCalla15c2d62018-01-18 09:27:56 +0000150 }
Sam McCall545a20d2018-01-19 14:34:02 +0000151 USR += Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
152 Sym.ID = SymbolID(USR);
Sam McCalla15c2d62018-01-18 09:27:56 +0000153 Sym.CompletionPlainInsertText = Sym.Name;
Sam McCall545a20d2018-01-19 14:34:02 +0000154 Sym.CompletionSnippetInsertText = Sym.Name;
Sam McCalla15c2d62018-01-18 09:27:56 +0000155 Sym.CompletionLabel = Sym.Name;
156 Sym.SymInfo.Kind = Kind;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000157 Sym.IsIndexedForCodeCompletion = true;
Sam McCalla15c2d62018-01-18 09:27:56 +0000158 return Sym;
159}
Sam McCall545a20d2018-01-19 14:34:02 +0000160Symbol func(StringRef Name) { // Assumes the function has no args.
161 return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
162}
163Symbol cls(StringRef Name) {
Eric Liu9b3cba72018-05-30 09:03:39 +0000164 return sym(Name, index::SymbolKind::Class, "@S@\\0");
Sam McCall545a20d2018-01-19 14:34:02 +0000165}
166Symbol var(StringRef Name) {
167 return sym(Name, index::SymbolKind::Variable, "@\\0");
168}
Sam McCalldc8abc42018-05-03 14:53:02 +0000169Symbol ns(StringRef Name) {
170 return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
171}
172Symbol withReferences(int N, Symbol S) {
173 S.References = N;
174 return S;
175}
Sam McCalla15c2d62018-01-18 09:27:56 +0000176
Sam McCallf6ae3232017-12-05 20:11:29 +0000177TEST(CompletionTest, Limit) {
178 clangd::CodeCompleteOptions Opts;
179 Opts.Limit = 2;
180 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000181struct ClassWithMembers {
182 int AAA();
183 int BBB();
184 int CCC();
185}
Sam McCallf6ae3232017-12-05 20:11:29 +0000186int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000187 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000188 /*IndexSymbols=*/{}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000189
190 EXPECT_TRUE(Results.isIncomplete);
Sam McCallf6ae3232017-12-05 20:11:29 +0000191 EXPECT_THAT(Results.items, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000192}
193
Sam McCallf6ae3232017-12-05 20:11:29 +0000194TEST(CompletionTest, Filter) {
195 std::string Body = R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000196 int Abracadabra;
197 int Alakazam;
198 struct S {
199 int FooBar;
200 int FooBaz;
201 int Qux;
202 };
203 )cpp";
Sam McCallf6ae3232017-12-05 20:11:29 +0000204 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").items,
205 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000206
Sam McCallf6ae3232017-12-05 20:11:29 +0000207 EXPECT_THAT(completions(Body + "int main() { S().FR^ }").items,
208 AllOf(Has("FooBar"), Not(Has("FooBaz")), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000209
Sam McCallf6ae3232017-12-05 20:11:29 +0000210 EXPECT_THAT(completions(Body + "int main() { S().opr^ }").items,
211 Has("operator="));
Sam McCall9aad25f2017-12-05 07:20:26 +0000212
Sam McCallf6ae3232017-12-05 20:11:29 +0000213 EXPECT_THAT(completions(Body + "int main() { aaa^ }").items,
214 AllOf(Has("Abracadabra"), Has("Alakazam")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000215
Sam McCallf6ae3232017-12-05 20:11:29 +0000216 EXPECT_THAT(completions(Body + "int main() { _a^ }").items,
217 AllOf(Has("static_cast"), Not(Has("Abracadabra"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000218}
219
Sam McCallf6ae3232017-12-05 20:11:29 +0000220void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000221 auto Results = completions(
222 R"cpp(
223 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000224
Sam McCall44fdcec22017-12-08 15:00:59 +0000225 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000226
Sam McCall44fdcec22017-12-08 15:00:59 +0000227 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000228
Sam McCall44fdcec22017-12-08 15:00:59 +0000229 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000230
Sam McCall44fdcec22017-12-08 15:00:59 +0000231 struct ClassWithMembers {
232 /// Doc for method.
233 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000234
Sam McCall44fdcec22017-12-08 15:00:59 +0000235 int field;
236 private:
237 int private_field;
238 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000239
Sam McCall44fdcec22017-12-08 15:00:59 +0000240 int test() {
241 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000242
Sam McCall44fdcec22017-12-08 15:00:59 +0000243 /// Doc for local_var.
244 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000245
Sam McCall44fdcec22017-12-08 15:00:59 +0000246 ClassWithMembers().^
247 }
248 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000249 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000250
Sam McCallf6ae3232017-12-05 20:11:29 +0000251 // Class members. The only items that must be present in after-dot
252 // completion.
Sam McCall44fdcec22017-12-08 15:00:59 +0000253 EXPECT_THAT(
254 Results.items,
255 AllOf(Has(Opts.EnableSnippets ? "method()" : "method"), Has("field")));
256 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.items,
257 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000258 // Global items.
Sam McCall545a20d2018-01-19 14:34:02 +0000259 EXPECT_THAT(
260 Results.items,
261 Not(AnyOf(Has("global_var"), Has("index_var"), Has("global_func"),
262 Has("global_func()"), Has("index_func"), Has("GlobalClass"),
263 Has("IndexClass"), Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000264 // There should be no code patterns (aka snippets) in after-dot
265 // completion. At least there aren't any we're aware of.
Sam McCall44fdcec22017-12-08 15:00:59 +0000266 EXPECT_THAT(Results.items, Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000267 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000268 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000269}
Sam McCall9aad25f2017-12-05 07:20:26 +0000270
Sam McCallf6ae3232017-12-05 20:11:29 +0000271void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000272 auto Results = completions(
273 R"cpp(
274 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000275
Sam McCall44fdcec22017-12-08 15:00:59 +0000276 int global_var;
277 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000278
Sam McCall44fdcec22017-12-08 15:00:59 +0000279 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000280
Sam McCall44fdcec22017-12-08 15:00:59 +0000281 struct ClassWithMembers {
282 /// Doc for method.
283 int method();
284 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000285
Sam McCall44fdcec22017-12-08 15:00:59 +0000286 int test() {
287 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000288
Sam McCall44fdcec22017-12-08 15:00:59 +0000289 /// Doc for local_var.
290 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000291
Sam McCall44fdcec22017-12-08 15:00:59 +0000292 ^
293 }
294 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000295 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000296
297 // Class members. Should never be present in global completions.
Sam McCall44fdcec22017-12-08 15:00:59 +0000298 EXPECT_THAT(Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000299 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
300 // Global items.
Sam McCalld8169a82018-01-18 15:31:30 +0000301 EXPECT_THAT(Results.items,
Sam McCall545a20d2018-01-19 14:34:02 +0000302 AllOf(Has("global_var"), Has("index_var"),
Sam McCalld8169a82018-01-18 15:31:30 +0000303 Has(Opts.EnableSnippets ? "global_func()" : "global_func"),
Sam McCall545a20d2018-01-19 14:34:02 +0000304 Has("index_func" /* our fake symbol doesn't include () */),
305 Has("GlobalClass"), Has("IndexClass")));
Sam McCallf6ae3232017-12-05 20:11:29 +0000306 // A macro.
Sam McCall44fdcec22017-12-08 15:00:59 +0000307 EXPECT_IFF(Opts.IncludeMacros, Results.items, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000308 // Local items. Must be present always.
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000309 EXPECT_THAT(Results.items,
310 AllOf(Has("local_var"), Has("LocalClass"),
311 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000312 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000313 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000314}
315
316TEST(CompletionTest, CompletionOptions) {
Sam McCall2c3849a2018-01-16 12:21:24 +0000317 auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
318 TestAfterDotCompletion(Opts);
319 TestGlobalScopeCompletion(Opts);
320 };
321 // We used to test every combination of options, but that got too slow (2^N).
322 auto Flags = {
Ilya Biryukov71028b82018-03-12 15:28:22 +0000323 &clangd::CodeCompleteOptions::IncludeMacros,
Ilya Biryukov43714502018-05-16 12:32:44 +0000324 &clangd::CodeCompleteOptions::IncludeComments,
Ilya Biryukov71028b82018-03-12 15:28:22 +0000325 &clangd::CodeCompleteOptions::EnableSnippets,
326 &clangd::CodeCompleteOptions::IncludeCodePatterns,
327 &clangd::CodeCompleteOptions::IncludeIneligibleResults,
Sam McCall2c3849a2018-01-16 12:21:24 +0000328 };
329 // Test default options.
330 Test({});
331 // Test with one flag flipped.
332 for (auto &F : Flags) {
333 clangd::CodeCompleteOptions O;
334 O.*F ^= true;
335 Test(O);
Sam McCall9aad25f2017-12-05 07:20:26 +0000336 }
337}
338
Sam McCall44fdcec22017-12-08 15:00:59 +0000339TEST(CompletionTest, Priorities) {
340 auto Internal = completions(R"cpp(
341 class Foo {
342 public: void pub();
343 protected: void prot();
344 private: void priv();
345 };
346 void Foo::pub() { this->^ }
347 )cpp");
348 EXPECT_THAT(Internal.items,
349 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
350
351 auto External = completions(R"cpp(
352 class Foo {
353 public: void pub();
354 protected: void prot();
355 private: void priv();
356 };
357 void test() {
358 Foo F;
359 F.^
360 }
361 )cpp");
362 EXPECT_THAT(External.items,
363 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
364}
365
366TEST(CompletionTest, Qualifiers) {
367 auto Results = completions(R"cpp(
368 class Foo {
369 public: int foo() const;
370 int bar() const;
371 };
372 class Bar : public Foo {
373 int foo() const;
374 };
375 void test() { Bar().^ }
376 )cpp");
377 EXPECT_THAT(Results.items, HasSubsequence(Labeled("bar() const"),
378 Labeled("Foo::foo() const")));
379 EXPECT_THAT(Results.items, Not(Contains(Labeled("foo() const")))); // private
380}
381
382TEST(CompletionTest, Snippets) {
383 clangd::CodeCompleteOptions Opts;
384 Opts.EnableSnippets = true;
385 auto Results = completions(
386 R"cpp(
387 struct fake {
388 int a;
389 int f(int i, const float f) const;
390 };
391 int main() {
392 fake f;
393 f.^
394 }
395 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000396 /*IndexSymbols=*/{}, Opts);
Sam McCall44fdcec22017-12-08 15:00:59 +0000397 EXPECT_THAT(Results.items,
Eric Liu63696e12017-12-20 17:24:31 +0000398 HasSubsequence(Snippet("a"),
Sam McCall44fdcec22017-12-08 15:00:59 +0000399 Snippet("f(${1:int i}, ${2:const float f})")));
400}
401
402TEST(CompletionTest, Kinds) {
Sam McCall545a20d2018-01-19 14:34:02 +0000403 auto Results = completions(
404 R"cpp(
405 #define MACRO X
406 int variable;
407 struct Struct {};
408 int function();
409 int X = ^
410 )cpp",
411 {func("indexFunction"), var("indexVariable"), cls("indexClass")});
412 EXPECT_THAT(Results.items,
413 AllOf(Has("function", CompletionItemKind::Function),
414 Has("variable", CompletionItemKind::Variable),
415 Has("int", CompletionItemKind::Keyword),
416 Has("Struct", CompletionItemKind::Class),
417 Has("MACRO", CompletionItemKind::Text),
418 Has("indexFunction", CompletionItemKind::Function),
419 Has("indexVariable", CompletionItemKind::Variable),
420 Has("indexClass", CompletionItemKind::Class)));
Sam McCall44fdcec22017-12-08 15:00:59 +0000421
Sam McCall44fdcec22017-12-08 15:00:59 +0000422 Results = completions("nam^");
423 EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
424}
425
Sam McCall84652cc2018-01-12 16:16:09 +0000426TEST(CompletionTest, NoDuplicates) {
Sam McCall545a20d2018-01-19 14:34:02 +0000427 auto Results = completions(
428 R"cpp(
429 class Adapter {
Sam McCall545a20d2018-01-19 14:34:02 +0000430 };
Sam McCall84652cc2018-01-12 16:16:09 +0000431
Eric Liu9b3cba72018-05-30 09:03:39 +0000432 void f() {
Sam McCall545a20d2018-01-19 14:34:02 +0000433 Adapter^
434 }
435 )cpp",
436 {cls("Adapter")});
Sam McCall84652cc2018-01-12 16:16:09 +0000437
438 // Make sure there are no duplicate entries of 'Adapter'.
Sam McCalld2a95922018-01-22 21:05:00 +0000439 EXPECT_THAT(Results.items, ElementsAre(Named("Adapter")));
Sam McCall84652cc2018-01-12 16:16:09 +0000440}
441
Sam McCall545a20d2018-01-19 14:34:02 +0000442TEST(CompletionTest, ScopedNoIndex) {
443 auto Results = completions(
444 R"cpp(
445 namespace fake { int BigBang, Babble, Ball; };
446 int main() { fake::bb^ }
447 ")cpp");
Sam McCall84652cc2018-01-12 16:16:09 +0000448 // BigBang is a better match than Babble. Ball doesn't match at all.
Sam McCall545a20d2018-01-19 14:34:02 +0000449 EXPECT_THAT(Results.items, ElementsAre(Named("BigBang"), Named("Babble")));
Sam McCall84652cc2018-01-12 16:16:09 +0000450}
451
Sam McCall545a20d2018-01-19 14:34:02 +0000452TEST(CompletionTest, Scoped) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000453 auto Results = completions(
454 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000455 namespace fake { int Babble, Ball; };
456 int main() { fake::bb^ }
457 ")cpp",
458 {var("fake::BigBang")});
459 EXPECT_THAT(Results.items, ElementsAre(Named("BigBang"), Named("Babble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000460}
461
Sam McCall545a20d2018-01-19 14:34:02 +0000462TEST(CompletionTest, ScopedWithFilter) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000463 auto Results = completions(
464 R"cpp(
465 void f() { ns::x^ }
466 )cpp",
467 {cls("ns::XYZ"), func("ns::foo")});
468 EXPECT_THAT(Results.items,
469 UnorderedElementsAre(AllOf(Named("XYZ"), Filter("XYZ"))));
470}
471
Sam McCalldc8abc42018-05-03 14:53:02 +0000472TEST(CompletionTest, ReferencesAffectRanking) {
473 auto Results = completions("int main() { abs^ }", {ns("absl"), func("abs")});
474 EXPECT_THAT(Results.items, HasSubsequence(Named("abs"), Named("absl")));
475 Results = completions("int main() { abs^ }",
476 {withReferences(10000, ns("absl")), func("abs")});
477 EXPECT_THAT(Results.items, HasSubsequence(Named("absl"), Named("abs")));
478}
479
Sam McCall545a20d2018-01-19 14:34:02 +0000480TEST(CompletionTest, GlobalQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000481 auto Results = completions(
482 R"cpp(
483 void f() { ::^ }
484 )cpp",
485 {cls("XYZ")});
486 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
487 Has("f", CompletionItemKind::Function)));
488}
489
Sam McCall545a20d2018-01-19 14:34:02 +0000490TEST(CompletionTest, FullyQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000491 auto Results = completions(
492 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000493 namespace ns { void bar(); }
Sam McCalla15c2d62018-01-18 09:27:56 +0000494 void f() { ::ns::^ }
495 )cpp",
496 {cls("ns::XYZ")});
Sam McCall545a20d2018-01-19 14:34:02 +0000497 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
498 Has("bar", CompletionItemKind::Function)));
499}
500
501TEST(CompletionTest, SemaIndexMerge) {
502 auto Results = completions(
503 R"cpp(
504 namespace ns { int local; void both(); }
505 void f() { ::ns::^ }
506 )cpp",
507 {func("ns::both"), cls("ns::Index")});
508 // We get results from both index and sema, with no duplicates.
509 EXPECT_THAT(
510 Results.items,
511 UnorderedElementsAre(Named("local"), Named("Index"), Named("both")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000512}
513
Haojian Wu48b48652018-01-25 09:20:09 +0000514TEST(CompletionTest, SemaIndexMergeWithLimit) {
515 clangd::CodeCompleteOptions Opts;
516 Opts.Limit = 1;
517 auto Results = completions(
518 R"cpp(
519 namespace ns { int local; void both(); }
520 void f() { ::ns::^ }
521 )cpp",
522 {func("ns::both"), cls("ns::Index")}, Opts);
523 EXPECT_EQ(Results.items.size(), Opts.Limit);
524 EXPECT_TRUE(Results.isIncomplete);
525}
526
Eric Liu63f419a2018-05-15 15:29:32 +0000527TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
528 MockFSProvider FS;
529 MockCompilationDatabase CDB;
530 std::string Subdir = testPath("sub");
531 std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
532 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
533 std::string BarHeader = testPath("sub/bar.h");
534 FS.Files[BarHeader] = "";
535
536 IgnoreDiagnostics DiagConsumer;
537 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
538 Symbol::Details Scratch;
539 auto BarURI = URI::createFile(BarHeader).toString();
540 Symbol Sym = cls("ns::X");
541 Sym.CanonicalDeclaration.FileURI = BarURI;
542 Scratch.IncludeHeader = BarURI;
543 Sym.Detail = &Scratch;
544 // Shoten include path based on search dirctory and insert.
545 auto Results = completions(Server,
546 R"cpp(
547 int main() { ns::^ }
548 )cpp",
549 {Sym});
550 EXPECT_THAT(Results.items,
551 ElementsAre(AllOf(Named("X"), InsertInclude("\"bar.h\""))));
552 // Duplicate based on inclusions in preamble.
553 Results = completions(Server,
554 R"cpp(
555 #include "sub/bar.h" // not shortest, so should only match resolved.
556 int main() { ns::^ }
557 )cpp",
558 {Sym});
559 EXPECT_THAT(Results.items,
560 ElementsAre(AllOf(Named("X"), Not(HasAdditionalEdits()))));
561}
562
Eric Liu9b3cba72018-05-30 09:03:39 +0000563TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
564 MockFSProvider FS;
565 MockCompilationDatabase CDB;
566
567 IgnoreDiagnostics DiagConsumer;
568 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
569 Symbol::Details Scratch;
570 Symbol SymX = cls("ns::X");
571 Symbol SymY = cls("ns::Y");
572 std::string BarHeader = testPath("bar.h");
573 auto BarURI = URI::createFile(BarHeader).toString();
574 SymX.CanonicalDeclaration.FileURI = BarURI;
575 SymY.CanonicalDeclaration.FileURI = BarURI;
576 Scratch.IncludeHeader = "<bar>";
577 SymX.Detail = &Scratch;
578 SymY.Detail = &Scratch;
579 // Shoten include path based on search dirctory and insert.
580 auto Results = completions(Server,
581 R"cpp(
582 namespace ns {
583 class X;
584 class Y {}
585 }
586 int main() { ns::^ }
587 )cpp",
588 {SymX, SymY});
589 EXPECT_THAT(Results.items,
590 ElementsAre(AllOf(Named("X"), Not(HasAdditionalEdits())),
591 AllOf(Named("Y"), Not(HasAdditionalEdits()))));
592}
593
Sam McCalla15c2d62018-01-18 09:27:56 +0000594TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
595 MockFSProvider FS;
596 MockCompilationDatabase CDB;
597 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000598 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCalla15c2d62018-01-18 09:27:56 +0000599
Sam McCallc1568062018-02-16 09:41:43 +0000600 FS.Files[testPath("bar.h")] =
Sam McCalld5ea3e32018-01-24 17:53:32 +0000601 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
Sam McCallc1568062018-02-16 09:41:43 +0000602 auto File = testPath("foo.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000603 Annotations Test(R"cpp(
604 #include "bar.h"
605 namespace ns { int local; }
Sam McCalld5ea3e32018-01-24 17:53:32 +0000606 void f() { ns::^; }
607 void f() { ns::preamble().$2^; }
Sam McCalla15c2d62018-01-18 09:27:56 +0000608 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000609 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000610 clangd::CodeCompleteOptions Opts = {};
611
Sam McCalla15c2d62018-01-18 09:27:56 +0000612 auto I = memIndex({var("ns::index")});
613 Opts.Index = I.get();
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000614 auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalla15c2d62018-01-18 09:27:56 +0000615 EXPECT_THAT(WithIndex.items,
616 UnorderedElementsAre(Named("local"), Named("index")));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000617 auto ClassFromPreamble =
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000618 cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000619 EXPECT_THAT(ClassFromPreamble.items, Contains(Named("member")));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000620
621 Opts.Index = nullptr;
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000622 auto WithoutIndex =
623 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000624 EXPECT_THAT(WithoutIndex.items,
625 UnorderedElementsAre(Named("local"), Named("preamble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000626}
627
628TEST(CompletionTest, DynamicIndexMultiFile) {
629 MockFSProvider FS;
630 MockCompilationDatabase CDB;
631 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000632 auto Opts = ClangdServer::optsForTest();
633 Opts.BuildDynamicSymbolIndex = true;
634 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCalla15c2d62018-01-18 09:27:56 +0000635
Eric Liu709bde82018-02-19 18:48:44 +0000636 FS.Files[testPath("foo.h")] = R"cpp(
Sam McCalla15c2d62018-01-18 09:27:56 +0000637 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liu709bde82018-02-19 18:48:44 +0000638 )cpp";
Sam McCall7363a2f2018-03-05 17:28:54 +0000639 runAddDocument(Server, testPath("foo.cpp"), R"cpp(
Eric Liu709bde82018-02-19 18:48:44 +0000640 #include "foo.h"
Sam McCall0bb24cd2018-02-13 08:59:23 +0000641 )cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000642
Sam McCallc1568062018-02-16 09:41:43 +0000643 auto File = testPath("bar.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000644 Annotations Test(R"cpp(
645 namespace ns {
646 class XXX {};
647 /// Doooc
648 void fooooo() {}
649 }
650 void f() { ns::^ }
651 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000652 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000653
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000654 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
Sam McCalla15c2d62018-01-18 09:27:56 +0000655 // "XYZ" and "foo" are not included in the file being completed but are still
656 // visible through the index.
657 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
658 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
659 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
660 EXPECT_THAT(Results.items, Contains(AllOf(Named("fooooo"), Filter("fooooo"),
661 Kind(CompletionItemKind::Function),
662 Doc("Doooc"), Detail("void"))));
663}
664
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000665TEST(CompletionTest, Documentation) {
666 auto Results = completions(
667 R"cpp(
668 // Non-doxygen comment.
669 int foo();
670 /// Doxygen comment.
671 /// \param int a
672 int bar(int a);
673 /* Multi-line
674 block comment
675 */
676 int baz();
677
678 int x = ^
679 )cpp");
680 EXPECT_THAT(Results.items,
681 Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
682 EXPECT_THAT(
683 Results.items,
684 Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
685 EXPECT_THAT(Results.items,
686 Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
687}
688
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000689TEST(CompletionTest, GlobalCompletionFiltering) {
690
691 Symbol Class = cls("XYZ");
692 Class.IsIndexedForCodeCompletion = false;
693 Symbol Func = func("XYZ::foooo");
694 Func.IsIndexedForCodeCompletion = false;
695
696 auto Results = completions(R"(// void f() {
697 XYZ::foooo^
698 })",
699 {Class, Func});
700 EXPECT_THAT(Results.items, IsEmpty());
701}
702
Haojian Wu58d208d2018-01-25 09:44:06 +0000703TEST(CodeCompleteTest, DisableTypoCorrection) {
704 auto Results = completions(R"cpp(
705 namespace clang { int v; }
706 void f() { clangd::^
707 )cpp");
708 EXPECT_TRUE(Results.items.empty());
709}
710
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000711TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
712 auto Results = completions(R"cpp(
713 namespace clang { }
714 void f() {
715 clan^
716 }
717 )cpp");
718
719 EXPECT_THAT(Results.items, Contains(Labeled("clang")));
720 EXPECT_THAT(Results.items, Not(Contains(Labeled("clang::"))));
721}
722
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000723TEST(CompletionTest, BacktrackCrashes) {
724 // Sema calls code completion callbacks twice in these cases.
725 auto Results = completions(R"cpp(
726 namespace ns {
727 struct FooBarBaz {};
728 } // namespace ns
729
730 int foo(ns::FooBar^
731 )cpp");
732
733 EXPECT_THAT(Results.items, ElementsAre(Labeled("FooBarBaz")));
734
735 // Check we don't crash in that case too.
736 completions(R"cpp(
737 struct FooBarBaz {};
738 void test() {
739 if (FooBarBaz * x^) {}
740 }
741)cpp");
742}
743
Eric Liu42abe412018-05-24 11:20:19 +0000744TEST(CompletionTest, CompleteInMacroWithStringification) {
745 auto Results = completions(R"cpp(
746void f(const char *, int x);
747#define F(x) f(#x, x)
748
749namespace ns {
750int X;
751int Y;
752} // namespace ns
753
754int f(int input_num) {
755 F(ns::^)
756}
757)cpp");
758
759 EXPECT_THAT(Results.items,
760 UnorderedElementsAre(Named("X"), Named("Y")));
761}
762
763TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
764 auto Results = completions(R"cpp(
765void f(const char *, int x);
766#define F(x) f(#x, x)
767
768namespace ns {
769int X;
770
771int f(int input_num) {
772 F(^)
773}
774} // namespace ns
775)cpp");
776
777 EXPECT_THAT(Results.items, Contains(Named("X")));
778}
779
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000780TEST(CompletionTest, CompleteInExcludedPPBranch) {
781 auto Results = completions(R"cpp(
782 int bar(int param_in_bar) {
783 }
784
785 int foo(int param_in_foo) {
786#if 0
787 par^
788#endif
789 }
790)cpp");
791
792 EXPECT_THAT(Results.items, Contains(Labeled("param_in_foo")));
793 EXPECT_THAT(Results.items, Not(Contains(Labeled("param_in_bar"))));
794}
795
Sam McCall800d4372017-12-19 10:29:27 +0000796SignatureHelp signatures(StringRef Text) {
797 MockFSProvider FS;
798 MockCompilationDatabase CDB;
799 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000800 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCallc1568062018-02-16 09:41:43 +0000801 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000802 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000803 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000804 return cantFail(runSignatureHelp(Server, File, Test.point()));
Sam McCall800d4372017-12-19 10:29:27 +0000805}
806
807MATCHER_P(ParamsAre, P, "") {
808 if (P.size() != arg.parameters.size())
809 return false;
810 for (unsigned I = 0; I < P.size(); ++I)
811 if (P[I] != arg.parameters[I].label)
812 return false;
813 return true;
814}
815
816Matcher<SignatureInformation> Sig(std::string Label,
817 std::vector<std::string> Params) {
818 return AllOf(Labeled(Label), ParamsAre(Params));
819}
820
821TEST(SignatureHelpTest, Overloads) {
822 auto Results = signatures(R"cpp(
823 void foo(int x, int y);
824 void foo(int x, float y);
825 void foo(float x, int y);
826 void foo(float x, float y);
827 void bar(int x, int y = 0);
828 int main() { foo(^); }
829 )cpp");
830 EXPECT_THAT(Results.signatures,
831 UnorderedElementsAre(
832 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
833 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
834 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
835 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
836 // We always prefer the first signature.
837 EXPECT_EQ(0, Results.activeSignature);
838 EXPECT_EQ(0, Results.activeParameter);
839}
840
841TEST(SignatureHelpTest, DefaultArgs) {
842 auto Results = signatures(R"cpp(
843 void bar(int x, int y = 0);
844 void bar(float x = 0, int y = 42);
845 int main() { bar(^
846 )cpp");
847 EXPECT_THAT(Results.signatures,
848 UnorderedElementsAre(
849 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
850 Sig("bar(float x = 0, int y = 42) -> void",
851 {"float x = 0", "int y = 42"})));
852 EXPECT_EQ(0, Results.activeSignature);
853 EXPECT_EQ(0, Results.activeParameter);
854}
855
856TEST(SignatureHelpTest, ActiveArg) {
857 auto Results = signatures(R"cpp(
858 int baz(int a, int b, int c);
859 int main() { baz(baz(1,2,3), ^); }
860 )cpp");
861 EXPECT_THAT(Results.signatures,
862 ElementsAre(Sig("baz(int a, int b, int c) -> int",
863 {"int a", "int b", "int c"})));
864 EXPECT_EQ(0, Results.activeSignature);
865 EXPECT_EQ(1, Results.activeParameter);
866}
867
Haojian Wu061c73e2018-01-23 11:37:26 +0000868class IndexRequestCollector : public SymbolIndex {
869public:
870 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000871 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000872 llvm::function_ref<void(const Symbol &)> Callback) const override {
873 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000874 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000875 }
876
Eric Liu9ec459f2018-03-14 09:48:05 +0000877 void lookup(const LookupRequest &,
878 llvm::function_ref<void(const Symbol &)>) const override {}
879
Haojian Wu061c73e2018-01-23 11:37:26 +0000880 const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
881
882private:
883 mutable std::vector<FuzzyFindRequest> Requests;
884};
885
886std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
887 clangd::CodeCompleteOptions Opts;
888 IndexRequestCollector Requests;
889 Opts.Index = &Requests;
890 completions(Code, {}, Opts);
891 return Requests.allRequests();
892}
893
894TEST(CompletionTest, UnqualifiedIdQuery) {
895 auto Requests = captureIndexRequests(R"cpp(
896 namespace std {}
897 using namespace std;
898 namespace ns {
899 void f() {
900 vec^
901 }
902 }
903 )cpp");
904
905 EXPECT_THAT(Requests,
906 ElementsAre(Field(&FuzzyFindRequest::Scopes,
907 UnorderedElementsAre("", "ns::", "std::"))));
908}
909
910TEST(CompletionTest, ResolvedQualifiedIdQuery) {
911 auto Requests = captureIndexRequests(R"cpp(
912 namespace ns1 {}
913 namespace ns2 {} // ignore
914 namespace ns3 { namespace nns3 {} }
915 namespace foo {
916 using namespace ns1;
917 using namespace ns3::nns3;
918 }
919 namespace ns {
920 void f() {
921 foo::^
922 }
923 }
924 )cpp");
925
926 EXPECT_THAT(Requests,
927 ElementsAre(Field(
928 &FuzzyFindRequest::Scopes,
929 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
930}
931
932TEST(CompletionTest, UnresolvedQualifierIdQuery) {
933 auto Requests = captureIndexRequests(R"cpp(
934 namespace a {}
935 using namespace a;
936 namespace ns {
937 void f() {
938 bar::^
939 }
940 } // namespace ns
941 )cpp");
942
943 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
944 UnorderedElementsAre("bar::"))));
945}
946
947TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
948 auto Requests = captureIndexRequests(R"cpp(
949 namespace a {}
950 using namespace a;
951 namespace ns {
952 void f() {
953 ::a::bar::^
954 }
955 } // namespace ns
956 )cpp");
957
958 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
959 UnorderedElementsAre("a::bar::"))));
960}
961
962TEST(CompletionTest, EmptyQualifiedQuery) {
963 auto Requests = captureIndexRequests(R"cpp(
964 namespace ns {
965 void f() {
966 ^
967 }
968 } // namespace ns
969 )cpp");
970
971 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
972 UnorderedElementsAre("", "ns::"))));
973}
974
975TEST(CompletionTest, GlobalQualifiedQuery) {
976 auto Requests = captureIndexRequests(R"cpp(
977 namespace ns {
978 void f() {
979 ::^
980 }
981 } // namespace ns
982 )cpp");
983
984 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
985 UnorderedElementsAre(""))));
986}
987
Ilya Biryukova907ba42018-05-14 10:50:04 +0000988TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
989 auto Completions = completions(
990 R"cpp(
991 struct Foo {
992 int SomeNameOfField;
993 typedef int SomeNameOfTypedefField;
994 };
995
996 Foo::^)cpp",
997 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
998
999 EXPECT_THAT(Completions.items,
1000 AllOf(Contains(Labeled("SomeNameOfField")),
1001 Contains(Labeled("SomeNameOfTypedefField")),
1002 Not(Contains(Labeled("SomeNameInTheIndex")))));
1003}
1004
1005TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
1006 {
1007 auto Completions = completions(
1008 R"cpp(
1009 template <class T>
1010 void foo() {
1011 T::^
1012 }
1013 )cpp",
1014 {func("::SomeNameInTheIndex")});
1015
1016 EXPECT_THAT(Completions.items,
1017 Not(Contains(Labeled("SomeNameInTheIndex"))));
1018 }
1019
1020 {
1021 auto Completions = completions(
1022 R"cpp(
1023 template <class T>
1024 void foo() {
1025 T::template Y<int>::^
1026 }
1027 )cpp",
1028 {func("::SomeNameInTheIndex")});
1029
1030 EXPECT_THAT(Completions.items,
1031 Not(Contains(Labeled("SomeNameInTheIndex"))));
1032 }
1033
1034 {
1035 auto Completions = completions(
1036 R"cpp(
1037 template <class T>
1038 void foo() {
1039 T::foo::^
1040 }
1041 )cpp",
1042 {func("::SomeNameInTheIndex")});
1043
1044 EXPECT_THAT(Completions.items,
1045 Not(Contains(Labeled("SomeNameInTheIndex"))));
1046 }
1047}
1048
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001049TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001050 MockFSProvider FS;
1051 auto FooH = testPath("foo.h");
1052 auto FooCpp = testPath("foo.cpp");
1053 FS.Files[FooH] = R"cpp(
1054 // this is my documentation comment.
1055 int func();
1056 )cpp";
1057 FS.Files[FooCpp] = "";
1058
1059 MockCompilationDatabase CDB;
1060 IgnoreDiagnostics DiagConsumer;
1061 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1062
1063 Annotations Source(R"cpp(
1064 #include "foo.h"
1065 int func() {
1066 // This makes sure we have func from header in the AST.
1067 }
1068 int a = fun^
1069 )cpp");
1070 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1071 // We need to wait for preamble to build.
1072 ASSERT_TRUE(Server.blockUntilIdleForTest());
1073
1074 // Change the header file. Completion will reuse the old preamble!
1075 FS.Files[FooH] = R"cpp(
1076 int func();
1077 )cpp";
1078
1079 clangd::CodeCompleteOptions Opts;
1080 Opts.IncludeComments = true;
1081 CompletionList Completions =
1082 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1083 // We shouldn't crash. Unfortunately, current workaround is to not produce
1084 // comments for symbols from headers.
1085 EXPECT_THAT(Completions.items,
1086 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1087}
1088
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001089TEST(CompletionTest, CompleteOnInvalidLine) {
1090 auto FooCpp = testPath("foo.cpp");
1091
1092 MockCompilationDatabase CDB;
1093 IgnoreDiagnostics DiagConsumer;
1094 MockFSProvider FS;
1095 FS.Files[FooCpp] = "// empty file";
1096
1097 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1098 // Run completion outside the file range.
1099 Position Pos;
1100 Pos.line = 100;
1101 Pos.character = 0;
1102 EXPECT_THAT_EXPECTED(
1103 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1104 Failed());
1105}
1106
1107
Sam McCall9aad25f2017-12-05 07:20:26 +00001108} // namespace
1109} // namespace clangd
1110} // namespace clang