blob: 5f22fe9385a91a646275a0249424dd73ec493bb2 [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 McCall8b2dcc12018-06-14 13:50:30 +0000196 #define MotorCar
197 int Car;
Sam McCall9aad25f2017-12-05 07:20:26 +0000198 struct S {
199 int FooBar;
200 int FooBaz;
201 int Qux;
202 };
203 )cpp";
Sam McCall8b2dcc12018-06-14 13:50:30 +0000204
205 // Only items matching the fuzzy query are returned.
Sam McCallf6ae3232017-12-05 20:11:29 +0000206 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").items,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000207 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000208
Sam McCall8b2dcc12018-06-14 13:50:30 +0000209 // Macros require prefix match.
210 EXPECT_THAT(completions(Body + "int main() { C^ }").items,
211 AllOf(Has("Car"), Not(Has("MotorCar"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000212}
213
Sam McCallf6ae3232017-12-05 20:11:29 +0000214void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000215 auto Results = completions(
216 R"cpp(
217 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000218
Sam McCall44fdcec22017-12-08 15:00:59 +0000219 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000220
Sam McCall44fdcec22017-12-08 15:00:59 +0000221 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000222
Sam McCall44fdcec22017-12-08 15:00:59 +0000223 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000224
Sam McCall44fdcec22017-12-08 15:00:59 +0000225 struct ClassWithMembers {
226 /// Doc for method.
227 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000228
Sam McCall44fdcec22017-12-08 15:00:59 +0000229 int field;
230 private:
231 int private_field;
232 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000233
Sam McCall44fdcec22017-12-08 15:00:59 +0000234 int test() {
235 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000236
Sam McCall44fdcec22017-12-08 15:00:59 +0000237 /// Doc for local_var.
238 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000239
Sam McCall44fdcec22017-12-08 15:00:59 +0000240 ClassWithMembers().^
241 }
242 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000243 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000244
Sam McCallf6ae3232017-12-05 20:11:29 +0000245 // Class members. The only items that must be present in after-dot
246 // completion.
Sam McCall4caa8512018-06-07 12:49:17 +0000247 EXPECT_THAT(Results.items,
248 AllOf(Has(Opts.EnableSnippets ? "method()" : "method"),
249 Has("field"), Not(Has("ClassWithMembers")),
250 Not(Has("operator=")), Not(Has("~ClassWithMembers"))));
Sam McCall44fdcec22017-12-08 15:00:59 +0000251 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.items,
252 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000253 // Global items.
Sam McCall545a20d2018-01-19 14:34:02 +0000254 EXPECT_THAT(
255 Results.items,
256 Not(AnyOf(Has("global_var"), Has("index_var"), Has("global_func"),
257 Has("global_func()"), Has("index_func"), Has("GlobalClass"),
258 Has("IndexClass"), Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000259 // There should be no code patterns (aka snippets) in after-dot
260 // completion. At least there aren't any we're aware of.
Sam McCall44fdcec22017-12-08 15:00:59 +0000261 EXPECT_THAT(Results.items, Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000262 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000263 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000264}
Sam McCall9aad25f2017-12-05 07:20:26 +0000265
Sam McCallf6ae3232017-12-05 20:11:29 +0000266void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000267 auto Results = completions(
268 R"cpp(
269 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000270
Sam McCall44fdcec22017-12-08 15:00:59 +0000271 int global_var;
272 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000273
Sam McCall44fdcec22017-12-08 15:00:59 +0000274 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000275
Sam McCall44fdcec22017-12-08 15:00:59 +0000276 struct ClassWithMembers {
277 /// Doc for method.
278 int method();
279 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000280
Sam McCall44fdcec22017-12-08 15:00:59 +0000281 int test() {
282 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000283
Sam McCall44fdcec22017-12-08 15:00:59 +0000284 /// Doc for local_var.
285 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000286
Sam McCall44fdcec22017-12-08 15:00:59 +0000287 ^
288 }
289 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000290 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000291
292 // Class members. Should never be present in global completions.
Sam McCall44fdcec22017-12-08 15:00:59 +0000293 EXPECT_THAT(Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000294 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
295 // Global items.
Sam McCalld8169a82018-01-18 15:31:30 +0000296 EXPECT_THAT(Results.items,
Sam McCall545a20d2018-01-19 14:34:02 +0000297 AllOf(Has("global_var"), Has("index_var"),
Sam McCalld8169a82018-01-18 15:31:30 +0000298 Has(Opts.EnableSnippets ? "global_func()" : "global_func"),
Sam McCall545a20d2018-01-19 14:34:02 +0000299 Has("index_func" /* our fake symbol doesn't include () */),
300 Has("GlobalClass"), Has("IndexClass")));
Sam McCallf6ae3232017-12-05 20:11:29 +0000301 // A macro.
Sam McCall44fdcec22017-12-08 15:00:59 +0000302 EXPECT_IFF(Opts.IncludeMacros, Results.items, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000303 // Local items. Must be present always.
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000304 EXPECT_THAT(Results.items,
305 AllOf(Has("local_var"), Has("LocalClass"),
306 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000307 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000308 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000309}
310
311TEST(CompletionTest, CompletionOptions) {
Sam McCall2c3849a2018-01-16 12:21:24 +0000312 auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
313 TestAfterDotCompletion(Opts);
314 TestGlobalScopeCompletion(Opts);
315 };
316 // We used to test every combination of options, but that got too slow (2^N).
317 auto Flags = {
Ilya Biryukov71028b82018-03-12 15:28:22 +0000318 &clangd::CodeCompleteOptions::IncludeMacros,
Ilya Biryukov43714502018-05-16 12:32:44 +0000319 &clangd::CodeCompleteOptions::IncludeComments,
Ilya Biryukov71028b82018-03-12 15:28:22 +0000320 &clangd::CodeCompleteOptions::EnableSnippets,
321 &clangd::CodeCompleteOptions::IncludeCodePatterns,
322 &clangd::CodeCompleteOptions::IncludeIneligibleResults,
Sam McCall2c3849a2018-01-16 12:21:24 +0000323 };
324 // Test default options.
325 Test({});
326 // Test with one flag flipped.
327 for (auto &F : Flags) {
328 clangd::CodeCompleteOptions O;
329 O.*F ^= true;
330 Test(O);
Sam McCall9aad25f2017-12-05 07:20:26 +0000331 }
332}
333
Sam McCall44fdcec22017-12-08 15:00:59 +0000334TEST(CompletionTest, Priorities) {
335 auto Internal = completions(R"cpp(
336 class Foo {
337 public: void pub();
338 protected: void prot();
339 private: void priv();
340 };
341 void Foo::pub() { this->^ }
342 )cpp");
343 EXPECT_THAT(Internal.items,
344 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
345
346 auto External = completions(R"cpp(
347 class Foo {
348 public: void pub();
349 protected: void prot();
350 private: void priv();
351 };
352 void test() {
353 Foo F;
354 F.^
355 }
356 )cpp");
357 EXPECT_THAT(External.items,
358 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
359}
360
361TEST(CompletionTest, Qualifiers) {
362 auto Results = completions(R"cpp(
363 class Foo {
364 public: int foo() const;
365 int bar() const;
366 };
367 class Bar : public Foo {
368 int foo() const;
369 };
370 void test() { Bar().^ }
371 )cpp");
372 EXPECT_THAT(Results.items, HasSubsequence(Labeled("bar() const"),
373 Labeled("Foo::foo() const")));
374 EXPECT_THAT(Results.items, Not(Contains(Labeled("foo() const")))); // private
375}
376
Sam McCall4caa8512018-06-07 12:49:17 +0000377TEST(CompletionTest, InjectedTypename) {
378 // These are suppressed when accessed as a member...
379 EXPECT_THAT(completions("struct X{}; void foo(){ X().^ }").items,
380 Not(Has("X")));
381 EXPECT_THAT(completions("struct X{ void foo(){ this->^ } };").items,
382 Not(Has("X")));
383 // ...but accessible in other, more useful cases.
384 EXPECT_THAT(completions("struct X{ void foo(){ ^ } };").items, Has("X"));
385 EXPECT_THAT(completions("struct Y{}; struct X:Y{ void foo(){ ^ } };").items,
386 Has("Y"));
387 EXPECT_THAT(
388 completions(
389 "template<class> struct Y{}; struct X:Y<int>{ void foo(){ ^ } };")
390 .items,
391 Has("Y"));
392 // This case is marginal (`using X::X` is useful), we allow it for now.
393 EXPECT_THAT(completions("struct X{}; void foo(){ X::^ }").items, Has("X"));
394}
395
Sam McCall44fdcec22017-12-08 15:00:59 +0000396TEST(CompletionTest, Snippets) {
397 clangd::CodeCompleteOptions Opts;
398 Opts.EnableSnippets = true;
399 auto Results = completions(
400 R"cpp(
401 struct fake {
402 int a;
403 int f(int i, const float f) const;
404 };
405 int main() {
406 fake f;
407 f.^
408 }
409 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000410 /*IndexSymbols=*/{}, Opts);
Sam McCall44fdcec22017-12-08 15:00:59 +0000411 EXPECT_THAT(Results.items,
Eric Liu63696e12017-12-20 17:24:31 +0000412 HasSubsequence(Snippet("a"),
Sam McCall44fdcec22017-12-08 15:00:59 +0000413 Snippet("f(${1:int i}, ${2:const float f})")));
414}
415
416TEST(CompletionTest, Kinds) {
Sam McCall545a20d2018-01-19 14:34:02 +0000417 auto Results = completions(
418 R"cpp(
419 #define MACRO X
420 int variable;
421 struct Struct {};
422 int function();
423 int X = ^
424 )cpp",
425 {func("indexFunction"), var("indexVariable"), cls("indexClass")});
426 EXPECT_THAT(Results.items,
427 AllOf(Has("function", CompletionItemKind::Function),
428 Has("variable", CompletionItemKind::Variable),
429 Has("int", CompletionItemKind::Keyword),
430 Has("Struct", CompletionItemKind::Class),
431 Has("MACRO", CompletionItemKind::Text),
432 Has("indexFunction", CompletionItemKind::Function),
433 Has("indexVariable", CompletionItemKind::Variable),
434 Has("indexClass", CompletionItemKind::Class)));
Sam McCall44fdcec22017-12-08 15:00:59 +0000435
Sam McCall44fdcec22017-12-08 15:00:59 +0000436 Results = completions("nam^");
437 EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
438}
439
Sam McCall84652cc2018-01-12 16:16:09 +0000440TEST(CompletionTest, NoDuplicates) {
Sam McCall545a20d2018-01-19 14:34:02 +0000441 auto Results = completions(
442 R"cpp(
443 class Adapter {
Sam McCall545a20d2018-01-19 14:34:02 +0000444 };
Sam McCall84652cc2018-01-12 16:16:09 +0000445
Eric Liu9b3cba72018-05-30 09:03:39 +0000446 void f() {
Sam McCall545a20d2018-01-19 14:34:02 +0000447 Adapter^
448 }
449 )cpp",
450 {cls("Adapter")});
Sam McCall84652cc2018-01-12 16:16:09 +0000451
452 // Make sure there are no duplicate entries of 'Adapter'.
Sam McCalld2a95922018-01-22 21:05:00 +0000453 EXPECT_THAT(Results.items, ElementsAre(Named("Adapter")));
Sam McCall84652cc2018-01-12 16:16:09 +0000454}
455
Sam McCall545a20d2018-01-19 14:34:02 +0000456TEST(CompletionTest, ScopedNoIndex) {
457 auto Results = completions(
458 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000459 namespace fake { int BigBang, Babble, Box; };
460 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000461 ")cpp");
Sam McCall8b2dcc12018-06-14 13:50:30 +0000462 // Babble is a better match than BigBang. Box doesn't match at all.
463 EXPECT_THAT(Results.items, ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCall84652cc2018-01-12 16:16:09 +0000464}
465
Sam McCall545a20d2018-01-19 14:34:02 +0000466TEST(CompletionTest, Scoped) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000467 auto Results = completions(
468 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000469 namespace fake { int Babble, Box; };
470 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000471 ")cpp",
472 {var("fake::BigBang")});
Sam McCall8b2dcc12018-06-14 13:50:30 +0000473 EXPECT_THAT(Results.items, ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000474}
475
Sam McCall545a20d2018-01-19 14:34:02 +0000476TEST(CompletionTest, ScopedWithFilter) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000477 auto Results = completions(
478 R"cpp(
479 void f() { ns::x^ }
480 )cpp",
481 {cls("ns::XYZ"), func("ns::foo")});
482 EXPECT_THAT(Results.items,
483 UnorderedElementsAre(AllOf(Named("XYZ"), Filter("XYZ"))));
484}
485
Sam McCalldc8abc42018-05-03 14:53:02 +0000486TEST(CompletionTest, ReferencesAffectRanking) {
487 auto Results = completions("int main() { abs^ }", {ns("absl"), func("abs")});
488 EXPECT_THAT(Results.items, HasSubsequence(Named("abs"), Named("absl")));
489 Results = completions("int main() { abs^ }",
490 {withReferences(10000, ns("absl")), func("abs")});
491 EXPECT_THAT(Results.items, HasSubsequence(Named("absl"), Named("abs")));
492}
493
Sam McCall545a20d2018-01-19 14:34:02 +0000494TEST(CompletionTest, GlobalQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000495 auto Results = completions(
496 R"cpp(
497 void f() { ::^ }
498 )cpp",
499 {cls("XYZ")});
500 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
501 Has("f", CompletionItemKind::Function)));
502}
503
Sam McCall545a20d2018-01-19 14:34:02 +0000504TEST(CompletionTest, FullyQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000505 auto Results = completions(
506 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000507 namespace ns { void bar(); }
Sam McCalla15c2d62018-01-18 09:27:56 +0000508 void f() { ::ns::^ }
509 )cpp",
510 {cls("ns::XYZ")});
Sam McCall545a20d2018-01-19 14:34:02 +0000511 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
512 Has("bar", CompletionItemKind::Function)));
513}
514
515TEST(CompletionTest, SemaIndexMerge) {
516 auto Results = completions(
517 R"cpp(
518 namespace ns { int local; void both(); }
519 void f() { ::ns::^ }
520 )cpp",
521 {func("ns::both"), cls("ns::Index")});
522 // We get results from both index and sema, with no duplicates.
523 EXPECT_THAT(
524 Results.items,
525 UnorderedElementsAre(Named("local"), Named("Index"), Named("both")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000526}
527
Haojian Wu48b48652018-01-25 09:20:09 +0000528TEST(CompletionTest, SemaIndexMergeWithLimit) {
529 clangd::CodeCompleteOptions Opts;
530 Opts.Limit = 1;
531 auto Results = completions(
532 R"cpp(
533 namespace ns { int local; void both(); }
534 void f() { ::ns::^ }
535 )cpp",
536 {func("ns::both"), cls("ns::Index")}, Opts);
537 EXPECT_EQ(Results.items.size(), Opts.Limit);
538 EXPECT_TRUE(Results.isIncomplete);
539}
540
Eric Liu63f419a2018-05-15 15:29:32 +0000541TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
542 MockFSProvider FS;
543 MockCompilationDatabase CDB;
544 std::string Subdir = testPath("sub");
545 std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
546 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
547 std::string BarHeader = testPath("sub/bar.h");
548 FS.Files[BarHeader] = "";
549
550 IgnoreDiagnostics DiagConsumer;
551 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
552 Symbol::Details Scratch;
553 auto BarURI = URI::createFile(BarHeader).toString();
554 Symbol Sym = cls("ns::X");
555 Sym.CanonicalDeclaration.FileURI = BarURI;
556 Scratch.IncludeHeader = BarURI;
557 Sym.Detail = &Scratch;
558 // Shoten include path based on search dirctory and insert.
559 auto Results = completions(Server,
560 R"cpp(
561 int main() { ns::^ }
562 )cpp",
563 {Sym});
564 EXPECT_THAT(Results.items,
565 ElementsAre(AllOf(Named("X"), InsertInclude("\"bar.h\""))));
566 // Duplicate based on inclusions in preamble.
567 Results = completions(Server,
568 R"cpp(
569 #include "sub/bar.h" // not shortest, so should only match resolved.
570 int main() { ns::^ }
571 )cpp",
572 {Sym});
573 EXPECT_THAT(Results.items,
574 ElementsAre(AllOf(Named("X"), Not(HasAdditionalEdits()))));
575}
576
Eric Liu9b3cba72018-05-30 09:03:39 +0000577TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
578 MockFSProvider FS;
579 MockCompilationDatabase CDB;
580
581 IgnoreDiagnostics DiagConsumer;
582 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
583 Symbol::Details Scratch;
584 Symbol SymX = cls("ns::X");
585 Symbol SymY = cls("ns::Y");
586 std::string BarHeader = testPath("bar.h");
587 auto BarURI = URI::createFile(BarHeader).toString();
588 SymX.CanonicalDeclaration.FileURI = BarURI;
589 SymY.CanonicalDeclaration.FileURI = BarURI;
590 Scratch.IncludeHeader = "<bar>";
591 SymX.Detail = &Scratch;
592 SymY.Detail = &Scratch;
593 // Shoten include path based on search dirctory and insert.
594 auto Results = completions(Server,
595 R"cpp(
596 namespace ns {
597 class X;
598 class Y {}
599 }
600 int main() { ns::^ }
601 )cpp",
602 {SymX, SymY});
603 EXPECT_THAT(Results.items,
604 ElementsAre(AllOf(Named("X"), Not(HasAdditionalEdits())),
605 AllOf(Named("Y"), Not(HasAdditionalEdits()))));
606}
607
Sam McCalla15c2d62018-01-18 09:27:56 +0000608TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
609 MockFSProvider FS;
610 MockCompilationDatabase CDB;
611 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000612 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCalla15c2d62018-01-18 09:27:56 +0000613
Sam McCallc1568062018-02-16 09:41:43 +0000614 FS.Files[testPath("bar.h")] =
Sam McCalld5ea3e32018-01-24 17:53:32 +0000615 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
Sam McCallc1568062018-02-16 09:41:43 +0000616 auto File = testPath("foo.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000617 Annotations Test(R"cpp(
618 #include "bar.h"
619 namespace ns { int local; }
Sam McCalld5ea3e32018-01-24 17:53:32 +0000620 void f() { ns::^; }
621 void f() { ns::preamble().$2^; }
Sam McCalla15c2d62018-01-18 09:27:56 +0000622 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000623 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000624 clangd::CodeCompleteOptions Opts = {};
625
Sam McCalla15c2d62018-01-18 09:27:56 +0000626 auto I = memIndex({var("ns::index")});
627 Opts.Index = I.get();
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000628 auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalla15c2d62018-01-18 09:27:56 +0000629 EXPECT_THAT(WithIndex.items,
630 UnorderedElementsAre(Named("local"), Named("index")));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000631 auto ClassFromPreamble =
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000632 cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000633 EXPECT_THAT(ClassFromPreamble.items, Contains(Named("member")));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000634
635 Opts.Index = nullptr;
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000636 auto WithoutIndex =
637 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000638 EXPECT_THAT(WithoutIndex.items,
639 UnorderedElementsAre(Named("local"), Named("preamble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000640}
641
642TEST(CompletionTest, DynamicIndexMultiFile) {
643 MockFSProvider FS;
644 MockCompilationDatabase CDB;
645 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000646 auto Opts = ClangdServer::optsForTest();
647 Opts.BuildDynamicSymbolIndex = true;
648 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCalla15c2d62018-01-18 09:27:56 +0000649
Eric Liu709bde82018-02-19 18:48:44 +0000650 FS.Files[testPath("foo.h")] = R"cpp(
Sam McCalla15c2d62018-01-18 09:27:56 +0000651 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liu709bde82018-02-19 18:48:44 +0000652 )cpp";
Sam McCall7363a2f2018-03-05 17:28:54 +0000653 runAddDocument(Server, testPath("foo.cpp"), R"cpp(
Eric Liu709bde82018-02-19 18:48:44 +0000654 #include "foo.h"
Sam McCall0bb24cd2018-02-13 08:59:23 +0000655 )cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000656
Sam McCallc1568062018-02-16 09:41:43 +0000657 auto File = testPath("bar.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000658 Annotations Test(R"cpp(
659 namespace ns {
660 class XXX {};
661 /// Doooc
662 void fooooo() {}
663 }
664 void f() { ns::^ }
665 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000666 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000667
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000668 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
Sam McCalla15c2d62018-01-18 09:27:56 +0000669 // "XYZ" and "foo" are not included in the file being completed but are still
670 // visible through the index.
671 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
672 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
673 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
674 EXPECT_THAT(Results.items, Contains(AllOf(Named("fooooo"), Filter("fooooo"),
675 Kind(CompletionItemKind::Function),
676 Doc("Doooc"), Detail("void"))));
677}
678
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000679TEST(CompletionTest, Documentation) {
680 auto Results = completions(
681 R"cpp(
682 // Non-doxygen comment.
683 int foo();
684 /// Doxygen comment.
685 /// \param int a
686 int bar(int a);
687 /* Multi-line
688 block comment
689 */
690 int baz();
691
692 int x = ^
693 )cpp");
694 EXPECT_THAT(Results.items,
695 Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
696 EXPECT_THAT(
697 Results.items,
698 Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
699 EXPECT_THAT(Results.items,
700 Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
701}
702
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000703TEST(CompletionTest, GlobalCompletionFiltering) {
704
705 Symbol Class = cls("XYZ");
706 Class.IsIndexedForCodeCompletion = false;
707 Symbol Func = func("XYZ::foooo");
708 Func.IsIndexedForCodeCompletion = false;
709
710 auto Results = completions(R"(// void f() {
711 XYZ::foooo^
712 })",
713 {Class, Func});
714 EXPECT_THAT(Results.items, IsEmpty());
715}
716
Haojian Wu58d208d2018-01-25 09:44:06 +0000717TEST(CodeCompleteTest, DisableTypoCorrection) {
718 auto Results = completions(R"cpp(
719 namespace clang { int v; }
720 void f() { clangd::^
721 )cpp");
722 EXPECT_TRUE(Results.items.empty());
723}
724
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000725TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
726 auto Results = completions(R"cpp(
727 namespace clang { }
728 void f() {
729 clan^
730 }
731 )cpp");
732
733 EXPECT_THAT(Results.items, Contains(Labeled("clang")));
734 EXPECT_THAT(Results.items, Not(Contains(Labeled("clang::"))));
735}
736
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000737TEST(CompletionTest, BacktrackCrashes) {
738 // Sema calls code completion callbacks twice in these cases.
739 auto Results = completions(R"cpp(
740 namespace ns {
741 struct FooBarBaz {};
742 } // namespace ns
743
744 int foo(ns::FooBar^
745 )cpp");
746
747 EXPECT_THAT(Results.items, ElementsAre(Labeled("FooBarBaz")));
748
749 // Check we don't crash in that case too.
750 completions(R"cpp(
751 struct FooBarBaz {};
752 void test() {
753 if (FooBarBaz * x^) {}
754 }
755)cpp");
756}
757
Eric Liu42abe412018-05-24 11:20:19 +0000758TEST(CompletionTest, CompleteInMacroWithStringification) {
759 auto Results = completions(R"cpp(
760void f(const char *, int x);
761#define F(x) f(#x, x)
762
763namespace ns {
764int X;
765int Y;
766} // namespace ns
767
768int f(int input_num) {
769 F(ns::^)
770}
771)cpp");
772
773 EXPECT_THAT(Results.items,
774 UnorderedElementsAre(Named("X"), Named("Y")));
775}
776
777TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
778 auto Results = completions(R"cpp(
779void f(const char *, int x);
780#define F(x) f(#x, x)
781
782namespace ns {
783int X;
784
785int f(int input_num) {
786 F(^)
787}
788} // namespace ns
789)cpp");
790
791 EXPECT_THAT(Results.items, Contains(Named("X")));
792}
793
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000794TEST(CompletionTest, CompleteInExcludedPPBranch) {
795 auto Results = completions(R"cpp(
796 int bar(int param_in_bar) {
797 }
798
799 int foo(int param_in_foo) {
800#if 0
801 par^
802#endif
803 }
804)cpp");
805
806 EXPECT_THAT(Results.items, Contains(Labeled("param_in_foo")));
807 EXPECT_THAT(Results.items, Not(Contains(Labeled("param_in_bar"))));
808}
809
Sam McCall800d4372017-12-19 10:29:27 +0000810SignatureHelp signatures(StringRef Text) {
811 MockFSProvider FS;
812 MockCompilationDatabase CDB;
813 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000814 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCallc1568062018-02-16 09:41:43 +0000815 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000816 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000817 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000818 return cantFail(runSignatureHelp(Server, File, Test.point()));
Sam McCall800d4372017-12-19 10:29:27 +0000819}
820
821MATCHER_P(ParamsAre, P, "") {
822 if (P.size() != arg.parameters.size())
823 return false;
824 for (unsigned I = 0; I < P.size(); ++I)
825 if (P[I] != arg.parameters[I].label)
826 return false;
827 return true;
828}
829
830Matcher<SignatureInformation> Sig(std::string Label,
831 std::vector<std::string> Params) {
832 return AllOf(Labeled(Label), ParamsAre(Params));
833}
834
835TEST(SignatureHelpTest, Overloads) {
836 auto Results = signatures(R"cpp(
837 void foo(int x, int y);
838 void foo(int x, float y);
839 void foo(float x, int y);
840 void foo(float x, float y);
841 void bar(int x, int y = 0);
842 int main() { foo(^); }
843 )cpp");
844 EXPECT_THAT(Results.signatures,
845 UnorderedElementsAre(
846 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
847 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
848 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
849 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
850 // We always prefer the first signature.
851 EXPECT_EQ(0, Results.activeSignature);
852 EXPECT_EQ(0, Results.activeParameter);
853}
854
855TEST(SignatureHelpTest, DefaultArgs) {
856 auto Results = signatures(R"cpp(
857 void bar(int x, int y = 0);
858 void bar(float x = 0, int y = 42);
859 int main() { bar(^
860 )cpp");
861 EXPECT_THAT(Results.signatures,
862 UnorderedElementsAre(
863 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
864 Sig("bar(float x = 0, int y = 42) -> void",
865 {"float x = 0", "int y = 42"})));
866 EXPECT_EQ(0, Results.activeSignature);
867 EXPECT_EQ(0, Results.activeParameter);
868}
869
870TEST(SignatureHelpTest, ActiveArg) {
871 auto Results = signatures(R"cpp(
872 int baz(int a, int b, int c);
873 int main() { baz(baz(1,2,3), ^); }
874 )cpp");
875 EXPECT_THAT(Results.signatures,
876 ElementsAre(Sig("baz(int a, int b, int c) -> int",
877 {"int a", "int b", "int c"})));
878 EXPECT_EQ(0, Results.activeSignature);
879 EXPECT_EQ(1, Results.activeParameter);
880}
881
Haojian Wu061c73e2018-01-23 11:37:26 +0000882class IndexRequestCollector : public SymbolIndex {
883public:
884 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000885 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000886 llvm::function_ref<void(const Symbol &)> Callback) const override {
887 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000888 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000889 }
890
Eric Liu9ec459f2018-03-14 09:48:05 +0000891 void lookup(const LookupRequest &,
892 llvm::function_ref<void(const Symbol &)>) const override {}
893
Haojian Wu061c73e2018-01-23 11:37:26 +0000894 const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
895
896private:
897 mutable std::vector<FuzzyFindRequest> Requests;
898};
899
900std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
901 clangd::CodeCompleteOptions Opts;
902 IndexRequestCollector Requests;
903 Opts.Index = &Requests;
904 completions(Code, {}, Opts);
905 return Requests.allRequests();
906}
907
908TEST(CompletionTest, UnqualifiedIdQuery) {
909 auto Requests = captureIndexRequests(R"cpp(
910 namespace std {}
911 using namespace std;
912 namespace ns {
913 void f() {
914 vec^
915 }
916 }
917 )cpp");
918
919 EXPECT_THAT(Requests,
920 ElementsAre(Field(&FuzzyFindRequest::Scopes,
921 UnorderedElementsAre("", "ns::", "std::"))));
922}
923
924TEST(CompletionTest, ResolvedQualifiedIdQuery) {
925 auto Requests = captureIndexRequests(R"cpp(
926 namespace ns1 {}
927 namespace ns2 {} // ignore
928 namespace ns3 { namespace nns3 {} }
929 namespace foo {
930 using namespace ns1;
931 using namespace ns3::nns3;
932 }
933 namespace ns {
934 void f() {
935 foo::^
936 }
937 }
938 )cpp");
939
940 EXPECT_THAT(Requests,
941 ElementsAre(Field(
942 &FuzzyFindRequest::Scopes,
943 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
944}
945
946TEST(CompletionTest, UnresolvedQualifierIdQuery) {
947 auto Requests = captureIndexRequests(R"cpp(
948 namespace a {}
949 using namespace a;
950 namespace ns {
951 void f() {
952 bar::^
953 }
954 } // namespace ns
955 )cpp");
956
957 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
958 UnorderedElementsAre("bar::"))));
959}
960
961TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
962 auto Requests = captureIndexRequests(R"cpp(
963 namespace a {}
964 using namespace a;
965 namespace ns {
966 void f() {
967 ::a::bar::^
968 }
969 } // namespace ns
970 )cpp");
971
972 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
973 UnorderedElementsAre("a::bar::"))));
974}
975
976TEST(CompletionTest, EmptyQualifiedQuery) {
977 auto Requests = captureIndexRequests(R"cpp(
978 namespace ns {
979 void f() {
980 ^
981 }
982 } // namespace ns
983 )cpp");
984
985 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
986 UnorderedElementsAre("", "ns::"))));
987}
988
989TEST(CompletionTest, GlobalQualifiedQuery) {
990 auto Requests = captureIndexRequests(R"cpp(
991 namespace ns {
992 void f() {
993 ::^
994 }
995 } // namespace ns
996 )cpp");
997
998 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
999 UnorderedElementsAre(""))));
1000}
1001
Ilya Biryukova907ba42018-05-14 10:50:04 +00001002TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
1003 auto Completions = completions(
1004 R"cpp(
1005 struct Foo {
1006 int SomeNameOfField;
1007 typedef int SomeNameOfTypedefField;
1008 };
1009
1010 Foo::^)cpp",
1011 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
1012
1013 EXPECT_THAT(Completions.items,
1014 AllOf(Contains(Labeled("SomeNameOfField")),
1015 Contains(Labeled("SomeNameOfTypedefField")),
1016 Not(Contains(Labeled("SomeNameInTheIndex")))));
1017}
1018
1019TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
1020 {
1021 auto Completions = completions(
1022 R"cpp(
1023 template <class T>
1024 void foo() {
1025 T::^
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::template Y<int>::^
1040 }
1041 )cpp",
1042 {func("::SomeNameInTheIndex")});
1043
1044 EXPECT_THAT(Completions.items,
1045 Not(Contains(Labeled("SomeNameInTheIndex"))));
1046 }
1047
1048 {
1049 auto Completions = completions(
1050 R"cpp(
1051 template <class T>
1052 void foo() {
1053 T::foo::^
1054 }
1055 )cpp",
1056 {func("::SomeNameInTheIndex")});
1057
1058 EXPECT_THAT(Completions.items,
1059 Not(Contains(Labeled("SomeNameInTheIndex"))));
1060 }
1061}
1062
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001063TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001064 MockFSProvider FS;
1065 auto FooH = testPath("foo.h");
1066 auto FooCpp = testPath("foo.cpp");
1067 FS.Files[FooH] = R"cpp(
1068 // this is my documentation comment.
1069 int func();
1070 )cpp";
1071 FS.Files[FooCpp] = "";
1072
1073 MockCompilationDatabase CDB;
1074 IgnoreDiagnostics DiagConsumer;
1075 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1076
1077 Annotations Source(R"cpp(
1078 #include "foo.h"
1079 int func() {
1080 // This makes sure we have func from header in the AST.
1081 }
1082 int a = fun^
1083 )cpp");
1084 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1085 // We need to wait for preamble to build.
1086 ASSERT_TRUE(Server.blockUntilIdleForTest());
1087
1088 // Change the header file. Completion will reuse the old preamble!
1089 FS.Files[FooH] = R"cpp(
1090 int func();
1091 )cpp";
1092
1093 clangd::CodeCompleteOptions Opts;
1094 Opts.IncludeComments = true;
1095 CompletionList Completions =
1096 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1097 // We shouldn't crash. Unfortunately, current workaround is to not produce
1098 // comments for symbols from headers.
1099 EXPECT_THAT(Completions.items,
1100 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1101}
1102
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001103TEST(CompletionTest, NonDocComments) {
1104 MockFSProvider FS;
1105 auto FooCpp = testPath("foo.cpp");
1106 FS.Files[FooCpp] = "";
1107
1108 MockCompilationDatabase CDB;
1109 IgnoreDiagnostics DiagConsumer;
1110 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1111
1112 Annotations Source(R"cpp(
1113 // ------------------
1114 int comments_foo();
1115
1116 // A comment and a decl are separated by newlines.
1117 // Therefore, the comment shouldn't show up as doc comment.
1118
1119 int comments_bar();
1120
1121 // this comment should be in the results.
1122 int comments_baz();
1123
1124
1125 template <class T>
1126 struct Struct {
1127 int comments_qux();
1128 int comments_quux();
1129 };
1130
1131
1132 // This comment should not be there.
1133
1134 template <class T>
1135 int Struct<T>::comments_qux() {
1136 }
1137
1138 // This comment **should** be in results.
1139 template <class T>
1140 int Struct<T>::comments_quux() {
1141 int a = comments^;
1142 }
1143 )cpp");
1144 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1145 CompletionList Completions = cantFail(runCodeComplete(
1146 Server, FooCpp, Source.point(), clangd::CodeCompleteOptions()));
1147
1148 // We should not get any of those comments in completion.
1149 EXPECT_THAT(
1150 Completions.items,
1151 UnorderedElementsAre(AllOf(Not(IsDocumented()), Named("comments_foo")),
1152 AllOf(IsDocumented(), Named("comments_baz")),
1153 AllOf(IsDocumented(), Named("comments_quux")),
1154 // FIXME(ibiryukov): the following items should have
1155 // empty documentation, since they are separated from
1156 // a comment with an empty line. Unfortunately, I
1157 // couldn't make Sema tests pass if we ignore those.
1158 AllOf(IsDocumented(), Named("comments_bar")),
1159 AllOf(IsDocumented(), Named("comments_qux"))));
1160}
1161
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001162TEST(CompletionTest, CompleteOnInvalidLine) {
1163 auto FooCpp = testPath("foo.cpp");
1164
1165 MockCompilationDatabase CDB;
1166 IgnoreDiagnostics DiagConsumer;
1167 MockFSProvider FS;
1168 FS.Files[FooCpp] = "// empty file";
1169
1170 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1171 // Run completion outside the file range.
1172 Position Pos;
1173 Pos.line = 100;
1174 Pos.character = 0;
1175 EXPECT_THAT_EXPECTED(
1176 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1177 Failed());
1178}
1179
1180
Sam McCall9aad25f2017-12-05 07:20:26 +00001181} // namespace
1182} // namespace clangd
1183} // namespace clang