blob: 49d8dca9e471fe8db15dbd62b59c0f5250adfcdf [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 McCalle746a2b2018-07-02 11:13:16 +000016#include "Quality.h"
Sam McCallb536a2a2017-12-19 12:23:48 +000017#include "SourceCode.h"
Ilya Biryukovcd5eb002018-02-12 11:37:28 +000018#include "SyncAPI.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000019#include "TestFS.h"
Eric Liu6f648df2017-12-19 16:50:37 +000020#include "index/MemIndex.h"
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +000021#include "llvm/Support/Error.h"
Ilya Biryukov981a35d2018-05-28 12:11:37 +000022#include "llvm/Testing/Support/Error.h"
Sam McCallf6ae3232017-12-05 20:11:29 +000023#include "gmock/gmock.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000024#include "gtest/gtest.h"
25
26namespace clang {
27namespace clangd {
Sam McCallf6ae3232017-12-05 20:11:29 +000028
Sam McCall9aad25f2017-12-05 07:20:26 +000029namespace {
30using namespace llvm;
Sam McCallf6ae3232017-12-05 20:11:29 +000031using ::testing::AllOf;
32using ::testing::Contains;
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000033using ::testing::Each;
Sam McCallf6ae3232017-12-05 20:11:29 +000034using ::testing::ElementsAre;
Ilya Biryukov71028b82018-03-12 15:28:22 +000035using ::testing::Field;
Sam McCallc18c2802018-06-15 11:06:29 +000036using ::testing::HasSubstr;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +000037using ::testing::IsEmpty;
Sam McCallf6ae3232017-12-05 20:11:29 +000038using ::testing::Not;
Sam McCall3d139c52018-01-12 18:30:08 +000039using ::testing::UnorderedElementsAre;
Sam McCall9aad25f2017-12-05 07:20:26 +000040
41class IgnoreDiagnostics : public DiagnosticsConsumer {
Ilya Biryukov71028b82018-03-12 15:28:22 +000042 void onDiagnosticsReady(PathRef File,
Sam McCalla7bb0cc2018-03-12 23:22:35 +000043 std::vector<Diag> Diagnostics) override {}
Sam McCall9aad25f2017-12-05 07:20:26 +000044};
45
Sam McCallf6ae3232017-12-05 20:11:29 +000046// GMock helpers for matching completion items.
Sam McCalle746a2b2018-07-02 11:13:16 +000047MATCHER_P(Named, Name, "") { return arg.Name == Name; }
48MATCHER_P(Scope, S, "") { return arg.Scope == S; }
49MATCHER_P(Qualifier, Q, "") { return arg.RequiredQualifier == Q; }
Eric Liu8f3678d2018-06-15 13:34:18 +000050MATCHER_P(Labeled, Label, "") {
Sam McCalle746a2b2018-07-02 11:13:16 +000051 return arg.RequiredQualifier + arg.Name + arg.Signature == Label;
Eric Liu8f3678d2018-06-15 13:34:18 +000052}
53MATCHER_P(SigHelpLabeled, Label, "") { return arg.label == Label; }
Sam McCalle746a2b2018-07-02 11:13:16 +000054MATCHER_P(Kind, K, "") { return arg.Kind == K; }
55MATCHER_P(Doc, D, "") { return arg.Documentation == D; }
56MATCHER_P(ReturnType, D, "") { return arg.ReturnType == D; }
Eric Liu63f419a2018-05-15 15:29:32 +000057MATCHER_P(InsertInclude, IncludeHeader, "") {
Sam McCalle746a2b2018-07-02 11:13:16 +000058 return arg.Header == IncludeHeader && bool(arg.HeaderInsertion);
Eric Liu63f419a2018-05-15 15:29:32 +000059}
Sam McCalle746a2b2018-07-02 11:13:16 +000060MATCHER(InsertInclude, "") { return bool(arg.HeaderInsertion); }
61MATCHER_P(SnippetSuffix, Text, "") { return arg.SnippetSuffix == Text; }
Eric Liu63f419a2018-05-15 15:29:32 +000062
Sam McCallf6ae3232017-12-05 20:11:29 +000063// Shorthand for Contains(Named(Name)).
Sam McCalle746a2b2018-07-02 11:13:16 +000064Matcher<const std::vector<CodeCompletion> &> Has(std::string Name) {
Sam McCallf6ae3232017-12-05 20:11:29 +000065 return Contains(Named(std::move(Name)));
66}
Sam McCalle746a2b2018-07-02 11:13:16 +000067Matcher<const std::vector<CodeCompletion> &> Has(std::string Name,
Sam McCall44fdcec22017-12-08 15:00:59 +000068 CompletionItemKind K) {
69 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000070}
Sam McCalle746a2b2018-07-02 11:13:16 +000071MATCHER(IsDocumented, "") { return !arg.Documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000072
Sam McCalla15c2d62018-01-18 09:27:56 +000073std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
74 SymbolSlab::Builder Slab;
75 for (const auto &Sym : Symbols)
76 Slab.insert(Sym);
77 return MemIndex::build(std::move(Slab).build());
78}
79
Sam McCalle746a2b2018-07-02 11:13:16 +000080CodeCompleteResult completions(ClangdServer &Server, StringRef Text,
81 std::vector<Symbol> IndexSymbols = {},
82 clangd::CodeCompleteOptions Opts = {}) {
Sam McCalla15c2d62018-01-18 09:27:56 +000083 std::unique_ptr<SymbolIndex> OverrideIndex;
84 if (!IndexSymbols.empty()) {
85 assert(!Opts.Index && "both Index and IndexSymbols given!");
86 OverrideIndex = memIndex(std::move(IndexSymbols));
87 Opts.Index = OverrideIndex.get();
88 }
89
Sam McCallc1568062018-02-16 09:41:43 +000090 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +000091 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +000092 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +000093 auto CompletionList =
94 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000095 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +000096}
97
Eric Liu63f419a2018-05-15 15:29:32 +000098// Builds a server and runs code completion.
99// If IndexSymbols is non-empty, an index will be built and passed to opts.
Sam McCalle746a2b2018-07-02 11:13:16 +0000100CodeCompleteResult completions(StringRef Text,
101 std::vector<Symbol> IndexSymbols = {},
102 clangd::CodeCompleteOptions Opts = {}) {
Eric Liu63f419a2018-05-15 15:29:32 +0000103 MockFSProvider FS;
104 MockCompilationDatabase CDB;
105 IgnoreDiagnostics DiagConsumer;
106 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
107 return completions(Server, Text, std::move(IndexSymbols), std::move(Opts));
108}
109
Sam McCall545a20d2018-01-19 14:34:02 +0000110std::string replace(StringRef Haystack, StringRef Needle, StringRef Repl) {
111 std::string Result;
112 raw_string_ostream OS(Result);
113 std::pair<StringRef, StringRef> Split;
114 for (Split = Haystack.split(Needle); !Split.second.empty();
115 Split = Split.first.split(Needle))
116 OS << Split.first << Repl;
117 Result += Split.first;
118 OS.flush();
119 return Result;
120}
121
Sam McCalla15c2d62018-01-18 09:27:56 +0000122// Helpers to produce fake index symbols for memIndex() or completions().
Sam McCall545a20d2018-01-19 14:34:02 +0000123// USRFormat is a regex replacement string for the unqualified part of the USR.
124Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000125 Symbol Sym;
Sam McCall545a20d2018-01-19 14:34:02 +0000126 std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
Sam McCalla15c2d62018-01-18 09:27:56 +0000127 size_t Pos = QName.rfind("::");
128 if (Pos == llvm::StringRef::npos) {
129 Sym.Name = QName;
130 Sym.Scope = "";
131 } else {
132 Sym.Name = QName.substr(Pos + 2);
Sam McCall8b2faee2018-01-19 22:18:21 +0000133 Sym.Scope = QName.substr(0, Pos + 2);
134 USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
Sam McCalla15c2d62018-01-18 09:27:56 +0000135 }
Sam McCall545a20d2018-01-19 14:34:02 +0000136 USR += Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
137 Sym.ID = SymbolID(USR);
Sam McCalla15c2d62018-01-18 09:27:56 +0000138 Sym.SymInfo.Kind = Kind;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000139 Sym.IsIndexedForCodeCompletion = true;
Sam McCalla15c2d62018-01-18 09:27:56 +0000140 return Sym;
141}
Sam McCall545a20d2018-01-19 14:34:02 +0000142Symbol func(StringRef Name) { // Assumes the function has no args.
143 return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
144}
145Symbol cls(StringRef Name) {
Eric Liu9b3cba72018-05-30 09:03:39 +0000146 return sym(Name, index::SymbolKind::Class, "@S@\\0");
Sam McCall545a20d2018-01-19 14:34:02 +0000147}
148Symbol var(StringRef Name) {
149 return sym(Name, index::SymbolKind::Variable, "@\\0");
150}
Sam McCalldc8abc42018-05-03 14:53:02 +0000151Symbol ns(StringRef Name) {
152 return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
153}
154Symbol withReferences(int N, Symbol S) {
155 S.References = N;
156 return S;
157}
Sam McCalla15c2d62018-01-18 09:27:56 +0000158
Sam McCallf6ae3232017-12-05 20:11:29 +0000159TEST(CompletionTest, Limit) {
160 clangd::CodeCompleteOptions Opts;
161 Opts.Limit = 2;
162 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000163struct ClassWithMembers {
164 int AAA();
165 int BBB();
166 int CCC();
167}
Sam McCallf6ae3232017-12-05 20:11:29 +0000168int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000169 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000170 /*IndexSymbols=*/{}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000171
Sam McCalle746a2b2018-07-02 11:13:16 +0000172 EXPECT_TRUE(Results.HasMore);
173 EXPECT_THAT(Results.Completions, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000174}
175
Sam McCallf6ae3232017-12-05 20:11:29 +0000176TEST(CompletionTest, Filter) {
177 std::string Body = R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000178 #define MotorCar
179 int Car;
Sam McCall9aad25f2017-12-05 07:20:26 +0000180 struct S {
181 int FooBar;
182 int FooBaz;
183 int Qux;
184 };
185 )cpp";
Sam McCall8b2dcc12018-06-14 13:50:30 +0000186
187 // Only items matching the fuzzy query are returned.
Sam McCalle746a2b2018-07-02 11:13:16 +0000188 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").Completions,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000189 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000190
Sam McCall8b2dcc12018-06-14 13:50:30 +0000191 // Macros require prefix match.
Sam McCalle746a2b2018-07-02 11:13:16 +0000192 EXPECT_THAT(completions(Body + "int main() { C^ }").Completions,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000193 AllOf(Has("Car"), Not(Has("MotorCar"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000194}
195
Sam McCallf6ae3232017-12-05 20:11:29 +0000196void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000197 auto Results = completions(
198 R"cpp(
199 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000200
Sam McCall44fdcec22017-12-08 15:00:59 +0000201 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000202
Sam McCall44fdcec22017-12-08 15:00:59 +0000203 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000204
Sam McCall44fdcec22017-12-08 15:00:59 +0000205 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000206
Sam McCall44fdcec22017-12-08 15:00:59 +0000207 struct ClassWithMembers {
208 /// Doc for method.
209 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000210
Sam McCall44fdcec22017-12-08 15:00:59 +0000211 int field;
212 private:
213 int private_field;
214 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000215
Sam McCall44fdcec22017-12-08 15:00:59 +0000216 int test() {
217 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000218
Sam McCall44fdcec22017-12-08 15:00:59 +0000219 /// Doc for local_var.
220 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000221
Sam McCall44fdcec22017-12-08 15:00:59 +0000222 ClassWithMembers().^
223 }
224 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000225 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000226
Sam McCallf6ae3232017-12-05 20:11:29 +0000227 // Class members. The only items that must be present in after-dot
228 // completion.
Sam McCalle746a2b2018-07-02 11:13:16 +0000229 EXPECT_THAT(Results.Completions,
230 AllOf(Has("method"), Has("field"), Not(Has("ClassWithMembers")),
Sam McCall4caa8512018-06-07 12:49:17 +0000231 Not(Has("operator=")), Not(Has("~ClassWithMembers"))));
Sam McCalle746a2b2018-07-02 11:13:16 +0000232 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000233 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000234 // Global items.
Sam McCall545a20d2018-01-19 14:34:02 +0000235 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +0000236 Results.Completions,
Sam McCall545a20d2018-01-19 14:34:02 +0000237 Not(AnyOf(Has("global_var"), Has("index_var"), Has("global_func"),
238 Has("global_func()"), Has("index_func"), Has("GlobalClass"),
239 Has("IndexClass"), Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000240 // There should be no code patterns (aka snippets) in after-dot
241 // completion. At least there aren't any we're aware of.
Sam McCalle746a2b2018-07-02 11:13:16 +0000242 EXPECT_THAT(Results.Completions,
243 Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000244 // Check documentation.
Sam McCalle746a2b2018-07-02 11:13:16 +0000245 EXPECT_IFF(Opts.IncludeComments, Results.Completions,
246 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000247}
Sam McCall9aad25f2017-12-05 07:20:26 +0000248
Sam McCallf6ae3232017-12-05 20:11:29 +0000249void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000250 auto Results = completions(
251 R"cpp(
252 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000253
Sam McCall44fdcec22017-12-08 15:00:59 +0000254 int global_var;
255 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000256
Sam McCall44fdcec22017-12-08 15:00:59 +0000257 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000258
Sam McCall44fdcec22017-12-08 15:00:59 +0000259 struct ClassWithMembers {
260 /// Doc for method.
261 int method();
262 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000263
Sam McCall44fdcec22017-12-08 15:00:59 +0000264 int test() {
265 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000266
Sam McCall44fdcec22017-12-08 15:00:59 +0000267 /// Doc for local_var.
268 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000269
Sam McCall44fdcec22017-12-08 15:00:59 +0000270 ^
271 }
272 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000273 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000274
275 // Class members. Should never be present in global completions.
Sam McCalle746a2b2018-07-02 11:13:16 +0000276 EXPECT_THAT(Results.Completions,
Sam McCallf6ae3232017-12-05 20:11:29 +0000277 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
278 // Global items.
Sam McCalle746a2b2018-07-02 11:13:16 +0000279 EXPECT_THAT(Results.Completions,
280 AllOf(Has("global_var"), Has("index_var"), Has("global_func"),
Sam McCall545a20d2018-01-19 14:34:02 +0000281 Has("index_func" /* our fake symbol doesn't include () */),
282 Has("GlobalClass"), Has("IndexClass")));
Sam McCallf6ae3232017-12-05 20:11:29 +0000283 // A macro.
Sam McCalle746a2b2018-07-02 11:13:16 +0000284 EXPECT_IFF(Opts.IncludeMacros, Results.Completions, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000285 // Local items. Must be present always.
Sam McCalle746a2b2018-07-02 11:13:16 +0000286 EXPECT_THAT(Results.Completions,
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000287 AllOf(Has("local_var"), Has("LocalClass"),
288 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000289 // Check documentation.
Sam McCalle746a2b2018-07-02 11:13:16 +0000290 EXPECT_IFF(Opts.IncludeComments, Results.Completions,
291 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000292}
293
294TEST(CompletionTest, CompletionOptions) {
Sam McCall2c3849a2018-01-16 12:21:24 +0000295 auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
296 TestAfterDotCompletion(Opts);
297 TestGlobalScopeCompletion(Opts);
298 };
299 // We used to test every combination of options, but that got too slow (2^N).
300 auto Flags = {
Ilya Biryukov71028b82018-03-12 15:28:22 +0000301 &clangd::CodeCompleteOptions::IncludeMacros,
Ilya Biryukov43714502018-05-16 12:32:44 +0000302 &clangd::CodeCompleteOptions::IncludeComments,
Ilya Biryukov71028b82018-03-12 15:28:22 +0000303 &clangd::CodeCompleteOptions::IncludeCodePatterns,
304 &clangd::CodeCompleteOptions::IncludeIneligibleResults,
Sam McCall2c3849a2018-01-16 12:21:24 +0000305 };
306 // Test default options.
307 Test({});
308 // Test with one flag flipped.
309 for (auto &F : Flags) {
310 clangd::CodeCompleteOptions O;
311 O.*F ^= true;
312 Test(O);
Sam McCall9aad25f2017-12-05 07:20:26 +0000313 }
314}
315
Sam McCall44fdcec22017-12-08 15:00:59 +0000316TEST(CompletionTest, Priorities) {
317 auto Internal = completions(R"cpp(
318 class Foo {
319 public: void pub();
320 protected: void prot();
321 private: void priv();
322 };
323 void Foo::pub() { this->^ }
324 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000325 EXPECT_THAT(Internal.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000326 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
327
328 auto External = completions(R"cpp(
329 class Foo {
330 public: void pub();
331 protected: void prot();
332 private: void priv();
333 };
334 void test() {
335 Foo F;
336 F.^
337 }
338 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000339 EXPECT_THAT(External.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000340 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
341}
342
343TEST(CompletionTest, Qualifiers) {
344 auto Results = completions(R"cpp(
345 class Foo {
346 public: int foo() const;
347 int bar() const;
348 };
349 class Bar : public Foo {
350 int foo() const;
351 };
352 void test() { Bar().^ }
353 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000354 EXPECT_THAT(Results.Completions,
355 HasSubsequence(AllOf(Qualifier(""), Named("bar")),
356 AllOf(Qualifier("Foo::"), Named("foo"))));
357 EXPECT_THAT(Results.Completions,
358 Not(Contains(AllOf(Qualifier(""), Named("foo"))))); // private
Sam McCall44fdcec22017-12-08 15:00:59 +0000359}
360
Sam McCall4caa8512018-06-07 12:49:17 +0000361TEST(CompletionTest, InjectedTypename) {
362 // These are suppressed when accessed as a member...
Sam McCalle746a2b2018-07-02 11:13:16 +0000363 EXPECT_THAT(completions("struct X{}; void foo(){ X().^ }").Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000364 Not(Has("X")));
Sam McCalle746a2b2018-07-02 11:13:16 +0000365 EXPECT_THAT(completions("struct X{ void foo(){ this->^ } };").Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000366 Not(Has("X")));
367 // ...but accessible in other, more useful cases.
Sam McCalle746a2b2018-07-02 11:13:16 +0000368 EXPECT_THAT(completions("struct X{ void foo(){ ^ } };").Completions,
369 Has("X"));
370 EXPECT_THAT(
371 completions("struct Y{}; struct X:Y{ void foo(){ ^ } };").Completions,
372 Has("Y"));
Sam McCall4caa8512018-06-07 12:49:17 +0000373 EXPECT_THAT(
374 completions(
375 "template<class> struct Y{}; struct X:Y<int>{ void foo(){ ^ } };")
Sam McCalle746a2b2018-07-02 11:13:16 +0000376 .Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000377 Has("Y"));
378 // This case is marginal (`using X::X` is useful), we allow it for now.
Sam McCalle746a2b2018-07-02 11:13:16 +0000379 EXPECT_THAT(completions("struct X{}; void foo(){ X::^ }").Completions,
380 Has("X"));
Sam McCall4caa8512018-06-07 12:49:17 +0000381}
382
Sam McCall44fdcec22017-12-08 15:00:59 +0000383TEST(CompletionTest, Snippets) {
384 clangd::CodeCompleteOptions Opts;
Sam McCall44fdcec22017-12-08 15:00:59 +0000385 auto Results = completions(
386 R"cpp(
387 struct fake {
388 int a;
389 int f(int i, const float f) const;
390 };
391 int main() {
392 fake f;
393 f.^
394 }
395 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000396 /*IndexSymbols=*/{}, Opts);
Sam McCalle746a2b2018-07-02 11:13:16 +0000397 EXPECT_THAT(
398 Results.Completions,
399 HasSubsequence(Named("a"),
400 SnippetSuffix("(${1:int i}, ${2:const float f})")));
Sam McCall44fdcec22017-12-08 15:00:59 +0000401}
402
403TEST(CompletionTest, Kinds) {
Sam McCall545a20d2018-01-19 14:34:02 +0000404 auto Results = completions(
405 R"cpp(
406 #define MACRO X
407 int variable;
408 struct Struct {};
409 int function();
410 int X = ^
411 )cpp",
412 {func("indexFunction"), var("indexVariable"), cls("indexClass")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000413 EXPECT_THAT(Results.Completions,
Sam McCall545a20d2018-01-19 14:34:02 +0000414 AllOf(Has("function", CompletionItemKind::Function),
415 Has("variable", CompletionItemKind::Variable),
416 Has("int", CompletionItemKind::Keyword),
417 Has("Struct", CompletionItemKind::Class),
418 Has("MACRO", CompletionItemKind::Text),
419 Has("indexFunction", CompletionItemKind::Function),
420 Has("indexVariable", CompletionItemKind::Variable),
421 Has("indexClass", CompletionItemKind::Class)));
Sam McCall44fdcec22017-12-08 15:00:59 +0000422
Sam McCall44fdcec22017-12-08 15:00:59 +0000423 Results = completions("nam^");
Sam McCalle746a2b2018-07-02 11:13:16 +0000424 EXPECT_THAT(Results.Completions,
425 Has("namespace", CompletionItemKind::Snippet));
Sam McCall44fdcec22017-12-08 15:00:59 +0000426}
427
Sam McCall84652cc2018-01-12 16:16:09 +0000428TEST(CompletionTest, NoDuplicates) {
Sam McCall545a20d2018-01-19 14:34:02 +0000429 auto Results = completions(
430 R"cpp(
431 class Adapter {
Sam McCall545a20d2018-01-19 14:34:02 +0000432 };
Sam McCall84652cc2018-01-12 16:16:09 +0000433
Eric Liu9b3cba72018-05-30 09:03:39 +0000434 void f() {
Sam McCall545a20d2018-01-19 14:34:02 +0000435 Adapter^
436 }
437 )cpp",
438 {cls("Adapter")});
Sam McCall84652cc2018-01-12 16:16:09 +0000439
440 // Make sure there are no duplicate entries of 'Adapter'.
Sam McCalle746a2b2018-07-02 11:13:16 +0000441 EXPECT_THAT(Results.Completions, ElementsAre(Named("Adapter")));
Sam McCall84652cc2018-01-12 16:16:09 +0000442}
443
Sam McCall545a20d2018-01-19 14:34:02 +0000444TEST(CompletionTest, ScopedNoIndex) {
445 auto Results = completions(
446 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000447 namespace fake { int BigBang, Babble, Box; };
448 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000449 ")cpp");
Sam McCall8b2dcc12018-06-14 13:50:30 +0000450 // Babble is a better match than BigBang. Box doesn't match at all.
Sam McCalle746a2b2018-07-02 11:13:16 +0000451 EXPECT_THAT(Results.Completions,
452 ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCall84652cc2018-01-12 16:16:09 +0000453}
454
Sam McCall545a20d2018-01-19 14:34:02 +0000455TEST(CompletionTest, Scoped) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000456 auto Results = completions(
457 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000458 namespace fake { int Babble, Box; };
459 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000460 ")cpp",
461 {var("fake::BigBang")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000462 EXPECT_THAT(Results.Completions,
463 ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000464}
465
Sam McCall545a20d2018-01-19 14:34:02 +0000466TEST(CompletionTest, ScopedWithFilter) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000467 auto Results = completions(
468 R"cpp(
469 void f() { ns::x^ }
470 )cpp",
471 {cls("ns::XYZ"), func("ns::foo")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000472 EXPECT_THAT(Results.Completions, UnorderedElementsAre(Named("XYZ")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000473}
474
Sam McCalldc8abc42018-05-03 14:53:02 +0000475TEST(CompletionTest, ReferencesAffectRanking) {
476 auto Results = completions("int main() { abs^ }", {ns("absl"), func("abs")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000477 EXPECT_THAT(Results.Completions, HasSubsequence(Named("abs"), Named("absl")));
Sam McCalldc8abc42018-05-03 14:53:02 +0000478 Results = completions("int main() { abs^ }",
479 {withReferences(10000, ns("absl")), func("abs")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000480 EXPECT_THAT(Results.Completions, HasSubsequence(Named("absl"), Named("abs")));
Sam McCalldc8abc42018-05-03 14:53:02 +0000481}
482
Sam McCall545a20d2018-01-19 14:34:02 +0000483TEST(CompletionTest, GlobalQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000484 auto Results = completions(
485 R"cpp(
486 void f() { ::^ }
487 )cpp",
488 {cls("XYZ")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000489 EXPECT_THAT(Results.Completions,
490 AllOf(Has("XYZ", CompletionItemKind::Class),
491 Has("f", CompletionItemKind::Function)));
Sam McCalla15c2d62018-01-18 09:27:56 +0000492}
493
Sam McCall545a20d2018-01-19 14:34:02 +0000494TEST(CompletionTest, FullyQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000495 auto Results = completions(
496 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000497 namespace ns { void bar(); }
Sam McCalla15c2d62018-01-18 09:27:56 +0000498 void f() { ::ns::^ }
499 )cpp",
500 {cls("ns::XYZ")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000501 EXPECT_THAT(Results.Completions,
502 AllOf(Has("XYZ", CompletionItemKind::Class),
503 Has("bar", CompletionItemKind::Function)));
Sam McCall545a20d2018-01-19 14:34:02 +0000504}
505
506TEST(CompletionTest, SemaIndexMerge) {
507 auto Results = completions(
508 R"cpp(
509 namespace ns { int local; void both(); }
510 void f() { ::ns::^ }
511 )cpp",
512 {func("ns::both"), cls("ns::Index")});
513 // We get results from both index and sema, with no duplicates.
514 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +0000515 Results.Completions,
Sam McCall545a20d2018-01-19 14:34:02 +0000516 UnorderedElementsAre(Named("local"), Named("Index"), Named("both")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000517}
518
Haojian Wu48b48652018-01-25 09:20:09 +0000519TEST(CompletionTest, SemaIndexMergeWithLimit) {
520 clangd::CodeCompleteOptions Opts;
521 Opts.Limit = 1;
522 auto Results = completions(
523 R"cpp(
524 namespace ns { int local; void both(); }
525 void f() { ::ns::^ }
526 )cpp",
527 {func("ns::both"), cls("ns::Index")}, Opts);
Sam McCalle746a2b2018-07-02 11:13:16 +0000528 EXPECT_EQ(Results.Completions.size(), Opts.Limit);
529 EXPECT_TRUE(Results.HasMore);
Haojian Wu48b48652018-01-25 09:20:09 +0000530}
531
Eric Liu63f419a2018-05-15 15:29:32 +0000532TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
533 MockFSProvider FS;
534 MockCompilationDatabase CDB;
535 std::string Subdir = testPath("sub");
536 std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
537 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
538 std::string BarHeader = testPath("sub/bar.h");
539 FS.Files[BarHeader] = "";
540
541 IgnoreDiagnostics DiagConsumer;
542 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
543 Symbol::Details Scratch;
544 auto BarURI = URI::createFile(BarHeader).toString();
545 Symbol Sym = cls("ns::X");
546 Sym.CanonicalDeclaration.FileURI = BarURI;
547 Scratch.IncludeHeader = BarURI;
548 Sym.Detail = &Scratch;
549 // Shoten include path based on search dirctory and insert.
550 auto Results = completions(Server,
551 R"cpp(
552 int main() { ns::^ }
553 )cpp",
554 {Sym});
Sam McCalle746a2b2018-07-02 11:13:16 +0000555 EXPECT_THAT(Results.Completions,
556 ElementsAre(AllOf(Named("X"), InsertInclude("\"bar.h\""))));
Eric Liu63f419a2018-05-15 15:29:32 +0000557 // Duplicate based on inclusions in preamble.
558 Results = completions(Server,
559 R"cpp(
560 #include "sub/bar.h" // not shortest, so should only match resolved.
561 int main() { ns::^ }
562 )cpp",
563 {Sym});
Sam McCalle746a2b2018-07-02 11:13:16 +0000564 EXPECT_THAT(Results.Completions, ElementsAre(AllOf(Named("X"), Labeled("X"),
565 Not(InsertInclude()))));
Eric Liu63f419a2018-05-15 15:29:32 +0000566}
567
Eric Liu9b3cba72018-05-30 09:03:39 +0000568TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
569 MockFSProvider FS;
570 MockCompilationDatabase CDB;
571
572 IgnoreDiagnostics DiagConsumer;
573 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
574 Symbol::Details Scratch;
575 Symbol SymX = cls("ns::X");
576 Symbol SymY = cls("ns::Y");
577 std::string BarHeader = testPath("bar.h");
578 auto BarURI = URI::createFile(BarHeader).toString();
579 SymX.CanonicalDeclaration.FileURI = BarURI;
580 SymY.CanonicalDeclaration.FileURI = BarURI;
581 Scratch.IncludeHeader = "<bar>";
582 SymX.Detail = &Scratch;
583 SymY.Detail = &Scratch;
584 // Shoten include path based on search dirctory and insert.
585 auto Results = completions(Server,
586 R"cpp(
587 namespace ns {
588 class X;
589 class Y {}
590 }
591 int main() { ns::^ }
592 )cpp",
593 {SymX, SymY});
Sam McCalle746a2b2018-07-02 11:13:16 +0000594 EXPECT_THAT(Results.Completions,
595 ElementsAre(AllOf(Named("X"), Not(InsertInclude())),
596 AllOf(Named("Y"), Not(InsertInclude()))));
Eric Liu9b3cba72018-05-30 09:03:39 +0000597}
598
Sam McCalla15c2d62018-01-18 09:27:56 +0000599TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
600 MockFSProvider FS;
601 MockCompilationDatabase CDB;
602 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000603 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCalla15c2d62018-01-18 09:27:56 +0000604
Sam McCallc1568062018-02-16 09:41:43 +0000605 FS.Files[testPath("bar.h")] =
Sam McCalld5ea3e32018-01-24 17:53:32 +0000606 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
Sam McCallc1568062018-02-16 09:41:43 +0000607 auto File = testPath("foo.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000608 Annotations Test(R"cpp(
609 #include "bar.h"
610 namespace ns { int local; }
Sam McCalld5ea3e32018-01-24 17:53:32 +0000611 void f() { ns::^; }
612 void f() { ns::preamble().$2^; }
Sam McCalla15c2d62018-01-18 09:27:56 +0000613 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000614 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000615 clangd::CodeCompleteOptions Opts = {};
616
Sam McCalla15c2d62018-01-18 09:27:56 +0000617 auto I = memIndex({var("ns::index")});
618 Opts.Index = I.get();
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000619 auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000620 EXPECT_THAT(WithIndex.Completions,
Sam McCalla15c2d62018-01-18 09:27:56 +0000621 UnorderedElementsAre(Named("local"), Named("index")));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000622 auto ClassFromPreamble =
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000623 cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000624 EXPECT_THAT(ClassFromPreamble.Completions, Contains(Named("member")));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000625
626 Opts.Index = nullptr;
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000627 auto WithoutIndex =
628 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000629 EXPECT_THAT(WithoutIndex.Completions,
Sam McCall0bb24cd2018-02-13 08:59:23 +0000630 UnorderedElementsAre(Named("local"), Named("preamble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000631}
632
633TEST(CompletionTest, DynamicIndexMultiFile) {
634 MockFSProvider FS;
635 MockCompilationDatabase CDB;
636 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000637 auto Opts = ClangdServer::optsForTest();
638 Opts.BuildDynamicSymbolIndex = true;
639 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCalla15c2d62018-01-18 09:27:56 +0000640
Eric Liu709bde82018-02-19 18:48:44 +0000641 FS.Files[testPath("foo.h")] = R"cpp(
Sam McCalla15c2d62018-01-18 09:27:56 +0000642 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liu709bde82018-02-19 18:48:44 +0000643 )cpp";
Sam McCall7363a2f2018-03-05 17:28:54 +0000644 runAddDocument(Server, testPath("foo.cpp"), R"cpp(
Eric Liu709bde82018-02-19 18:48:44 +0000645 #include "foo.h"
Sam McCall0bb24cd2018-02-13 08:59:23 +0000646 )cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000647
Sam McCallc1568062018-02-16 09:41:43 +0000648 auto File = testPath("bar.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000649 Annotations Test(R"cpp(
650 namespace ns {
651 class XXX {};
652 /// Doooc
653 void fooooo() {}
654 }
655 void f() { ns::^ }
656 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000657 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000658
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000659 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
Sam McCalla15c2d62018-01-18 09:27:56 +0000660 // "XYZ" and "foo" are not included in the file being completed but are still
661 // visible through the index.
Sam McCalle746a2b2018-07-02 11:13:16 +0000662 EXPECT_THAT(Results.Completions, Has("XYZ", CompletionItemKind::Class));
663 EXPECT_THAT(Results.Completions, Has("foo", CompletionItemKind::Function));
664 EXPECT_THAT(Results.Completions, Has("XXX", CompletionItemKind::Class));
665 EXPECT_THAT(Results.Completions,
666 Contains((Named("fooooo"), Kind(CompletionItemKind::Function),
667 Doc("Doooc"), ReturnType("void"))));
Sam McCalla15c2d62018-01-18 09:27:56 +0000668}
669
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000670TEST(CompletionTest, Documentation) {
671 auto Results = completions(
672 R"cpp(
673 // Non-doxygen comment.
674 int foo();
675 /// Doxygen comment.
676 /// \param int a
677 int bar(int a);
678 /* Multi-line
679 block comment
680 */
681 int baz();
682
683 int x = ^
684 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000685 EXPECT_THAT(Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000686 Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
687 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +0000688 Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000689 Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
Sam McCalle746a2b2018-07-02 11:13:16 +0000690 EXPECT_THAT(Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000691 Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
692}
693
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000694TEST(CompletionTest, GlobalCompletionFiltering) {
695
696 Symbol Class = cls("XYZ");
697 Class.IsIndexedForCodeCompletion = false;
698 Symbol Func = func("XYZ::foooo");
699 Func.IsIndexedForCodeCompletion = false;
700
701 auto Results = completions(R"(// void f() {
702 XYZ::foooo^
703 })",
704 {Class, Func});
Sam McCalle746a2b2018-07-02 11:13:16 +0000705 EXPECT_THAT(Results.Completions, IsEmpty());
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000706}
707
Haojian Wu58d208d2018-01-25 09:44:06 +0000708TEST(CodeCompleteTest, DisableTypoCorrection) {
709 auto Results = completions(R"cpp(
710 namespace clang { int v; }
711 void f() { clangd::^
712 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000713 EXPECT_TRUE(Results.Completions.empty());
Haojian Wu58d208d2018-01-25 09:44:06 +0000714}
715
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000716TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
717 auto Results = completions(R"cpp(
718 namespace clang { }
719 void f() {
720 clan^
721 }
722 )cpp");
723
Sam McCalle746a2b2018-07-02 11:13:16 +0000724 EXPECT_THAT(Results.Completions, Contains(Labeled("clang")));
725 EXPECT_THAT(Results.Completions, Not(Contains(Labeled("clang::"))));
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000726}
727
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000728TEST(CompletionTest, BacktrackCrashes) {
729 // Sema calls code completion callbacks twice in these cases.
730 auto Results = completions(R"cpp(
731 namespace ns {
732 struct FooBarBaz {};
733 } // namespace ns
734
735 int foo(ns::FooBar^
736 )cpp");
737
Sam McCalle746a2b2018-07-02 11:13:16 +0000738 EXPECT_THAT(Results.Completions, ElementsAre(Labeled("FooBarBaz")));
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000739
740 // Check we don't crash in that case too.
741 completions(R"cpp(
742 struct FooBarBaz {};
743 void test() {
744 if (FooBarBaz * x^) {}
745 }
746)cpp");
747}
748
Eric Liu42abe412018-05-24 11:20:19 +0000749TEST(CompletionTest, CompleteInMacroWithStringification) {
750 auto Results = completions(R"cpp(
751void f(const char *, int x);
752#define F(x) f(#x, x)
753
754namespace ns {
755int X;
756int Y;
757} // namespace ns
758
759int f(int input_num) {
760 F(ns::^)
761}
762)cpp");
763
Sam McCalle746a2b2018-07-02 11:13:16 +0000764 EXPECT_THAT(Results.Completions,
Eric Liu42abe412018-05-24 11:20:19 +0000765 UnorderedElementsAre(Named("X"), Named("Y")));
766}
767
768TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
769 auto Results = completions(R"cpp(
770void f(const char *, int x);
771#define F(x) f(#x, x)
772
773namespace ns {
774int X;
775
776int f(int input_num) {
777 F(^)
778}
779} // namespace ns
780)cpp");
781
Sam McCalle746a2b2018-07-02 11:13:16 +0000782 EXPECT_THAT(Results.Completions, Contains(Named("X")));
Eric Liu42abe412018-05-24 11:20:19 +0000783}
784
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000785TEST(CompletionTest, CompleteInExcludedPPBranch) {
786 auto Results = completions(R"cpp(
787 int bar(int param_in_bar) {
788 }
789
790 int foo(int param_in_foo) {
791#if 0
792 par^
793#endif
794 }
795)cpp");
796
Sam McCalle746a2b2018-07-02 11:13:16 +0000797 EXPECT_THAT(Results.Completions, Contains(Labeled("param_in_foo")));
798 EXPECT_THAT(Results.Completions, Not(Contains(Labeled("param_in_bar"))));
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000799}
800
Sam McCall800d4372017-12-19 10:29:27 +0000801SignatureHelp signatures(StringRef Text) {
802 MockFSProvider FS;
803 MockCompilationDatabase CDB;
804 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000805 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCallc1568062018-02-16 09:41:43 +0000806 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000807 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000808 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000809 return cantFail(runSignatureHelp(Server, File, Test.point()));
Sam McCall800d4372017-12-19 10:29:27 +0000810}
811
812MATCHER_P(ParamsAre, P, "") {
813 if (P.size() != arg.parameters.size())
814 return false;
815 for (unsigned I = 0; I < P.size(); ++I)
816 if (P[I] != arg.parameters[I].label)
817 return false;
818 return true;
819}
820
821Matcher<SignatureInformation> Sig(std::string Label,
822 std::vector<std::string> Params) {
Eric Liu8f3678d2018-06-15 13:34:18 +0000823 return AllOf(SigHelpLabeled(Label), ParamsAre(Params));
Sam McCall800d4372017-12-19 10:29:27 +0000824}
825
826TEST(SignatureHelpTest, Overloads) {
827 auto Results = signatures(R"cpp(
828 void foo(int x, int y);
829 void foo(int x, float y);
830 void foo(float x, int y);
831 void foo(float x, float y);
832 void bar(int x, int y = 0);
833 int main() { foo(^); }
834 )cpp");
835 EXPECT_THAT(Results.signatures,
836 UnorderedElementsAre(
837 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
838 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
839 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
840 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
841 // We always prefer the first signature.
842 EXPECT_EQ(0, Results.activeSignature);
843 EXPECT_EQ(0, Results.activeParameter);
844}
845
846TEST(SignatureHelpTest, DefaultArgs) {
847 auto Results = signatures(R"cpp(
848 void bar(int x, int y = 0);
849 void bar(float x = 0, int y = 42);
850 int main() { bar(^
851 )cpp");
852 EXPECT_THAT(Results.signatures,
853 UnorderedElementsAre(
854 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
855 Sig("bar(float x = 0, int y = 42) -> void",
856 {"float x = 0", "int y = 42"})));
857 EXPECT_EQ(0, Results.activeSignature);
858 EXPECT_EQ(0, Results.activeParameter);
859}
860
861TEST(SignatureHelpTest, ActiveArg) {
862 auto Results = signatures(R"cpp(
863 int baz(int a, int b, int c);
864 int main() { baz(baz(1,2,3), ^); }
865 )cpp");
866 EXPECT_THAT(Results.signatures,
867 ElementsAre(Sig("baz(int a, int b, int c) -> int",
868 {"int a", "int b", "int c"})));
869 EXPECT_EQ(0, Results.activeSignature);
870 EXPECT_EQ(1, Results.activeParameter);
871}
872
Haojian Wu061c73e2018-01-23 11:37:26 +0000873class IndexRequestCollector : public SymbolIndex {
874public:
875 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000876 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000877 llvm::function_ref<void(const Symbol &)> Callback) const override {
878 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000879 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000880 }
881
Eric Liu9ec459f2018-03-14 09:48:05 +0000882 void lookup(const LookupRequest &,
883 llvm::function_ref<void(const Symbol &)>) const override {}
884
Haojian Wu061c73e2018-01-23 11:37:26 +0000885 const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
886
887private:
888 mutable std::vector<FuzzyFindRequest> Requests;
889};
890
891std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
892 clangd::CodeCompleteOptions Opts;
893 IndexRequestCollector Requests;
894 Opts.Index = &Requests;
895 completions(Code, {}, Opts);
896 return Requests.allRequests();
897}
898
899TEST(CompletionTest, UnqualifiedIdQuery) {
900 auto Requests = captureIndexRequests(R"cpp(
901 namespace std {}
902 using namespace std;
903 namespace ns {
904 void f() {
905 vec^
906 }
907 }
908 )cpp");
909
910 EXPECT_THAT(Requests,
911 ElementsAre(Field(&FuzzyFindRequest::Scopes,
912 UnorderedElementsAre("", "ns::", "std::"))));
913}
914
915TEST(CompletionTest, ResolvedQualifiedIdQuery) {
916 auto Requests = captureIndexRequests(R"cpp(
917 namespace ns1 {}
918 namespace ns2 {} // ignore
919 namespace ns3 { namespace nns3 {} }
920 namespace foo {
921 using namespace ns1;
922 using namespace ns3::nns3;
923 }
924 namespace ns {
925 void f() {
926 foo::^
927 }
928 }
929 )cpp");
930
931 EXPECT_THAT(Requests,
932 ElementsAre(Field(
933 &FuzzyFindRequest::Scopes,
934 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
935}
936
937TEST(CompletionTest, UnresolvedQualifierIdQuery) {
938 auto Requests = captureIndexRequests(R"cpp(
939 namespace a {}
940 using namespace a;
941 namespace ns {
942 void f() {
943 bar::^
944 }
945 } // namespace ns
946 )cpp");
947
948 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
949 UnorderedElementsAre("bar::"))));
950}
951
952TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
953 auto Requests = captureIndexRequests(R"cpp(
954 namespace a {}
955 using namespace a;
956 namespace ns {
957 void f() {
958 ::a::bar::^
959 }
960 } // namespace ns
961 )cpp");
962
963 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
964 UnorderedElementsAre("a::bar::"))));
965}
966
967TEST(CompletionTest, EmptyQualifiedQuery) {
968 auto Requests = captureIndexRequests(R"cpp(
969 namespace ns {
970 void f() {
971 ^
972 }
973 } // namespace ns
974 )cpp");
975
976 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
977 UnorderedElementsAre("", "ns::"))));
978}
979
980TEST(CompletionTest, GlobalQualifiedQuery) {
981 auto Requests = captureIndexRequests(R"cpp(
982 namespace ns {
983 void f() {
984 ::^
985 }
986 } // namespace ns
987 )cpp");
988
989 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
990 UnorderedElementsAre(""))));
991}
992
Ilya Biryukova907ba42018-05-14 10:50:04 +0000993TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
994 auto Completions = completions(
995 R"cpp(
996 struct Foo {
997 int SomeNameOfField;
998 typedef int SomeNameOfTypedefField;
999 };
1000
1001 Foo::^)cpp",
1002 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
1003
Sam McCalle746a2b2018-07-02 11:13:16 +00001004 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001005 AllOf(Contains(Labeled("SomeNameOfField")),
1006 Contains(Labeled("SomeNameOfTypedefField")),
1007 Not(Contains(Labeled("SomeNameInTheIndex")))));
1008}
1009
1010TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
1011 {
1012 auto Completions = completions(
1013 R"cpp(
1014 template <class T>
1015 void foo() {
1016 T::^
1017 }
1018 )cpp",
1019 {func("::SomeNameInTheIndex")});
1020
Sam McCalle746a2b2018-07-02 11:13:16 +00001021 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001022 Not(Contains(Labeled("SomeNameInTheIndex"))));
1023 }
1024
1025 {
1026 auto Completions = completions(
1027 R"cpp(
1028 template <class T>
1029 void foo() {
1030 T::template Y<int>::^
1031 }
1032 )cpp",
1033 {func("::SomeNameInTheIndex")});
1034
Sam McCalle746a2b2018-07-02 11:13:16 +00001035 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001036 Not(Contains(Labeled("SomeNameInTheIndex"))));
1037 }
1038
1039 {
1040 auto Completions = completions(
1041 R"cpp(
1042 template <class T>
1043 void foo() {
1044 T::foo::^
1045 }
1046 )cpp",
1047 {func("::SomeNameInTheIndex")});
1048
Sam McCalle746a2b2018-07-02 11:13:16 +00001049 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001050 Not(Contains(Labeled("SomeNameInTheIndex"))));
1051 }
1052}
1053
Sam McCallc18c2802018-06-15 11:06:29 +00001054TEST(CompletionTest, OverloadBundling) {
1055 clangd::CodeCompleteOptions Opts;
1056 Opts.BundleOverloads = true;
1057
1058 std::string Context = R"cpp(
1059 struct X {
1060 // Overload with int
1061 int a(int);
1062 // Overload with bool
1063 int a(bool);
1064 int b(float);
1065 };
1066 int GFuncC(int);
1067 int GFuncD(int);
1068 )cpp";
1069
1070 // Member completions are bundled.
Sam McCalle746a2b2018-07-02 11:13:16 +00001071 EXPECT_THAT(completions(Context + "int y = X().^", {}, Opts).Completions,
Sam McCallc18c2802018-06-15 11:06:29 +00001072 UnorderedElementsAre(Labeled("a(…)"), Labeled("b(float)")));
1073
1074 // Non-member completions are bundled, including index+sema.
1075 Symbol NoArgsGFunc = func("GFuncC");
1076 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001077 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
Sam McCallc18c2802018-06-15 11:06:29 +00001078 UnorderedElementsAre(Labeled("GFuncC(…)"), Labeled("GFuncD(int)")));
1079
1080 // Differences in header-to-insert suppress bundling.
1081 Symbol::Details Detail;
1082 std::string DeclFile = URI::createFile(testPath("foo")).toString();
1083 NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile;
1084 Detail.IncludeHeader = "<foo>";
1085 NoArgsGFunc.Detail = &Detail;
1086 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001087 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
1088 UnorderedElementsAre(AllOf(Named("GFuncC"), InsertInclude("<foo>")),
1089 Labeled("GFuncC(int)"), Labeled("GFuncD(int)")));
Sam McCallc18c2802018-06-15 11:06:29 +00001090
1091 // Examine a bundled completion in detail.
Sam McCalle746a2b2018-07-02 11:13:16 +00001092 auto A =
1093 completions(Context + "int y = X().a^", {}, Opts).Completions.front();
1094 EXPECT_EQ(A.Name, "a");
1095 EXPECT_EQ(A.Signature, "(…)");
1096 EXPECT_EQ(A.BundleSize, 2u);
1097 EXPECT_EQ(A.Kind, CompletionItemKind::Method);
1098 EXPECT_EQ(A.ReturnType, "int"); // All overloads return int.
Sam McCallc18c2802018-06-15 11:06:29 +00001099 // For now we just return one of the doc strings arbitrarily.
Sam McCalle746a2b2018-07-02 11:13:16 +00001100 EXPECT_THAT(A.Documentation, AnyOf(HasSubstr("Overload with int"),
Sam McCallc18c2802018-06-15 11:06:29 +00001101 HasSubstr("Overload with bool")));
Sam McCalle746a2b2018-07-02 11:13:16 +00001102 EXPECT_EQ(A.SnippetSuffix, "(${0})");
Sam McCallc18c2802018-06-15 11:06:29 +00001103}
1104
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001105TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001106 MockFSProvider FS;
1107 auto FooH = testPath("foo.h");
1108 auto FooCpp = testPath("foo.cpp");
1109 FS.Files[FooH] = R"cpp(
1110 // this is my documentation comment.
1111 int func();
1112 )cpp";
1113 FS.Files[FooCpp] = "";
1114
1115 MockCompilationDatabase CDB;
1116 IgnoreDiagnostics DiagConsumer;
1117 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1118
1119 Annotations Source(R"cpp(
1120 #include "foo.h"
1121 int func() {
1122 // This makes sure we have func from header in the AST.
1123 }
1124 int a = fun^
1125 )cpp");
1126 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1127 // We need to wait for preamble to build.
1128 ASSERT_TRUE(Server.blockUntilIdleForTest());
1129
1130 // Change the header file. Completion will reuse the old preamble!
1131 FS.Files[FooH] = R"cpp(
1132 int func();
1133 )cpp";
1134
1135 clangd::CodeCompleteOptions Opts;
1136 Opts.IncludeComments = true;
Sam McCalle746a2b2018-07-02 11:13:16 +00001137 CodeCompleteResult Completions =
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001138 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1139 // We shouldn't crash. Unfortunately, current workaround is to not produce
1140 // comments for symbols from headers.
Sam McCalle746a2b2018-07-02 11:13:16 +00001141 EXPECT_THAT(Completions.Completions,
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001142 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1143}
1144
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001145TEST(CompletionTest, NonDocComments) {
1146 MockFSProvider FS;
1147 auto FooCpp = testPath("foo.cpp");
1148 FS.Files[FooCpp] = "";
1149
1150 MockCompilationDatabase CDB;
1151 IgnoreDiagnostics DiagConsumer;
1152 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1153
1154 Annotations Source(R"cpp(
Ilya Biryukovda8dd8b2018-06-27 09:47:20 +00001155 // We ignore namespace comments, for rationale see CodeCompletionStrings.h.
1156 namespace comments_ns {
1157 }
1158
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001159 // ------------------
1160 int comments_foo();
1161
1162 // A comment and a decl are separated by newlines.
1163 // Therefore, the comment shouldn't show up as doc comment.
1164
1165 int comments_bar();
1166
1167 // this comment should be in the results.
1168 int comments_baz();
1169
1170
1171 template <class T>
1172 struct Struct {
1173 int comments_qux();
1174 int comments_quux();
1175 };
1176
1177
1178 // This comment should not be there.
1179
1180 template <class T>
1181 int Struct<T>::comments_qux() {
1182 }
1183
1184 // This comment **should** be in results.
1185 template <class T>
1186 int Struct<T>::comments_quux() {
1187 int a = comments^;
1188 }
1189 )cpp");
Reid Kleckner80274b12018-06-18 18:55:10 +00001190 // FIXME: Auto-completion in a template requires disabling delayed template
1191 // parsing.
1192 CDB.ExtraClangFlags.push_back("-fno-delayed-template-parsing");
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001193 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
Sam McCalle746a2b2018-07-02 11:13:16 +00001194 CodeCompleteResult Completions = cantFail(runCodeComplete(
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001195 Server, FooCpp, Source.point(), clangd::CodeCompleteOptions()));
1196
1197 // We should not get any of those comments in completion.
1198 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001199 Completions.Completions,
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001200 UnorderedElementsAre(AllOf(Not(IsDocumented()), Named("comments_foo")),
1201 AllOf(IsDocumented(), Named("comments_baz")),
1202 AllOf(IsDocumented(), Named("comments_quux")),
Ilya Biryukovda8dd8b2018-06-27 09:47:20 +00001203 AllOf(Not(IsDocumented()), Named("comments_ns")),
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001204 // FIXME(ibiryukov): the following items should have
1205 // empty documentation, since they are separated from
1206 // a comment with an empty line. Unfortunately, I
1207 // couldn't make Sema tests pass if we ignore those.
1208 AllOf(IsDocumented(), Named("comments_bar")),
1209 AllOf(IsDocumented(), Named("comments_qux"))));
1210}
1211
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001212TEST(CompletionTest, CompleteOnInvalidLine) {
1213 auto FooCpp = testPath("foo.cpp");
1214
1215 MockCompilationDatabase CDB;
1216 IgnoreDiagnostics DiagConsumer;
1217 MockFSProvider FS;
1218 FS.Files[FooCpp] = "// empty file";
1219
1220 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1221 // Run completion outside the file range.
1222 Position Pos;
1223 Pos.line = 100;
1224 Pos.character = 0;
1225 EXPECT_THAT_EXPECTED(
1226 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1227 Failed());
1228}
1229
Eric Liu7ad16962018-06-22 10:46:59 +00001230TEST(CompletionTest, QualifiedNames) {
1231 auto Results = completions(
1232 R"cpp(
1233 namespace ns { int local; void both(); }
1234 void f() { ::ns::^ }
1235 )cpp",
1236 {func("ns::both"), cls("ns::Index")});
1237 // We get results from both index and sema, with no duplicates.
Sam McCalle746a2b2018-07-02 11:13:16 +00001238 EXPECT_THAT(
1239 Results.Completions,
1240 UnorderedElementsAre(Scope("ns::"), Scope("ns::"), Scope("ns::")));
1241}
1242
1243TEST(CompletionTest, Render) {
1244 CodeCompletion C;
1245 C.Name = "x";
1246 C.Signature = "(bool) const";
1247 C.SnippetSuffix = "(${0:bool})";
1248 C.ReturnType = "int";
1249 C.RequiredQualifier = "Foo::";
1250 C.Scope = "ns::Foo::";
1251 C.Documentation = "This is x().";
1252 C.Header = "\"foo.h\"";
1253 C.Kind = CompletionItemKind::Method;
1254 C.Score.Total = 1.0;
1255
1256 CodeCompleteOptions Opts;
1257 Opts.IncludeIndicator.Insert = "^";
1258 Opts.IncludeIndicator.NoInsert = "";
1259 Opts.EnableSnippets = false;
1260
1261 auto R = C.render(Opts);
1262 EXPECT_EQ(R.label, "Foo::x(bool) const");
1263 EXPECT_EQ(R.insertText, "Foo::x");
1264 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText);
1265 EXPECT_EQ(R.filterText, "x");
1266 EXPECT_EQ(R.detail, "int\n\"foo.h\"");
1267 EXPECT_EQ(R.documentation, "This is x().");
1268 EXPECT_THAT(R.additionalTextEdits, IsEmpty());
1269 EXPECT_EQ(R.SymbolScope, "ns::Foo::");
1270 EXPECT_EQ(R.sortText, sortText(1.0, "x"));
1271
1272 Opts.EnableSnippets = true;
1273 R = C.render(Opts);
1274 EXPECT_EQ(R.insertText, "Foo::x(${0:bool})");
1275 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet);
1276
1277 C.HeaderInsertion.emplace();
1278 R = C.render(Opts);
1279 EXPECT_EQ(R.label, "^Foo::x(bool) const");
1280 EXPECT_THAT(R.additionalTextEdits, Not(IsEmpty()));
1281
1282 C.BundleSize = 2;
1283 R = C.render(Opts);
1284 EXPECT_EQ(R.detail, "[2 overloads]\n\"foo.h\"");
Eric Liu7ad16962018-06-22 10:46:59 +00001285}
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001286
Sam McCall9aad25f2017-12-05 07:20:26 +00001287} // namespace
1288} // namespace clangd
1289} // namespace clang