blob: fa6a1bae2cdb936e1f35629a4071ef5ae363c9a4 [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
Eric Liu485074f2018-07-11 13:15:31 +0000790TEST(CompletionTest, IgnoreCompleteInExcludedPPBranchWithRecoveryContext) {
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000791 auto Results = completions(R"cpp(
792 int bar(int param_in_bar) {
793 }
794
795 int foo(int param_in_foo) {
796#if 0
Eric Liu485074f2018-07-11 13:15:31 +0000797 // In recorvery mode, "param_in_foo" will also be suggested among many other
798 // unrelated symbols; however, this is really a special case where this works.
799 // If the #if block is outside of the function, "param_in_foo" is still
800 // suggested, but "bar" and "foo" are missing. So the recovery mode doesn't
801 // really provide useful results in excluded branches.
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000802 par^
803#endif
804 }
805)cpp");
806
Eric Liu485074f2018-07-11 13:15:31 +0000807 EXPECT_TRUE(Results.Completions.empty());
Ilya Biryukov94da7bd2018-03-16 15:23:44 +0000808}
809
Sam McCall800d4372017-12-19 10:29:27 +0000810SignatureHelp signatures(StringRef Text) {
811 MockFSProvider FS;
812 MockCompilationDatabase CDB;
813 IgnoreDiagnostics DiagConsumer;
Sam McCall7363a2f2018-03-05 17:28:54 +0000814 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
Sam McCallc1568062018-02-16 09:41:43 +0000815 auto File = testPath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000816 Annotations Test(Text);
Sam McCall7363a2f2018-03-05 17:28:54 +0000817 runAddDocument(Server, File, Test.code());
Sam McCalla7bb0cc2018-03-12 23:22:35 +0000818 return cantFail(runSignatureHelp(Server, File, Test.point()));
Sam McCall800d4372017-12-19 10:29:27 +0000819}
820
821MATCHER_P(ParamsAre, P, "") {
822 if (P.size() != arg.parameters.size())
823 return false;
824 for (unsigned I = 0; I < P.size(); ++I)
825 if (P[I] != arg.parameters[I].label)
826 return false;
827 return true;
828}
829
830Matcher<SignatureInformation> Sig(std::string Label,
831 std::vector<std::string> Params) {
Eric Liu8f3678d2018-06-15 13:34:18 +0000832 return AllOf(SigHelpLabeled(Label), ParamsAre(Params));
Sam McCall800d4372017-12-19 10:29:27 +0000833}
834
835TEST(SignatureHelpTest, Overloads) {
836 auto Results = signatures(R"cpp(
837 void foo(int x, int y);
838 void foo(int x, float y);
839 void foo(float x, int y);
840 void foo(float x, float y);
841 void bar(int x, int y = 0);
842 int main() { foo(^); }
843 )cpp");
844 EXPECT_THAT(Results.signatures,
845 UnorderedElementsAre(
846 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
847 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
848 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
849 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
850 // We always prefer the first signature.
851 EXPECT_EQ(0, Results.activeSignature);
852 EXPECT_EQ(0, Results.activeParameter);
853}
854
855TEST(SignatureHelpTest, DefaultArgs) {
856 auto Results = signatures(R"cpp(
857 void bar(int x, int y = 0);
858 void bar(float x = 0, int y = 42);
859 int main() { bar(^
860 )cpp");
861 EXPECT_THAT(Results.signatures,
862 UnorderedElementsAre(
863 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
864 Sig("bar(float x = 0, int y = 42) -> void",
865 {"float x = 0", "int y = 42"})));
866 EXPECT_EQ(0, Results.activeSignature);
867 EXPECT_EQ(0, Results.activeParameter);
868}
869
870TEST(SignatureHelpTest, ActiveArg) {
871 auto Results = signatures(R"cpp(
872 int baz(int a, int b, int c);
873 int main() { baz(baz(1,2,3), ^); }
874 )cpp");
875 EXPECT_THAT(Results.signatures,
876 ElementsAre(Sig("baz(int a, int b, int c) -> int",
877 {"int a", "int b", "int c"})));
878 EXPECT_EQ(0, Results.activeSignature);
879 EXPECT_EQ(1, Results.activeParameter);
880}
881
Haojian Wu061c73e2018-01-23 11:37:26 +0000882class IndexRequestCollector : public SymbolIndex {
883public:
884 bool
Sam McCalld1a7a372018-01-31 13:40:48 +0000885 fuzzyFind(const FuzzyFindRequest &Req,
Haojian Wu061c73e2018-01-23 11:37:26 +0000886 llvm::function_ref<void(const Symbol &)> Callback) const override {
887 Requests.push_back(Req);
Sam McCallab8e3932018-02-19 13:04:41 +0000888 return true;
Haojian Wu061c73e2018-01-23 11:37:26 +0000889 }
890
Eric Liu9ec459f2018-03-14 09:48:05 +0000891 void lookup(const LookupRequest &,
892 llvm::function_ref<void(const Symbol &)>) const override {}
893
Haojian Wu061c73e2018-01-23 11:37:26 +0000894 const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
895
896private:
897 mutable std::vector<FuzzyFindRequest> Requests;
898};
899
900std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
901 clangd::CodeCompleteOptions Opts;
902 IndexRequestCollector Requests;
903 Opts.Index = &Requests;
904 completions(Code, {}, Opts);
905 return Requests.allRequests();
906}
907
908TEST(CompletionTest, UnqualifiedIdQuery) {
909 auto Requests = captureIndexRequests(R"cpp(
910 namespace std {}
911 using namespace std;
912 namespace ns {
913 void f() {
914 vec^
915 }
916 }
917 )cpp");
918
919 EXPECT_THAT(Requests,
920 ElementsAre(Field(&FuzzyFindRequest::Scopes,
921 UnorderedElementsAre("", "ns::", "std::"))));
922}
923
924TEST(CompletionTest, ResolvedQualifiedIdQuery) {
925 auto Requests = captureIndexRequests(R"cpp(
926 namespace ns1 {}
927 namespace ns2 {} // ignore
928 namespace ns3 { namespace nns3 {} }
929 namespace foo {
930 using namespace ns1;
931 using namespace ns3::nns3;
932 }
933 namespace ns {
934 void f() {
935 foo::^
936 }
937 }
938 )cpp");
939
940 EXPECT_THAT(Requests,
941 ElementsAre(Field(
942 &FuzzyFindRequest::Scopes,
943 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
944}
945
946TEST(CompletionTest, UnresolvedQualifierIdQuery) {
947 auto Requests = captureIndexRequests(R"cpp(
948 namespace a {}
949 using namespace a;
950 namespace ns {
951 void f() {
952 bar::^
953 }
954 } // namespace ns
955 )cpp");
956
957 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
958 UnorderedElementsAre("bar::"))));
959}
960
961TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
962 auto Requests = captureIndexRequests(R"cpp(
963 namespace a {}
964 using namespace a;
965 namespace ns {
966 void f() {
967 ::a::bar::^
968 }
969 } // namespace ns
970 )cpp");
971
972 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
973 UnorderedElementsAre("a::bar::"))));
974}
975
976TEST(CompletionTest, EmptyQualifiedQuery) {
977 auto Requests = captureIndexRequests(R"cpp(
978 namespace ns {
979 void f() {
980 ^
981 }
982 } // namespace ns
983 )cpp");
984
985 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
986 UnorderedElementsAre("", "ns::"))));
987}
988
989TEST(CompletionTest, GlobalQualifiedQuery) {
990 auto Requests = captureIndexRequests(R"cpp(
991 namespace ns {
992 void f() {
993 ::^
994 }
995 } // namespace ns
996 )cpp");
997
998 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
999 UnorderedElementsAre(""))));
1000}
1001
Ilya Biryukova907ba42018-05-14 10:50:04 +00001002TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
1003 auto Completions = completions(
1004 R"cpp(
1005 struct Foo {
1006 int SomeNameOfField;
1007 typedef int SomeNameOfTypedefField;
1008 };
1009
1010 Foo::^)cpp",
1011 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
1012
Sam McCalle746a2b2018-07-02 11:13:16 +00001013 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001014 AllOf(Contains(Labeled("SomeNameOfField")),
1015 Contains(Labeled("SomeNameOfTypedefField")),
1016 Not(Contains(Labeled("SomeNameInTheIndex")))));
1017}
1018
1019TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
1020 {
1021 auto Completions = completions(
1022 R"cpp(
1023 template <class T>
1024 void foo() {
1025 T::^
1026 }
1027 )cpp",
1028 {func("::SomeNameInTheIndex")});
1029
Sam McCalle746a2b2018-07-02 11:13:16 +00001030 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001031 Not(Contains(Labeled("SomeNameInTheIndex"))));
1032 }
1033
1034 {
1035 auto Completions = completions(
1036 R"cpp(
1037 template <class T>
1038 void foo() {
1039 T::template Y<int>::^
1040 }
1041 )cpp",
1042 {func("::SomeNameInTheIndex")});
1043
Sam McCalle746a2b2018-07-02 11:13:16 +00001044 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001045 Not(Contains(Labeled("SomeNameInTheIndex"))));
1046 }
1047
1048 {
1049 auto Completions = completions(
1050 R"cpp(
1051 template <class T>
1052 void foo() {
1053 T::foo::^
1054 }
1055 )cpp",
1056 {func("::SomeNameInTheIndex")});
1057
Sam McCalle746a2b2018-07-02 11:13:16 +00001058 EXPECT_THAT(Completions.Completions,
Ilya Biryukova907ba42018-05-14 10:50:04 +00001059 Not(Contains(Labeled("SomeNameInTheIndex"))));
1060 }
1061}
1062
Sam McCallc18c2802018-06-15 11:06:29 +00001063TEST(CompletionTest, OverloadBundling) {
1064 clangd::CodeCompleteOptions Opts;
1065 Opts.BundleOverloads = true;
1066
1067 std::string Context = R"cpp(
1068 struct X {
1069 // Overload with int
1070 int a(int);
1071 // Overload with bool
1072 int a(bool);
1073 int b(float);
1074 };
1075 int GFuncC(int);
1076 int GFuncD(int);
1077 )cpp";
1078
1079 // Member completions are bundled.
Sam McCalle746a2b2018-07-02 11:13:16 +00001080 EXPECT_THAT(completions(Context + "int y = X().^", {}, Opts).Completions,
Sam McCallc18c2802018-06-15 11:06:29 +00001081 UnorderedElementsAre(Labeled("a(…)"), Labeled("b(float)")));
1082
1083 // Non-member completions are bundled, including index+sema.
1084 Symbol NoArgsGFunc = func("GFuncC");
1085 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001086 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
Sam McCallc18c2802018-06-15 11:06:29 +00001087 UnorderedElementsAre(Labeled("GFuncC(…)"), Labeled("GFuncD(int)")));
1088
1089 // Differences in header-to-insert suppress bundling.
1090 Symbol::Details Detail;
1091 std::string DeclFile = URI::createFile(testPath("foo")).toString();
1092 NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile;
1093 Detail.IncludeHeader = "<foo>";
1094 NoArgsGFunc.Detail = &Detail;
1095 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001096 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
1097 UnorderedElementsAre(AllOf(Named("GFuncC"), InsertInclude("<foo>")),
1098 Labeled("GFuncC(int)"), Labeled("GFuncD(int)")));
Sam McCallc18c2802018-06-15 11:06:29 +00001099
1100 // Examine a bundled completion in detail.
Sam McCalle746a2b2018-07-02 11:13:16 +00001101 auto A =
1102 completions(Context + "int y = X().a^", {}, Opts).Completions.front();
1103 EXPECT_EQ(A.Name, "a");
1104 EXPECT_EQ(A.Signature, "(…)");
1105 EXPECT_EQ(A.BundleSize, 2u);
1106 EXPECT_EQ(A.Kind, CompletionItemKind::Method);
1107 EXPECT_EQ(A.ReturnType, "int"); // All overloads return int.
Sam McCallc18c2802018-06-15 11:06:29 +00001108 // For now we just return one of the doc strings arbitrarily.
Sam McCalle746a2b2018-07-02 11:13:16 +00001109 EXPECT_THAT(A.Documentation, AnyOf(HasSubstr("Overload with int"),
Sam McCallc18c2802018-06-15 11:06:29 +00001110 HasSubstr("Overload with bool")));
Sam McCalle746a2b2018-07-02 11:13:16 +00001111 EXPECT_EQ(A.SnippetSuffix, "(${0})");
Sam McCallc18c2802018-06-15 11:06:29 +00001112}
1113
Ilya Biryukov30b04b12018-05-28 09:54:51 +00001114TEST(CompletionTest, DocumentationFromChangedFileCrash) {
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001115 MockFSProvider FS;
1116 auto FooH = testPath("foo.h");
1117 auto FooCpp = testPath("foo.cpp");
1118 FS.Files[FooH] = R"cpp(
1119 // this is my documentation comment.
1120 int func();
1121 )cpp";
1122 FS.Files[FooCpp] = "";
1123
1124 MockCompilationDatabase CDB;
1125 IgnoreDiagnostics DiagConsumer;
1126 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1127
1128 Annotations Source(R"cpp(
1129 #include "foo.h"
1130 int func() {
1131 // This makes sure we have func from header in the AST.
1132 }
1133 int a = fun^
1134 )cpp");
1135 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
1136 // We need to wait for preamble to build.
1137 ASSERT_TRUE(Server.blockUntilIdleForTest());
1138
1139 // Change the header file. Completion will reuse the old preamble!
1140 FS.Files[FooH] = R"cpp(
1141 int func();
1142 )cpp";
1143
1144 clangd::CodeCompleteOptions Opts;
1145 Opts.IncludeComments = true;
Sam McCalle746a2b2018-07-02 11:13:16 +00001146 CodeCompleteResult Completions =
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001147 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
1148 // We shouldn't crash. Unfortunately, current workaround is to not produce
1149 // comments for symbols from headers.
Sam McCalle746a2b2018-07-02 11:13:16 +00001150 EXPECT_THAT(Completions.Completions,
Ilya Biryukovbe0eb8f2018-05-24 14:49:23 +00001151 Contains(AllOf(Not(IsDocumented()), Named("func"))));
1152}
1153
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001154TEST(CompletionTest, NonDocComments) {
1155 MockFSProvider FS;
1156 auto FooCpp = testPath("foo.cpp");
1157 FS.Files[FooCpp] = "";
1158
1159 MockCompilationDatabase CDB;
1160 IgnoreDiagnostics DiagConsumer;
1161 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1162
1163 Annotations Source(R"cpp(
Ilya Biryukovda8dd8b2018-06-27 09:47:20 +00001164 // We ignore namespace comments, for rationale see CodeCompletionStrings.h.
1165 namespace comments_ns {
1166 }
1167
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001168 // ------------------
1169 int comments_foo();
1170
1171 // A comment and a decl are separated by newlines.
1172 // Therefore, the comment shouldn't show up as doc comment.
1173
1174 int comments_bar();
1175
1176 // this comment should be in the results.
1177 int comments_baz();
1178
1179
1180 template <class T>
1181 struct Struct {
1182 int comments_qux();
1183 int comments_quux();
1184 };
1185
1186
1187 // This comment should not be there.
1188
1189 template <class T>
1190 int Struct<T>::comments_qux() {
1191 }
1192
1193 // This comment **should** be in results.
1194 template <class T>
1195 int Struct<T>::comments_quux() {
1196 int a = comments^;
1197 }
1198 )cpp");
Reid Kleckner80274b12018-06-18 18:55:10 +00001199 // FIXME: Auto-completion in a template requires disabling delayed template
1200 // parsing.
1201 CDB.ExtraClangFlags.push_back("-fno-delayed-template-parsing");
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001202 Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
Sam McCalle746a2b2018-07-02 11:13:16 +00001203 CodeCompleteResult Completions = cantFail(runCodeComplete(
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001204 Server, FooCpp, Source.point(), clangd::CodeCompleteOptions()));
1205
1206 // We should not get any of those comments in completion.
1207 EXPECT_THAT(
Sam McCalle746a2b2018-07-02 11:13:16 +00001208 Completions.Completions,
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001209 UnorderedElementsAre(AllOf(Not(IsDocumented()), Named("comments_foo")),
1210 AllOf(IsDocumented(), Named("comments_baz")),
1211 AllOf(IsDocumented(), Named("comments_quux")),
Ilya Biryukovda8dd8b2018-06-27 09:47:20 +00001212 AllOf(Not(IsDocumented()), Named("comments_ns")),
Ilya Biryukov89fcf6b2018-06-15 08:31:17 +00001213 // FIXME(ibiryukov): the following items should have
1214 // empty documentation, since they are separated from
1215 // a comment with an empty line. Unfortunately, I
1216 // couldn't make Sema tests pass if we ignore those.
1217 AllOf(IsDocumented(), Named("comments_bar")),
1218 AllOf(IsDocumented(), Named("comments_qux"))));
1219}
1220
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001221TEST(CompletionTest, CompleteOnInvalidLine) {
1222 auto FooCpp = testPath("foo.cpp");
1223
1224 MockCompilationDatabase CDB;
1225 IgnoreDiagnostics DiagConsumer;
1226 MockFSProvider FS;
1227 FS.Files[FooCpp] = "// empty file";
1228
1229 ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1230 // Run completion outside the file range.
1231 Position Pos;
1232 Pos.line = 100;
1233 Pos.character = 0;
1234 EXPECT_THAT_EXPECTED(
1235 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
1236 Failed());
1237}
1238
Eric Liu7ad16962018-06-22 10:46:59 +00001239TEST(CompletionTest, QualifiedNames) {
1240 auto Results = completions(
1241 R"cpp(
1242 namespace ns { int local; void both(); }
1243 void f() { ::ns::^ }
1244 )cpp",
1245 {func("ns::both"), cls("ns::Index")});
1246 // We get results from both index and sema, with no duplicates.
Sam McCalle746a2b2018-07-02 11:13:16 +00001247 EXPECT_THAT(
1248 Results.Completions,
1249 UnorderedElementsAre(Scope("ns::"), Scope("ns::"), Scope("ns::")));
1250}
1251
1252TEST(CompletionTest, Render) {
1253 CodeCompletion C;
1254 C.Name = "x";
1255 C.Signature = "(bool) const";
1256 C.SnippetSuffix = "(${0:bool})";
1257 C.ReturnType = "int";
1258 C.RequiredQualifier = "Foo::";
1259 C.Scope = "ns::Foo::";
1260 C.Documentation = "This is x().";
1261 C.Header = "\"foo.h\"";
1262 C.Kind = CompletionItemKind::Method;
1263 C.Score.Total = 1.0;
Sam McCall4e5742a2018-07-06 11:50:49 +00001264 C.Origin = SymbolOrigin::AST | SymbolOrigin::Static;
Sam McCalle746a2b2018-07-02 11:13:16 +00001265
1266 CodeCompleteOptions Opts;
1267 Opts.IncludeIndicator.Insert = "^";
1268 Opts.IncludeIndicator.NoInsert = "";
1269 Opts.EnableSnippets = false;
1270
1271 auto R = C.render(Opts);
1272 EXPECT_EQ(R.label, "Foo::x(bool) const");
1273 EXPECT_EQ(R.insertText, "Foo::x");
1274 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText);
1275 EXPECT_EQ(R.filterText, "x");
1276 EXPECT_EQ(R.detail, "int\n\"foo.h\"");
1277 EXPECT_EQ(R.documentation, "This is x().");
1278 EXPECT_THAT(R.additionalTextEdits, IsEmpty());
Sam McCalle746a2b2018-07-02 11:13:16 +00001279 EXPECT_EQ(R.sortText, sortText(1.0, "x"));
1280
1281 Opts.EnableSnippets = true;
1282 R = C.render(Opts);
1283 EXPECT_EQ(R.insertText, "Foo::x(${0:bool})");
1284 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet);
1285
1286 C.HeaderInsertion.emplace();
1287 R = C.render(Opts);
1288 EXPECT_EQ(R.label, "^Foo::x(bool) const");
1289 EXPECT_THAT(R.additionalTextEdits, Not(IsEmpty()));
1290
Sam McCall2161ec72018-07-05 06:20:41 +00001291 Opts.ShowOrigins = true;
1292 R = C.render(Opts);
1293 EXPECT_EQ(R.label, "^[AS]Foo::x(bool) const");
1294
Sam McCalle746a2b2018-07-02 11:13:16 +00001295 C.BundleSize = 2;
1296 R = C.render(Opts);
1297 EXPECT_EQ(R.detail, "[2 overloads]\n\"foo.h\"");
Eric Liu7ad16962018-06-22 10:46:59 +00001298}
Ilya Biryukov981a35d2018-05-28 12:11:37 +00001299
Eric Liu485074f2018-07-11 13:15:31 +00001300TEST(CompletionTest, IgnoreRecoveryResults) {
1301 auto Results = completions(
1302 R"cpp(
1303 namespace ns { int NotRecovered() { return 0; } }
1304 void f() {
1305 // Sema enters recovery mode first and then normal mode.
1306 if (auto x = ns::NotRecover^)
1307 }
1308 )cpp");
1309 EXPECT_THAT(Results.Completions, UnorderedElementsAre(Named("NotRecovered")));
1310}
1311
Eric Liuf433c2d2018-07-18 15:31:14 +00001312TEST(CompletionTest, ScopeOfClassFieldInConstructorInitializer) {
1313 auto Results = completions(
1314 R"cpp(
1315 namespace ns {
1316 class X { public: X(); int x_; };
1317 X::X() : x_^(0) {}
1318 }
1319 )cpp");
1320 EXPECT_THAT(Results.Completions,
1321 UnorderedElementsAre(AllOf(Scope("ns::X::"), Named("x_"))));
1322}
1323
Sam McCall9aad25f2017-12-05 07:20:26 +00001324} // namespace
1325} // namespace clangd
1326} // namespace clang