blob: c8c45d799d4ac56954b39350f39070de479cf861 [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; }
Sam McCall2161ec72018-07-05 06:20:41 +000062MATCHER_P(Origin, OriginSet, "") { return arg.Origin == OriginSet; }
Eric Liu63f419a2018-05-15 15:29:32 +000063
Sam McCallf6ae3232017-12-05 20:11:29 +000064// Shorthand for Contains(Named(Name)).
Sam McCalle746a2b2018-07-02 11:13:16 +000065Matcher<const std::vector<CodeCompletion> &> Has(std::string Name) {
Sam McCallf6ae3232017-12-05 20:11:29 +000066 return Contains(Named(std::move(Name)));
67}
Sam McCalle746a2b2018-07-02 11:13:16 +000068Matcher<const std::vector<CodeCompletion> &> Has(std::string Name,
Sam McCall44fdcec22017-12-08 15:00:59 +000069 CompletionItemKind K) {
70 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000071}
Sam McCalle746a2b2018-07-02 11:13:16 +000072MATCHER(IsDocumented, "") { return !arg.Documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000073
Sam McCalla15c2d62018-01-18 09:27:56 +000074std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
75 SymbolSlab::Builder Slab;
76 for (const auto &Sym : Symbols)
77 Slab.insert(Sym);
78 return MemIndex::build(std::move(Slab).build());
79}
80
Sam McCalle746a2b2018-07-02 11:13:16 +000081CodeCompleteResult completions(ClangdServer &Server, StringRef Text,
82 std::vector<Symbol> IndexSymbols = {},
83 clangd::CodeCompleteOptions Opts = {}) {
Sam McCalla15c2d62018-01-18 09:27:56 +000084 std::unique_ptr<SymbolIndex> OverrideIndex;
85 if (!IndexSymbols.empty()) {
86 assert(!Opts.Index && "both Index and IndexSymbols given!");
87 OverrideIndex = memIndex(std::move(IndexSymbols));
88 Opts.Index = OverrideIndex.get();
89 }
90
Sam McCallc1568062018-02-16 09:41:43 +000091 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +000092 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +000093 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +000094 auto CompletionList =
95 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000096 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +000097}
98
Eric Liu63f419a2018-05-15 15:29:32 +000099// Builds a server and runs code completion.
100// If IndexSymbols is non-empty, an index will be built and passed to opts.
Sam McCalle746a2b2018-07-02 11:13:16 +0000101CodeCompleteResult completions(StringRef Text,
102 std::vector<Symbol> IndexSymbols = {},
103 clangd::CodeCompleteOptions Opts = {}) {
Eric Liu63f419a2018-05-15 15:29:32 +0000104 MockFSProvider FS;
105 MockCompilationDatabase CDB;
106 IgnoreDiagnostics DiagConsumer;
107 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
108 return completions(Server, Text, std::move(IndexSymbols), std::move(Opts));
109}
110
Sam McCall545a20d2018-01-19 14:34:02 +0000111std::string replace(StringRef Haystack, StringRef Needle, StringRef Repl) {
112 std::string Result;
113 raw_string_ostream OS(Result);
114 std::pair<StringRef, StringRef> Split;
115 for (Split = Haystack.split(Needle); !Split.second.empty();
116 Split = Split.first.split(Needle))
117 OS << Split.first << Repl;
118 Result += Split.first;
119 OS.flush();
120 return Result;
121}
122
Sam McCalla15c2d62018-01-18 09:27:56 +0000123// Helpers to produce fake index symbols for memIndex() or completions().
Sam McCall545a20d2018-01-19 14:34:02 +0000124// USRFormat is a regex replacement string for the unqualified part of the USR.
125Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000126 Symbol Sym;
Sam McCall545a20d2018-01-19 14:34:02 +0000127 std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
Sam McCalla15c2d62018-01-18 09:27:56 +0000128 size_t Pos = QName.rfind("::");
129 if (Pos == llvm::StringRef::npos) {
130 Sym.Name = QName;
131 Sym.Scope = "";
132 } else {
133 Sym.Name = QName.substr(Pos + 2);
Sam McCall8b2faee2018-01-19 22:18:21 +0000134 Sym.Scope = QName.substr(0, Pos + 2);
135 USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
Sam McCalla15c2d62018-01-18 09:27:56 +0000136 }
Sam McCall545a20d2018-01-19 14:34:02 +0000137 USR += Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
138 Sym.ID = SymbolID(USR);
Sam McCalla15c2d62018-01-18 09:27:56 +0000139 Sym.SymInfo.Kind = Kind;
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000140 Sym.IsIndexedForCodeCompletion = true;
Sam McCall2161ec72018-07-05 06:20:41 +0000141 Sym.Origin = SymbolOrigin::Static;
Sam McCalla15c2d62018-01-18 09:27:56 +0000142 return Sym;
143}
Sam McCall545a20d2018-01-19 14:34:02 +0000144Symbol func(StringRef Name) { // Assumes the function has no args.
145 return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
146}
147Symbol cls(StringRef Name) {
Eric Liu9b3cba72018-05-30 09:03:39 +0000148 return sym(Name, index::SymbolKind::Class, "@S@\\0");
Sam McCall545a20d2018-01-19 14:34:02 +0000149}
150Symbol var(StringRef Name) {
151 return sym(Name, index::SymbolKind::Variable, "@\\0");
152}
Sam McCalldc8abc42018-05-03 14:53:02 +0000153Symbol ns(StringRef Name) {
154 return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
155}
156Symbol withReferences(int N, Symbol S) {
157 S.References = N;
158 return S;
159}
Sam McCalla15c2d62018-01-18 09:27:56 +0000160
Sam McCallf6ae3232017-12-05 20:11:29 +0000161TEST(CompletionTest, Limit) {
162 clangd::CodeCompleteOptions Opts;
163 Opts.Limit = 2;
164 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000165struct ClassWithMembers {
166 int AAA();
167 int BBB();
168 int CCC();
169}
Sam McCallf6ae3232017-12-05 20:11:29 +0000170int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000171 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000172 /*IndexSymbols=*/{}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000173
Sam McCalle746a2b2018-07-02 11:13:16 +0000174 EXPECT_TRUE(Results.HasMore);
175 EXPECT_THAT(Results.Completions, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000176}
177
Sam McCallf6ae3232017-12-05 20:11:29 +0000178TEST(CompletionTest, Filter) {
179 std::string Body = R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000180 #define MotorCar
181 int Car;
Sam McCall9aad25f2017-12-05 07:20:26 +0000182 struct S {
183 int FooBar;
184 int FooBaz;
185 int Qux;
186 };
187 )cpp";
Sam McCall8b2dcc12018-06-14 13:50:30 +0000188
189 // Only items matching the fuzzy query are returned.
Sam McCalle746a2b2018-07-02 11:13:16 +0000190 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").Completions,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000191 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000192
Sam McCall8b2dcc12018-06-14 13:50:30 +0000193 // Macros require prefix match.
Sam McCalle746a2b2018-07-02 11:13:16 +0000194 EXPECT_THAT(completions(Body + "int main() { C^ }").Completions,
Sam McCall8b2dcc12018-06-14 13:50:30 +0000195 AllOf(Has("Car"), Not(Has("MotorCar"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000196}
197
Sam McCallf6ae3232017-12-05 20:11:29 +0000198void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000199 auto Results = completions(
200 R"cpp(
201 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000202
Sam McCall44fdcec22017-12-08 15:00:59 +0000203 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000204
Sam McCall44fdcec22017-12-08 15:00:59 +0000205 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000206
Sam McCall44fdcec22017-12-08 15:00:59 +0000207 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000208
Sam McCall44fdcec22017-12-08 15:00:59 +0000209 struct ClassWithMembers {
210 /// Doc for method.
211 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000212
Sam McCall44fdcec22017-12-08 15:00:59 +0000213 int field;
214 private:
215 int private_field;
216 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000217
Sam McCall44fdcec22017-12-08 15:00:59 +0000218 int test() {
219 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000220
Sam McCall44fdcec22017-12-08 15:00:59 +0000221 /// Doc for local_var.
222 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000223
Sam McCall44fdcec22017-12-08 15:00:59 +0000224 ClassWithMembers().^
225 }
226 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000227 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000228
Sam McCallf6ae3232017-12-05 20:11:29 +0000229 // Class members. The only items that must be present in after-dot
230 // completion.
Sam McCalle746a2b2018-07-02 11:13:16 +0000231 EXPECT_THAT(Results.Completions,
232 AllOf(Has("method"), Has("field"), Not(Has("ClassWithMembers")),
Sam McCall4caa8512018-06-07 12:49:17 +0000233 Not(Has("operator=")), Not(Has("~ClassWithMembers"))));
Sam McCalle746a2b2018-07-02 11:13:16 +0000234 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000235 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000236 // Global items.
Sam McCall545a20d2018-01-19 14:34:02 +0000237 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +0000238 Results.Completions,
Sam McCall545a20d2018-01-19 14:34:02 +0000239 Not(AnyOf(Has("global_var"), Has("index_var"), Has("global_func"),
240 Has("global_func()"), Has("index_func"), Has("GlobalClass"),
241 Has("IndexClass"), Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000242 // There should be no code patterns (aka snippets) in after-dot
243 // completion. At least there aren't any we're aware of.
Sam McCalle746a2b2018-07-02 11:13:16 +0000244 EXPECT_THAT(Results.Completions,
245 Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000246 // Check documentation.
Sam McCalle746a2b2018-07-02 11:13:16 +0000247 EXPECT_IFF(Opts.IncludeComments, Results.Completions,
248 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000249}
Sam McCall9aad25f2017-12-05 07:20:26 +0000250
Sam McCallf6ae3232017-12-05 20:11:29 +0000251void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000252 auto Results = completions(
253 R"cpp(
254 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000255
Sam McCall44fdcec22017-12-08 15:00:59 +0000256 int global_var;
257 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000258
Sam McCall44fdcec22017-12-08 15:00:59 +0000259 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000260
Sam McCall44fdcec22017-12-08 15:00:59 +0000261 struct ClassWithMembers {
262 /// Doc for method.
263 int method();
264 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000265
Sam McCall44fdcec22017-12-08 15:00:59 +0000266 int test() {
267 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000268
Sam McCall44fdcec22017-12-08 15:00:59 +0000269 /// Doc for local_var.
270 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000271
Sam McCall44fdcec22017-12-08 15:00:59 +0000272 ^
273 }
274 )cpp",
Sam McCall545a20d2018-01-19 14:34:02 +0000275 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000276
277 // Class members. Should never be present in global completions.
Sam McCalle746a2b2018-07-02 11:13:16 +0000278 EXPECT_THAT(Results.Completions,
Sam McCallf6ae3232017-12-05 20:11:29 +0000279 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
280 // Global items.
Sam McCalle746a2b2018-07-02 11:13:16 +0000281 EXPECT_THAT(Results.Completions,
282 AllOf(Has("global_var"), Has("index_var"), Has("global_func"),
Sam McCall545a20d2018-01-19 14:34:02 +0000283 Has("index_func" /* our fake symbol doesn't include () */),
284 Has("GlobalClass"), Has("IndexClass")));
Sam McCallf6ae3232017-12-05 20:11:29 +0000285 // A macro.
Sam McCalle746a2b2018-07-02 11:13:16 +0000286 EXPECT_IFF(Opts.IncludeMacros, Results.Completions, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000287 // Local items. Must be present always.
Sam McCalle746a2b2018-07-02 11:13:16 +0000288 EXPECT_THAT(Results.Completions,
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000289 AllOf(Has("local_var"), Has("LocalClass"),
290 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000291 // Check documentation.
Sam McCalle746a2b2018-07-02 11:13:16 +0000292 EXPECT_IFF(Opts.IncludeComments, Results.Completions,
293 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000294}
295
296TEST(CompletionTest, CompletionOptions) {
Sam McCall2c3849a2018-01-16 12:21:24 +0000297 auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
298 TestAfterDotCompletion(Opts);
299 TestGlobalScopeCompletion(Opts);
300 };
301 // We used to test every combination of options, but that got too slow (2^N).
302 auto Flags = {
Ilya Biryukov71028b82018-03-12 15:28:22 +0000303 &clangd::CodeCompleteOptions::IncludeMacros,
Ilya Biryukov43714502018-05-16 12:32:44 +0000304 &clangd::CodeCompleteOptions::IncludeComments,
Ilya Biryukov71028b82018-03-12 15:28:22 +0000305 &clangd::CodeCompleteOptions::IncludeCodePatterns,
306 &clangd::CodeCompleteOptions::IncludeIneligibleResults,
Sam McCall2c3849a2018-01-16 12:21:24 +0000307 };
308 // Test default options.
309 Test({});
310 // Test with one flag flipped.
311 for (auto &F : Flags) {
312 clangd::CodeCompleteOptions O;
313 O.*F ^= true;
314 Test(O);
Sam McCall9aad25f2017-12-05 07:20:26 +0000315 }
316}
317
Sam McCall44fdcec22017-12-08 15:00:59 +0000318TEST(CompletionTest, Priorities) {
319 auto Internal = completions(R"cpp(
320 class Foo {
321 public: void pub();
322 protected: void prot();
323 private: void priv();
324 };
325 void Foo::pub() { this->^ }
326 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000327 EXPECT_THAT(Internal.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000328 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
329
330 auto External = completions(R"cpp(
331 class Foo {
332 public: void pub();
333 protected: void prot();
334 private: void priv();
335 };
336 void test() {
337 Foo F;
338 F.^
339 }
340 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000341 EXPECT_THAT(External.Completions,
Sam McCall44fdcec22017-12-08 15:00:59 +0000342 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
343}
344
345TEST(CompletionTest, Qualifiers) {
346 auto Results = completions(R"cpp(
347 class Foo {
348 public: int foo() const;
349 int bar() const;
350 };
351 class Bar : public Foo {
352 int foo() const;
353 };
354 void test() { Bar().^ }
355 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000356 EXPECT_THAT(Results.Completions,
357 HasSubsequence(AllOf(Qualifier(""), Named("bar")),
358 AllOf(Qualifier("Foo::"), Named("foo"))));
359 EXPECT_THAT(Results.Completions,
360 Not(Contains(AllOf(Qualifier(""), Named("foo"))))); // private
Sam McCall44fdcec22017-12-08 15:00:59 +0000361}
362
Sam McCall4caa8512018-06-07 12:49:17 +0000363TEST(CompletionTest, InjectedTypename) {
364 // These are suppressed when accessed as a member...
Sam McCalle746a2b2018-07-02 11:13:16 +0000365 EXPECT_THAT(completions("struct X{}; void foo(){ X().^ }").Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000366 Not(Has("X")));
Sam McCalle746a2b2018-07-02 11:13:16 +0000367 EXPECT_THAT(completions("struct X{ void foo(){ this->^ } };").Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000368 Not(Has("X")));
369 // ...but accessible in other, more useful cases.
Sam McCalle746a2b2018-07-02 11:13:16 +0000370 EXPECT_THAT(completions("struct X{ void foo(){ ^ } };").Completions,
371 Has("X"));
372 EXPECT_THAT(
373 completions("struct Y{}; struct X:Y{ void foo(){ ^ } };").Completions,
374 Has("Y"));
Sam McCall4caa8512018-06-07 12:49:17 +0000375 EXPECT_THAT(
376 completions(
377 "template<class> struct Y{}; struct X:Y<int>{ void foo(){ ^ } };")
Sam McCalle746a2b2018-07-02 11:13:16 +0000378 .Completions,
Sam McCall4caa8512018-06-07 12:49:17 +0000379 Has("Y"));
380 // This case is marginal (`using X::X` is useful), we allow it for now.
Sam McCalle746a2b2018-07-02 11:13:16 +0000381 EXPECT_THAT(completions("struct X{}; void foo(){ X::^ }").Completions,
382 Has("X"));
Sam McCall4caa8512018-06-07 12:49:17 +0000383}
384
Sam McCall44fdcec22017-12-08 15:00:59 +0000385TEST(CompletionTest, Snippets) {
386 clangd::CodeCompleteOptions Opts;
Sam McCall44fdcec22017-12-08 15:00:59 +0000387 auto Results = completions(
388 R"cpp(
389 struct fake {
390 int a;
391 int f(int i, const float f) const;
392 };
393 int main() {
394 fake f;
395 f.^
396 }
397 )cpp",
Sam McCalla15c2d62018-01-18 09:27:56 +0000398 /*IndexSymbols=*/{}, Opts);
Sam McCalle746a2b2018-07-02 11:13:16 +0000399 EXPECT_THAT(
400 Results.Completions,
401 HasSubsequence(Named("a"),
402 SnippetSuffix("(${1:int i}, ${2:const float f})")));
Sam McCall44fdcec22017-12-08 15:00:59 +0000403}
404
405TEST(CompletionTest, Kinds) {
Sam McCall545a20d2018-01-19 14:34:02 +0000406 auto Results = completions(
407 R"cpp(
408 #define MACRO X
409 int variable;
410 struct Struct {};
411 int function();
412 int X = ^
413 )cpp",
414 {func("indexFunction"), var("indexVariable"), cls("indexClass")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000415 EXPECT_THAT(Results.Completions,
Sam McCall545a20d2018-01-19 14:34:02 +0000416 AllOf(Has("function", CompletionItemKind::Function),
417 Has("variable", CompletionItemKind::Variable),
418 Has("int", CompletionItemKind::Keyword),
419 Has("Struct", CompletionItemKind::Class),
420 Has("MACRO", CompletionItemKind::Text),
421 Has("indexFunction", CompletionItemKind::Function),
422 Has("indexVariable", CompletionItemKind::Variable),
423 Has("indexClass", CompletionItemKind::Class)));
Sam McCall44fdcec22017-12-08 15:00:59 +0000424
Sam McCall44fdcec22017-12-08 15:00:59 +0000425 Results = completions("nam^");
Sam McCalle746a2b2018-07-02 11:13:16 +0000426 EXPECT_THAT(Results.Completions,
427 Has("namespace", CompletionItemKind::Snippet));
Sam McCall44fdcec22017-12-08 15:00:59 +0000428}
429
Sam McCall84652cc2018-01-12 16:16:09 +0000430TEST(CompletionTest, NoDuplicates) {
Sam McCall545a20d2018-01-19 14:34:02 +0000431 auto Results = completions(
432 R"cpp(
433 class Adapter {
Sam McCall545a20d2018-01-19 14:34:02 +0000434 };
Sam McCall84652cc2018-01-12 16:16:09 +0000435
Eric Liu9b3cba72018-05-30 09:03:39 +0000436 void f() {
Sam McCall545a20d2018-01-19 14:34:02 +0000437 Adapter^
438 }
439 )cpp",
440 {cls("Adapter")});
Sam McCall84652cc2018-01-12 16:16:09 +0000441
442 // Make sure there are no duplicate entries of 'Adapter'.
Sam McCalle746a2b2018-07-02 11:13:16 +0000443 EXPECT_THAT(Results.Completions, ElementsAre(Named("Adapter")));
Sam McCall84652cc2018-01-12 16:16:09 +0000444}
445
Sam McCall545a20d2018-01-19 14:34:02 +0000446TEST(CompletionTest, ScopedNoIndex) {
447 auto Results = completions(
448 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000449 namespace fake { int BigBang, Babble, Box; };
450 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000451 ")cpp");
Sam McCall8b2dcc12018-06-14 13:50:30 +0000452 // Babble is a better match than BigBang. Box doesn't match at all.
Sam McCalle746a2b2018-07-02 11:13:16 +0000453 EXPECT_THAT(Results.Completions,
454 ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCall84652cc2018-01-12 16:16:09 +0000455}
456
Sam McCall545a20d2018-01-19 14:34:02 +0000457TEST(CompletionTest, Scoped) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000458 auto Results = completions(
459 R"cpp(
Sam McCall8b2dcc12018-06-14 13:50:30 +0000460 namespace fake { int Babble, Box; };
461 int main() { fake::ba^ }
Sam McCall545a20d2018-01-19 14:34:02 +0000462 ")cpp",
463 {var("fake::BigBang")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000464 EXPECT_THAT(Results.Completions,
465 ElementsAre(Named("Babble"), Named("BigBang")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000466}
467
Sam McCall545a20d2018-01-19 14:34:02 +0000468TEST(CompletionTest, ScopedWithFilter) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000469 auto Results = completions(
470 R"cpp(
471 void f() { ns::x^ }
472 )cpp",
473 {cls("ns::XYZ"), func("ns::foo")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000474 EXPECT_THAT(Results.Completions, UnorderedElementsAre(Named("XYZ")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000475}
476
Sam McCalldc8abc42018-05-03 14:53:02 +0000477TEST(CompletionTest, ReferencesAffectRanking) {
478 auto Results = completions("int main() { abs^ }", {ns("absl"), func("abs")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000479 EXPECT_THAT(Results.Completions, HasSubsequence(Named("abs"), Named("absl")));
Sam McCalldc8abc42018-05-03 14:53:02 +0000480 Results = completions("int main() { abs^ }",
481 {withReferences(10000, ns("absl")), func("abs")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000482 EXPECT_THAT(Results.Completions, HasSubsequence(Named("absl"), Named("abs")));
Sam McCalldc8abc42018-05-03 14:53:02 +0000483}
484
Sam McCall545a20d2018-01-19 14:34:02 +0000485TEST(CompletionTest, GlobalQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000486 auto Results = completions(
487 R"cpp(
488 void f() { ::^ }
489 )cpp",
490 {cls("XYZ")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000491 EXPECT_THAT(Results.Completions,
492 AllOf(Has("XYZ", CompletionItemKind::Class),
493 Has("f", CompletionItemKind::Function)));
Sam McCalla15c2d62018-01-18 09:27:56 +0000494}
495
Sam McCall545a20d2018-01-19 14:34:02 +0000496TEST(CompletionTest, FullyQualified) {
Sam McCalla15c2d62018-01-18 09:27:56 +0000497 auto Results = completions(
498 R"cpp(
Sam McCall545a20d2018-01-19 14:34:02 +0000499 namespace ns { void bar(); }
Sam McCalla15c2d62018-01-18 09:27:56 +0000500 void f() { ::ns::^ }
501 )cpp",
502 {cls("ns::XYZ")});
Sam McCalle746a2b2018-07-02 11:13:16 +0000503 EXPECT_THAT(Results.Completions,
504 AllOf(Has("XYZ", CompletionItemKind::Class),
505 Has("bar", CompletionItemKind::Function)));
Sam McCall545a20d2018-01-19 14:34:02 +0000506}
507
508TEST(CompletionTest, SemaIndexMerge) {
509 auto Results = completions(
510 R"cpp(
511 namespace ns { int local; void both(); }
512 void f() { ::ns::^ }
513 )cpp",
514 {func("ns::both"), cls("ns::Index")});
515 // We get results from both index and sema, with no duplicates.
Sam McCall2161ec72018-07-05 06:20:41 +0000516 EXPECT_THAT(Results.Completions,
517 UnorderedElementsAre(
518 AllOf(Named("local"), Origin(SymbolOrigin::AST)),
519 AllOf(Named("Index"), Origin(SymbolOrigin::Static)),
520 AllOf(Named("both"),
521 Origin(SymbolOrigin::AST | SymbolOrigin::Static))));
Sam McCalla15c2d62018-01-18 09:27:56 +0000522}
523
Haojian Wu48b48652018-01-25 09:20:09 +0000524TEST(CompletionTest, SemaIndexMergeWithLimit) {
525 clangd::CodeCompleteOptions Opts;
526 Opts.Limit = 1;
527 auto Results = completions(
528 R"cpp(
529 namespace ns { int local; void both(); }
530 void f() { ::ns::^ }
531 )cpp",
532 {func("ns::both"), cls("ns::Index")}, Opts);
Sam McCalle746a2b2018-07-02 11:13:16 +0000533 EXPECT_EQ(Results.Completions.size(), Opts.Limit);
534 EXPECT_TRUE(Results.HasMore);
Haojian Wu48b48652018-01-25 09:20:09 +0000535}
536
Eric Liu63f419a2018-05-15 15:29:32 +0000537TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
538 MockFSProvider FS;
539 MockCompilationDatabase CDB;
540 std::string Subdir = testPath("sub");
541 std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
542 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
543 std::string BarHeader = testPath("sub/bar.h");
544 FS.Files[BarHeader] = "";
545
546 IgnoreDiagnostics DiagConsumer;
547 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
548 Symbol::Details Scratch;
549 auto BarURI = URI::createFile(BarHeader).toString();
550 Symbol Sym = cls("ns::X");
551 Sym.CanonicalDeclaration.FileURI = BarURI;
552 Scratch.IncludeHeader = BarURI;
553 Sym.Detail = &Scratch;
554 // Shoten include path based on search dirctory and insert.
555 auto Results = completions(Server,
556 R"cpp(
557 int main() { ns::^ }
558 )cpp",
559 {Sym});
Sam McCalle746a2b2018-07-02 11:13:16 +0000560 EXPECT_THAT(Results.Completions,
561 ElementsAre(AllOf(Named("X"), InsertInclude("\"bar.h\""))));
Eric Liu63f419a2018-05-15 15:29:32 +0000562 // Duplicate based on inclusions in preamble.
563 Results = completions(Server,
564 R"cpp(
565 #include "sub/bar.h" // not shortest, so should only match resolved.
566 int main() { ns::^ }
567 )cpp",
568 {Sym});
Sam McCalle746a2b2018-07-02 11:13:16 +0000569 EXPECT_THAT(Results.Completions, ElementsAre(AllOf(Named("X"), Labeled("X"),
570 Not(InsertInclude()))));
Eric Liu63f419a2018-05-15 15:29:32 +0000571}
572
Eric Liu9b3cba72018-05-30 09:03:39 +0000573TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
574 MockFSProvider FS;
575 MockCompilationDatabase CDB;
576
577 IgnoreDiagnostics DiagConsumer;
578 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
579 Symbol::Details Scratch;
580 Symbol SymX = cls("ns::X");
581 Symbol SymY = cls("ns::Y");
582 std::string BarHeader = testPath("bar.h");
583 auto BarURI = URI::createFile(BarHeader).toString();
584 SymX.CanonicalDeclaration.FileURI = BarURI;
585 SymY.CanonicalDeclaration.FileURI = BarURI;
586 Scratch.IncludeHeader = "<bar>";
587 SymX.Detail = &Scratch;
588 SymY.Detail = &Scratch;
589 // Shoten include path based on search dirctory and insert.
590 auto Results = completions(Server,
591 R"cpp(
592 namespace ns {
593 class X;
594 class Y {}
595 }
596 int main() { ns::^ }
597 )cpp",
598 {SymX, SymY});
Sam McCalle746a2b2018-07-02 11:13:16 +0000599 EXPECT_THAT(Results.Completions,
600 ElementsAre(AllOf(Named("X"), Not(InsertInclude())),
601 AllOf(Named("Y"), Not(InsertInclude()))));
Eric Liu9b3cba72018-05-30 09:03:39 +0000602}
603
Sam McCalla15c2d62018-01-18 09:27:56 +0000604TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
605 MockFSProvider FS;
606 MockCompilationDatabase CDB;
607 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000608 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCalla15c2d62018-01-18 09:27:56 +0000609
Sam McCallc1568062018-02-16 09:41:43 +0000610 FS.Files[testPath("bar.h")] =
Sam McCalld5ea3e32018-01-24 17:53:32 +0000611 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
Sam McCallc1568062018-02-16 09:41:43 +0000612 auto File = testPath("foo.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000613 Annotations Test(R"cpp(
614 #include "bar.h"
615 namespace ns { int local; }
Sam McCalld5ea3e32018-01-24 17:53:32 +0000616 void f() { ns::^; }
617 void f() { ns::preamble().$2^; }
Sam McCalla15c2d62018-01-18 09:27:56 +0000618 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000619 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000620 clangd::CodeCompleteOptions Opts = {};
621
Sam McCalla15c2d62018-01-18 09:27:56 +0000622 auto I = memIndex({var("ns::index")});
623 Opts.Index = I.get();
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000624 auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000625 EXPECT_THAT(WithIndex.Completions,
Sam McCalla15c2d62018-01-18 09:27:56 +0000626 UnorderedElementsAre(Named("local"), Named("index")));
Sam McCalld5ea3e32018-01-24 17:53:32 +0000627 auto ClassFromPreamble =
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000628 cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000629 EXPECT_THAT(ClassFromPreamble.Completions, Contains(Named("member")));
Sam McCall0bb24cd2018-02-13 08:59:23 +0000630
631 Opts.Index = nullptr;
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000632 auto WithoutIndex =
633 cantFail(runCodeComplete(Server, File, Test.point(), Opts));
Sam McCalle746a2b2018-07-02 11:13:16 +0000634 EXPECT_THAT(WithoutIndex.Completions,
Sam McCall0bb24cd2018-02-13 08:59:23 +0000635 UnorderedElementsAre(Named("local"), Named("preamble")));
Sam McCalla15c2d62018-01-18 09:27:56 +0000636}
637
638TEST(CompletionTest, DynamicIndexMultiFile) {
639 MockFSProvider FS;
640 MockCompilationDatabase CDB;
641 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000642 auto Opts = ClangdServer::optsForTest();
643 Opts.BuildDynamicSymbolIndex = true;
644 ClangdServer Server(CDB, FS, DiagConsumer, Opts);
Sam McCalla15c2d62018-01-18 09:27:56 +0000645
Eric Liu709bde82018-02-19 18:48:44 +0000646 FS.Files[testPath("foo.h")] = R"cpp(
Sam McCalla15c2d62018-01-18 09:27:56 +0000647 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liu709bde82018-02-19 18:48:44 +0000648 )cpp";
Sam McCall7363a2f2018-03-05 17:28:54 +0000649 runAddDocument(Server, testPath("foo.cpp"), R"cpp(
Eric Liu709bde82018-02-19 18:48:44 +0000650 #include "foo.h"
Sam McCall0bb24cd2018-02-13 08:59:23 +0000651 )cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000652
Sam McCallc1568062018-02-16 09:41:43 +0000653 auto File = testPath("bar.cpp");
Sam McCalla15c2d62018-01-18 09:27:56 +0000654 Annotations Test(R"cpp(
655 namespace ns {
656 class XXX {};
657 /// Doooc
658 void fooooo() {}
659 }
660 void f() { ns::^ }
661 )cpp");
Sam McCall7363a2f2018-03-05 17:28:54 +0000662 runAddDocument(Server, File, Test.code());
Sam McCalla15c2d62018-01-18 09:27:56 +0000663
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000664 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
Sam McCalla15c2d62018-01-18 09:27:56 +0000665 // "XYZ" and "foo" are not included in the file being completed but are still
666 // visible through the index.
Sam McCalle746a2b2018-07-02 11:13:16 +0000667 EXPECT_THAT(Results.Completions, Has("XYZ", CompletionItemKind::Class));
668 EXPECT_THAT(Results.Completions, Has("foo", CompletionItemKind::Function));
669 EXPECT_THAT(Results.Completions, Has("XXX", CompletionItemKind::Class));
670 EXPECT_THAT(Results.Completions,
671 Contains((Named("fooooo"), Kind(CompletionItemKind::Function),
672 Doc("Doooc"), ReturnType("void"))));
Sam McCalla15c2d62018-01-18 09:27:56 +0000673}
674
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000675TEST(CompletionTest, Documentation) {
676 auto Results = completions(
677 R"cpp(
678 // Non-doxygen comment.
679 int foo();
680 /// Doxygen comment.
681 /// \param int a
682 int bar(int a);
683 /* Multi-line
684 block comment
685 */
686 int baz();
687
688 int x = ^
689 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000690 EXPECT_THAT(Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000691 Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
692 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +0000693 Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000694 Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
Sam McCalle746a2b2018-07-02 11:13:16 +0000695 EXPECT_THAT(Results.Completions,
Ilya Biryukovc22d3442018-05-16 12:32:49 +0000696 Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
697}
698
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000699TEST(CompletionTest, GlobalCompletionFiltering) {
700
701 Symbol Class = cls("XYZ");
702 Class.IsIndexedForCodeCompletion = false;
703 Symbol Func = func("XYZ::foooo");
704 Func.IsIndexedForCodeCompletion = false;
705
706 auto Results = completions(R"(// void f() {
707 XYZ::foooo^
708 })",
709 {Class, Func});
Sam McCalle746a2b2018-07-02 11:13:16 +0000710 EXPECT_THAT(Results.Completions, IsEmpty());
Marc-Andre Laperle945b5a32018-06-05 14:01:40 +0000711}
712
Haojian Wu58d208d2018-01-25 09:44:06 +0000713TEST(CodeCompleteTest, DisableTypoCorrection) {
714 auto Results = completions(R"cpp(
715 namespace clang { int v; }
716 void f() { clangd::^
717 )cpp");
Sam McCalle746a2b2018-07-02 11:13:16 +0000718 EXPECT_TRUE(Results.Completions.empty());
Haojian Wu58d208d2018-01-25 09:44:06 +0000719}
720
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000721TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
722 auto Results = completions(R"cpp(
723 namespace clang { }
724 void f() {
725 clan^
726 }
727 )cpp");
728
Sam McCalle746a2b2018-07-02 11:13:16 +0000729 EXPECT_THAT(Results.Completions, Contains(Labeled("clang")));
730 EXPECT_THAT(Results.Completions, Not(Contains(Labeled("clang::"))));
Ilya Biryukov53d6d932018-03-06 16:45:21 +0000731}
732
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000733TEST(CompletionTest, BacktrackCrashes) {
734 // Sema calls code completion callbacks twice in these cases.
735 auto Results = completions(R"cpp(
736 namespace ns {
737 struct FooBarBaz {};
738 } // namespace ns
739
740 int foo(ns::FooBar^
741 )cpp");
742
Sam McCalle746a2b2018-07-02 11:13:16 +0000743 EXPECT_THAT(Results.Completions, ElementsAre(Labeled("FooBarBaz")));
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000744
745 // Check we don't crash in that case too.
746 completions(R"cpp(
747 struct FooBarBaz {};
748 void test() {
749 if (FooBarBaz * x^) {}
750 }
751)cpp");
752}
753
Eric Liu42abe412018-05-24 11:20:19 +0000754TEST(CompletionTest, CompleteInMacroWithStringification) {
755 auto Results = completions(R"cpp(
756void f(const char *, int x);
757#define F(x) f(#x, x)
758
759namespace ns {
760int X;
761int Y;
762} // namespace ns
763
764int f(int input_num) {
765 F(ns::^)
766}
767)cpp");
768
Sam McCalle746a2b2018-07-02 11:13:16 +0000769 EXPECT_THAT(Results.Completions,
Eric Liu42abe412018-05-24 11:20:19 +0000770 UnorderedElementsAre(Named("X"), Named("Y")));
771}
772
773TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
774 auto Results = completions(R"cpp(
775void f(const char *, int x);
776#define F(x) f(#x, x)
777
778namespace ns {
779int X;
780
781int f(int input_num) {
782 F(^)
783}
784} // namespace ns
785)cpp");
786
Sam McCalle746a2b2018-07-02 11:13:16 +0000787 EXPECT_THAT(Results.Completions, Contains(Named("X")));
Eric Liu42abe412018-05-24 11:20:19 +0000788}
789
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000790TEST(CompletionTest, CompleteInExcludedPPBranch) {
791 auto Results = completions(R"cpp(
792 int bar(int param_in_bar) {
793 }
794
795 int foo(int param_in_foo) {
796#if 0
797 par^
798#endif
799 }
800)cpp");
801
Sam McCalle746a2b2018-07-02 11:13:16 +0000802 EXPECT_THAT(Results.Completions, Contains(Labeled("param_in_foo")));
803 EXPECT_THAT(Results.Completions, Not(Contains(Labeled("param_in_bar"))));
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000804}
805
Sam McCall800d4372017-12-19 10:29:27 +0000806SignatureHelp signatures(StringRef Text) {
807 MockFSProvider FS;
808 MockCompilationDatabase CDB;
809 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000810 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCallc1568062018-02-16 09:41:43 +0000811 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000812 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000813 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000814 return cantFail(runSignatureHelp(Server, File, Test.point()));
Sam McCall800d4372017-12-19 10:29:27 +0000815}
816
817MATCHER_P(ParamsAre, P, "") {
818 if (P.size() != arg.parameters.size())
819 return false;
820 for (unsigned I = 0; I < P.size(); ++I)
821 if (P[I] != arg.parameters[I].label)
822 return false;
823 return true;
824}
825
826Matcher<SignatureInformation> Sig(std::string Label,
827 std::vector<std::string> Params) {
Eric Liu8f3678d2018-06-15 13:34:18 +0000828 return AllOf(SigHelpLabeled(Label), ParamsAre(Params));
Sam McCall800d4372017-12-19 10:29:27 +0000829}
830
831TEST(SignatureHelpTest, Overloads) {
832 auto Results = signatures(R"cpp(
833 void foo(int x, int y);
834 void foo(int x, float y);
835 void foo(float x, int y);
836 void foo(float x, float y);
837 void bar(int x, int y = 0);
838 int main() { foo(^); }
839 )cpp");
840 EXPECT_THAT(Results.signatures,
841 UnorderedElementsAre(
842 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
843 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
844 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
845 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
846 // We always prefer the first signature.
847 EXPECT_EQ(0, Results.activeSignature);
848 EXPECT_EQ(0, Results.activeParameter);
849}
850
851TEST(SignatureHelpTest, DefaultArgs) {
852 auto Results = signatures(R"cpp(
853 void bar(int x, int y = 0);
854 void bar(float x = 0, int y = 42);
855 int main() { bar(^
856 )cpp");
857 EXPECT_THAT(Results.signatures,
858 UnorderedElementsAre(
859 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
860 Sig("bar(float x = 0, int y = 42) -> void",
861 {"float x = 0", "int y = 42"})));
862 EXPECT_EQ(0, Results.activeSignature);
863 EXPECT_EQ(0, Results.activeParameter);
864}
865
866TEST(SignatureHelpTest, ActiveArg) {
867 auto Results = signatures(R"cpp(
868 int baz(int a, int b, int c);
869 int main() { baz(baz(1,2,3), ^); }
870 )cpp");
871 EXPECT_THAT(Results.signatures,
872 ElementsAre(Sig("baz(int a, int b, int c) -> int",
873 {"int a", "int b", "int c"})));
874 EXPECT_EQ(0, Results.activeSignature);
875 EXPECT_EQ(1, Results.activeParameter);
876}
877
Haojian Wu061c73e2018-01-23 11:37:26 +0000878class IndexRequestCollector : public SymbolIndex {
879public:
880 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000881 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000882 llvm::function_ref<void(const Symbol &)> Callback) const override {
883 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000884 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000885 }
886
Eric Liu9ec459f2018-03-14 09:48:05 +0000887 void lookup(const LookupRequest &,
888 llvm::function_ref<void(const Symbol &)>) const override {}
889
Haojian Wu061c73e2018-01-23 11:37:26 +0000890 const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
891
892private:
893 mutable std::vector<FuzzyFindRequest> Requests;
894};
895
896std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
897 clangd::CodeCompleteOptions Opts;
898 IndexRequestCollector Requests;
899 Opts.Index = &Requests;
900 completions(Code, {}, Opts);
901 return Requests.allRequests();
902}
903
904TEST(CompletionTest, UnqualifiedIdQuery) {
905 auto Requests = captureIndexRequests(R"cpp(
906 namespace std {}
907 using namespace std;
908 namespace ns {
909 void f() {
910 vec^
911 }
912 }
913 )cpp");
914
915 EXPECT_THAT(Requests,
916 ElementsAre(Field(&FuzzyFindRequest::Scopes,
917 UnorderedElementsAre("", "ns::", "std::"))));
918}
919
920TEST(CompletionTest, ResolvedQualifiedIdQuery) {
921 auto Requests = captureIndexRequests(R"cpp(
922 namespace ns1 {}
923 namespace ns2 {} // ignore
924 namespace ns3 { namespace nns3 {} }
925 namespace foo {
926 using namespace ns1;
927 using namespace ns3::nns3;
928 }
929 namespace ns {
930 void f() {
931 foo::^
932 }
933 }
934 )cpp");
935
936 EXPECT_THAT(Requests,
937 ElementsAre(Field(
938 &FuzzyFindRequest::Scopes,
939 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
940}
941
942TEST(CompletionTest, UnresolvedQualifierIdQuery) {
943 auto Requests = captureIndexRequests(R"cpp(
944 namespace a {}
945 using namespace a;
946 namespace ns {
947 void f() {
948 bar::^
949 }
950 } // namespace ns
951 )cpp");
952
953 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
954 UnorderedElementsAre("bar::"))));
955}
956
957TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
958 auto Requests = captureIndexRequests(R"cpp(
959 namespace a {}
960 using namespace a;
961 namespace ns {
962 void f() {
963 ::a::bar::^
964 }
965 } // namespace ns
966 )cpp");
967
968 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
969 UnorderedElementsAre("a::bar::"))));
970}
971
972TEST(CompletionTest, EmptyQualifiedQuery) {
973 auto Requests = captureIndexRequests(R"cpp(
974 namespace ns {
975 void f() {
976 ^
977 }
978 } // namespace ns
979 )cpp");
980
981 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
982 UnorderedElementsAre("", "ns::"))));
983}
984
985TEST(CompletionTest, GlobalQualifiedQuery) {
986 auto Requests = captureIndexRequests(R"cpp(
987 namespace ns {
988 void f() {
989 ::^
990 }
991 } // namespace ns
992 )cpp");
993
994 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
995 UnorderedElementsAre(""))));
996}
997
Ilya Biryukova907ba42018-05-14 10:50:04 +0000998TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
999 auto Completions = completions(
1000 R"cpp(
1001 struct Foo {
1002 int SomeNameOfField;
1003 typedef int SomeNameOfTypedefField;
1004 };
1005
1006 Foo::^)cpp",
1007 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
1008
Sam McCalle746a2b2018-07-02 11:13:16 +00001009 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001010 AllOf(Contains(Labeled("SomeNameOfField")),
1011 Contains(Labeled("SomeNameOfTypedefField")),
1012 Not(Contains(Labeled("SomeNameInTheIndex")))));
1013}
1014
1015TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
1016 {
1017 auto Completions = completions(
1018 R"cpp(
1019 template <class T>
1020 void foo() {
1021 T::^
1022 }
1023 )cpp",
1024 {func("::SomeNameInTheIndex")});
1025
Sam McCalle746a2b2018-07-02 11:13:16 +00001026 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001027 Not(Contains(Labeled("SomeNameInTheIndex"))));
1028 }
1029
1030 {
1031 auto Completions = completions(
1032 R"cpp(
1033 template <class T>
1034 void foo() {
1035 T::template Y<int>::^
1036 }
1037 )cpp",
1038 {func("::SomeNameInTheIndex")});
1039
Sam McCalle746a2b2018-07-02 11:13:16 +00001040 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001041 Not(Contains(Labeled("SomeNameInTheIndex"))));
1042 }
1043
1044 {
1045 auto Completions = completions(
1046 R"cpp(
1047 template <class T>
1048 void foo() {
1049 T::foo::^
1050 }
1051 )cpp",
1052 {func("::SomeNameInTheIndex")});
1053
Sam McCalle746a2b2018-07-02 11:13:16 +00001054 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001055 Not(Contains(Labeled("SomeNameInTheIndex"))));
1056 }
1057}
1058
Sam McCallc18c2802018-06-15 11:06:29 +00001059TEST(CompletionTest, OverloadBundling) {
1060 clangd::CodeCompleteOptions Opts;
1061 Opts.BundleOverloads = true;
1062
1063 std::string Context = R"cpp(
1064 struct X {
1065 // Overload with int
1066 int a(int);
1067 // Overload with bool
1068 int a(bool);
1069 int b(float);
1070 };
1071 int GFuncC(int);
1072 int GFuncD(int);
1073 )cpp";
1074
1075 // Member completions are bundled.
Sam McCalle746a2b2018-07-02 11:13:16 +00001076 EXPECT_THAT(completions(Context + "int y = X().^", {}, Opts).Completions,
Sam McCallc18c2802018-06-15 11:06:29 +00001077 UnorderedElementsAre(Labeled("a(…)"), Labeled("b(float)")));
1078
1079 // Non-member completions are bundled, including index+sema.
1080 Symbol NoArgsGFunc = func("GFuncC");
1081 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001082 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
Sam McCallc18c2802018-06-15 11:06:29 +00001083 UnorderedElementsAre(Labeled("GFuncC(…)"), Labeled("GFuncD(int)")));
1084
1085 // Differences in header-to-insert suppress bundling.
1086 Symbol::Details Detail;
1087 std::string DeclFile = URI::createFile(testPath("foo")).toString();
1088 NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile;
1089 Detail.IncludeHeader = "<foo>";
1090 NoArgsGFunc.Detail = &Detail;
1091 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001092 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
1093 UnorderedElementsAre(AllOf(Named("GFuncC"), InsertInclude("<foo>")),
1094 Labeled("GFuncC(int)"), Labeled("GFuncD(int)")));
Sam McCallc18c2802018-06-15 11:06:29 +00001095
1096 // Examine a bundled completion in detail.
Sam McCalle746a2b2018-07-02 11:13:16 +00001097 auto A =
1098 completions(Context + "int y = X().a^", {}, Opts).Completions.front();
1099 EXPECT_EQ(A.Name, "a");
1100 EXPECT_EQ(A.Signature, "(…)");
1101 EXPECT_EQ(A.BundleSize, 2u);
1102 EXPECT_EQ(A.Kind, CompletionItemKind::Method);
1103 EXPECT_EQ(A.ReturnType, "int"); // All overloads return int.
Sam McCallc18c2802018-06-15 11:06:29 +00001104 // For now we just return one of the doc strings arbitrarily.
Sam McCalle746a2b2018-07-02 11:13:16 +00001105 EXPECT_THAT(A.Documentation, AnyOf(HasSubstr("Overload with int"),
Sam McCallc18c2802018-06-15 11:06:29 +00001106 HasSubstr("Overload with bool")));
Sam McCalle746a2b2018-07-02 11:13:16 +00001107 EXPECT_EQ(A.SnippetSuffix, "(${0})");
Sam McCallc18c2802018-06-15 11:06:29 +00001108}
1109
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001110TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001111 MockFSProvider FS;
1112 auto FooH = testPath("foo.h");
1113 auto FooCpp = testPath("foo.cpp");
1114 FS.Files[FooH] = R"cpp(
1115 // this is my documentation comment.
1116 int func();
1117 )cpp";
1118 FS.Files[FooCpp] = "";
1119
1120 MockCompilationDatabase CDB;
1121 IgnoreDiagnostics DiagConsumer;
1122 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1123
1124 Annotations Source(R"cpp(
1125 #include "foo.h"
1126 int func() {
1127 // This makes sure we have func from header in the AST.
1128 }
1129 int a = fun^
1130 )cpp");
1131 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1132 // We need to wait for preamble to build.
1133 ASSERT_TRUE(Server.blockUntilIdleForTest());
1134
1135 // Change the header file. Completion will reuse the old preamble!
1136 FS.Files[FooH] = R"cpp(
1137 int func();
1138 )cpp";
1139
1140 clangd::CodeCompleteOptions Opts;
1141 Opts.IncludeComments = true;
Sam McCalle746a2b2018-07-02 11:13:16 +00001142 CodeCompleteResult Completions =
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001143 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1144 // We shouldn't crash. Unfortunately, current workaround is to not produce
1145 // comments for symbols from headers.
Sam McCalle746a2b2018-07-02 11:13:16 +00001146 EXPECT_THAT(Completions.Completions,
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001147 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1148}
1149
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001150TEST(CompletionTest, NonDocComments) {
1151 MockFSProvider FS;
1152 auto FooCpp = testPath("foo.cpp");
1153 FS.Files[FooCpp] = "";
1154
1155 MockCompilationDatabase CDB;
1156 IgnoreDiagnostics DiagConsumer;
1157 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1158
1159 Annotations Source(R"cpp(
Ilya Biryukovda8dd8b2018-06-27 09:47:20 +00001160 // We ignore namespace comments, for rationale see CodeCompletionStrings.h.
1161 namespace comments_ns {
1162 }
1163
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001164 // ------------------
1165 int comments_foo();
1166
1167 // A comment and a decl are separated by newlines.
1168 // Therefore, the comment shouldn't show up as doc comment.
1169
1170 int comments_bar();
1171
1172 // this comment should be in the results.
1173 int comments_baz();
1174
1175
1176 template <class T>
1177 struct Struct {
1178 int comments_qux();
1179 int comments_quux();
1180 };
1181
1182
1183 // This comment should not be there.
1184
1185 template <class T>
1186 int Struct<T>::comments_qux() {
1187 }
1188
1189 // This comment **should** be in results.
1190 template <class T>
1191 int Struct<T>::comments_quux() {
1192 int a = comments^;
1193 }
1194 )cpp");
Reid Kleckner80274b12018-06-18 18:55:10 +00001195 // FIXME: Auto-completion in a template requires disabling delayed template
1196 // parsing.
1197 CDB.ExtraClangFlags.push_back("-fno-delayed-template-parsing");
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001198 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
Sam McCalle746a2b2018-07-02 11:13:16 +00001199 CodeCompleteResult Completions = cantFail(runCodeComplete(
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001200 Server, FooCpp, Source.point(), clangd::CodeCompleteOptions()));
1201
1202 // We should not get any of those comments in completion.
1203 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001204 Completions.Completions,
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001205 UnorderedElementsAre(AllOf(Not(IsDocumented()), Named("comments_foo")),
1206 AllOf(IsDocumented(), Named("comments_baz")),
1207 AllOf(IsDocumented(), Named("comments_quux")),
Ilya Biryukovda8dd8b2018-06-27 09:47:20 +00001208 AllOf(Not(IsDocumented()), Named("comments_ns")),
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001209 // FIXME(ibiryukov): the following items should have
1210 // empty documentation, since they are separated from
1211 // a comment with an empty line. Unfortunately, I
1212 // couldn't make Sema tests pass if we ignore those.
1213 AllOf(IsDocumented(), Named("comments_bar")),
1214 AllOf(IsDocumented(), Named("comments_qux"))));
1215}
1216
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001217TEST(CompletionTest, CompleteOnInvalidLine) {
1218 auto FooCpp = testPath("foo.cpp");
1219
1220 MockCompilationDatabase CDB;
1221 IgnoreDiagnostics DiagConsumer;
1222 MockFSProvider FS;
1223 FS.Files[FooCpp] = "// empty file";
1224
1225 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1226 // Run completion outside the file range.
1227 Position Pos;
1228 Pos.line = 100;
1229 Pos.character = 0;
1230 EXPECT_THAT_EXPECTED(
1231 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1232 Failed());
1233}
1234
Eric Liu7ad16962018-06-22 10:46:59 +00001235TEST(CompletionTest, QualifiedNames) {
1236 auto Results = completions(
1237 R"cpp(
1238 namespace ns { int local; void both(); }
1239 void f() { ::ns::^ }
1240 )cpp",
1241 {func("ns::both"), cls("ns::Index")});
1242 // We get results from both index and sema, with no duplicates.
Sam McCalle746a2b2018-07-02 11:13:16 +00001243 EXPECT_THAT(
1244 Results.Completions,
1245 UnorderedElementsAre(Scope("ns::"), Scope("ns::"), Scope("ns::")));
1246}
1247
1248TEST(CompletionTest, Render) {
1249 CodeCompletion C;
1250 C.Name = "x";
1251 C.Signature = "(bool) const";
1252 C.SnippetSuffix = "(${0:bool})";
1253 C.ReturnType = "int";
1254 C.RequiredQualifier = "Foo::";
1255 C.Scope = "ns::Foo::";
1256 C.Documentation = "This is x().";
1257 C.Header = "\"foo.h\"";
1258 C.Kind = CompletionItemKind::Method;
1259 C.Score.Total = 1.0;
Sam McCall2161ec72018-07-05 06:20:41 +00001260 C.Origin =
1261 static_cast<SymbolOrigin>(SymbolOrigin::AST | SymbolOrigin::Static);
Sam McCalle746a2b2018-07-02 11:13:16 +00001262
1263 CodeCompleteOptions Opts;
1264 Opts.IncludeIndicator.Insert = "^";
1265 Opts.IncludeIndicator.NoInsert = "";
1266 Opts.EnableSnippets = false;
1267
1268 auto R = C.render(Opts);
1269 EXPECT_EQ(R.label, "Foo::x(bool) const");
1270 EXPECT_EQ(R.insertText, "Foo::x");
1271 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText);
1272 EXPECT_EQ(R.filterText, "x");
1273 EXPECT_EQ(R.detail, "int\n\"foo.h\"");
1274 EXPECT_EQ(R.documentation, "This is x().");
1275 EXPECT_THAT(R.additionalTextEdits, IsEmpty());
Sam McCalle746a2b2018-07-02 11:13:16 +00001276 EXPECT_EQ(R.sortText, sortText(1.0, "x"));
1277
1278 Opts.EnableSnippets = true;
1279 R = C.render(Opts);
1280 EXPECT_EQ(R.insertText, "Foo::x(${0:bool})");
1281 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet);
1282
1283 C.HeaderInsertion.emplace();
1284 R = C.render(Opts);
1285 EXPECT_EQ(R.label, "^Foo::x(bool) const");
1286 EXPECT_THAT(R.additionalTextEdits, Not(IsEmpty()));
1287
Sam McCall2161ec72018-07-05 06:20:41 +00001288 Opts.ShowOrigins = true;
1289 R = C.render(Opts);
1290 EXPECT_EQ(R.label, "^[AS]Foo::x(bool) const");
1291
Sam McCalle746a2b2018-07-02 11:13:16 +00001292 C.BundleSize = 2;
1293 R = C.render(Opts);
1294 EXPECT_EQ(R.detail, "[2 overloads]\n\"foo.h\"");
Eric Liu7ad16962018-06-22 10:46:59 +00001295}
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001296
Sam McCall9aad25f2017-12-05 07:20:26 +00001297} // namespace
1298} // namespace clangd
1299} // namespace clang