blob: 825504eb00e95201a867ef5e8c6518fd59f08e6b [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 McCallc18c2802018-06-15 11:06:29 +000035using ::testing::HasSubstr;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +000036using ::testing::IsEmpty;
Sam McCallf6ae3232017-12-05 20:11:29 +000037using ::testing::Not;
Sam McCall3d139c52018-01-12 18:30:08 +000038using ::testing::UnorderedElementsAre;
Sam McCall9aad25f2017-12-05 07:20:26 +000039
40class IgnoreDiagnostics : public DiagnosticsConsumer {
Ilya Biryukov71028b82018-03-12 15:28:22 +000041 void onDiagnosticsReady(PathRef File,
Sam McCalla7bb0cc2018-03-12 23:22:35 +000042 std::vector<Diag> Diagnostics) override {}
Sam McCall9aad25f2017-12-05 07:20:26 +000043};
44
Sam McCallf6ae3232017-12-05 20:11:29 +000045// GMock helpers for matching completion items.
46MATCHER_P(Named, Name, "") { return arg.insertText == Name; }
Sam McCall44fdcec22017-12-08 15:00:59 +000047MATCHER_P(Labeled, Label, "") { return arg.label == Label; }
48MATCHER_P(Kind, K, "") { return arg.kind == K; }
Eric Liu6f648df2017-12-19 16:50:37 +000049MATCHER_P(Filter, F, "") { return arg.filterText == F; }
Eric Liu76f6b442018-01-09 17:32:00 +000050MATCHER_P(Doc, D, "") { return arg.documentation == D; }
51MATCHER_P(Detail, D, "") { return arg.detail == D; }
Eric Liu63f419a2018-05-15 15:29:32 +000052MATCHER_P(InsertInclude, IncludeHeader, "") {
53 if (arg.additionalTextEdits.size() != 1)
54 return false;
55 const auto &Edit = arg.additionalTextEdits[0];
56 if (Edit.range.start != Edit.range.end)
57 return false;
58 SmallVector<StringRef, 2> Matches;
59 llvm::Regex RE(R"(#include[ ]*(["<][^">]*[">]))");
60 return RE.match(Edit.newText, &Matches) && Matches[1] == IncludeHeader;
61}
Sam McCall44fdcec22017-12-08 15:00:59 +000062MATCHER_P(PlainText, Text, "") {
63 return arg.insertTextFormat == clangd::InsertTextFormat::PlainText &&
64 arg.insertText == Text;
65}
66MATCHER_P(Snippet, Text, "") {
67 return arg.insertTextFormat == clangd::InsertTextFormat::Snippet &&
68 arg.insertText == Text;
69}
Sam McCall545a20d2018-01-19 14:34:02 +000070MATCHER(NameContainsFilter, "") {
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000071 if (arg.filterText.empty())
72 return true;
73 return llvm::StringRef(arg.insertText).contains(arg.filterText);
74}
Eric Liu63f419a2018-05-15 15:29:32 +000075MATCHER(HasAdditionalEdits, "") { return !arg.additionalTextEdits.empty(); }
76
Sam McCallf6ae3232017-12-05 20:11:29 +000077// Shorthand for Contains(Named(Name)).
78Matcher<const std::vector<CompletionItem> &> Has(std::string Name) {
79 return Contains(Named(std::move(Name)));
80}
Sam McCall44fdcec22017-12-08 15:00:59 +000081Matcher<const std::vector<CompletionItem> &> Has(std::string Name,
82 CompletionItemKind K) {
83 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000084}
Sam McCall44fdcec22017-12-08 15:00:59 +000085MATCHER(IsDocumented, "") { return !arg.documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000086
Sam McCalla15c2d62018-01-18 09:27:56 +000087std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
88 SymbolSlab::Builder Slab;
89 for (const auto &Sym : Symbols)
90 Slab.insert(Sym);
91 return MemIndex::build(std::move(Slab).build());
92}
93
Eric Liu63f419a2018-05-15 15:29:32 +000094CompletionList completions(ClangdServer &Server, StringRef Text,
Sam McCalla15c2d62018-01-18 09:27:56 +000095 std::vector<Symbol> IndexSymbols = {},
Sam McCallf6ae3232017-12-05 20:11:29 +000096 clangd::CodeCompleteOptions Opts = {}) {
Sam McCalla15c2d62018-01-18 09:27:56 +000097 std::unique_ptr<SymbolIndex> OverrideIndex;
98 if (!IndexSymbols.empty()) {
99 assert(!Opts.Index && "both Index and IndexSymbols given!");
100 OverrideIndex = memIndex(std::move(IndexSymbols));
101 Opts.Index = OverrideIndex.get();
102 }
103
Sam McCallc1568062018-02-16 09:41:43 +0000104 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000105 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000106 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000107 auto CompletionList =
108 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000109 // Sanity-check that filterText is valid.
Sam McCall545a20d2018-01-19 14:34:02 +0000110 EXPECT_THAT(CompletionList.items, Each(NameContainsFilter()));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000111 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +0000112}
113
Eric Liu63f419a2018-05-15 15:29:32 +0000114// Builds a server and runs code completion.
115// If IndexSymbols is non-empty, an index will be built and passed to opts.
116CompletionList completions(StringRef Text,
117 std::vector<Symbol> IndexSymbols = {},
118 clangd::CodeCompleteOptions Opts = {}) {
119 MockFSProvider FS;
120 MockCompilationDatabase CDB;
121 IgnoreDiagnostics DiagConsumer;
122 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
123 return completions(Server, Text, std::move(IndexSymbols), std::move(Opts));
124}
125
Sam McCall545a20d2018-01-19 14:34:02 +0000126std::string replace(StringRef Haystack, StringRef Needle, StringRef Repl) {
127 std::string Result;
128 raw_string_ostream OS(Result);
129 std::pair<StringRef, StringRef> Split;
130 for (Split = Haystack.split(Needle); !Split.second.empty();
131 Split = Split.first.split(Needle))
132 OS << Split.first << Repl;
133 Result += Split.first;
134 OS.flush();
135 return Result;
136}
137
Sam McCalla15c2d62018-01-18 09:27:56 +0000138// Helpers to produce fake index symbols for memIndex() or completions().
Sam McCall545a20d2018-01-19 14:34:02 +0000139// USRFormat is a regex replacement string for the unqualified part of the USR.
140Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000141 Symbol Sym;
Sam McCall545a20d2018-01-19 14:34:02 +0000142 std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
Sam McCalla15c2d62018-01-18 09:27:56 +0000143 size_t Pos = QName.rfind("::");
144 if (Pos == llvm::StringRef::npos) {
145 Sym.Name = QName;
146 Sym.Scope = "";
147 } else {
148 Sym.Name = QName.substr(Pos + 2);
Sam McCall8b2faee2018-01-19 22:18:21 +0000149 Sym.Scope = QName.substr(0, Pos + 2);
150 USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
Sam McCalla15c2d62018-01-18 09:27:56 +0000151 }
Sam McCall545a20d2018-01-19 14:34:02 +0000152 USR += Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
153 Sym.ID = SymbolID(USR);
Sam McCalla15c2d62018-01-18 09:27:56 +0000154 Sym.CompletionPlainInsertText = Sym.Name;
Sam McCall545a20d2018-01-19 14:34:02 +0000155 Sym.CompletionSnippetInsertText = Sym.Name;
Sam McCalla15c2d62018-01-18 09:27:56 +0000156 Sym.CompletionLabel = Sym.Name;
157 Sym.SymInfo.Kind = Kind;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000158 Sym.IsIndexedForCodeCompletion = true;
Sam McCalla15c2d62018-01-18 09:27:56 +0000159 return Sym;
160}
Sam McCall545a20d2018-01-19 14:34:02 +0000161Symbol func(StringRef Name) { // Assumes the function has no args.
162 return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
163}
164Symbol cls(StringRef Name) {
Eric Liu9b3cba72018-05-30 09:03:39 +0000165 return sym(Name, index::SymbolKind::Class, "@S@\\0");
Sam McCall545a20d2018-01-19 14:34:02 +0000166}
167Symbol var(StringRef Name) {
168 return sym(Name, index::SymbolKind::Variable, "@\\0");
169}
Sam McCalldc8abc42018-05-03 14:53:02 +0000170Symbol ns(StringRef Name) {
171 return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
172}
173Symbol withReferences(int N, Symbol S) {
174 S.References = N;
175 return S;
176}
Sam McCalla15c2d62018-01-18 09:27:56 +0000177
Sam McCallf6ae3232017-12-05 20:11:29 +0000178TEST(CompletionTest, Limit) {
179 clangd::CodeCompleteOptions Opts;
180 Opts.Limit = 2;
181 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000182struct ClassWithMembers {
183 int AAA();
184 int BBB();
185 int CCC();
186}
Sam McCallf6ae3232017-12-05 20:11:29 +0000187int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000188 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000189 /*IndexSymbols=*/{}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000190
191 EXPECT_TRUE(Results.isIncomplete);
Sam McCallf6ae3232017-12-05 20:11:29 +0000192 EXPECT_THAT(Results.items, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000193}
194
Sam McCallf6ae3232017-12-05 20:11:29 +0000195TEST(CompletionTest, Filter) {
196 std::string Body = R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000197 #define MotorCar
198 int Car;
Sam McCall9aad25f2017-12-05 07:20:26 +0000199 struct S {
200 int FooBar;
201 int FooBaz;
202 int Qux;
203 };
204 )cpp";
Sam McCall8b2dcc12018-06-14 13:50:30 +0000205
206 // Only items matching the fuzzy query are returned.
Sam McCallf6ae3232017-12-05 20:11:29 +0000207 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").items,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000208 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000209
Sam McCall8b2dcc12018-06-14 13:50:30 +0000210 // Macros require prefix match.
211 EXPECT_THAT(completions(Body + "int main() { C^ }").items,
212 AllOf(Has("Car"), Not(Has("MotorCar"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000213}
214
Sam McCallf6ae3232017-12-05 20:11:29 +0000215void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000216 auto Results = completions(
217 R"cpp(
218 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000219
Sam McCall44fdcec22017-12-08 15:00:59 +0000220 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000221
Sam McCall44fdcec22017-12-08 15:00:59 +0000222 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000223
Sam McCall44fdcec22017-12-08 15:00:59 +0000224 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000225
Sam McCall44fdcec22017-12-08 15:00:59 +0000226 struct ClassWithMembers {
227 /// Doc for method.
228 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000229
Sam McCall44fdcec22017-12-08 15:00:59 +0000230 int field;
231 private:
232 int private_field;
233 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000234
Sam McCall44fdcec22017-12-08 15:00:59 +0000235 int test() {
236 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000237
Sam McCall44fdcec22017-12-08 15:00:59 +0000238 /// Doc for local_var.
239 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000240
Sam McCall44fdcec22017-12-08 15:00:59 +0000241 ClassWithMembers().^
242 }
243 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000244 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000245
Sam McCallf6ae3232017-12-05 20:11:29 +0000246 // Class members. The only items that must be present in after-dot
247 // completion.
Sam McCall4caa8512018-06-07 12:49:17 +0000248 EXPECT_THAT(Results.items,
249 AllOf(Has(Opts.EnableSnippets ? "method()" : "method"),
250 Has("field"), Not(Has("ClassWithMembers")),
251 Not(Has("operator=")), Not(Has("~ClassWithMembers"))));
Sam McCall44fdcec22017-12-08 15:00:59 +0000252 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.items,
253 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000254 // Global items.
Sam McCall545a20d2018-01-19 14:34:02 +0000255 EXPECT_THAT(
256 Results.items,
257 Not(AnyOf(Has("global_var"), Has("index_var"), Has("global_func"),
258 Has("global_func()"), Has("index_func"), Has("GlobalClass"),
259 Has("IndexClass"), Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000260 // There should be no code patterns (aka snippets) in after-dot
261 // completion. At least there aren't any we're aware of.
Sam McCall44fdcec22017-12-08 15:00:59 +0000262 EXPECT_THAT(Results.items, Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000263 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000264 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000265}
Sam McCall9aad25f2017-12-05 07:20:26 +0000266
Sam McCallf6ae3232017-12-05 20:11:29 +0000267void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000268 auto Results = completions(
269 R"cpp(
270 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000271
Sam McCall44fdcec22017-12-08 15:00:59 +0000272 int global_var;
273 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000274
Sam McCall44fdcec22017-12-08 15:00:59 +0000275 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000276
Sam McCall44fdcec22017-12-08 15:00:59 +0000277 struct ClassWithMembers {
278 /// Doc for method.
279 int method();
280 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000281
Sam McCall44fdcec22017-12-08 15:00:59 +0000282 int test() {
283 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000284
Sam McCall44fdcec22017-12-08 15:00:59 +0000285 /// Doc for local_var.
286 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000287
Sam McCall44fdcec22017-12-08 15:00:59 +0000288 ^
289 }
290 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000291 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000292
293 // Class members. Should never be present in global completions.
Sam McCall44fdcec22017-12-08 15:00:59 +0000294 EXPECT_THAT(Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000295 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
296 // Global items.
Sam McCalld8169a82018-01-18 15:31:30 +0000297 EXPECT_THAT(Results.items,
Sam McCall545a20d2018-01-19 14:34:02 +0000298 AllOf(Has("global_var"), Has("index_var"),
Sam McCalld8169a82018-01-18 15:31:30 +0000299 Has(Opts.EnableSnippets ? "global_func()" : "global_func"),
Sam McCall545a20d2018-01-19 14:34:02 +0000300 Has("index_func" /* our fake symbol doesn't include () */),
301 Has("GlobalClass"), Has("IndexClass")));
Sam McCallf6ae3232017-12-05 20:11:29 +0000302 // A macro.
Sam McCall44fdcec22017-12-08 15:00:59 +0000303 EXPECT_IFF(Opts.IncludeMacros, Results.items, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000304 // Local items. Must be present always.
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000305 EXPECT_THAT(Results.items,
306 AllOf(Has("local_var"), Has("LocalClass"),
307 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000308 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000309 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000310}
311
312TEST(CompletionTest, CompletionOptions) {
Sam McCall2c3849a2018-01-16 12:21:24 +0000313 auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
314 TestAfterDotCompletion(Opts);
315 TestGlobalScopeCompletion(Opts);
316 };
317 // We used to test every combination of options, but that got too slow (2^N).
318 auto Flags = {
Ilya Biryukov71028b82018-03-12 15:28:22 +0000319 &clangd::CodeCompleteOptions::IncludeMacros,
Ilya Biryukov43714502018-05-16 12:32:44 +0000320 &clangd::CodeCompleteOptions::IncludeComments,
Ilya Biryukov71028b82018-03-12 15:28:22 +0000321 &clangd::CodeCompleteOptions::EnableSnippets,
322 &clangd::CodeCompleteOptions::IncludeCodePatterns,
323 &clangd::CodeCompleteOptions::IncludeIneligibleResults,
Sam McCall2c3849a2018-01-16 12:21:24 +0000324 };
325 // Test default options.
326 Test({});
327 // Test with one flag flipped.
328 for (auto &F : Flags) {
329 clangd::CodeCompleteOptions O;
330 O.*F ^= true;
331 Test(O);
Sam McCall9aad25f2017-12-05 07:20:26 +0000332 }
333}
334
Sam McCall44fdcec22017-12-08 15:00:59 +0000335TEST(CompletionTest, Priorities) {
336 auto Internal = completions(R"cpp(
337 class Foo {
338 public: void pub();
339 protected: void prot();
340 private: void priv();
341 };
342 void Foo::pub() { this->^ }
343 )cpp");
344 EXPECT_THAT(Internal.items,
345 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
346
347 auto External = completions(R"cpp(
348 class Foo {
349 public: void pub();
350 protected: void prot();
351 private: void priv();
352 };
353 void test() {
354 Foo F;
355 F.^
356 }
357 )cpp");
358 EXPECT_THAT(External.items,
359 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
360}
361
362TEST(CompletionTest, Qualifiers) {
363 auto Results = completions(R"cpp(
364 class Foo {
365 public: int foo() const;
366 int bar() const;
367 };
368 class Bar : public Foo {
369 int foo() const;
370 };
371 void test() { Bar().^ }
372 )cpp");
373 EXPECT_THAT(Results.items, HasSubsequence(Labeled("bar() const"),
374 Labeled("Foo::foo() const")));
375 EXPECT_THAT(Results.items, Not(Contains(Labeled("foo() const")))); // private
376}
377
Sam McCall4caa8512018-06-07 12:49:17 +0000378TEST(CompletionTest, InjectedTypename) {
379 // These are suppressed when accessed as a member...
380 EXPECT_THAT(completions("struct X{}; void foo(){ X().^ }").items,
381 Not(Has("X")));
382 EXPECT_THAT(completions("struct X{ void foo(){ this->^ } };").items,
383 Not(Has("X")));
384 // ...but accessible in other, more useful cases.
385 EXPECT_THAT(completions("struct X{ void foo(){ ^ } };").items, Has("X"));
386 EXPECT_THAT(completions("struct Y{}; struct X:Y{ void foo(){ ^ } };").items,
387 Has("Y"));
388 EXPECT_THAT(
389 completions(
390 "template<class> struct Y{}; struct X:Y<int>{ void foo(){ ^ } };")
391 .items,
392 Has("Y"));
393 // This case is marginal (`using X::X` is useful), we allow it for now.
394 EXPECT_THAT(completions("struct X{}; void foo(){ X::^ }").items, Has("X"));
395}
396
Sam McCall44fdcec22017-12-08 15:00:59 +0000397TEST(CompletionTest, Snippets) {
398 clangd::CodeCompleteOptions Opts;
399 Opts.EnableSnippets = true;
400 auto Results = completions(
401 R"cpp(
402 struct fake {
403 int a;
404 int f(int i, const float f) const;
405 };
406 int main() {
407 fake f;
408 f.^
409 }
410 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000411 /*IndexSymbols=*/{}, Opts);
Sam McCall44fdcec22017-12-08 15:00:59 +0000412 EXPECT_THAT(Results.items,
Eric Liu63696e12017-12-20 17:24:31 +0000413 HasSubsequence(Snippet("a"),
Sam McCall44fdcec22017-12-08 15:00:59 +0000414 Snippet("f(${1:int i}, ${2:const float f})")));
415}
416
417TEST(CompletionTest, Kinds) {
Sam McCall545a20d2018-01-19 14:34:02 +0000418 auto Results = completions(
419 R"cpp(
420 #define MACRO X
421 int variable;
422 struct Struct {};
423 int function();
424 int X = ^
425 )cpp",
426 {func("indexFunction"), var("indexVariable"), cls("indexClass")});
427 EXPECT_THAT(Results.items,
428 AllOf(Has("function", CompletionItemKind::Function),
429 Has("variable", CompletionItemKind::Variable),
430 Has("int", CompletionItemKind::Keyword),
431 Has("Struct", CompletionItemKind::Class),
432 Has("MACRO", CompletionItemKind::Text),
433 Has("indexFunction", CompletionItemKind::Function),
434 Has("indexVariable", CompletionItemKind::Variable),
435 Has("indexClass", CompletionItemKind::Class)));
Sam McCall44fdcec22017-12-08 15:00:59 +0000436
Sam McCall44fdcec22017-12-08 15:00:59 +0000437 Results = completions("nam^");
438 EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
439}
440
Sam McCall84652cc2018-01-12 16:16:09 +0000441TEST(CompletionTest, NoDuplicates) {
Sam McCall545a20d2018-01-19 14:34:02 +0000442 auto Results = completions(
443 R"cpp(
444 class Adapter {
Sam McCall545a20d2018-01-19 14:34:02 +0000445 };
Sam McCall84652cc2018-01-12 16:16:09 +0000446
Eric Liu9b3cba72018-05-30 09:03:39 +0000447 void f() {
Sam McCall545a20d2018-01-19 14:34:02 +0000448 Adapter^
449 }
450 )cpp",
451 {cls("Adapter")});
Sam McCall84652cc2018-01-12 16:16:09 +0000452
453 // Make sure there are no duplicate entries of 'Adapter'.
Sam McCalld2a95922018-01-22 21:05:00 +0000454 EXPECT_THAT(Results.items, ElementsAre(Named("Adapter")));
Sam McCall84652cc2018-01-12 16:16:09 +0000455}
456
Sam McCall545a20d2018-01-19 14:34:02 +0000457TEST(CompletionTest, ScopedNoIndex) {
458 auto Results = completions(
459 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000460 namespace fake { int BigBang, Babble, Box; };
461 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000462 ")cpp");
Sam McCall8b2dcc12018-06-14 13:50:30 +0000463 // Babble is a better match than BigBang. Box doesn't match at all.
464 EXPECT_THAT(Results.items, ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCall84652cc2018-01-12 16:16:09 +0000465}
466
Sam McCall545a20d2018-01-19 14:34:02 +0000467TEST(CompletionTest, Scoped) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000468 auto Results = completions(
469 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000470 namespace fake { int Babble, Box; };
471 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000472 ")cpp",
473 {var("fake::BigBang")});
Sam McCall8b2dcc12018-06-14 13:50:30 +0000474 EXPECT_THAT(Results.items, ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000475}
476
Sam McCall545a20d2018-01-19 14:34:02 +0000477TEST(CompletionTest, ScopedWithFilter) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000478 auto Results = completions(
479 R"cpp(
480 void f() { ns::x^ }
481 )cpp",
482 {cls("ns::XYZ"), func("ns::foo")});
483 EXPECT_THAT(Results.items,
484 UnorderedElementsAre(AllOf(Named("XYZ"), Filter("XYZ"))));
485}
486
Sam McCalldc8abc42018-05-03 14:53:02 +0000487TEST(CompletionTest, ReferencesAffectRanking) {
488 auto Results = completions("int main() { abs^ }", {ns("absl"), func("abs")});
489 EXPECT_THAT(Results.items, HasSubsequence(Named("abs"), Named("absl")));
490 Results = completions("int main() { abs^ }",
491 {withReferences(10000, ns("absl")), func("abs")});
492 EXPECT_THAT(Results.items, HasSubsequence(Named("absl"), Named("abs")));
493}
494
Sam McCall545a20d2018-01-19 14:34:02 +0000495TEST(CompletionTest, GlobalQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000496 auto Results = completions(
497 R"cpp(
498 void f() { ::^ }
499 )cpp",
500 {cls("XYZ")});
501 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
502 Has("f", CompletionItemKind::Function)));
503}
504
Sam McCall545a20d2018-01-19 14:34:02 +0000505TEST(CompletionTest, FullyQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000506 auto Results = completions(
507 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000508 namespace ns { void bar(); }
Sam McCalla15c2d62018-01-18 09:27:56 +0000509 void f() { ::ns::^ }
510 )cpp",
511 {cls("ns::XYZ")});
Sam McCall545a20d2018-01-19 14:34:02 +0000512 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
513 Has("bar", CompletionItemKind::Function)));
514}
515
516TEST(CompletionTest, SemaIndexMerge) {
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")});
523 // We get results from both index and sema, with no duplicates.
524 EXPECT_THAT(
525 Results.items,
526 UnorderedElementsAre(Named("local"), Named("Index"), Named("both")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000527}
528
Haojian Wu48b48652018-01-25 09:20:09 +0000529TEST(CompletionTest, SemaIndexMergeWithLimit) {
530 clangd::CodeCompleteOptions Opts;
531 Opts.Limit = 1;
532 auto Results = completions(
533 R"cpp(
534 namespace ns { int local; void both(); }
535 void f() { ::ns::^ }
536 )cpp",
537 {func("ns::both"), cls("ns::Index")}, Opts);
538 EXPECT_EQ(Results.items.size(), Opts.Limit);
539 EXPECT_TRUE(Results.isIncomplete);
540}
541
Eric Liu63f419a2018-05-15 15:29:32 +0000542TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
543 MockFSProvider FS;
544 MockCompilationDatabase CDB;
545 std::string Subdir = testPath("sub");
546 std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
547 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
548 std::string BarHeader = testPath("sub/bar.h");
549 FS.Files[BarHeader] = "";
550
551 IgnoreDiagnostics DiagConsumer;
552 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
553 Symbol::Details Scratch;
554 auto BarURI = URI::createFile(BarHeader).toString();
555 Symbol Sym = cls("ns::X");
556 Sym.CanonicalDeclaration.FileURI = BarURI;
557 Scratch.IncludeHeader = BarURI;
558 Sym.Detail = &Scratch;
559 // Shoten include path based on search dirctory and insert.
560 auto Results = completions(Server,
561 R"cpp(
562 int main() { ns::^ }
563 )cpp",
564 {Sym});
565 EXPECT_THAT(Results.items,
566 ElementsAre(AllOf(Named("X"), InsertInclude("\"bar.h\""))));
567 // Duplicate based on inclusions in preamble.
568 Results = completions(Server,
569 R"cpp(
570 #include "sub/bar.h" // not shortest, so should only match resolved.
571 int main() { ns::^ }
572 )cpp",
573 {Sym});
574 EXPECT_THAT(Results.items,
575 ElementsAre(AllOf(Named("X"), Not(HasAdditionalEdits()))));
576}
577
Eric Liu9b3cba72018-05-30 09:03:39 +0000578TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
579 MockFSProvider FS;
580 MockCompilationDatabase CDB;
581
582 IgnoreDiagnostics DiagConsumer;
583 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
584 Symbol::Details Scratch;
585 Symbol SymX = cls("ns::X");
586 Symbol SymY = cls("ns::Y");
587 std::string BarHeader = testPath("bar.h");
588 auto BarURI = URI::createFile(BarHeader).toString();
589 SymX.CanonicalDeclaration.FileURI = BarURI;
590 SymY.CanonicalDeclaration.FileURI = BarURI;
591 Scratch.IncludeHeader = "<bar>";
592 SymX.Detail = &Scratch;
593 SymY.Detail = &Scratch;
594 // Shoten include path based on search dirctory and insert.
595 auto Results = completions(Server,
596 R"cpp(
597 namespace ns {
598 class X;
599 class Y {}
600 }
601 int main() { ns::^ }
602 )cpp",
603 {SymX, SymY});
604 EXPECT_THAT(Results.items,
605 ElementsAre(AllOf(Named("X"), Not(HasAdditionalEdits())),
606 AllOf(Named("Y"), Not(HasAdditionalEdits()))));
607}
608
Sam McCalla15c2d62018-01-18 09:27:56 +0000609TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
610 MockFSProvider FS;
611 MockCompilationDatabase CDB;
612 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000613 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCalla15c2d62018-01-18 09:27:56 +0000614
Sam McCallc1568062018-02-16 09:41:43 +0000615 FS.Files[testPath("bar.h")] =
Sam McCalld5ea3e32018-01-24 17:53:32 +0000616 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
Sam McCallc1568062018-02-16 09:41:43 +0000617 auto File = testPath("foo.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000618 Annotations Test(R"cpp(
619 #include "bar.h"
620 namespace ns { int local; }
Sam McCalld5ea3e32018-01-24 17:53:32 +0000621 void f() { ns::^; }
622 void f() { ns::preamble().$2^; }
Sam McCalla15c2d62018-01-18 09:27:56 +0000623 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000624 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000625 clangd::CodeCompleteOptions Opts = {};
626
Sam McCalla15c2d62018-01-18 09:27:56 +0000627 auto I = memIndex({var("ns::index")});
628 Opts.Index = I.get();
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000629 auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalla15c2d62018-01-18 09:27:56 +0000630 EXPECT_THAT(WithIndex.items,
631 UnorderedElementsAre(Named("local"), Named("index")));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000632 auto ClassFromPreamble =
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000633 cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000634 EXPECT_THAT(ClassFromPreamble.items, Contains(Named("member")));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000635
636 Opts.Index = nullptr;
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000637 auto WithoutIndex =
638 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000639 EXPECT_THAT(WithoutIndex.items,
640 UnorderedElementsAre(Named("local"), Named("preamble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000641}
642
643TEST(CompletionTest, DynamicIndexMultiFile) {
644 MockFSProvider FS;
645 MockCompilationDatabase CDB;
646 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000647 auto Opts = ClangdServer::optsForTest();
648 Opts.BuildDynamicSymbolIndex = true;
649 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCalla15c2d62018-01-18 09:27:56 +0000650
Eric Liu709bde82018-02-19 18:48:44 +0000651 FS.Files[testPath("foo.h")] = R"cpp(
Sam McCalla15c2d62018-01-18 09:27:56 +0000652 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liu709bde82018-02-19 18:48:44 +0000653 )cpp";
Sam McCall7363a2f2018-03-05 17:28:54 +0000654 runAddDocument(Server, testPath("foo.cpp"), R"cpp(
Eric Liu709bde82018-02-19 18:48:44 +0000655 #include "foo.h"
Sam McCall0bb24cd2018-02-13 08:59:23 +0000656 )cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000657
Sam McCallc1568062018-02-16 09:41:43 +0000658 auto File = testPath("bar.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000659 Annotations Test(R"cpp(
660 namespace ns {
661 class XXX {};
662 /// Doooc
663 void fooooo() {}
664 }
665 void f() { ns::^ }
666 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000667 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000668
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000669 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
Sam McCalla15c2d62018-01-18 09:27:56 +0000670 // "XYZ" and "foo" are not included in the file being completed but are still
671 // visible through the index.
672 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
673 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
674 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
675 EXPECT_THAT(Results.items, Contains(AllOf(Named("fooooo"), Filter("fooooo"),
676 Kind(CompletionItemKind::Function),
677 Doc("Doooc"), Detail("void"))));
678}
679
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000680TEST(CompletionTest, Documentation) {
681 auto Results = completions(
682 R"cpp(
683 // Non-doxygen comment.
684 int foo();
685 /// Doxygen comment.
686 /// \param int a
687 int bar(int a);
688 /* Multi-line
689 block comment
690 */
691 int baz();
692
693 int x = ^
694 )cpp");
695 EXPECT_THAT(Results.items,
696 Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
697 EXPECT_THAT(
698 Results.items,
699 Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
700 EXPECT_THAT(Results.items,
701 Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
702}
703
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000704TEST(CompletionTest, GlobalCompletionFiltering) {
705
706 Symbol Class = cls("XYZ");
707 Class.IsIndexedForCodeCompletion = false;
708 Symbol Func = func("XYZ::foooo");
709 Func.IsIndexedForCodeCompletion = false;
710
711 auto Results = completions(R"(// void f() {
712 XYZ::foooo^
713 })",
714 {Class, Func});
715 EXPECT_THAT(Results.items, IsEmpty());
716}
717
Haojian Wu58d208d2018-01-25 09:44:06 +0000718TEST(CodeCompleteTest, DisableTypoCorrection) {
719 auto Results = completions(R"cpp(
720 namespace clang { int v; }
721 void f() { clangd::^
722 )cpp");
723 EXPECT_TRUE(Results.items.empty());
724}
725
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000726TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
727 auto Results = completions(R"cpp(
728 namespace clang { }
729 void f() {
730 clan^
731 }
732 )cpp");
733
734 EXPECT_THAT(Results.items, Contains(Labeled("clang")));
735 EXPECT_THAT(Results.items, Not(Contains(Labeled("clang::"))));
736}
737
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000738TEST(CompletionTest, BacktrackCrashes) {
739 // Sema calls code completion callbacks twice in these cases.
740 auto Results = completions(R"cpp(
741 namespace ns {
742 struct FooBarBaz {};
743 } // namespace ns
744
745 int foo(ns::FooBar^
746 )cpp");
747
748 EXPECT_THAT(Results.items, ElementsAre(Labeled("FooBarBaz")));
749
750 // Check we don't crash in that case too.
751 completions(R"cpp(
752 struct FooBarBaz {};
753 void test() {
754 if (FooBarBaz * x^) {}
755 }
756)cpp");
757}
758
Eric Liu42abe412018-05-24 11:20:19 +0000759TEST(CompletionTest, CompleteInMacroWithStringification) {
760 auto Results = completions(R"cpp(
761void f(const char *, int x);
762#define F(x) f(#x, x)
763
764namespace ns {
765int X;
766int Y;
767} // namespace ns
768
769int f(int input_num) {
770 F(ns::^)
771}
772)cpp");
773
774 EXPECT_THAT(Results.items,
775 UnorderedElementsAre(Named("X"), Named("Y")));
776}
777
778TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
779 auto Results = completions(R"cpp(
780void f(const char *, int x);
781#define F(x) f(#x, x)
782
783namespace ns {
784int X;
785
786int f(int input_num) {
787 F(^)
788}
789} // namespace ns
790)cpp");
791
792 EXPECT_THAT(Results.items, Contains(Named("X")));
793}
794
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000795TEST(CompletionTest, CompleteInExcludedPPBranch) {
796 auto Results = completions(R"cpp(
797 int bar(int param_in_bar) {
798 }
799
800 int foo(int param_in_foo) {
801#if 0
802 par^
803#endif
804 }
805)cpp");
806
807 EXPECT_THAT(Results.items, Contains(Labeled("param_in_foo")));
808 EXPECT_THAT(Results.items, Not(Contains(Labeled("param_in_bar"))));
809}
810
Sam McCall800d4372017-12-19 10:29:27 +0000811SignatureHelp signatures(StringRef Text) {
812 MockFSProvider FS;
813 MockCompilationDatabase CDB;
814 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000815 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCallc1568062018-02-16 09:41:43 +0000816 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000817 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000818 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000819 return cantFail(runSignatureHelp(Server, File, Test.point()));
Sam McCall800d4372017-12-19 10:29:27 +0000820}
821
822MATCHER_P(ParamsAre, P, "") {
823 if (P.size() != arg.parameters.size())
824 return false;
825 for (unsigned I = 0; I < P.size(); ++I)
826 if (P[I] != arg.parameters[I].label)
827 return false;
828 return true;
829}
830
831Matcher<SignatureInformation> Sig(std::string Label,
832 std::vector<std::string> Params) {
833 return AllOf(Labeled(Label), ParamsAre(Params));
834}
835
836TEST(SignatureHelpTest, Overloads) {
837 auto Results = signatures(R"cpp(
838 void foo(int x, int y);
839 void foo(int x, float y);
840 void foo(float x, int y);
841 void foo(float x, float y);
842 void bar(int x, int y = 0);
843 int main() { foo(^); }
844 )cpp");
845 EXPECT_THAT(Results.signatures,
846 UnorderedElementsAre(
847 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
848 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
849 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
850 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
851 // We always prefer the first signature.
852 EXPECT_EQ(0, Results.activeSignature);
853 EXPECT_EQ(0, Results.activeParameter);
854}
855
856TEST(SignatureHelpTest, DefaultArgs) {
857 auto Results = signatures(R"cpp(
858 void bar(int x, int y = 0);
859 void bar(float x = 0, int y = 42);
860 int main() { bar(^
861 )cpp");
862 EXPECT_THAT(Results.signatures,
863 UnorderedElementsAre(
864 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
865 Sig("bar(float x = 0, int y = 42) -> void",
866 {"float x = 0", "int y = 42"})));
867 EXPECT_EQ(0, Results.activeSignature);
868 EXPECT_EQ(0, Results.activeParameter);
869}
870
871TEST(SignatureHelpTest, ActiveArg) {
872 auto Results = signatures(R"cpp(
873 int baz(int a, int b, int c);
874 int main() { baz(baz(1,2,3), ^); }
875 )cpp");
876 EXPECT_THAT(Results.signatures,
877 ElementsAre(Sig("baz(int a, int b, int c) -> int",
878 {"int a", "int b", "int c"})));
879 EXPECT_EQ(0, Results.activeSignature);
880 EXPECT_EQ(1, Results.activeParameter);
881}
882
Haojian Wu061c73e2018-01-23 11:37:26 +0000883class IndexRequestCollector : public SymbolIndex {
884public:
885 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000886 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000887 llvm::function_ref<void(const Symbol &)> Callback) const override {
888 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000889 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000890 }
891
Eric Liu9ec459f2018-03-14 09:48:05 +0000892 void lookup(const LookupRequest &,
893 llvm::function_ref<void(const Symbol &)>) const override {}
894
Haojian Wu061c73e2018-01-23 11:37:26 +0000895 const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
896
897private:
898 mutable std::vector<FuzzyFindRequest> Requests;
899};
900
901std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
902 clangd::CodeCompleteOptions Opts;
903 IndexRequestCollector Requests;
904 Opts.Index = &Requests;
905 completions(Code, {}, Opts);
906 return Requests.allRequests();
907}
908
909TEST(CompletionTest, UnqualifiedIdQuery) {
910 auto Requests = captureIndexRequests(R"cpp(
911 namespace std {}
912 using namespace std;
913 namespace ns {
914 void f() {
915 vec^
916 }
917 }
918 )cpp");
919
920 EXPECT_THAT(Requests,
921 ElementsAre(Field(&FuzzyFindRequest::Scopes,
922 UnorderedElementsAre("", "ns::", "std::"))));
923}
924
925TEST(CompletionTest, ResolvedQualifiedIdQuery) {
926 auto Requests = captureIndexRequests(R"cpp(
927 namespace ns1 {}
928 namespace ns2 {} // ignore
929 namespace ns3 { namespace nns3 {} }
930 namespace foo {
931 using namespace ns1;
932 using namespace ns3::nns3;
933 }
934 namespace ns {
935 void f() {
936 foo::^
937 }
938 }
939 )cpp");
940
941 EXPECT_THAT(Requests,
942 ElementsAre(Field(
943 &FuzzyFindRequest::Scopes,
944 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
945}
946
947TEST(CompletionTest, UnresolvedQualifierIdQuery) {
948 auto Requests = captureIndexRequests(R"cpp(
949 namespace a {}
950 using namespace a;
951 namespace ns {
952 void f() {
953 bar::^
954 }
955 } // namespace ns
956 )cpp");
957
958 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
959 UnorderedElementsAre("bar::"))));
960}
961
962TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
963 auto Requests = captureIndexRequests(R"cpp(
964 namespace a {}
965 using namespace a;
966 namespace ns {
967 void f() {
968 ::a::bar::^
969 }
970 } // namespace ns
971 )cpp");
972
973 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
974 UnorderedElementsAre("a::bar::"))));
975}
976
977TEST(CompletionTest, EmptyQualifiedQuery) {
978 auto Requests = captureIndexRequests(R"cpp(
979 namespace ns {
980 void f() {
981 ^
982 }
983 } // namespace ns
984 )cpp");
985
986 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
987 UnorderedElementsAre("", "ns::"))));
988}
989
990TEST(CompletionTest, GlobalQualifiedQuery) {
991 auto Requests = captureIndexRequests(R"cpp(
992 namespace ns {
993 void f() {
994 ::^
995 }
996 } // namespace ns
997 )cpp");
998
999 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1000 UnorderedElementsAre(""))));
1001}
1002
Ilya Biryukova907ba42018-05-14 10:50:04 +00001003TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
1004 auto Completions = completions(
1005 R"cpp(
1006 struct Foo {
1007 int SomeNameOfField;
1008 typedef int SomeNameOfTypedefField;
1009 };
1010
1011 Foo::^)cpp",
1012 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
1013
1014 EXPECT_THAT(Completions.items,
1015 AllOf(Contains(Labeled("SomeNameOfField")),
1016 Contains(Labeled("SomeNameOfTypedefField")),
1017 Not(Contains(Labeled("SomeNameInTheIndex")))));
1018}
1019
1020TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
1021 {
1022 auto Completions = completions(
1023 R"cpp(
1024 template <class T>
1025 void foo() {
1026 T::^
1027 }
1028 )cpp",
1029 {func("::SomeNameInTheIndex")});
1030
1031 EXPECT_THAT(Completions.items,
1032 Not(Contains(Labeled("SomeNameInTheIndex"))));
1033 }
1034
1035 {
1036 auto Completions = completions(
1037 R"cpp(
1038 template <class T>
1039 void foo() {
1040 T::template Y<int>::^
1041 }
1042 )cpp",
1043 {func("::SomeNameInTheIndex")});
1044
1045 EXPECT_THAT(Completions.items,
1046 Not(Contains(Labeled("SomeNameInTheIndex"))));
1047 }
1048
1049 {
1050 auto Completions = completions(
1051 R"cpp(
1052 template <class T>
1053 void foo() {
1054 T::foo::^
1055 }
1056 )cpp",
1057 {func("::SomeNameInTheIndex")});
1058
1059 EXPECT_THAT(Completions.items,
1060 Not(Contains(Labeled("SomeNameInTheIndex"))));
1061 }
1062}
1063
Sam McCallc18c2802018-06-15 11:06:29 +00001064TEST(CompletionTest, OverloadBundling) {
1065 clangd::CodeCompleteOptions Opts;
1066 Opts.BundleOverloads = true;
1067
1068 std::string Context = R"cpp(
1069 struct X {
1070 // Overload with int
1071 int a(int);
1072 // Overload with bool
1073 int a(bool);
1074 int b(float);
1075 };
1076 int GFuncC(int);
1077 int GFuncD(int);
1078 )cpp";
1079
1080 // Member completions are bundled.
1081 EXPECT_THAT(completions(Context + "int y = X().^", {}, Opts).items,
1082 UnorderedElementsAre(Labeled("a(…)"), Labeled("b(float)")));
1083
1084 // Non-member completions are bundled, including index+sema.
1085 Symbol NoArgsGFunc = func("GFuncC");
1086 EXPECT_THAT(
1087 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).items,
1088 UnorderedElementsAre(Labeled("GFuncC(…)"), Labeled("GFuncD(int)")));
1089
1090 // Differences in header-to-insert suppress bundling.
1091 Symbol::Details Detail;
1092 std::string DeclFile = URI::createFile(testPath("foo")).toString();
1093 NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile;
1094 Detail.IncludeHeader = "<foo>";
1095 NoArgsGFunc.Detail = &Detail;
1096 EXPECT_THAT(
1097 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).items,
1098 UnorderedElementsAre(AllOf(Named("GFuncC"), InsertInclude("<foo>")),
1099 Labeled("GFuncC(int)"), Labeled("GFuncD(int)")));
1100
1101 // Examine a bundled completion in detail.
1102 auto A = completions(Context + "int y = X().a^", {}, Opts).items.front();
1103 EXPECT_EQ(A.label, "a(…)");
1104 EXPECT_EQ(A.detail, "[2 overloads]");
1105 EXPECT_EQ(A.insertText, "a");
1106 EXPECT_EQ(A.kind, CompletionItemKind::Method);
1107 // For now we just return one of the doc strings arbitrarily.
1108 EXPECT_THAT(A.documentation, AnyOf(HasSubstr("Overload with int"),
1109 HasSubstr("Overload with bool")));
1110 Opts.EnableSnippets = true;
1111 A = completions(Context + "int y = X().a^", {}, Opts).items.front();
1112 EXPECT_EQ(A.insertText, "a(${0})");
1113}
1114
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001115TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001116 MockFSProvider FS;
1117 auto FooH = testPath("foo.h");
1118 auto FooCpp = testPath("foo.cpp");
1119 FS.Files[FooH] = R"cpp(
1120 // this is my documentation comment.
1121 int func();
1122 )cpp";
1123 FS.Files[FooCpp] = "";
1124
1125 MockCompilationDatabase CDB;
1126 IgnoreDiagnostics DiagConsumer;
1127 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1128
1129 Annotations Source(R"cpp(
1130 #include "foo.h"
1131 int func() {
1132 // This makes sure we have func from header in the AST.
1133 }
1134 int a = fun^
1135 )cpp");
1136 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1137 // We need to wait for preamble to build.
1138 ASSERT_TRUE(Server.blockUntilIdleForTest());
1139
1140 // Change the header file. Completion will reuse the old preamble!
1141 FS.Files[FooH] = R"cpp(
1142 int func();
1143 )cpp";
1144
1145 clangd::CodeCompleteOptions Opts;
1146 Opts.IncludeComments = true;
1147 CompletionList Completions =
1148 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1149 // We shouldn't crash. Unfortunately, current workaround is to not produce
1150 // comments for symbols from headers.
1151 EXPECT_THAT(Completions.items,
1152 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1153}
1154
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001155TEST(CompletionTest, NonDocComments) {
1156 MockFSProvider FS;
1157 auto FooCpp = testPath("foo.cpp");
1158 FS.Files[FooCpp] = "";
1159
1160 MockCompilationDatabase CDB;
1161 IgnoreDiagnostics DiagConsumer;
1162 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1163
1164 Annotations Source(R"cpp(
1165 // ------------------
1166 int comments_foo();
1167
1168 // A comment and a decl are separated by newlines.
1169 // Therefore, the comment shouldn't show up as doc comment.
1170
1171 int comments_bar();
1172
1173 // this comment should be in the results.
1174 int comments_baz();
1175
1176
1177 template <class T>
1178 struct Struct {
1179 int comments_qux();
1180 int comments_quux();
1181 };
1182
1183
1184 // This comment should not be there.
1185
1186 template <class T>
1187 int Struct<T>::comments_qux() {
1188 }
1189
1190 // This comment **should** be in results.
1191 template <class T>
1192 int Struct<T>::comments_quux() {
1193 int a = comments^;
1194 }
1195 )cpp");
1196 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1197 CompletionList Completions = cantFail(runCodeComplete(
1198 Server, FooCpp, Source.point(), clangd::CodeCompleteOptions()));
1199
1200 // We should not get any of those comments in completion.
1201 EXPECT_THAT(
1202 Completions.items,
1203 UnorderedElementsAre(AllOf(Not(IsDocumented()), Named("comments_foo")),
1204 AllOf(IsDocumented(), Named("comments_baz")),
1205 AllOf(IsDocumented(), Named("comments_quux")),
1206 // FIXME(ibiryukov): the following items should have
1207 // empty documentation, since they are separated from
1208 // a comment with an empty line. Unfortunately, I
1209 // couldn't make Sema tests pass if we ignore those.
1210 AllOf(IsDocumented(), Named("comments_bar")),
1211 AllOf(IsDocumented(), Named("comments_qux"))));
1212}
1213
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001214TEST(CompletionTest, CompleteOnInvalidLine) {
1215 auto FooCpp = testPath("foo.cpp");
1216
1217 MockCompilationDatabase CDB;
1218 IgnoreDiagnostics DiagConsumer;
1219 MockFSProvider FS;
1220 FS.Files[FooCpp] = "// empty file";
1221
1222 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1223 // Run completion outside the file range.
1224 Position Pos;
1225 Pos.line = 100;
1226 Pos.character = 0;
1227 EXPECT_THAT_EXPECTED(
1228 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1229 Failed());
1230}
1231
1232
Sam McCall9aad25f2017-12-05 07:20:26 +00001233} // namespace
1234} // namespace clangd
1235} // namespace clang