blob: 7b40900b005257473084482b004686a714053c70 [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 Liu8f3678d2018-06-15 13:34:18 +000047MATCHER_P(Labeled, Label, "") {
48 std::string Indented;
49 if (!StringRef(Label).startswith(
50 CodeCompleteOptions().IncludeIndicator.Insert) &&
51 !StringRef(Label).startswith(
52 CodeCompleteOptions().IncludeIndicator.NoInsert))
53 Indented =
54 (Twine(CodeCompleteOptions().IncludeIndicator.NoInsert) + Label).str();
55 else
56 Indented = Label;
57 return arg.label == Indented;
58}
59MATCHER_P(SigHelpLabeled, Label, "") { return arg.label == Label; }
Sam McCall44fdcec22017-12-08 15:00:59 +000060MATCHER_P(Kind, K, "") { return arg.kind == K; }
Eric Liu6f648df2017-12-19 16:50:37 +000061MATCHER_P(Filter, F, "") { return arg.filterText == F; }
Eric Liu76f6b442018-01-09 17:32:00 +000062MATCHER_P(Doc, D, "") { return arg.documentation == D; }
63MATCHER_P(Detail, D, "") { return arg.detail == D; }
Eric Liu63f419a2018-05-15 15:29:32 +000064MATCHER_P(InsertInclude, IncludeHeader, "") {
65 if (arg.additionalTextEdits.size() != 1)
66 return false;
67 const auto &Edit = arg.additionalTextEdits[0];
68 if (Edit.range.start != Edit.range.end)
69 return false;
70 SmallVector<StringRef, 2> Matches;
71 llvm::Regex RE(R"(#include[ ]*(["<][^">]*[">]))");
72 return RE.match(Edit.newText, &Matches) && Matches[1] == IncludeHeader;
73}
Sam McCall44fdcec22017-12-08 15:00:59 +000074MATCHER_P(PlainText, Text, "") {
75 return arg.insertTextFormat == clangd::InsertTextFormat::PlainText &&
76 arg.insertText == Text;
77}
78MATCHER_P(Snippet, Text, "") {
79 return arg.insertTextFormat == clangd::InsertTextFormat::Snippet &&
80 arg.insertText == Text;
81}
Sam McCall545a20d2018-01-19 14:34:02 +000082MATCHER(NameContainsFilter, "") {
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000083 if (arg.filterText.empty())
84 return true;
85 return llvm::StringRef(arg.insertText).contains(arg.filterText);
86}
Eric Liu63f419a2018-05-15 15:29:32 +000087MATCHER(HasAdditionalEdits, "") { return !arg.additionalTextEdits.empty(); }
88
Sam McCallf6ae3232017-12-05 20:11:29 +000089// Shorthand for Contains(Named(Name)).
90Matcher<const std::vector<CompletionItem> &> Has(std::string Name) {
91 return Contains(Named(std::move(Name)));
92}
Sam McCall44fdcec22017-12-08 15:00:59 +000093Matcher<const std::vector<CompletionItem> &> Has(std::string Name,
94 CompletionItemKind K) {
95 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000096}
Sam McCall44fdcec22017-12-08 15:00:59 +000097MATCHER(IsDocumented, "") { return !arg.documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000098
Sam McCalla15c2d62018-01-18 09:27:56 +000099std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
100 SymbolSlab::Builder Slab;
101 for (const auto &Sym : Symbols)
102 Slab.insert(Sym);
103 return MemIndex::build(std::move(Slab).build());
104}
105
Eric Liu63f419a2018-05-15 15:29:32 +0000106CompletionList completions(ClangdServer &Server, StringRef Text,
Sam McCalla15c2d62018-01-18 09:27:56 +0000107 std::vector<Symbol> IndexSymbols = {},
Sam McCallf6ae3232017-12-05 20:11:29 +0000108 clangd::CodeCompleteOptions Opts = {}) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000109 std::unique_ptr<SymbolIndex> OverrideIndex;
110 if (!IndexSymbols.empty()) {
111 assert(!Opts.Index && "both Index and IndexSymbols given!");
112 OverrideIndex = memIndex(std::move(IndexSymbols));
113 Opts.Index = OverrideIndex.get();
114 }
115
Sam McCallc1568062018-02-16 09:41:43 +0000116 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000117 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000118 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000119 auto CompletionList =
120 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000121 // Sanity-check that filterText is valid.
Sam McCall545a20d2018-01-19 14:34:02 +0000122 EXPECT_THAT(CompletionList.items, Each(NameContainsFilter()));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000123 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +0000124}
125
Eric Liu63f419a2018-05-15 15:29:32 +0000126// Builds a server and runs code completion.
127// If IndexSymbols is non-empty, an index will be built and passed to opts.
128CompletionList completions(StringRef Text,
129 std::vector<Symbol> IndexSymbols = {},
130 clangd::CodeCompleteOptions Opts = {}) {
131 MockFSProvider FS;
132 MockCompilationDatabase CDB;
133 IgnoreDiagnostics DiagConsumer;
134 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
135 return completions(Server, Text, std::move(IndexSymbols), std::move(Opts));
136}
137
Sam McCall545a20d2018-01-19 14:34:02 +0000138std::string replace(StringRef Haystack, StringRef Needle, StringRef Repl) {
139 std::string Result;
140 raw_string_ostream OS(Result);
141 std::pair<StringRef, StringRef> Split;
142 for (Split = Haystack.split(Needle); !Split.second.empty();
143 Split = Split.first.split(Needle))
144 OS << Split.first << Repl;
145 Result += Split.first;
146 OS.flush();
147 return Result;
148}
149
Sam McCalla15c2d62018-01-18 09:27:56 +0000150// Helpers to produce fake index symbols for memIndex() or completions().
Sam McCall545a20d2018-01-19 14:34:02 +0000151// USRFormat is a regex replacement string for the unqualified part of the USR.
152Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000153 Symbol Sym;
Sam McCall545a20d2018-01-19 14:34:02 +0000154 std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
Sam McCalla15c2d62018-01-18 09:27:56 +0000155 size_t Pos = QName.rfind("::");
156 if (Pos == llvm::StringRef::npos) {
157 Sym.Name = QName;
158 Sym.Scope = "";
159 } else {
160 Sym.Name = QName.substr(Pos + 2);
Sam McCall8b2faee2018-01-19 22:18:21 +0000161 Sym.Scope = QName.substr(0, Pos + 2);
162 USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
Sam McCalla15c2d62018-01-18 09:27:56 +0000163 }
Sam McCall545a20d2018-01-19 14:34:02 +0000164 USR += Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
165 Sym.ID = SymbolID(USR);
Sam McCalla15c2d62018-01-18 09:27:56 +0000166 Sym.CompletionPlainInsertText = Sym.Name;
Sam McCall545a20d2018-01-19 14:34:02 +0000167 Sym.CompletionSnippetInsertText = Sym.Name;
Sam McCalla15c2d62018-01-18 09:27:56 +0000168 Sym.CompletionLabel = Sym.Name;
169 Sym.SymInfo.Kind = Kind;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000170 Sym.IsIndexedForCodeCompletion = true;
Sam McCalla15c2d62018-01-18 09:27:56 +0000171 return Sym;
172}
Sam McCall545a20d2018-01-19 14:34:02 +0000173Symbol func(StringRef Name) { // Assumes the function has no args.
174 return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
175}
176Symbol cls(StringRef Name) {
Eric Liu9b3cba72018-05-30 09:03:39 +0000177 return sym(Name, index::SymbolKind::Class, "@S@\\0");
Sam McCall545a20d2018-01-19 14:34:02 +0000178}
179Symbol var(StringRef Name) {
180 return sym(Name, index::SymbolKind::Variable, "@\\0");
181}
Sam McCalldc8abc42018-05-03 14:53:02 +0000182Symbol ns(StringRef Name) {
183 return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
184}
185Symbol withReferences(int N, Symbol S) {
186 S.References = N;
187 return S;
188}
Sam McCalla15c2d62018-01-18 09:27:56 +0000189
Sam McCallf6ae3232017-12-05 20:11:29 +0000190TEST(CompletionTest, Limit) {
191 clangd::CodeCompleteOptions Opts;
192 Opts.Limit = 2;
193 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000194struct ClassWithMembers {
195 int AAA();
196 int BBB();
197 int CCC();
198}
Sam McCallf6ae3232017-12-05 20:11:29 +0000199int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000200 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000201 /*IndexSymbols=*/{}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000202
203 EXPECT_TRUE(Results.isIncomplete);
Sam McCallf6ae3232017-12-05 20:11:29 +0000204 EXPECT_THAT(Results.items, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000205}
206
Sam McCallf6ae3232017-12-05 20:11:29 +0000207TEST(CompletionTest, Filter) {
208 std::string Body = R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000209 #define MotorCar
210 int Car;
Sam McCall9aad25f2017-12-05 07:20:26 +0000211 struct S {
212 int FooBar;
213 int FooBaz;
214 int Qux;
215 };
216 )cpp";
Sam McCall8b2dcc12018-06-14 13:50:30 +0000217
218 // Only items matching the fuzzy query are returned.
Sam McCallf6ae3232017-12-05 20:11:29 +0000219 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").items,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000220 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000221
Sam McCall8b2dcc12018-06-14 13:50:30 +0000222 // Macros require prefix match.
223 EXPECT_THAT(completions(Body + "int main() { C^ }").items,
224 AllOf(Has("Car"), Not(Has("MotorCar"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000225}
226
Sam McCallf6ae3232017-12-05 20:11:29 +0000227void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000228 auto Results = completions(
229 R"cpp(
230 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000231
Sam McCall44fdcec22017-12-08 15:00:59 +0000232 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000233
Sam McCall44fdcec22017-12-08 15:00:59 +0000234 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000235
Sam McCall44fdcec22017-12-08 15:00:59 +0000236 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000237
Sam McCall44fdcec22017-12-08 15:00:59 +0000238 struct ClassWithMembers {
239 /// Doc for method.
240 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000241
Sam McCall44fdcec22017-12-08 15:00:59 +0000242 int field;
243 private:
244 int private_field;
245 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000246
Sam McCall44fdcec22017-12-08 15:00:59 +0000247 int test() {
248 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000249
Sam McCall44fdcec22017-12-08 15:00:59 +0000250 /// Doc for local_var.
251 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000252
Sam McCall44fdcec22017-12-08 15:00:59 +0000253 ClassWithMembers().^
254 }
255 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000256 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000257
Sam McCallf6ae3232017-12-05 20:11:29 +0000258 // Class members. The only items that must be present in after-dot
259 // completion.
Sam McCall4caa8512018-06-07 12:49:17 +0000260 EXPECT_THAT(Results.items,
261 AllOf(Has(Opts.EnableSnippets ? "method()" : "method"),
262 Has("field"), Not(Has("ClassWithMembers")),
263 Not(Has("operator=")), Not(Has("~ClassWithMembers"))));
Sam McCall44fdcec22017-12-08 15:00:59 +0000264 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.items,
265 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000266 // Global items.
Sam McCall545a20d2018-01-19 14:34:02 +0000267 EXPECT_THAT(
268 Results.items,
269 Not(AnyOf(Has("global_var"), Has("index_var"), Has("global_func"),
270 Has("global_func()"), Has("index_func"), Has("GlobalClass"),
271 Has("IndexClass"), Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000272 // There should be no code patterns (aka snippets) in after-dot
273 // completion. At least there aren't any we're aware of.
Sam McCall44fdcec22017-12-08 15:00:59 +0000274 EXPECT_THAT(Results.items, Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000275 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000276 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000277}
Sam McCall9aad25f2017-12-05 07:20:26 +0000278
Sam McCallf6ae3232017-12-05 20:11:29 +0000279void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000280 auto Results = completions(
281 R"cpp(
282 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000283
Sam McCall44fdcec22017-12-08 15:00:59 +0000284 int global_var;
285 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000286
Sam McCall44fdcec22017-12-08 15:00:59 +0000287 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000288
Sam McCall44fdcec22017-12-08 15:00:59 +0000289 struct ClassWithMembers {
290 /// Doc for method.
291 int method();
292 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000293
Sam McCall44fdcec22017-12-08 15:00:59 +0000294 int test() {
295 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000296
Sam McCall44fdcec22017-12-08 15:00:59 +0000297 /// Doc for local_var.
298 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000299
Sam McCall44fdcec22017-12-08 15:00:59 +0000300 ^
301 }
302 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000303 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000304
305 // Class members. Should never be present in global completions.
Sam McCall44fdcec22017-12-08 15:00:59 +0000306 EXPECT_THAT(Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000307 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
308 // Global items.
Sam McCalld8169a82018-01-18 15:31:30 +0000309 EXPECT_THAT(Results.items,
Sam McCall545a20d2018-01-19 14:34:02 +0000310 AllOf(Has("global_var"), Has("index_var"),
Sam McCalld8169a82018-01-18 15:31:30 +0000311 Has(Opts.EnableSnippets ? "global_func()" : "global_func"),
Sam McCall545a20d2018-01-19 14:34:02 +0000312 Has("index_func" /* our fake symbol doesn't include () */),
313 Has("GlobalClass"), Has("IndexClass")));
Sam McCallf6ae3232017-12-05 20:11:29 +0000314 // A macro.
Sam McCall44fdcec22017-12-08 15:00:59 +0000315 EXPECT_IFF(Opts.IncludeMacros, Results.items, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000316 // Local items. Must be present always.
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000317 EXPECT_THAT(Results.items,
318 AllOf(Has("local_var"), Has("LocalClass"),
319 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000320 // Check documentation.
Ilya Biryukov43714502018-05-16 12:32:44 +0000321 EXPECT_IFF(Opts.IncludeComments, Results.items, Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000322}
323
324TEST(CompletionTest, CompletionOptions) {
Sam McCall2c3849a2018-01-16 12:21:24 +0000325 auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
326 TestAfterDotCompletion(Opts);
327 TestGlobalScopeCompletion(Opts);
328 };
329 // We used to test every combination of options, but that got too slow (2^N).
330 auto Flags = {
Ilya Biryukov71028b82018-03-12 15:28:22 +0000331 &clangd::CodeCompleteOptions::IncludeMacros,
Ilya Biryukov43714502018-05-16 12:32:44 +0000332 &clangd::CodeCompleteOptions::IncludeComments,
Ilya Biryukov71028b82018-03-12 15:28:22 +0000333 &clangd::CodeCompleteOptions::EnableSnippets,
334 &clangd::CodeCompleteOptions::IncludeCodePatterns,
335 &clangd::CodeCompleteOptions::IncludeIneligibleResults,
Sam McCall2c3849a2018-01-16 12:21:24 +0000336 };
337 // Test default options.
338 Test({});
339 // Test with one flag flipped.
340 for (auto &F : Flags) {
341 clangd::CodeCompleteOptions O;
342 O.*F ^= true;
343 Test(O);
Sam McCall9aad25f2017-12-05 07:20:26 +0000344 }
345}
346
Sam McCall44fdcec22017-12-08 15:00:59 +0000347TEST(CompletionTest, Priorities) {
348 auto Internal = completions(R"cpp(
349 class Foo {
350 public: void pub();
351 protected: void prot();
352 private: void priv();
353 };
354 void Foo::pub() { this->^ }
355 )cpp");
356 EXPECT_THAT(Internal.items,
357 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
358
359 auto External = completions(R"cpp(
360 class Foo {
361 public: void pub();
362 protected: void prot();
363 private: void priv();
364 };
365 void test() {
366 Foo F;
367 F.^
368 }
369 )cpp");
370 EXPECT_THAT(External.items,
371 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
372}
373
374TEST(CompletionTest, Qualifiers) {
375 auto Results = completions(R"cpp(
376 class Foo {
377 public: int foo() const;
378 int bar() const;
379 };
380 class Bar : public Foo {
381 int foo() const;
382 };
383 void test() { Bar().^ }
384 )cpp");
385 EXPECT_THAT(Results.items, HasSubsequence(Labeled("bar() const"),
386 Labeled("Foo::foo() const")));
387 EXPECT_THAT(Results.items, Not(Contains(Labeled("foo() const")))); // private
388}
389
Sam McCall4caa8512018-06-07 12:49:17 +0000390TEST(CompletionTest, InjectedTypename) {
391 // These are suppressed when accessed as a member...
392 EXPECT_THAT(completions("struct X{}; void foo(){ X().^ }").items,
393 Not(Has("X")));
394 EXPECT_THAT(completions("struct X{ void foo(){ this->^ } };").items,
395 Not(Has("X")));
396 // ...but accessible in other, more useful cases.
397 EXPECT_THAT(completions("struct X{ void foo(){ ^ } };").items, Has("X"));
398 EXPECT_THAT(completions("struct Y{}; struct X:Y{ void foo(){ ^ } };").items,
399 Has("Y"));
400 EXPECT_THAT(
401 completions(
402 "template<class> struct Y{}; struct X:Y<int>{ void foo(){ ^ } };")
403 .items,
404 Has("Y"));
405 // This case is marginal (`using X::X` is useful), we allow it for now.
406 EXPECT_THAT(completions("struct X{}; void foo(){ X::^ }").items, Has("X"));
407}
408
Sam McCall44fdcec22017-12-08 15:00:59 +0000409TEST(CompletionTest, Snippets) {
410 clangd::CodeCompleteOptions Opts;
411 Opts.EnableSnippets = true;
412 auto Results = completions(
413 R"cpp(
414 struct fake {
415 int a;
416 int f(int i, const float f) const;
417 };
418 int main() {
419 fake f;
420 f.^
421 }
422 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000423 /*IndexSymbols=*/{}, Opts);
Sam McCall44fdcec22017-12-08 15:00:59 +0000424 EXPECT_THAT(Results.items,
Eric Liu63696e12017-12-20 17:24:31 +0000425 HasSubsequence(Snippet("a"),
Sam McCall44fdcec22017-12-08 15:00:59 +0000426 Snippet("f(${1:int i}, ${2:const float f})")));
427}
428
429TEST(CompletionTest, Kinds) {
Sam McCall545a20d2018-01-19 14:34:02 +0000430 auto Results = completions(
431 R"cpp(
432 #define MACRO X
433 int variable;
434 struct Struct {};
435 int function();
436 int X = ^
437 )cpp",
438 {func("indexFunction"), var("indexVariable"), cls("indexClass")});
439 EXPECT_THAT(Results.items,
440 AllOf(Has("function", CompletionItemKind::Function),
441 Has("variable", CompletionItemKind::Variable),
442 Has("int", CompletionItemKind::Keyword),
443 Has("Struct", CompletionItemKind::Class),
444 Has("MACRO", CompletionItemKind::Text),
445 Has("indexFunction", CompletionItemKind::Function),
446 Has("indexVariable", CompletionItemKind::Variable),
447 Has("indexClass", CompletionItemKind::Class)));
Sam McCall44fdcec22017-12-08 15:00:59 +0000448
Sam McCall44fdcec22017-12-08 15:00:59 +0000449 Results = completions("nam^");
450 EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
451}
452
Sam McCall84652cc2018-01-12 16:16:09 +0000453TEST(CompletionTest, NoDuplicates) {
Sam McCall545a20d2018-01-19 14:34:02 +0000454 auto Results = completions(
455 R"cpp(
456 class Adapter {
Sam McCall545a20d2018-01-19 14:34:02 +0000457 };
Sam McCall84652cc2018-01-12 16:16:09 +0000458
Eric Liu9b3cba72018-05-30 09:03:39 +0000459 void f() {
Sam McCall545a20d2018-01-19 14:34:02 +0000460 Adapter^
461 }
462 )cpp",
463 {cls("Adapter")});
Sam McCall84652cc2018-01-12 16:16:09 +0000464
465 // Make sure there are no duplicate entries of 'Adapter'.
Sam McCalld2a95922018-01-22 21:05:00 +0000466 EXPECT_THAT(Results.items, ElementsAre(Named("Adapter")));
Sam McCall84652cc2018-01-12 16:16:09 +0000467}
468
Sam McCall545a20d2018-01-19 14:34:02 +0000469TEST(CompletionTest, ScopedNoIndex) {
470 auto Results = completions(
471 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000472 namespace fake { int BigBang, Babble, Box; };
473 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000474 ")cpp");
Sam McCall8b2dcc12018-06-14 13:50:30 +0000475 // Babble is a better match than BigBang. Box doesn't match at all.
476 EXPECT_THAT(Results.items, ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCall84652cc2018-01-12 16:16:09 +0000477}
478
Sam McCall545a20d2018-01-19 14:34:02 +0000479TEST(CompletionTest, Scoped) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000480 auto Results = completions(
481 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000482 namespace fake { int Babble, Box; };
483 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000484 ")cpp",
485 {var("fake::BigBang")});
Sam McCall8b2dcc12018-06-14 13:50:30 +0000486 EXPECT_THAT(Results.items, ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000487}
488
Sam McCall545a20d2018-01-19 14:34:02 +0000489TEST(CompletionTest, ScopedWithFilter) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000490 auto Results = completions(
491 R"cpp(
492 void f() { ns::x^ }
493 )cpp",
494 {cls("ns::XYZ"), func("ns::foo")});
495 EXPECT_THAT(Results.items,
496 UnorderedElementsAre(AllOf(Named("XYZ"), Filter("XYZ"))));
497}
498
Sam McCalldc8abc42018-05-03 14:53:02 +0000499TEST(CompletionTest, ReferencesAffectRanking) {
500 auto Results = completions("int main() { abs^ }", {ns("absl"), func("abs")});
501 EXPECT_THAT(Results.items, HasSubsequence(Named("abs"), Named("absl")));
502 Results = completions("int main() { abs^ }",
503 {withReferences(10000, ns("absl")), func("abs")});
504 EXPECT_THAT(Results.items, HasSubsequence(Named("absl"), Named("abs")));
505}
506
Sam McCall545a20d2018-01-19 14:34:02 +0000507TEST(CompletionTest, GlobalQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000508 auto Results = completions(
509 R"cpp(
510 void f() { ::^ }
511 )cpp",
512 {cls("XYZ")});
513 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
514 Has("f", CompletionItemKind::Function)));
515}
516
Sam McCall545a20d2018-01-19 14:34:02 +0000517TEST(CompletionTest, FullyQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000518 auto Results = completions(
519 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000520 namespace ns { void bar(); }
Sam McCalla15c2d62018-01-18 09:27:56 +0000521 void f() { ::ns::^ }
522 )cpp",
523 {cls("ns::XYZ")});
Sam McCall545a20d2018-01-19 14:34:02 +0000524 EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
525 Has("bar", CompletionItemKind::Function)));
526}
527
528TEST(CompletionTest, SemaIndexMerge) {
529 auto Results = completions(
530 R"cpp(
531 namespace ns { int local; void both(); }
532 void f() { ::ns::^ }
533 )cpp",
534 {func("ns::both"), cls("ns::Index")});
535 // We get results from both index and sema, with no duplicates.
536 EXPECT_THAT(
537 Results.items,
538 UnorderedElementsAre(Named("local"), Named("Index"), Named("both")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000539}
540
Haojian Wu48b48652018-01-25 09:20:09 +0000541TEST(CompletionTest, SemaIndexMergeWithLimit) {
542 clangd::CodeCompleteOptions Opts;
543 Opts.Limit = 1;
544 auto Results = completions(
545 R"cpp(
546 namespace ns { int local; void both(); }
547 void f() { ::ns::^ }
548 )cpp",
549 {func("ns::both"), cls("ns::Index")}, Opts);
550 EXPECT_EQ(Results.items.size(), Opts.Limit);
551 EXPECT_TRUE(Results.isIncomplete);
552}
553
Eric Liu63f419a2018-05-15 15:29:32 +0000554TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
555 MockFSProvider FS;
556 MockCompilationDatabase CDB;
557 std::string Subdir = testPath("sub");
558 std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
559 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
560 std::string BarHeader = testPath("sub/bar.h");
561 FS.Files[BarHeader] = "";
562
563 IgnoreDiagnostics DiagConsumer;
564 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
565 Symbol::Details Scratch;
566 auto BarURI = URI::createFile(BarHeader).toString();
567 Symbol Sym = cls("ns::X");
568 Sym.CanonicalDeclaration.FileURI = BarURI;
569 Scratch.IncludeHeader = BarURI;
570 Sym.Detail = &Scratch;
571 // Shoten include path based on search dirctory and insert.
572 auto Results = completions(Server,
573 R"cpp(
574 int main() { ns::^ }
575 )cpp",
576 {Sym});
577 EXPECT_THAT(Results.items,
Eric Liu8f3678d2018-06-15 13:34:18 +0000578 ElementsAre(AllOf(
579 Named("X"),
580 Labeled(CodeCompleteOptions().IncludeIndicator.Insert + "X"),
581 InsertInclude("\"bar.h\""))));
Eric Liu63f419a2018-05-15 15:29:32 +0000582 // Duplicate based on inclusions in preamble.
583 Results = completions(Server,
584 R"cpp(
585 #include "sub/bar.h" // not shortest, so should only match resolved.
586 int main() { ns::^ }
587 )cpp",
588 {Sym});
Eric Liu8f3678d2018-06-15 13:34:18 +0000589 EXPECT_THAT(Results.items, ElementsAre(AllOf(Named("X"), Labeled("X"),
590 Not(HasAdditionalEdits()))));
Eric Liu63f419a2018-05-15 15:29:32 +0000591}
592
Eric Liu9b3cba72018-05-30 09:03:39 +0000593TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
594 MockFSProvider FS;
595 MockCompilationDatabase CDB;
596
597 IgnoreDiagnostics DiagConsumer;
598 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
599 Symbol::Details Scratch;
600 Symbol SymX = cls("ns::X");
601 Symbol SymY = cls("ns::Y");
602 std::string BarHeader = testPath("bar.h");
603 auto BarURI = URI::createFile(BarHeader).toString();
604 SymX.CanonicalDeclaration.FileURI = BarURI;
605 SymY.CanonicalDeclaration.FileURI = BarURI;
606 Scratch.IncludeHeader = "<bar>";
607 SymX.Detail = &Scratch;
608 SymY.Detail = &Scratch;
609 // Shoten include path based on search dirctory and insert.
610 auto Results = completions(Server,
611 R"cpp(
612 namespace ns {
613 class X;
614 class Y {}
615 }
616 int main() { ns::^ }
617 )cpp",
618 {SymX, SymY});
619 EXPECT_THAT(Results.items,
620 ElementsAre(AllOf(Named("X"), Not(HasAdditionalEdits())),
621 AllOf(Named("Y"), Not(HasAdditionalEdits()))));
622}
623
Sam McCalla15c2d62018-01-18 09:27:56 +0000624TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
625 MockFSProvider FS;
626 MockCompilationDatabase CDB;
627 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000628 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCalla15c2d62018-01-18 09:27:56 +0000629
Sam McCallc1568062018-02-16 09:41:43 +0000630 FS.Files[testPath("bar.h")] =
Sam McCalld5ea3e32018-01-24 17:53:32 +0000631 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
Sam McCallc1568062018-02-16 09:41:43 +0000632 auto File = testPath("foo.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000633 Annotations Test(R"cpp(
634 #include "bar.h"
635 namespace ns { int local; }
Sam McCalld5ea3e32018-01-24 17:53:32 +0000636 void f() { ns::^; }
637 void f() { ns::preamble().$2^; }
Sam McCalla15c2d62018-01-18 09:27:56 +0000638 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000639 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000640 clangd::CodeCompleteOptions Opts = {};
641
Sam McCalla15c2d62018-01-18 09:27:56 +0000642 auto I = memIndex({var("ns::index")});
643 Opts.Index = I.get();
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000644 auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalla15c2d62018-01-18 09:27:56 +0000645 EXPECT_THAT(WithIndex.items,
646 UnorderedElementsAre(Named("local"), Named("index")));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000647 auto ClassFromPreamble =
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000648 cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000649 EXPECT_THAT(ClassFromPreamble.items, Contains(Named("member")));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000650
651 Opts.Index = nullptr;
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000652 auto WithoutIndex =
653 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000654 EXPECT_THAT(WithoutIndex.items,
655 UnorderedElementsAre(Named("local"), Named("preamble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000656}
657
658TEST(CompletionTest, DynamicIndexMultiFile) {
659 MockFSProvider FS;
660 MockCompilationDatabase CDB;
661 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000662 auto Opts = ClangdServer::optsForTest();
663 Opts.BuildDynamicSymbolIndex = true;
664 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCalla15c2d62018-01-18 09:27:56 +0000665
Eric Liu709bde82018-02-19 18:48:44 +0000666 FS.Files[testPath("foo.h")] = R"cpp(
Sam McCalla15c2d62018-01-18 09:27:56 +0000667 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liu709bde82018-02-19 18:48:44 +0000668 )cpp";
Sam McCall7363a2f2018-03-05 17:28:54 +0000669 runAddDocument(Server, testPath("foo.cpp"), R"cpp(
Eric Liu709bde82018-02-19 18:48:44 +0000670 #include "foo.h"
Sam McCall0bb24cd2018-02-13 08:59:23 +0000671 )cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000672
Sam McCallc1568062018-02-16 09:41:43 +0000673 auto File = testPath("bar.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000674 Annotations Test(R"cpp(
675 namespace ns {
676 class XXX {};
677 /// Doooc
678 void fooooo() {}
679 }
680 void f() { ns::^ }
681 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000682 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000683
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000684 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
Sam McCalla15c2d62018-01-18 09:27:56 +0000685 // "XYZ" and "foo" are not included in the file being completed but are still
686 // visible through the index.
687 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
688 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
689 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
690 EXPECT_THAT(Results.items, Contains(AllOf(Named("fooooo"), Filter("fooooo"),
691 Kind(CompletionItemKind::Function),
692 Doc("Doooc"), Detail("void"))));
693}
694
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000695TEST(CompletionTest, Documentation) {
696 auto Results = completions(
697 R"cpp(
698 // Non-doxygen comment.
699 int foo();
700 /// Doxygen comment.
701 /// \param int a
702 int bar(int a);
703 /* Multi-line
704 block comment
705 */
706 int baz();
707
708 int x = ^
709 )cpp");
710 EXPECT_THAT(Results.items,
711 Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
712 EXPECT_THAT(
713 Results.items,
714 Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
715 EXPECT_THAT(Results.items,
716 Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
717}
718
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000719TEST(CompletionTest, GlobalCompletionFiltering) {
720
721 Symbol Class = cls("XYZ");
722 Class.IsIndexedForCodeCompletion = false;
723 Symbol Func = func("XYZ::foooo");
724 Func.IsIndexedForCodeCompletion = false;
725
726 auto Results = completions(R"(// void f() {
727 XYZ::foooo^
728 })",
729 {Class, Func});
730 EXPECT_THAT(Results.items, IsEmpty());
731}
732
Haojian Wu58d208d2018-01-25 09:44:06 +0000733TEST(CodeCompleteTest, DisableTypoCorrection) {
734 auto Results = completions(R"cpp(
735 namespace clang { int v; }
736 void f() { clangd::^
737 )cpp");
738 EXPECT_TRUE(Results.items.empty());
739}
740
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000741TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
742 auto Results = completions(R"cpp(
743 namespace clang { }
744 void f() {
745 clan^
746 }
747 )cpp");
748
749 EXPECT_THAT(Results.items, Contains(Labeled("clang")));
750 EXPECT_THAT(Results.items, Not(Contains(Labeled("clang::"))));
751}
752
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000753TEST(CompletionTest, BacktrackCrashes) {
754 // Sema calls code completion callbacks twice in these cases.
755 auto Results = completions(R"cpp(
756 namespace ns {
757 struct FooBarBaz {};
758 } // namespace ns
759
760 int foo(ns::FooBar^
761 )cpp");
762
763 EXPECT_THAT(Results.items, ElementsAre(Labeled("FooBarBaz")));
764
765 // Check we don't crash in that case too.
766 completions(R"cpp(
767 struct FooBarBaz {};
768 void test() {
769 if (FooBarBaz * x^) {}
770 }
771)cpp");
772}
773
Eric Liu42abe412018-05-24 11:20:19 +0000774TEST(CompletionTest, CompleteInMacroWithStringification) {
775 auto Results = completions(R"cpp(
776void f(const char *, int x);
777#define F(x) f(#x, x)
778
779namespace ns {
780int X;
781int Y;
782} // namespace ns
783
784int f(int input_num) {
785 F(ns::^)
786}
787)cpp");
788
789 EXPECT_THAT(Results.items,
790 UnorderedElementsAre(Named("X"), Named("Y")));
791}
792
793TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
794 auto Results = completions(R"cpp(
795void f(const char *, int x);
796#define F(x) f(#x, x)
797
798namespace ns {
799int X;
800
801int f(int input_num) {
802 F(^)
803}
804} // namespace ns
805)cpp");
806
807 EXPECT_THAT(Results.items, Contains(Named("X")));
808}
809
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000810TEST(CompletionTest, CompleteInExcludedPPBranch) {
811 auto Results = completions(R"cpp(
812 int bar(int param_in_bar) {
813 }
814
815 int foo(int param_in_foo) {
816#if 0
817 par^
818#endif
819 }
820)cpp");
821
822 EXPECT_THAT(Results.items, Contains(Labeled("param_in_foo")));
823 EXPECT_THAT(Results.items, Not(Contains(Labeled("param_in_bar"))));
824}
825
Sam McCall800d4372017-12-19 10:29:27 +0000826SignatureHelp signatures(StringRef Text) {
827 MockFSProvider FS;
828 MockCompilationDatabase CDB;
829 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000830 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCallc1568062018-02-16 09:41:43 +0000831 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000832 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000833 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000834 return cantFail(runSignatureHelp(Server, File, Test.point()));
Sam McCall800d4372017-12-19 10:29:27 +0000835}
836
837MATCHER_P(ParamsAre, P, "") {
838 if (P.size() != arg.parameters.size())
839 return false;
840 for (unsigned I = 0; I < P.size(); ++I)
841 if (P[I] != arg.parameters[I].label)
842 return false;
843 return true;
844}
845
846Matcher<SignatureInformation> Sig(std::string Label,
847 std::vector<std::string> Params) {
Eric Liu8f3678d2018-06-15 13:34:18 +0000848 return AllOf(SigHelpLabeled(Label), ParamsAre(Params));
Sam McCall800d4372017-12-19 10:29:27 +0000849}
850
851TEST(SignatureHelpTest, Overloads) {
852 auto Results = signatures(R"cpp(
853 void foo(int x, int y);
854 void foo(int x, float y);
855 void foo(float x, int y);
856 void foo(float x, float y);
857 void bar(int x, int y = 0);
858 int main() { foo(^); }
859 )cpp");
860 EXPECT_THAT(Results.signatures,
861 UnorderedElementsAre(
862 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
863 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
864 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
865 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
866 // We always prefer the first signature.
867 EXPECT_EQ(0, Results.activeSignature);
868 EXPECT_EQ(0, Results.activeParameter);
869}
870
871TEST(SignatureHelpTest, DefaultArgs) {
872 auto Results = signatures(R"cpp(
873 void bar(int x, int y = 0);
874 void bar(float x = 0, int y = 42);
875 int main() { bar(^
876 )cpp");
877 EXPECT_THAT(Results.signatures,
878 UnorderedElementsAre(
879 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
880 Sig("bar(float x = 0, int y = 42) -> void",
881 {"float x = 0", "int y = 42"})));
882 EXPECT_EQ(0, Results.activeSignature);
883 EXPECT_EQ(0, Results.activeParameter);
884}
885
886TEST(SignatureHelpTest, ActiveArg) {
887 auto Results = signatures(R"cpp(
888 int baz(int a, int b, int c);
889 int main() { baz(baz(1,2,3), ^); }
890 )cpp");
891 EXPECT_THAT(Results.signatures,
892 ElementsAre(Sig("baz(int a, int b, int c) -> int",
893 {"int a", "int b", "int c"})));
894 EXPECT_EQ(0, Results.activeSignature);
895 EXPECT_EQ(1, Results.activeParameter);
896}
897
Haojian Wu061c73e2018-01-23 11:37:26 +0000898class IndexRequestCollector : public SymbolIndex {
899public:
900 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000901 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000902 llvm::function_ref<void(const Symbol &)> Callback) const override {
903 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000904 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000905 }
906
Eric Liu9ec459f2018-03-14 09:48:05 +0000907 void lookup(const LookupRequest &,
908 llvm::function_ref<void(const Symbol &)>) const override {}
909
Haojian Wu061c73e2018-01-23 11:37:26 +0000910 const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
911
912private:
913 mutable std::vector<FuzzyFindRequest> Requests;
914};
915
916std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
917 clangd::CodeCompleteOptions Opts;
918 IndexRequestCollector Requests;
919 Opts.Index = &Requests;
920 completions(Code, {}, Opts);
921 return Requests.allRequests();
922}
923
924TEST(CompletionTest, UnqualifiedIdQuery) {
925 auto Requests = captureIndexRequests(R"cpp(
926 namespace std {}
927 using namespace std;
928 namespace ns {
929 void f() {
930 vec^
931 }
932 }
933 )cpp");
934
935 EXPECT_THAT(Requests,
936 ElementsAre(Field(&FuzzyFindRequest::Scopes,
937 UnorderedElementsAre("", "ns::", "std::"))));
938}
939
940TEST(CompletionTest, ResolvedQualifiedIdQuery) {
941 auto Requests = captureIndexRequests(R"cpp(
942 namespace ns1 {}
943 namespace ns2 {} // ignore
944 namespace ns3 { namespace nns3 {} }
945 namespace foo {
946 using namespace ns1;
947 using namespace ns3::nns3;
948 }
949 namespace ns {
950 void f() {
951 foo::^
952 }
953 }
954 )cpp");
955
956 EXPECT_THAT(Requests,
957 ElementsAre(Field(
958 &FuzzyFindRequest::Scopes,
959 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
960}
961
962TEST(CompletionTest, UnresolvedQualifierIdQuery) {
963 auto Requests = captureIndexRequests(R"cpp(
964 namespace a {}
965 using namespace a;
966 namespace ns {
967 void f() {
968 bar::^
969 }
970 } // namespace ns
971 )cpp");
972
973 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
974 UnorderedElementsAre("bar::"))));
975}
976
977TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
978 auto Requests = captureIndexRequests(R"cpp(
979 namespace a {}
980 using namespace a;
981 namespace ns {
982 void f() {
983 ::a::bar::^
984 }
985 } // namespace ns
986 )cpp");
987
988 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
989 UnorderedElementsAre("a::bar::"))));
990}
991
992TEST(CompletionTest, EmptyQualifiedQuery) {
993 auto Requests = captureIndexRequests(R"cpp(
994 namespace ns {
995 void f() {
996 ^
997 }
998 } // namespace ns
999 )cpp");
1000
1001 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1002 UnorderedElementsAre("", "ns::"))));
1003}
1004
1005TEST(CompletionTest, GlobalQualifiedQuery) {
1006 auto Requests = captureIndexRequests(R"cpp(
1007 namespace ns {
1008 void f() {
1009 ::^
1010 }
1011 } // namespace ns
1012 )cpp");
1013
1014 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1015 UnorderedElementsAre(""))));
1016}
1017
Ilya Biryukova907ba42018-05-14 10:50:04 +00001018TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
1019 auto Completions = completions(
1020 R"cpp(
1021 struct Foo {
1022 int SomeNameOfField;
1023 typedef int SomeNameOfTypedefField;
1024 };
1025
1026 Foo::^)cpp",
1027 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
1028
1029 EXPECT_THAT(Completions.items,
1030 AllOf(Contains(Labeled("SomeNameOfField")),
1031 Contains(Labeled("SomeNameOfTypedefField")),
1032 Not(Contains(Labeled("SomeNameInTheIndex")))));
1033}
1034
1035TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
1036 {
1037 auto Completions = completions(
1038 R"cpp(
1039 template <class T>
1040 void foo() {
1041 T::^
1042 }
1043 )cpp",
1044 {func("::SomeNameInTheIndex")});
1045
1046 EXPECT_THAT(Completions.items,
1047 Not(Contains(Labeled("SomeNameInTheIndex"))));
1048 }
1049
1050 {
1051 auto Completions = completions(
1052 R"cpp(
1053 template <class T>
1054 void foo() {
1055 T::template Y<int>::^
1056 }
1057 )cpp",
1058 {func("::SomeNameInTheIndex")});
1059
1060 EXPECT_THAT(Completions.items,
1061 Not(Contains(Labeled("SomeNameInTheIndex"))));
1062 }
1063
1064 {
1065 auto Completions = completions(
1066 R"cpp(
1067 template <class T>
1068 void foo() {
1069 T::foo::^
1070 }
1071 )cpp",
1072 {func("::SomeNameInTheIndex")});
1073
1074 EXPECT_THAT(Completions.items,
1075 Not(Contains(Labeled("SomeNameInTheIndex"))));
1076 }
1077}
1078
Sam McCallc18c2802018-06-15 11:06:29 +00001079TEST(CompletionTest, OverloadBundling) {
1080 clangd::CodeCompleteOptions Opts;
1081 Opts.BundleOverloads = true;
1082
1083 std::string Context = R"cpp(
1084 struct X {
1085 // Overload with int
1086 int a(int);
1087 // Overload with bool
1088 int a(bool);
1089 int b(float);
1090 };
1091 int GFuncC(int);
1092 int GFuncD(int);
1093 )cpp";
1094
1095 // Member completions are bundled.
1096 EXPECT_THAT(completions(Context + "int y = X().^", {}, Opts).items,
1097 UnorderedElementsAre(Labeled("a(…)"), Labeled("b(float)")));
1098
1099 // Non-member completions are bundled, including index+sema.
1100 Symbol NoArgsGFunc = func("GFuncC");
1101 EXPECT_THAT(
1102 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).items,
1103 UnorderedElementsAre(Labeled("GFuncC(…)"), Labeled("GFuncD(int)")));
1104
1105 // Differences in header-to-insert suppress bundling.
1106 Symbol::Details Detail;
1107 std::string DeclFile = URI::createFile(testPath("foo")).toString();
1108 NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile;
1109 Detail.IncludeHeader = "<foo>";
1110 NoArgsGFunc.Detail = &Detail;
1111 EXPECT_THAT(
1112 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).items,
Eric Liu8f3678d2018-06-15 13:34:18 +00001113 UnorderedElementsAre(
1114 AllOf(
1115 Named("GFuncC"),
1116 Labeled(CodeCompleteOptions().IncludeIndicator.Insert + "GFuncC"),
1117 InsertInclude("<foo>")),
1118 Labeled("GFuncC(int)"), Labeled("GFuncD(int)")));
Sam McCallc18c2802018-06-15 11:06:29 +00001119
1120 // Examine a bundled completion in detail.
1121 auto A = completions(Context + "int y = X().a^", {}, Opts).items.front();
Eric Liu8f3678d2018-06-15 13:34:18 +00001122 EXPECT_EQ(A.label, " a(…)");
Sam McCallc18c2802018-06-15 11:06:29 +00001123 EXPECT_EQ(A.detail, "[2 overloads]");
1124 EXPECT_EQ(A.insertText, "a");
1125 EXPECT_EQ(A.kind, CompletionItemKind::Method);
1126 // For now we just return one of the doc strings arbitrarily.
1127 EXPECT_THAT(A.documentation, AnyOf(HasSubstr("Overload with int"),
1128 HasSubstr("Overload with bool")));
1129 Opts.EnableSnippets = true;
1130 A = completions(Context + "int y = X().a^", {}, Opts).items.front();
1131 EXPECT_EQ(A.insertText, "a(${0})");
1132}
1133
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001134TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001135 MockFSProvider FS;
1136 auto FooH = testPath("foo.h");
1137 auto FooCpp = testPath("foo.cpp");
1138 FS.Files[FooH] = R"cpp(
1139 // this is my documentation comment.
1140 int func();
1141 )cpp";
1142 FS.Files[FooCpp] = "";
1143
1144 MockCompilationDatabase CDB;
1145 IgnoreDiagnostics DiagConsumer;
1146 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1147
1148 Annotations Source(R"cpp(
1149 #include "foo.h"
1150 int func() {
1151 // This makes sure we have func from header in the AST.
1152 }
1153 int a = fun^
1154 )cpp");
1155 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1156 // We need to wait for preamble to build.
1157 ASSERT_TRUE(Server.blockUntilIdleForTest());
1158
1159 // Change the header file. Completion will reuse the old preamble!
1160 FS.Files[FooH] = R"cpp(
1161 int func();
1162 )cpp";
1163
1164 clangd::CodeCompleteOptions Opts;
1165 Opts.IncludeComments = true;
1166 CompletionList Completions =
1167 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1168 // We shouldn't crash. Unfortunately, current workaround is to not produce
1169 // comments for symbols from headers.
1170 EXPECT_THAT(Completions.items,
1171 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1172}
1173
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001174TEST(CompletionTest, NonDocComments) {
1175 MockFSProvider FS;
1176 auto FooCpp = testPath("foo.cpp");
1177 FS.Files[FooCpp] = "";
1178
1179 MockCompilationDatabase CDB;
1180 IgnoreDiagnostics DiagConsumer;
1181 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1182
1183 Annotations Source(R"cpp(
1184 // ------------------
1185 int comments_foo();
1186
1187 // A comment and a decl are separated by newlines.
1188 // Therefore, the comment shouldn't show up as doc comment.
1189
1190 int comments_bar();
1191
1192 // this comment should be in the results.
1193 int comments_baz();
1194
1195
1196 template <class T>
1197 struct Struct {
1198 int comments_qux();
1199 int comments_quux();
1200 };
1201
1202
1203 // This comment should not be there.
1204
1205 template <class T>
1206 int Struct<T>::comments_qux() {
1207 }
1208
1209 // This comment **should** be in results.
1210 template <class T>
1211 int Struct<T>::comments_quux() {
1212 int a = comments^;
1213 }
1214 )cpp");
1215 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1216 CompletionList Completions = cantFail(runCodeComplete(
1217 Server, FooCpp, Source.point(), clangd::CodeCompleteOptions()));
1218
1219 // We should not get any of those comments in completion.
1220 EXPECT_THAT(
1221 Completions.items,
1222 UnorderedElementsAre(AllOf(Not(IsDocumented()), Named("comments_foo")),
1223 AllOf(IsDocumented(), Named("comments_baz")),
1224 AllOf(IsDocumented(), Named("comments_quux")),
1225 // FIXME(ibiryukov): the following items should have
1226 // empty documentation, since they are separated from
1227 // a comment with an empty line. Unfortunately, I
1228 // couldn't make Sema tests pass if we ignore those.
1229 AllOf(IsDocumented(), Named("comments_bar")),
1230 AllOf(IsDocumented(), Named("comments_qux"))));
1231}
1232
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001233TEST(CompletionTest, CompleteOnInvalidLine) {
1234 auto FooCpp = testPath("foo.cpp");
1235
1236 MockCompilationDatabase CDB;
1237 IgnoreDiagnostics DiagConsumer;
1238 MockFSProvider FS;
1239 FS.Files[FooCpp] = "// empty file";
1240
1241 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1242 // Run completion outside the file range.
1243 Position Pos;
1244 Pos.line = 100;
1245 Pos.character = 0;
1246 EXPECT_THAT_EXPECTED(
1247 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1248 Failed());
1249}
1250
1251
Sam McCall9aad25f2017-12-05 07:20:26 +00001252} // namespace
1253} // namespace clangd
1254} // namespace clang