blob: d78b4bdd579e0a5dd01e2532a1db74efc31c9239 [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) {
162 return sym(Name, index::SymbolKind::Class, "@S@\\0@S@\\0");
163}
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 {
428 void method();
429 };
Sam McCall84652cc2018-01-12 16:16:09 +0000430
Sam McCall545a20d2018-01-19 14:34:02 +0000431 void Adapter::method() {
432 Adapter^
433 }
434 )cpp",
435 {cls("Adapter")});
Sam McCall84652cc2018-01-12 16:16:09 +0000436
437 // Make sure there are no duplicate entries of 'Adapter'.
Sam McCalld2a95922018-01-22 21:05:00 +0000438 EXPECT_THAT(Results.items, ElementsAre(Named("Adapter")));
Sam McCall84652cc2018-01-12 16:16:09 +0000439}
440
Sam McCall545a20d2018-01-19 14:34:02 +0000441TEST(CompletionTest, ScopedNoIndex) {
442 auto Results = completions(
443 R"cpp(
444 namespace fake { int BigBang, Babble, Ball; };
445 int main() { fake::bb^ }
446 ")cpp");
Sam McCall84652cc2018-01-12 16:16:09 +0000447 // BigBang is a better match than Babble. Ball doesn't match at all.
Sam McCall545a20d2018-01-19 14:34:02 +0000448 EXPECT_THAT(Results.items, ElementsAre(Named("BigBang"), Named("Babble")));
Sam McCall84652cc2018-01-12 16:16:09 +0000449}
450
Sam McCall545a20d2018-01-19 14:34:02 +0000451TEST(CompletionTest, Scoped) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000452 auto Results = completions(
453 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000454 namespace fake { int Babble, Ball; };
455 int main() { fake::bb^ }
456 ")cpp",
457 {var("fake::BigBang")});
458 EXPECT_THAT(Results.items, ElementsAre(Named("BigBang"), Named("Babble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000459}
460
Sam McCall545a20d2018-01-19 14:34:02 +0000461TEST(CompletionTest, ScopedWithFilter) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000462 auto Results = completions(
463 R"cpp(
464 void f() { ns::x^ }
465 )cpp",
466 {cls("ns::XYZ"), func("ns::foo")});
467 EXPECT_THAT(Results.items,
468 UnorderedElementsAre(AllOf(Named("XYZ"), Filter("XYZ"))));
469}
470
Sam McCalldc8abc42018-05-03 14:53:02 +0000471TEST(CompletionTest, ReferencesAffectRanking) {
472 auto Results = completions("int main() { abs^ }", {ns("absl"), func("abs")});
473 EXPECT_THAT(Results.items, HasSubsequence(Named("abs"), Named("absl")));
474 Results = completions("int main() { abs^ }",
475 {withReferences(10000, ns("absl")), func("abs")});
476 EXPECT_THAT(Results.items, HasSubsequence(Named("absl"), Named("abs")));
477}
478
Sam McCall545a20d2018-01-19 14:34:02 +0000479TEST(CompletionTest, GlobalQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000480 auto Results = completions(
481 R"cpp(
482 void f() { ::^ }
483 )cpp",
484 {cls("XYZ")});
485 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
486 Has("f", CompletionItemKind::Function)));
487}
488
Sam McCall545a20d2018-01-19 14:34:02 +0000489TEST(CompletionTest, FullyQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000490 auto Results = completions(
491 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000492 namespace ns { void bar(); }
Sam McCalla15c2d62018-01-18 09:27:56 +0000493 void f() { ::ns::^ }
494 )cpp",
495 {cls("ns::XYZ")});
Sam McCall545a20d2018-01-19 14:34:02 +0000496 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
497 Has("bar", CompletionItemKind::Function)));
498}
499
500TEST(CompletionTest, SemaIndexMerge) {
501 auto Results = completions(
502 R"cpp(
503 namespace ns { int local; void both(); }
504 void f() { ::ns::^ }
505 )cpp",
506 {func("ns::both"), cls("ns::Index")});
507 // We get results from both index and sema, with no duplicates.
508 EXPECT_THAT(
509 Results.items,
510 UnorderedElementsAre(Named("local"), Named("Index"), Named("both")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000511}
512
Haojian Wu48b48652018-01-25 09:20:09 +0000513TEST(CompletionTest, SemaIndexMergeWithLimit) {
514 clangd::CodeCompleteOptions Opts;
515 Opts.Limit = 1;
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")}, Opts);
522 EXPECT_EQ(Results.items.size(), Opts.Limit);
523 EXPECT_TRUE(Results.isIncomplete);
524}
525
Eric Liu63f419a2018-05-15 15:29:32 +0000526TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
527 MockFSProvider FS;
528 MockCompilationDatabase CDB;
529 std::string Subdir = testPath("sub");
530 std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
531 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
532 std::string BarHeader = testPath("sub/bar.h");
533 FS.Files[BarHeader] = "";
534
535 IgnoreDiagnostics DiagConsumer;
536 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
537 Symbol::Details Scratch;
538 auto BarURI = URI::createFile(BarHeader).toString();
539 Symbol Sym = cls("ns::X");
540 Sym.CanonicalDeclaration.FileURI = BarURI;
541 Scratch.IncludeHeader = BarURI;
542 Sym.Detail = &Scratch;
543 // Shoten include path based on search dirctory and insert.
544 auto Results = completions(Server,
545 R"cpp(
546 int main() { ns::^ }
547 )cpp",
548 {Sym});
549 EXPECT_THAT(Results.items,
550 ElementsAre(AllOf(Named("X"), InsertInclude("\"bar.h\""))));
551 // Duplicate based on inclusions in preamble.
552 Results = completions(Server,
553 R"cpp(
554 #include "sub/bar.h" // not shortest, so should only match resolved.
555 int main() { ns::^ }
556 )cpp",
557 {Sym});
558 EXPECT_THAT(Results.items,
559 ElementsAre(AllOf(Named("X"), Not(HasAdditionalEdits()))));
560}
561
Sam McCalla15c2d62018-01-18 09:27:56 +0000562TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
563 MockFSProvider FS;
564 MockCompilationDatabase CDB;
565 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000566 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCalla15c2d62018-01-18 09:27:56 +0000567
Sam McCallc1568062018-02-16 09:41:43 +0000568 FS.Files[testPath("bar.h")] =
Sam McCalld5ea3e32018-01-24 17:53:32 +0000569 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
Sam McCallc1568062018-02-16 09:41:43 +0000570 auto File = testPath("foo.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000571 Annotations Test(R"cpp(
572 #include "bar.h"
573 namespace ns { int local; }
Sam McCalld5ea3e32018-01-24 17:53:32 +0000574 void f() { ns::^; }
575 void f() { ns::preamble().$2^; }
Sam McCalla15c2d62018-01-18 09:27:56 +0000576 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000577 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000578 clangd::CodeCompleteOptions Opts = {};
579
Sam McCalla15c2d62018-01-18 09:27:56 +0000580 auto I = memIndex({var("ns::index")});
581 Opts.Index = I.get();
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000582 auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalla15c2d62018-01-18 09:27:56 +0000583 EXPECT_THAT(WithIndex.items,
584 UnorderedElementsAre(Named("local"), Named("index")));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000585 auto ClassFromPreamble =
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000586 cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000587 EXPECT_THAT(ClassFromPreamble.items, Contains(Named("member")));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000588
589 Opts.Index = nullptr;
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000590 auto WithoutIndex =
591 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000592 EXPECT_THAT(WithoutIndex.items,
593 UnorderedElementsAre(Named("local"), Named("preamble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000594}
595
596TEST(CompletionTest, DynamicIndexMultiFile) {
597 MockFSProvider FS;
598 MockCompilationDatabase CDB;
599 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000600 auto Opts = ClangdServer::optsForTest();
601 Opts.BuildDynamicSymbolIndex = true;
602 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCalla15c2d62018-01-18 09:27:56 +0000603
Eric Liu709bde82018-02-19 18:48:44 +0000604 FS.Files[testPath("foo.h")] = R"cpp(
Sam McCalla15c2d62018-01-18 09:27:56 +0000605 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liu709bde82018-02-19 18:48:44 +0000606 )cpp";
Sam McCall7363a2f2018-03-05 17:28:54 +0000607 runAddDocument(Server, testPath("foo.cpp"), R"cpp(
Eric Liu709bde82018-02-19 18:48:44 +0000608 #include "foo.h"
Sam McCall0bb24cd2018-02-13 08:59:23 +0000609 )cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000610
Sam McCallc1568062018-02-16 09:41:43 +0000611 auto File = testPath("bar.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000612 Annotations Test(R"cpp(
613 namespace ns {
614 class XXX {};
615 /// Doooc
616 void fooooo() {}
617 }
618 void f() { ns::^ }
619 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000620 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000621
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000622 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
Sam McCalla15c2d62018-01-18 09:27:56 +0000623 // "XYZ" and "foo" are not included in the file being completed but are still
624 // visible through the index.
625 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
626 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
627 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
628 EXPECT_THAT(Results.items, Contains(AllOf(Named("fooooo"), Filter("fooooo"),
629 Kind(CompletionItemKind::Function),
630 Doc("Doooc"), Detail("void"))));
631}
632
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000633TEST(CompletionTest, Documentation) {
634 auto Results = completions(
635 R"cpp(
636 // Non-doxygen comment.
637 int foo();
638 /// Doxygen comment.
639 /// \param int a
640 int bar(int a);
641 /* Multi-line
642 block comment
643 */
644 int baz();
645
646 int x = ^
647 )cpp");
648 EXPECT_THAT(Results.items,
649 Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
650 EXPECT_THAT(
651 Results.items,
652 Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
653 EXPECT_THAT(Results.items,
654 Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
655}
656
Haojian Wu58d208d2018-01-25 09:44:06 +0000657TEST(CodeCompleteTest, DisableTypoCorrection) {
658 auto Results = completions(R"cpp(
659 namespace clang { int v; }
660 void f() { clangd::^
661 )cpp");
662 EXPECT_TRUE(Results.items.empty());
663}
664
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000665TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
666 auto Results = completions(R"cpp(
667 namespace clang { }
668 void f() {
669 clan^
670 }
671 )cpp");
672
673 EXPECT_THAT(Results.items, Contains(Labeled("clang")));
674 EXPECT_THAT(Results.items, Not(Contains(Labeled("clang::"))));
675}
676
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000677TEST(CompletionTest, BacktrackCrashes) {
678 // Sema calls code completion callbacks twice in these cases.
679 auto Results = completions(R"cpp(
680 namespace ns {
681 struct FooBarBaz {};
682 } // namespace ns
683
684 int foo(ns::FooBar^
685 )cpp");
686
687 EXPECT_THAT(Results.items, ElementsAre(Labeled("FooBarBaz")));
688
689 // Check we don't crash in that case too.
690 completions(R"cpp(
691 struct FooBarBaz {};
692 void test() {
693 if (FooBarBaz * x^) {}
694 }
695)cpp");
696}
697
Eric Liu42abe412018-05-24 11:20:19 +0000698TEST(CompletionTest, CompleteInMacroWithStringification) {
699 auto Results = completions(R"cpp(
700void f(const char *, int x);
701#define F(x) f(#x, x)
702
703namespace ns {
704int X;
705int Y;
706} // namespace ns
707
708int f(int input_num) {
709 F(ns::^)
710}
711)cpp");
712
713 EXPECT_THAT(Results.items,
714 UnorderedElementsAre(Named("X"), Named("Y")));
715}
716
717TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
718 auto Results = completions(R"cpp(
719void f(const char *, int x);
720#define F(x) f(#x, x)
721
722namespace ns {
723int X;
724
725int f(int input_num) {
726 F(^)
727}
728} // namespace ns
729)cpp");
730
731 EXPECT_THAT(Results.items, Contains(Named("X")));
732}
733
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000734TEST(CompletionTest, CompleteInExcludedPPBranch) {
735 auto Results = completions(R"cpp(
736 int bar(int param_in_bar) {
737 }
738
739 int foo(int param_in_foo) {
740#if 0
741 par^
742#endif
743 }
744)cpp");
745
746 EXPECT_THAT(Results.items, Contains(Labeled("param_in_foo")));
747 EXPECT_THAT(Results.items, Not(Contains(Labeled("param_in_bar"))));
748}
749
Sam McCall800d4372017-12-19 10:29:27 +0000750SignatureHelp signatures(StringRef Text) {
751 MockFSProvider FS;
752 MockCompilationDatabase CDB;
753 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000754 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCallc1568062018-02-16 09:41:43 +0000755 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000756 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000757 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000758 return cantFail(runSignatureHelp(Server, File, Test.point()));
Sam McCall800d4372017-12-19 10:29:27 +0000759}
760
761MATCHER_P(ParamsAre, P, "") {
762 if (P.size() != arg.parameters.size())
763 return false;
764 for (unsigned I = 0; I < P.size(); ++I)
765 if (P[I] != arg.parameters[I].label)
766 return false;
767 return true;
768}
769
770Matcher<SignatureInformation> Sig(std::string Label,
771 std::vector<std::string> Params) {
772 return AllOf(Labeled(Label), ParamsAre(Params));
773}
774
775TEST(SignatureHelpTest, Overloads) {
776 auto Results = signatures(R"cpp(
777 void foo(int x, int y);
778 void foo(int x, float y);
779 void foo(float x, int y);
780 void foo(float x, float y);
781 void bar(int x, int y = 0);
782 int main() { foo(^); }
783 )cpp");
784 EXPECT_THAT(Results.signatures,
785 UnorderedElementsAre(
786 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
787 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
788 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
789 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
790 // We always prefer the first signature.
791 EXPECT_EQ(0, Results.activeSignature);
792 EXPECT_EQ(0, Results.activeParameter);
793}
794
795TEST(SignatureHelpTest, DefaultArgs) {
796 auto Results = signatures(R"cpp(
797 void bar(int x, int y = 0);
798 void bar(float x = 0, int y = 42);
799 int main() { bar(^
800 )cpp");
801 EXPECT_THAT(Results.signatures,
802 UnorderedElementsAre(
803 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
804 Sig("bar(float x = 0, int y = 42) -> void",
805 {"float x = 0", "int y = 42"})));
806 EXPECT_EQ(0, Results.activeSignature);
807 EXPECT_EQ(0, Results.activeParameter);
808}
809
810TEST(SignatureHelpTest, ActiveArg) {
811 auto Results = signatures(R"cpp(
812 int baz(int a, int b, int c);
813 int main() { baz(baz(1,2,3), ^); }
814 )cpp");
815 EXPECT_THAT(Results.signatures,
816 ElementsAre(Sig("baz(int a, int b, int c) -> int",
817 {"int a", "int b", "int c"})));
818 EXPECT_EQ(0, Results.activeSignature);
819 EXPECT_EQ(1, Results.activeParameter);
820}
821
Haojian Wu061c73e2018-01-23 11:37:26 +0000822class IndexRequestCollector : public SymbolIndex {
823public:
824 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000825 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000826 llvm::function_ref<void(const Symbol &)> Callback) const override {
827 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000828 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000829 }
830
Eric Liu9ec459f2018-03-14 09:48:05 +0000831 void lookup(const LookupRequest &,
832 llvm::function_ref<void(const Symbol &)>) const override {}
833
Haojian Wu061c73e2018-01-23 11:37:26 +0000834 const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
835
836private:
837 mutable std::vector<FuzzyFindRequest> Requests;
838};
839
840std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
841 clangd::CodeCompleteOptions Opts;
842 IndexRequestCollector Requests;
843 Opts.Index = &Requests;
844 completions(Code, {}, Opts);
845 return Requests.allRequests();
846}
847
848TEST(CompletionTest, UnqualifiedIdQuery) {
849 auto Requests = captureIndexRequests(R"cpp(
850 namespace std {}
851 using namespace std;
852 namespace ns {
853 void f() {
854 vec^
855 }
856 }
857 )cpp");
858
859 EXPECT_THAT(Requests,
860 ElementsAre(Field(&FuzzyFindRequest::Scopes,
861 UnorderedElementsAre("", "ns::", "std::"))));
862}
863
864TEST(CompletionTest, ResolvedQualifiedIdQuery) {
865 auto Requests = captureIndexRequests(R"cpp(
866 namespace ns1 {}
867 namespace ns2 {} // ignore
868 namespace ns3 { namespace nns3 {} }
869 namespace foo {
870 using namespace ns1;
871 using namespace ns3::nns3;
872 }
873 namespace ns {
874 void f() {
875 foo::^
876 }
877 }
878 )cpp");
879
880 EXPECT_THAT(Requests,
881 ElementsAre(Field(
882 &FuzzyFindRequest::Scopes,
883 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
884}
885
886TEST(CompletionTest, UnresolvedQualifierIdQuery) {
887 auto Requests = captureIndexRequests(R"cpp(
888 namespace a {}
889 using namespace a;
890 namespace ns {
891 void f() {
892 bar::^
893 }
894 } // namespace ns
895 )cpp");
896
897 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
898 UnorderedElementsAre("bar::"))));
899}
900
901TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
902 auto Requests = captureIndexRequests(R"cpp(
903 namespace a {}
904 using namespace a;
905 namespace ns {
906 void f() {
907 ::a::bar::^
908 }
909 } // namespace ns
910 )cpp");
911
912 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
913 UnorderedElementsAre("a::bar::"))));
914}
915
916TEST(CompletionTest, EmptyQualifiedQuery) {
917 auto Requests = captureIndexRequests(R"cpp(
918 namespace ns {
919 void f() {
920 ^
921 }
922 } // namespace ns
923 )cpp");
924
925 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
926 UnorderedElementsAre("", "ns::"))));
927}
928
929TEST(CompletionTest, GlobalQualifiedQuery) {
930 auto Requests = captureIndexRequests(R"cpp(
931 namespace ns {
932 void f() {
933 ::^
934 }
935 } // namespace ns
936 )cpp");
937
938 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
939 UnorderedElementsAre(""))));
940}
941
Ilya Biryukova907ba42018-05-14 10:50:04 +0000942TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
943 auto Completions = completions(
944 R"cpp(
945 struct Foo {
946 int SomeNameOfField;
947 typedef int SomeNameOfTypedefField;
948 };
949
950 Foo::^)cpp",
951 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
952
953 EXPECT_THAT(Completions.items,
954 AllOf(Contains(Labeled("SomeNameOfField")),
955 Contains(Labeled("SomeNameOfTypedefField")),
956 Not(Contains(Labeled("SomeNameInTheIndex")))));
957}
958
959TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
960 {
961 auto Completions = completions(
962 R"cpp(
963 template <class T>
964 void foo() {
965 T::^
966 }
967 )cpp",
968 {func("::SomeNameInTheIndex")});
969
970 EXPECT_THAT(Completions.items,
971 Not(Contains(Labeled("SomeNameInTheIndex"))));
972 }
973
974 {
975 auto Completions = completions(
976 R"cpp(
977 template <class T>
978 void foo() {
979 T::template Y<int>::^
980 }
981 )cpp",
982 {func("::SomeNameInTheIndex")});
983
984 EXPECT_THAT(Completions.items,
985 Not(Contains(Labeled("SomeNameInTheIndex"))));
986 }
987
988 {
989 auto Completions = completions(
990 R"cpp(
991 template <class T>
992 void foo() {
993 T::foo::^
994 }
995 )cpp",
996 {func("::SomeNameInTheIndex")});
997
998 EXPECT_THAT(Completions.items,
999 Not(Contains(Labeled("SomeNameInTheIndex"))));
1000 }
1001}
1002
Ilya Biryukovd6e9f142018-05-25 14:55:18 +00001003// FIXME: This still crashes under asan. Fix it and reenable the test.
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001004TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001005 MockFSProvider FS;
1006 auto FooH = testPath("foo.h");
1007 auto FooCpp = testPath("foo.cpp");
1008 FS.Files[FooH] = R"cpp(
1009 // this is my documentation comment.
1010 int func();
1011 )cpp";
1012 FS.Files[FooCpp] = "";
1013
1014 MockCompilationDatabase CDB;
1015 IgnoreDiagnostics DiagConsumer;
1016 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1017
1018 Annotations Source(R"cpp(
1019 #include "foo.h"
1020 int func() {
1021 // This makes sure we have func from header in the AST.
1022 }
1023 int a = fun^
1024 )cpp");
1025 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1026 // We need to wait for preamble to build.
1027 ASSERT_TRUE(Server.blockUntilIdleForTest());
1028
1029 // Change the header file. Completion will reuse the old preamble!
1030 FS.Files[FooH] = R"cpp(
1031 int func();
1032 )cpp";
1033
1034 clangd::CodeCompleteOptions Opts;
1035 Opts.IncludeComments = true;
1036 CompletionList Completions =
1037 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1038 // We shouldn't crash. Unfortunately, current workaround is to not produce
1039 // comments for symbols from headers.
1040 EXPECT_THAT(Completions.items,
1041 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1042}
1043
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001044TEST(CompletionTest, CompleteOnInvalidLine) {
1045 auto FooCpp = testPath("foo.cpp");
1046
1047 MockCompilationDatabase CDB;
1048 IgnoreDiagnostics DiagConsumer;
1049 MockFSProvider FS;
1050 FS.Files[FooCpp] = "// empty file";
1051
1052 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1053 // Run completion outside the file range.
1054 Position Pos;
1055 Pos.line = 100;
1056 Pos.character = 0;
1057 EXPECT_THAT_EXPECTED(
1058 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1059 Failed());
1060}
1061
1062
Sam McCall9aad25f2017-12-05 07:20:26 +00001063} // namespace
1064} // namespace clangd
1065} // namespace clang