blob: eed9433d6532095e3f713edd77989179e080fd8d [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; }
Eric Liu7ad16962018-06-22 10:46:59 +000047MATCHER_P(Scope, Name, "") { return arg.SymbolScope == Name; }
Eric Liu8f3678d2018-06-15 13:34:18 +000048MATCHER_P(Labeled, Label, "") {
49 std::string Indented;
50 if (!StringRef(Label).startswith(
51 CodeCompleteOptions().IncludeIndicator.Insert) &&
52 !StringRef(Label).startswith(
53 CodeCompleteOptions().IncludeIndicator.NoInsert))
54 Indented =
55 (Twine(CodeCompleteOptions().IncludeIndicator.NoInsert) + Label).str();
56 else
57 Indented = Label;
58 return arg.label == Indented;
59}
60MATCHER_P(SigHelpLabeled, Label, "") { return arg.label == Label; }
Sam McCall44fdcec22017-12-08 15:00:59 +000061MATCHER_P(Kind, K, "") { return arg.kind == K; }
Eric Liu6f648df2017-12-19 16:50:37 +000062MATCHER_P(Filter, F, "") { return arg.filterText == F; }
Eric Liu76f6b442018-01-09 17:32:00 +000063MATCHER_P(Doc, D, "") { return arg.documentation == D; }
64MATCHER_P(Detail, D, "") { return arg.detail == D; }
Eric Liu63f419a2018-05-15 15:29:32 +000065MATCHER_P(InsertInclude, IncludeHeader, "") {
66 if (arg.additionalTextEdits.size() != 1)
67 return false;
68 const auto &Edit = arg.additionalTextEdits[0];
69 if (Edit.range.start != Edit.range.end)
70 return false;
71 SmallVector<StringRef, 2> Matches;
72 llvm::Regex RE(R"(#include[ ]*(["<][^">]*[">]))");
73 return RE.match(Edit.newText, &Matches) && Matches[1] == IncludeHeader;
74}
Sam McCall44fdcec22017-12-08 15:00:59 +000075MATCHER_P(PlainText, Text, "") {
76 return arg.insertTextFormat == clangd::InsertTextFormat::PlainText &&
77 arg.insertText == Text;
78}
79MATCHER_P(Snippet, Text, "") {
80 return arg.insertTextFormat == clangd::InsertTextFormat::Snippet &&
81 arg.insertText == Text;
82}
Sam McCall545a20d2018-01-19 14:34:02 +000083MATCHER(NameContainsFilter, "") {
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000084 if (arg.filterText.empty())
85 return true;
86 return llvm::StringRef(arg.insertText).contains(arg.filterText);
87}
Eric Liu63f419a2018-05-15 15:29:32 +000088MATCHER(HasAdditionalEdits, "") { return !arg.additionalTextEdits.empty(); }
89
Sam McCallf6ae3232017-12-05 20:11:29 +000090// Shorthand for Contains(Named(Name)).
91Matcher<const std::vector<CompletionItem> &> Has(std::string Name) {
92 return Contains(Named(std::move(Name)));
93}
Sam McCall44fdcec22017-12-08 15:00:59 +000094Matcher<const std::vector<CompletionItem> &> Has(std::string Name,
95 CompletionItemKind K) {
96 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000097}
Sam McCall44fdcec22017-12-08 15:00:59 +000098MATCHER(IsDocumented, "") { return !arg.documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000099
Sam McCalla15c2d62018-01-18 09:27:56 +0000100std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
101 SymbolSlab::Builder Slab;
102 for (const auto &Sym : Symbols)
103 Slab.insert(Sym);
104 return MemIndex::build(std::move(Slab).build());
105}
106
Eric Liu63f419a2018-05-15 15:29:32 +0000107CompletionList completions(ClangdServer &Server, StringRef Text,
Sam McCalla15c2d62018-01-18 09:27:56 +0000108 std::vector<Symbol> IndexSymbols = {},
Sam McCallf6ae3232017-12-05 20:11:29 +0000109 clangd::CodeCompleteOptions Opts = {}) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000110 std::unique_ptr<SymbolIndex> OverrideIndex;
111 if (!IndexSymbols.empty()) {
112 assert(!Opts.Index && "both Index and IndexSymbols given!");
113 OverrideIndex = memIndex(std::move(IndexSymbols));
114 Opts.Index = OverrideIndex.get();
115 }
116
Sam McCallc1568062018-02-16 09:41:43 +0000117 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000118 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000119 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000120 auto CompletionList =
121 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000122 // Sanity-check that filterText is valid.
Sam McCall545a20d2018-01-19 14:34:02 +0000123 EXPECT_THAT(CompletionList.items, Each(NameContainsFilter()));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000124 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +0000125}
126
Eric Liu63f419a2018-05-15 15:29:32 +0000127// Builds a server and runs code completion.
128// If IndexSymbols is non-empty, an index will be built and passed to opts.
129CompletionList completions(StringRef Text,
130 std::vector<Symbol> IndexSymbols = {},
131 clangd::CodeCompleteOptions Opts = {}) {
132 MockFSProvider FS;
133 MockCompilationDatabase CDB;
134 IgnoreDiagnostics DiagConsumer;
135 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
136 return completions(Server, Text, std::move(IndexSymbols), std::move(Opts));
137}
138
Sam McCall545a20d2018-01-19 14:34:02 +0000139std::string replace(StringRef Haystack, StringRef Needle, StringRef Repl) {
140 std::string Result;
141 raw_string_ostream OS(Result);
142 std::pair<StringRef, StringRef> Split;
143 for (Split = Haystack.split(Needle); !Split.second.empty();
144 Split = Split.first.split(Needle))
145 OS << Split.first << Repl;
146 Result += Split.first;
147 OS.flush();
148 return Result;
149}
150
Sam McCalla15c2d62018-01-18 09:27:56 +0000151// Helpers to produce fake index symbols for memIndex() or completions().
Sam McCall545a20d2018-01-19 14:34:02 +0000152// USRFormat is a regex replacement string for the unqualified part of the USR.
153Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000154 Symbol Sym;
Sam McCall545a20d2018-01-19 14:34:02 +0000155 std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
Sam McCalla15c2d62018-01-18 09:27:56 +0000156 size_t Pos = QName.rfind("::");
157 if (Pos == llvm::StringRef::npos) {
158 Sym.Name = QName;
159 Sym.Scope = "";
160 } else {
161 Sym.Name = QName.substr(Pos + 2);
Sam McCall8b2faee2018-01-19 22:18:21 +0000162 Sym.Scope = QName.substr(0, Pos + 2);
163 USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
Sam McCalla15c2d62018-01-18 09:27:56 +0000164 }
Sam McCall545a20d2018-01-19 14:34:02 +0000165 USR += Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
166 Sym.ID = SymbolID(USR);
Sam McCalla15c2d62018-01-18 09:27:56 +0000167 Sym.SymInfo.Kind = Kind;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000168 Sym.IsIndexedForCodeCompletion = true;
Sam McCalla15c2d62018-01-18 09:27:56 +0000169 return Sym;
170}
Sam McCall545a20d2018-01-19 14:34:02 +0000171Symbol func(StringRef Name) { // Assumes the function has no args.
172 return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
173}
174Symbol cls(StringRef Name) {
Eric Liu9b3cba72018-05-30 09:03:39 +0000175 return sym(Name, index::SymbolKind::Class, "@S@\\0");
Sam McCall545a20d2018-01-19 14:34:02 +0000176}
177Symbol var(StringRef Name) {
178 return sym(Name, index::SymbolKind::Variable, "@\\0");
179}
Sam McCalldc8abc42018-05-03 14:53:02 +0000180Symbol ns(StringRef Name) {
181 return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
182}
183Symbol withReferences(int N, Symbol S) {
184 S.References = N;
185 return S;
186}
Sam McCalla15c2d62018-01-18 09:27:56 +0000187
Sam McCallf6ae3232017-12-05 20:11:29 +0000188TEST(CompletionTest, Limit) {
189 clangd::CodeCompleteOptions Opts;
190 Opts.Limit = 2;
191 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000192struct ClassWithMembers {
193 int AAA();
194 int BBB();
195 int CCC();
196}
Sam McCallf6ae3232017-12-05 20:11:29 +0000197int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000198 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000199 /*IndexSymbols=*/{}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000200
201 EXPECT_TRUE(Results.isIncomplete);
Sam McCallf6ae3232017-12-05 20:11:29 +0000202 EXPECT_THAT(Results.items, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000203}
204
Sam McCallf6ae3232017-12-05 20:11:29 +0000205TEST(CompletionTest, Filter) {
206 std::string Body = R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000207 #define MotorCar
208 int Car;
Sam McCall9aad25f2017-12-05 07:20:26 +0000209 struct S {
210 int FooBar;
211 int FooBaz;
212 int Qux;
213 };
214 )cpp";
Sam McCall8b2dcc12018-06-14 13:50:30 +0000215
216 // Only items matching the fuzzy query are returned.
Sam McCallf6ae3232017-12-05 20:11:29 +0000217 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").items,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000218 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000219
Sam McCall8b2dcc12018-06-14 13:50:30 +0000220 // Macros require prefix match.
221 EXPECT_THAT(completions(Body + "int main() { C^ }").items,
222 AllOf(Has("Car"), Not(Has("MotorCar"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000223}
224
Sam McCallf6ae3232017-12-05 20:11:29 +0000225void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000226 auto Results = completions(
227 R"cpp(
228 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000229
Sam McCall44fdcec22017-12-08 15:00:59 +0000230 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000231
Sam McCall44fdcec22017-12-08 15:00:59 +0000232 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000233
Sam McCall44fdcec22017-12-08 15:00:59 +0000234 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000235
Sam McCall44fdcec22017-12-08 15:00:59 +0000236 struct ClassWithMembers {
237 /// Doc for method.
238 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000239
Sam McCall44fdcec22017-12-08 15:00:59 +0000240 int field;
241 private:
242 int private_field;
243 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000244
Sam McCall44fdcec22017-12-08 15:00:59 +0000245 int test() {
246 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000247
Sam McCall44fdcec22017-12-08 15:00:59 +0000248 /// Doc for local_var.
249 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000250
Sam McCall44fdcec22017-12-08 15:00:59 +0000251 ClassWithMembers().^
252 }
253 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000254 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000255
Sam McCallf6ae3232017-12-05 20:11:29 +0000256 // Class members. The only items that must be present in after-dot
257 // completion.
Sam McCall4caa8512018-06-07 12:49:17 +0000258 EXPECT_THAT(Results.items,
259 AllOf(Has(Opts.EnableSnippets ? "method()" : "method"),
260 Has("field"), Not(Has("ClassWithMembers")),
261 Not(Has("operator=")), Not(Has("~ClassWithMembers"))));
Sam McCall44fdcec22017-12-08 15:00:59 +0000262 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.items,
263 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000264 // Global items.
Sam McCall545a20d2018-01-19 14:34:02 +0000265 EXPECT_THAT(
266 Results.items,
267 Not(AnyOf(Has("global_var"), Has("index_var"), Has("global_func"),
268 Has("global_func()"), Has("index_func"), Has("GlobalClass"),
269 Has("IndexClass"), Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000270 // There should be no code patterns (aka snippets) in after-dot
271 // completion. At least there aren't any we're aware of.
Sam McCall44fdcec22017-12-08 15:00:59 +0000272 EXPECT_THAT(Results.items, Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000273 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000274 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000275}
Sam McCall9aad25f2017-12-05 07:20:26 +0000276
Sam McCallf6ae3232017-12-05 20:11:29 +0000277void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000278 auto Results = completions(
279 R"cpp(
280 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000281
Sam McCall44fdcec22017-12-08 15:00:59 +0000282 int global_var;
283 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000284
Sam McCall44fdcec22017-12-08 15:00:59 +0000285 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000286
Sam McCall44fdcec22017-12-08 15:00:59 +0000287 struct ClassWithMembers {
288 /// Doc for method.
289 int method();
290 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000291
Sam McCall44fdcec22017-12-08 15:00:59 +0000292 int test() {
293 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000294
Sam McCall44fdcec22017-12-08 15:00:59 +0000295 /// Doc for local_var.
296 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000297
Sam McCall44fdcec22017-12-08 15:00:59 +0000298 ^
299 }
300 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000301 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000302
303 // Class members. Should never be present in global completions.
Sam McCall44fdcec22017-12-08 15:00:59 +0000304 EXPECT_THAT(Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000305 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
306 // Global items.
Sam McCalld8169a82018-01-18 15:31:30 +0000307 EXPECT_THAT(Results.items,
Sam McCall545a20d2018-01-19 14:34:02 +0000308 AllOf(Has("global_var"), Has("index_var"),
Sam McCalld8169a82018-01-18 15:31:30 +0000309 Has(Opts.EnableSnippets ? "global_func()" : "global_func"),
Sam McCall545a20d2018-01-19 14:34:02 +0000310 Has("index_func" /* our fake symbol doesn't include () */),
311 Has("GlobalClass"), Has("IndexClass")));
Sam McCallf6ae3232017-12-05 20:11:29 +0000312 // A macro.
Sam McCall44fdcec22017-12-08 15:00:59 +0000313 EXPECT_IFF(Opts.IncludeMacros, Results.items, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000314 // Local items. Must be present always.
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000315 EXPECT_THAT(Results.items,
316 AllOf(Has("local_var"), Has("LocalClass"),
317 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000318 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000319 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000320}
321
322TEST(CompletionTest, CompletionOptions) {
Sam McCall2c3849a2018-01-16 12:21:24 +0000323 auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
324 TestAfterDotCompletion(Opts);
325 TestGlobalScopeCompletion(Opts);
326 };
327 // We used to test every combination of options, but that got too slow (2^N).
328 auto Flags = {
Ilya Biryukov71028b82018-03-12 15:28:22 +0000329 &clangd::CodeCompleteOptions::IncludeMacros,
Ilya Biryukov43714502018-05-16 12:32:44 +0000330 &clangd::CodeCompleteOptions::IncludeComments,
Ilya Biryukov71028b82018-03-12 15:28:22 +0000331 &clangd::CodeCompleteOptions::EnableSnippets,
332 &clangd::CodeCompleteOptions::IncludeCodePatterns,
333 &clangd::CodeCompleteOptions::IncludeIneligibleResults,
Sam McCall2c3849a2018-01-16 12:21:24 +0000334 };
335 // Test default options.
336 Test({});
337 // Test with one flag flipped.
338 for (auto &F : Flags) {
339 clangd::CodeCompleteOptions O;
340 O.*F ^= true;
341 Test(O);
Sam McCall9aad25f2017-12-05 07:20:26 +0000342 }
343}
344
Sam McCall44fdcec22017-12-08 15:00:59 +0000345TEST(CompletionTest, Priorities) {
346 auto Internal = completions(R"cpp(
347 class Foo {
348 public: void pub();
349 protected: void prot();
350 private: void priv();
351 };
352 void Foo::pub() { this->^ }
353 )cpp");
354 EXPECT_THAT(Internal.items,
355 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
356
357 auto External = completions(R"cpp(
358 class Foo {
359 public: void pub();
360 protected: void prot();
361 private: void priv();
362 };
363 void test() {
364 Foo F;
365 F.^
366 }
367 )cpp");
368 EXPECT_THAT(External.items,
369 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
370}
371
372TEST(CompletionTest, Qualifiers) {
373 auto Results = completions(R"cpp(
374 class Foo {
375 public: int foo() const;
376 int bar() const;
377 };
378 class Bar : public Foo {
379 int foo() const;
380 };
381 void test() { Bar().^ }
382 )cpp");
383 EXPECT_THAT(Results.items, HasSubsequence(Labeled("bar() const"),
384 Labeled("Foo::foo() const")));
385 EXPECT_THAT(Results.items, Not(Contains(Labeled("foo() const")))); // private
386}
387
Sam McCall4caa8512018-06-07 12:49:17 +0000388TEST(CompletionTest, InjectedTypename) {
389 // These are suppressed when accessed as a member...
390 EXPECT_THAT(completions("struct X{}; void foo(){ X().^ }").items,
391 Not(Has("X")));
392 EXPECT_THAT(completions("struct X{ void foo(){ this->^ } };").items,
393 Not(Has("X")));
394 // ...but accessible in other, more useful cases.
395 EXPECT_THAT(completions("struct X{ void foo(){ ^ } };").items, Has("X"));
396 EXPECT_THAT(completions("struct Y{}; struct X:Y{ void foo(){ ^ } };").items,
397 Has("Y"));
398 EXPECT_THAT(
399 completions(
400 "template<class> struct Y{}; struct X:Y<int>{ void foo(){ ^ } };")
401 .items,
402 Has("Y"));
403 // This case is marginal (`using X::X` is useful), we allow it for now.
404 EXPECT_THAT(completions("struct X{}; void foo(){ X::^ }").items, Has("X"));
405}
406
Sam McCall44fdcec22017-12-08 15:00:59 +0000407TEST(CompletionTest, Snippets) {
408 clangd::CodeCompleteOptions Opts;
409 Opts.EnableSnippets = true;
410 auto Results = completions(
411 R"cpp(
412 struct fake {
413 int a;
414 int f(int i, const float f) const;
415 };
416 int main() {
417 fake f;
418 f.^
419 }
420 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000421 /*IndexSymbols=*/{}, Opts);
Sam McCall44fdcec22017-12-08 15:00:59 +0000422 EXPECT_THAT(Results.items,
Eric Liu63696e12017-12-20 17:24:31 +0000423 HasSubsequence(Snippet("a"),
Sam McCall44fdcec22017-12-08 15:00:59 +0000424 Snippet("f(${1:int i}, ${2:const float f})")));
425}
426
427TEST(CompletionTest, Kinds) {
Sam McCall545a20d2018-01-19 14:34:02 +0000428 auto Results = completions(
429 R"cpp(
430 #define MACRO X
431 int variable;
432 struct Struct {};
433 int function();
434 int X = ^
435 )cpp",
436 {func("indexFunction"), var("indexVariable"), cls("indexClass")});
437 EXPECT_THAT(Results.items,
438 AllOf(Has("function", CompletionItemKind::Function),
439 Has("variable", CompletionItemKind::Variable),
440 Has("int", CompletionItemKind::Keyword),
441 Has("Struct", CompletionItemKind::Class),
442 Has("MACRO", CompletionItemKind::Text),
443 Has("indexFunction", CompletionItemKind::Function),
444 Has("indexVariable", CompletionItemKind::Variable),
445 Has("indexClass", CompletionItemKind::Class)));
Sam McCall44fdcec22017-12-08 15:00:59 +0000446
Sam McCall44fdcec22017-12-08 15:00:59 +0000447 Results = completions("nam^");
448 EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
449}
450
Sam McCall84652cc2018-01-12 16:16:09 +0000451TEST(CompletionTest, NoDuplicates) {
Sam McCall545a20d2018-01-19 14:34:02 +0000452 auto Results = completions(
453 R"cpp(
454 class Adapter {
Sam McCall545a20d2018-01-19 14:34:02 +0000455 };
Sam McCall84652cc2018-01-12 16:16:09 +0000456
Eric Liu9b3cba72018-05-30 09:03:39 +0000457 void f() {
Sam McCall545a20d2018-01-19 14:34:02 +0000458 Adapter^
459 }
460 )cpp",
461 {cls("Adapter")});
Sam McCall84652cc2018-01-12 16:16:09 +0000462
463 // Make sure there are no duplicate entries of 'Adapter'.
Sam McCalld2a95922018-01-22 21:05:00 +0000464 EXPECT_THAT(Results.items, ElementsAre(Named("Adapter")));
Sam McCall84652cc2018-01-12 16:16:09 +0000465}
466
Sam McCall545a20d2018-01-19 14:34:02 +0000467TEST(CompletionTest, ScopedNoIndex) {
468 auto Results = completions(
469 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000470 namespace fake { int BigBang, Babble, Box; };
471 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000472 ")cpp");
Sam McCall8b2dcc12018-06-14 13:50:30 +0000473 // Babble is a better match than BigBang. Box doesn't match at all.
474 EXPECT_THAT(Results.items, ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCall84652cc2018-01-12 16:16:09 +0000475}
476
Sam McCall545a20d2018-01-19 14:34:02 +0000477TEST(CompletionTest, Scoped) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000478 auto Results = completions(
479 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000480 namespace fake { int Babble, Box; };
481 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000482 ")cpp",
483 {var("fake::BigBang")});
Sam McCall8b2dcc12018-06-14 13:50:30 +0000484 EXPECT_THAT(Results.items, ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000485}
486
Sam McCall545a20d2018-01-19 14:34:02 +0000487TEST(CompletionTest, ScopedWithFilter) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000488 auto Results = completions(
489 R"cpp(
490 void f() { ns::x^ }
491 )cpp",
492 {cls("ns::XYZ"), func("ns::foo")});
493 EXPECT_THAT(Results.items,
494 UnorderedElementsAre(AllOf(Named("XYZ"), Filter("XYZ"))));
495}
496
Sam McCalldc8abc42018-05-03 14:53:02 +0000497TEST(CompletionTest, ReferencesAffectRanking) {
498 auto Results = completions("int main() { abs^ }", {ns("absl"), func("abs")});
499 EXPECT_THAT(Results.items, HasSubsequence(Named("abs"), Named("absl")));
500 Results = completions("int main() { abs^ }",
501 {withReferences(10000, ns("absl")), func("abs")});
502 EXPECT_THAT(Results.items, HasSubsequence(Named("absl"), Named("abs")));
503}
504
Sam McCall545a20d2018-01-19 14:34:02 +0000505TEST(CompletionTest, GlobalQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000506 auto Results = completions(
507 R"cpp(
508 void f() { ::^ }
509 )cpp",
510 {cls("XYZ")});
511 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
512 Has("f", CompletionItemKind::Function)));
513}
514
Sam McCall545a20d2018-01-19 14:34:02 +0000515TEST(CompletionTest, FullyQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000516 auto Results = completions(
517 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000518 namespace ns { void bar(); }
Sam McCalla15c2d62018-01-18 09:27:56 +0000519 void f() { ::ns::^ }
520 )cpp",
521 {cls("ns::XYZ")});
Sam McCall545a20d2018-01-19 14:34:02 +0000522 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
523 Has("bar", CompletionItemKind::Function)));
524}
525
526TEST(CompletionTest, SemaIndexMerge) {
527 auto Results = completions(
528 R"cpp(
529 namespace ns { int local; void both(); }
530 void f() { ::ns::^ }
531 )cpp",
532 {func("ns::both"), cls("ns::Index")});
533 // We get results from both index and sema, with no duplicates.
534 EXPECT_THAT(
535 Results.items,
536 UnorderedElementsAre(Named("local"), Named("Index"), Named("both")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000537}
538
Haojian Wu48b48652018-01-25 09:20:09 +0000539TEST(CompletionTest, SemaIndexMergeWithLimit) {
540 clangd::CodeCompleteOptions Opts;
541 Opts.Limit = 1;
542 auto Results = completions(
543 R"cpp(
544 namespace ns { int local; void both(); }
545 void f() { ::ns::^ }
546 )cpp",
547 {func("ns::both"), cls("ns::Index")}, Opts);
548 EXPECT_EQ(Results.items.size(), Opts.Limit);
549 EXPECT_TRUE(Results.isIncomplete);
550}
551
Eric Liu63f419a2018-05-15 15:29:32 +0000552TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
553 MockFSProvider FS;
554 MockCompilationDatabase CDB;
555 std::string Subdir = testPath("sub");
556 std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
557 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
558 std::string BarHeader = testPath("sub/bar.h");
559 FS.Files[BarHeader] = "";
560
561 IgnoreDiagnostics DiagConsumer;
562 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
563 Symbol::Details Scratch;
564 auto BarURI = URI::createFile(BarHeader).toString();
565 Symbol Sym = cls("ns::X");
566 Sym.CanonicalDeclaration.FileURI = BarURI;
567 Scratch.IncludeHeader = BarURI;
568 Sym.Detail = &Scratch;
569 // Shoten include path based on search dirctory and insert.
570 auto Results = completions(Server,
571 R"cpp(
572 int main() { ns::^ }
573 )cpp",
574 {Sym});
575 EXPECT_THAT(Results.items,
Eric Liu8f3678d2018-06-15 13:34:18 +0000576 ElementsAre(AllOf(
577 Named("X"),
578 Labeled(CodeCompleteOptions().IncludeIndicator.Insert + "X"),
579 InsertInclude("\"bar.h\""))));
Eric Liu63f419a2018-05-15 15:29:32 +0000580 // Duplicate based on inclusions in preamble.
581 Results = completions(Server,
582 R"cpp(
583 #include "sub/bar.h" // not shortest, so should only match resolved.
584 int main() { ns::^ }
585 )cpp",
586 {Sym});
Eric Liu8f3678d2018-06-15 13:34:18 +0000587 EXPECT_THAT(Results.items, ElementsAre(AllOf(Named("X"), Labeled("X"),
588 Not(HasAdditionalEdits()))));
Eric Liu63f419a2018-05-15 15:29:32 +0000589}
590
Eric Liu9b3cba72018-05-30 09:03:39 +0000591TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
592 MockFSProvider FS;
593 MockCompilationDatabase CDB;
594
595 IgnoreDiagnostics DiagConsumer;
596 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
597 Symbol::Details Scratch;
598 Symbol SymX = cls("ns::X");
599 Symbol SymY = cls("ns::Y");
600 std::string BarHeader = testPath("bar.h");
601 auto BarURI = URI::createFile(BarHeader).toString();
602 SymX.CanonicalDeclaration.FileURI = BarURI;
603 SymY.CanonicalDeclaration.FileURI = BarURI;
604 Scratch.IncludeHeader = "<bar>";
605 SymX.Detail = &Scratch;
606 SymY.Detail = &Scratch;
607 // Shoten include path based on search dirctory and insert.
608 auto Results = completions(Server,
609 R"cpp(
610 namespace ns {
611 class X;
612 class Y {}
613 }
614 int main() { ns::^ }
615 )cpp",
616 {SymX, SymY});
617 EXPECT_THAT(Results.items,
618 ElementsAre(AllOf(Named("X"), Not(HasAdditionalEdits())),
619 AllOf(Named("Y"), Not(HasAdditionalEdits()))));
620}
621
Sam McCalla15c2d62018-01-18 09:27:56 +0000622TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
623 MockFSProvider FS;
624 MockCompilationDatabase CDB;
625 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000626 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCalla15c2d62018-01-18 09:27:56 +0000627
Sam McCallc1568062018-02-16 09:41:43 +0000628 FS.Files[testPath("bar.h")] =
Sam McCalld5ea3e32018-01-24 17:53:32 +0000629 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
Sam McCallc1568062018-02-16 09:41:43 +0000630 auto File = testPath("foo.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000631 Annotations Test(R"cpp(
632 #include "bar.h"
633 namespace ns { int local; }
Sam McCalld5ea3e32018-01-24 17:53:32 +0000634 void f() { ns::^; }
635 void f() { ns::preamble().$2^; }
Sam McCalla15c2d62018-01-18 09:27:56 +0000636 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000637 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000638 clangd::CodeCompleteOptions Opts = {};
639
Sam McCalla15c2d62018-01-18 09:27:56 +0000640 auto I = memIndex({var("ns::index")});
641 Opts.Index = I.get();
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000642 auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalla15c2d62018-01-18 09:27:56 +0000643 EXPECT_THAT(WithIndex.items,
644 UnorderedElementsAre(Named("local"), Named("index")));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000645 auto ClassFromPreamble =
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000646 cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000647 EXPECT_THAT(ClassFromPreamble.items, Contains(Named("member")));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000648
649 Opts.Index = nullptr;
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000650 auto WithoutIndex =
651 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000652 EXPECT_THAT(WithoutIndex.items,
653 UnorderedElementsAre(Named("local"), Named("preamble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000654}
655
656TEST(CompletionTest, DynamicIndexMultiFile) {
657 MockFSProvider FS;
658 MockCompilationDatabase CDB;
659 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000660 auto Opts = ClangdServer::optsForTest();
661 Opts.BuildDynamicSymbolIndex = true;
662 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCalla15c2d62018-01-18 09:27:56 +0000663
Eric Liu709bde82018-02-19 18:48:44 +0000664 FS.Files[testPath("foo.h")] = R"cpp(
Sam McCalla15c2d62018-01-18 09:27:56 +0000665 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liu709bde82018-02-19 18:48:44 +0000666 )cpp";
Sam McCall7363a2f2018-03-05 17:28:54 +0000667 runAddDocument(Server, testPath("foo.cpp"), R"cpp(
Eric Liu709bde82018-02-19 18:48:44 +0000668 #include "foo.h"
Sam McCall0bb24cd2018-02-13 08:59:23 +0000669 )cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000670
Sam McCallc1568062018-02-16 09:41:43 +0000671 auto File = testPath("bar.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000672 Annotations Test(R"cpp(
673 namespace ns {
674 class XXX {};
675 /// Doooc
676 void fooooo() {}
677 }
678 void f() { ns::^ }
679 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000680 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000681
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000682 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
Sam McCalla15c2d62018-01-18 09:27:56 +0000683 // "XYZ" and "foo" are not included in the file being completed but are still
684 // visible through the index.
685 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
686 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
687 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
688 EXPECT_THAT(Results.items, Contains(AllOf(Named("fooooo"), Filter("fooooo"),
689 Kind(CompletionItemKind::Function),
690 Doc("Doooc"), Detail("void"))));
691}
692
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000693TEST(CompletionTest, Documentation) {
694 auto Results = completions(
695 R"cpp(
696 // Non-doxygen comment.
697 int foo();
698 /// Doxygen comment.
699 /// \param int a
700 int bar(int a);
701 /* Multi-line
702 block comment
703 */
704 int baz();
705
706 int x = ^
707 )cpp");
708 EXPECT_THAT(Results.items,
709 Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
710 EXPECT_THAT(
711 Results.items,
712 Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
713 EXPECT_THAT(Results.items,
714 Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
715}
716
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000717TEST(CompletionTest, GlobalCompletionFiltering) {
718
719 Symbol Class = cls("XYZ");
720 Class.IsIndexedForCodeCompletion = false;
721 Symbol Func = func("XYZ::foooo");
722 Func.IsIndexedForCodeCompletion = false;
723
724 auto Results = completions(R"(// void f() {
725 XYZ::foooo^
726 })",
727 {Class, Func});
728 EXPECT_THAT(Results.items, IsEmpty());
729}
730
Haojian Wu58d208d2018-01-25 09:44:06 +0000731TEST(CodeCompleteTest, DisableTypoCorrection) {
732 auto Results = completions(R"cpp(
733 namespace clang { int v; }
734 void f() { clangd::^
735 )cpp");
736 EXPECT_TRUE(Results.items.empty());
737}
738
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000739TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
740 auto Results = completions(R"cpp(
741 namespace clang { }
742 void f() {
743 clan^
744 }
745 )cpp");
746
747 EXPECT_THAT(Results.items, Contains(Labeled("clang")));
748 EXPECT_THAT(Results.items, Not(Contains(Labeled("clang::"))));
749}
750
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000751TEST(CompletionTest, BacktrackCrashes) {
752 // Sema calls code completion callbacks twice in these cases.
753 auto Results = completions(R"cpp(
754 namespace ns {
755 struct FooBarBaz {};
756 } // namespace ns
757
758 int foo(ns::FooBar^
759 )cpp");
760
761 EXPECT_THAT(Results.items, ElementsAre(Labeled("FooBarBaz")));
762
763 // Check we don't crash in that case too.
764 completions(R"cpp(
765 struct FooBarBaz {};
766 void test() {
767 if (FooBarBaz * x^) {}
768 }
769)cpp");
770}
771
Eric Liu42abe412018-05-24 11:20:19 +0000772TEST(CompletionTest, CompleteInMacroWithStringification) {
773 auto Results = completions(R"cpp(
774void f(const char *, int x);
775#define F(x) f(#x, x)
776
777namespace ns {
778int X;
779int Y;
780} // namespace ns
781
782int f(int input_num) {
783 F(ns::^)
784}
785)cpp");
786
787 EXPECT_THAT(Results.items,
788 UnorderedElementsAre(Named("X"), Named("Y")));
789}
790
791TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
792 auto Results = completions(R"cpp(
793void f(const char *, int x);
794#define F(x) f(#x, x)
795
796namespace ns {
797int X;
798
799int f(int input_num) {
800 F(^)
801}
802} // namespace ns
803)cpp");
804
805 EXPECT_THAT(Results.items, Contains(Named("X")));
806}
807
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000808TEST(CompletionTest, CompleteInExcludedPPBranch) {
809 auto Results = completions(R"cpp(
810 int bar(int param_in_bar) {
811 }
812
813 int foo(int param_in_foo) {
814#if 0
815 par^
816#endif
817 }
818)cpp");
819
820 EXPECT_THAT(Results.items, Contains(Labeled("param_in_foo")));
821 EXPECT_THAT(Results.items, Not(Contains(Labeled("param_in_bar"))));
822}
823
Sam McCall800d4372017-12-19 10:29:27 +0000824SignatureHelp signatures(StringRef Text) {
825 MockFSProvider FS;
826 MockCompilationDatabase CDB;
827 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000828 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCallc1568062018-02-16 09:41:43 +0000829 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000830 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000831 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000832 return cantFail(runSignatureHelp(Server, File, Test.point()));
Sam McCall800d4372017-12-19 10:29:27 +0000833}
834
835MATCHER_P(ParamsAre, P, "") {
836 if (P.size() != arg.parameters.size())
837 return false;
838 for (unsigned I = 0; I < P.size(); ++I)
839 if (P[I] != arg.parameters[I].label)
840 return false;
841 return true;
842}
843
844Matcher<SignatureInformation> Sig(std::string Label,
845 std::vector<std::string> Params) {
Eric Liu8f3678d2018-06-15 13:34:18 +0000846 return AllOf(SigHelpLabeled(Label), ParamsAre(Params));
Sam McCall800d4372017-12-19 10:29:27 +0000847}
848
849TEST(SignatureHelpTest, Overloads) {
850 auto Results = signatures(R"cpp(
851 void foo(int x, int y);
852 void foo(int x, float y);
853 void foo(float x, int y);
854 void foo(float x, float y);
855 void bar(int x, int y = 0);
856 int main() { foo(^); }
857 )cpp");
858 EXPECT_THAT(Results.signatures,
859 UnorderedElementsAre(
860 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
861 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
862 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
863 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
864 // We always prefer the first signature.
865 EXPECT_EQ(0, Results.activeSignature);
866 EXPECT_EQ(0, Results.activeParameter);
867}
868
869TEST(SignatureHelpTest, DefaultArgs) {
870 auto Results = signatures(R"cpp(
871 void bar(int x, int y = 0);
872 void bar(float x = 0, int y = 42);
873 int main() { bar(^
874 )cpp");
875 EXPECT_THAT(Results.signatures,
876 UnorderedElementsAre(
877 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
878 Sig("bar(float x = 0, int y = 42) -> void",
879 {"float x = 0", "int y = 42"})));
880 EXPECT_EQ(0, Results.activeSignature);
881 EXPECT_EQ(0, Results.activeParameter);
882}
883
884TEST(SignatureHelpTest, ActiveArg) {
885 auto Results = signatures(R"cpp(
886 int baz(int a, int b, int c);
887 int main() { baz(baz(1,2,3), ^); }
888 )cpp");
889 EXPECT_THAT(Results.signatures,
890 ElementsAre(Sig("baz(int a, int b, int c) -> int",
891 {"int a", "int b", "int c"})));
892 EXPECT_EQ(0, Results.activeSignature);
893 EXPECT_EQ(1, Results.activeParameter);
894}
895
Haojian Wu061c73e2018-01-23 11:37:26 +0000896class IndexRequestCollector : public SymbolIndex {
897public:
898 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000899 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000900 llvm::function_ref<void(const Symbol &)> Callback) const override {
901 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000902 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000903 }
904
Eric Liu9ec459f2018-03-14 09:48:05 +0000905 void lookup(const LookupRequest &,
906 llvm::function_ref<void(const Symbol &)>) const override {}
907
Haojian Wu061c73e2018-01-23 11:37:26 +0000908 const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
909
910private:
911 mutable std::vector<FuzzyFindRequest> Requests;
912};
913
914std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
915 clangd::CodeCompleteOptions Opts;
916 IndexRequestCollector Requests;
917 Opts.Index = &Requests;
918 completions(Code, {}, Opts);
919 return Requests.allRequests();
920}
921
922TEST(CompletionTest, UnqualifiedIdQuery) {
923 auto Requests = captureIndexRequests(R"cpp(
924 namespace std {}
925 using namespace std;
926 namespace ns {
927 void f() {
928 vec^
929 }
930 }
931 )cpp");
932
933 EXPECT_THAT(Requests,
934 ElementsAre(Field(&FuzzyFindRequest::Scopes,
935 UnorderedElementsAre("", "ns::", "std::"))));
936}
937
938TEST(CompletionTest, ResolvedQualifiedIdQuery) {
939 auto Requests = captureIndexRequests(R"cpp(
940 namespace ns1 {}
941 namespace ns2 {} // ignore
942 namespace ns3 { namespace nns3 {} }
943 namespace foo {
944 using namespace ns1;
945 using namespace ns3::nns3;
946 }
947 namespace ns {
948 void f() {
949 foo::^
950 }
951 }
952 )cpp");
953
954 EXPECT_THAT(Requests,
955 ElementsAre(Field(
956 &FuzzyFindRequest::Scopes,
957 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
958}
959
960TEST(CompletionTest, UnresolvedQualifierIdQuery) {
961 auto Requests = captureIndexRequests(R"cpp(
962 namespace a {}
963 using namespace a;
964 namespace ns {
965 void f() {
966 bar::^
967 }
968 } // namespace ns
969 )cpp");
970
971 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
972 UnorderedElementsAre("bar::"))));
973}
974
975TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
976 auto Requests = captureIndexRequests(R"cpp(
977 namespace a {}
978 using namespace a;
979 namespace ns {
980 void f() {
981 ::a::bar::^
982 }
983 } // namespace ns
984 )cpp");
985
986 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
987 UnorderedElementsAre("a::bar::"))));
988}
989
990TEST(CompletionTest, EmptyQualifiedQuery) {
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("", "ns::"))));
1001}
1002
1003TEST(CompletionTest, GlobalQualifiedQuery) {
1004 auto Requests = captureIndexRequests(R"cpp(
1005 namespace ns {
1006 void f() {
1007 ::^
1008 }
1009 } // namespace ns
1010 )cpp");
1011
1012 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1013 UnorderedElementsAre(""))));
1014}
1015
Ilya Biryukova907ba42018-05-14 10:50:04 +00001016TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
1017 auto Completions = completions(
1018 R"cpp(
1019 struct Foo {
1020 int SomeNameOfField;
1021 typedef int SomeNameOfTypedefField;
1022 };
1023
1024 Foo::^)cpp",
1025 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
1026
1027 EXPECT_THAT(Completions.items,
1028 AllOf(Contains(Labeled("SomeNameOfField")),
1029 Contains(Labeled("SomeNameOfTypedefField")),
1030 Not(Contains(Labeled("SomeNameInTheIndex")))));
1031}
1032
1033TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
1034 {
1035 auto Completions = completions(
1036 R"cpp(
1037 template <class T>
1038 void foo() {
1039 T::^
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::template Y<int>::^
1054 }
1055 )cpp",
1056 {func("::SomeNameInTheIndex")});
1057
1058 EXPECT_THAT(Completions.items,
1059 Not(Contains(Labeled("SomeNameInTheIndex"))));
1060 }
1061
1062 {
1063 auto Completions = completions(
1064 R"cpp(
1065 template <class T>
1066 void foo() {
1067 T::foo::^
1068 }
1069 )cpp",
1070 {func("::SomeNameInTheIndex")});
1071
1072 EXPECT_THAT(Completions.items,
1073 Not(Contains(Labeled("SomeNameInTheIndex"))));
1074 }
1075}
1076
Sam McCallc18c2802018-06-15 11:06:29 +00001077TEST(CompletionTest, OverloadBundling) {
1078 clangd::CodeCompleteOptions Opts;
1079 Opts.BundleOverloads = true;
1080
1081 std::string Context = R"cpp(
1082 struct X {
1083 // Overload with int
1084 int a(int);
1085 // Overload with bool
1086 int a(bool);
1087 int b(float);
1088 };
1089 int GFuncC(int);
1090 int GFuncD(int);
1091 )cpp";
1092
1093 // Member completions are bundled.
1094 EXPECT_THAT(completions(Context + "int y = X().^", {}, Opts).items,
1095 UnorderedElementsAre(Labeled("a(…)"), Labeled("b(float)")));
1096
1097 // Non-member completions are bundled, including index+sema.
1098 Symbol NoArgsGFunc = func("GFuncC");
1099 EXPECT_THAT(
1100 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).items,
1101 UnorderedElementsAre(Labeled("GFuncC(…)"), Labeled("GFuncD(int)")));
1102
1103 // Differences in header-to-insert suppress bundling.
1104 Symbol::Details Detail;
1105 std::string DeclFile = URI::createFile(testPath("foo")).toString();
1106 NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile;
1107 Detail.IncludeHeader = "<foo>";
1108 NoArgsGFunc.Detail = &Detail;
1109 EXPECT_THAT(
1110 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).items,
Eric Liu8f3678d2018-06-15 13:34:18 +00001111 UnorderedElementsAre(
1112 AllOf(
1113 Named("GFuncC"),
1114 Labeled(CodeCompleteOptions().IncludeIndicator.Insert + "GFuncC"),
1115 InsertInclude("<foo>")),
1116 Labeled("GFuncC(int)"), Labeled("GFuncD(int)")));
Sam McCallc18c2802018-06-15 11:06:29 +00001117
1118 // Examine a bundled completion in detail.
1119 auto A = completions(Context + "int y = X().a^", {}, Opts).items.front();
Eric Liu8f3678d2018-06-15 13:34:18 +00001120 EXPECT_EQ(A.label, " a(…)");
Sam McCallc18c2802018-06-15 11:06:29 +00001121 EXPECT_EQ(A.detail, "[2 overloads]");
1122 EXPECT_EQ(A.insertText, "a");
1123 EXPECT_EQ(A.kind, CompletionItemKind::Method);
1124 // For now we just return one of the doc strings arbitrarily.
1125 EXPECT_THAT(A.documentation, AnyOf(HasSubstr("Overload with int"),
1126 HasSubstr("Overload with bool")));
1127 Opts.EnableSnippets = true;
1128 A = completions(Context + "int y = X().a^", {}, Opts).items.front();
1129 EXPECT_EQ(A.insertText, "a(${0})");
1130}
1131
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001132TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001133 MockFSProvider FS;
1134 auto FooH = testPath("foo.h");
1135 auto FooCpp = testPath("foo.cpp");
1136 FS.Files[FooH] = R"cpp(
1137 // this is my documentation comment.
1138 int func();
1139 )cpp";
1140 FS.Files[FooCpp] = "";
1141
1142 MockCompilationDatabase CDB;
1143 IgnoreDiagnostics DiagConsumer;
1144 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1145
1146 Annotations Source(R"cpp(
1147 #include "foo.h"
1148 int func() {
1149 // This makes sure we have func from header in the AST.
1150 }
1151 int a = fun^
1152 )cpp");
1153 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1154 // We need to wait for preamble to build.
1155 ASSERT_TRUE(Server.blockUntilIdleForTest());
1156
1157 // Change the header file. Completion will reuse the old preamble!
1158 FS.Files[FooH] = R"cpp(
1159 int func();
1160 )cpp";
1161
1162 clangd::CodeCompleteOptions Opts;
1163 Opts.IncludeComments = true;
1164 CompletionList Completions =
1165 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1166 // We shouldn't crash. Unfortunately, current workaround is to not produce
1167 // comments for symbols from headers.
1168 EXPECT_THAT(Completions.items,
1169 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1170}
1171
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001172TEST(CompletionTest, NonDocComments) {
1173 MockFSProvider FS;
1174 auto FooCpp = testPath("foo.cpp");
1175 FS.Files[FooCpp] = "";
1176
1177 MockCompilationDatabase CDB;
1178 IgnoreDiagnostics DiagConsumer;
1179 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1180
1181 Annotations Source(R"cpp(
1182 // ------------------
1183 int comments_foo();
1184
1185 // A comment and a decl are separated by newlines.
1186 // Therefore, the comment shouldn't show up as doc comment.
1187
1188 int comments_bar();
1189
1190 // this comment should be in the results.
1191 int comments_baz();
1192
1193
1194 template <class T>
1195 struct Struct {
1196 int comments_qux();
1197 int comments_quux();
1198 };
1199
1200
1201 // This comment should not be there.
1202
1203 template <class T>
1204 int Struct<T>::comments_qux() {
1205 }
1206
1207 // This comment **should** be in results.
1208 template <class T>
1209 int Struct<T>::comments_quux() {
1210 int a = comments^;
1211 }
1212 )cpp");
Reid Kleckner80274b12018-06-18 18:55:10 +00001213 // FIXME: Auto-completion in a template requires disabling delayed template
1214 // parsing.
1215 CDB.ExtraClangFlags.push_back("-fno-delayed-template-parsing");
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001216 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1217 CompletionList Completions = cantFail(runCodeComplete(
1218 Server, FooCpp, Source.point(), clangd::CodeCompleteOptions()));
1219
1220 // We should not get any of those comments in completion.
1221 EXPECT_THAT(
1222 Completions.items,
1223 UnorderedElementsAre(AllOf(Not(IsDocumented()), Named("comments_foo")),
1224 AllOf(IsDocumented(), Named("comments_baz")),
1225 AllOf(IsDocumented(), Named("comments_quux")),
1226 // FIXME(ibiryukov): the following items should have
1227 // empty documentation, since they are separated from
1228 // a comment with an empty line. Unfortunately, I
1229 // couldn't make Sema tests pass if we ignore those.
1230 AllOf(IsDocumented(), Named("comments_bar")),
1231 AllOf(IsDocumented(), Named("comments_qux"))));
1232}
1233
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001234TEST(CompletionTest, CompleteOnInvalidLine) {
1235 auto FooCpp = testPath("foo.cpp");
1236
1237 MockCompilationDatabase CDB;
1238 IgnoreDiagnostics DiagConsumer;
1239 MockFSProvider FS;
1240 FS.Files[FooCpp] = "// empty file";
1241
1242 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1243 // Run completion outside the file range.
1244 Position Pos;
1245 Pos.line = 100;
1246 Pos.character = 0;
1247 EXPECT_THAT_EXPECTED(
1248 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1249 Failed());
1250}
1251
Eric Liu7ad16962018-06-22 10:46:59 +00001252TEST(CompletionTest, QualifiedNames) {
1253 auto Results = completions(
1254 R"cpp(
1255 namespace ns { int local; void both(); }
1256 void f() { ::ns::^ }
1257 )cpp",
1258 {func("ns::both"), cls("ns::Index")});
1259 // We get results from both index and sema, with no duplicates.
1260 EXPECT_THAT(Results.items, UnorderedElementsAre(Scope("ns::"), Scope("ns::"),
1261 Scope("ns::")));
1262}
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001263
Sam McCall9aad25f2017-12-05 07:20:26 +00001264} // namespace
1265} // namespace clangd
1266} // namespace clang