1 //===-- ClangdTests.cpp - Clangd unit tests ---------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Annotations.h"
10 #include "ClangdLSPServer.h"
11 #include "ClangdServer.h"
12 #include "CodeComplete.h"
13 #include "GlobalCompilationDatabase.h"
14 #include "Matchers.h"
15 #include "SyncAPI.h"
16 #include "TestFS.h"
17 #include "Threading.h"
18 #include "URI.h"
19 #include "clang/Config/config.h"
20 #include "clang/Sema/CodeCompleteConsumer.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/ADT/StringMap.h"
23 #include "llvm/Support/Errc.h"
24 #include "llvm/Support/Path.h"
25 #include "llvm/Support/Regex.h"
26 #include "gmock/gmock.h"
27 #include "gtest/gtest.h"
28 #include <algorithm>
29 #include <chrono>
30 #include <iostream>
31 #include <random>
32 #include <string>
33 #include <thread>
34 #include <vector>
35 
36 namespace clang {
37 namespace clangd {
38 
39 namespace {
40 
41 using ::testing::ElementsAre;
42 using ::testing::Field;
43 using ::testing::Gt;
44 using ::testing::IsEmpty;
45 using ::testing::Pair;
46 using ::testing::UnorderedElementsAre;
47 
48 MATCHER_P2(DeclAt, File, Range, "") {
49   return arg.PreferredDeclaration ==
50          Location{URIForFile::canonicalize(File, testRoot()), Range};
51 }
52 
diagsContainErrors(const std::vector<Diag> & Diagnostics)53 bool diagsContainErrors(const std::vector<Diag> &Diagnostics) {
54   for (auto D : Diagnostics) {
55     if (D.Severity == DiagnosticsEngine::Error ||
56         D.Severity == DiagnosticsEngine::Fatal)
57       return true;
58   }
59   return false;
60 }
61 
62 class ErrorCheckingDiagConsumer : public DiagnosticsConsumer {
63 public:
onDiagnosticsReady(PathRef File,std::vector<Diag> Diagnostics)64   void onDiagnosticsReady(PathRef File,
65                           std::vector<Diag> Diagnostics) override {
66     bool HadError = diagsContainErrors(Diagnostics);
67     std::lock_guard<std::mutex> Lock(Mutex);
68     HadErrorInLastDiags = HadError;
69   }
70 
hadErrorInLastDiags()71   bool hadErrorInLastDiags() {
72     std::lock_guard<std::mutex> Lock(Mutex);
73     return HadErrorInLastDiags;
74   }
75 
76 private:
77   std::mutex Mutex;
78   bool HadErrorInLastDiags = false;
79 };
80 
81 /// For each file, record whether the last published diagnostics contained at
82 /// least one error.
83 class MultipleErrorCheckingDiagConsumer : public DiagnosticsConsumer {
84 public:
onDiagnosticsReady(PathRef File,std::vector<Diag> Diagnostics)85   void onDiagnosticsReady(PathRef File,
86                           std::vector<Diag> Diagnostics) override {
87     bool HadError = diagsContainErrors(Diagnostics);
88 
89     std::lock_guard<std::mutex> Lock(Mutex);
90     LastDiagsHadError[File] = HadError;
91   }
92 
93   /// Exposes all files consumed by onDiagnosticsReady in an unspecified order.
94   /// For each file, a bool value indicates whether the last diagnostics
95   /// contained an error.
filesWithDiags() const96   std::vector<std::pair<Path, bool>> filesWithDiags() const {
97     std::vector<std::pair<Path, bool>> Result;
98     std::lock_guard<std::mutex> Lock(Mutex);
99     for (const auto &It : LastDiagsHadError)
100       Result.emplace_back(It.first(), It.second);
101     return Result;
102   }
103 
clear()104   void clear() {
105     std::lock_guard<std::mutex> Lock(Mutex);
106     LastDiagsHadError.clear();
107   }
108 
109 private:
110   mutable std::mutex Mutex;
111   llvm::StringMap<bool> LastDiagsHadError;
112 };
113 
114 /// Replaces all patterns of the form 0x123abc with spaces
replacePtrsInDump(std::string const & Dump)115 std::string replacePtrsInDump(std::string const &Dump) {
116   llvm::Regex RE("0x[0-9a-fA-F]+");
117   llvm::SmallVector<llvm::StringRef, 1> Matches;
118   llvm::StringRef Pending = Dump;
119 
120   std::string Result;
121   while (RE.match(Pending, &Matches)) {
122     assert(Matches.size() == 1 && "Exactly one match expected");
123     auto MatchPos = Matches[0].data() - Pending.data();
124 
125     Result += Pending.take_front(MatchPos);
126     Pending = Pending.drop_front(MatchPos + Matches[0].size());
127   }
128   Result += Pending;
129 
130   return Result;
131 }
132 
dumpASTWithoutMemoryLocs(ClangdServer & Server,PathRef File)133 std::string dumpASTWithoutMemoryLocs(ClangdServer &Server, PathRef File) {
134   auto DumpWithMemLocs = runDumpAST(Server, File);
135   return replacePtrsInDump(DumpWithMemLocs);
136 }
137 
138 class ClangdVFSTest : public ::testing::Test {
139 protected:
parseSourceAndDumpAST(PathRef SourceFileRelPath,llvm::StringRef SourceContents,std::vector<std::pair<PathRef,llvm::StringRef>> ExtraFiles={},bool ExpectErrors=false)140   std::string parseSourceAndDumpAST(
141       PathRef SourceFileRelPath, llvm::StringRef SourceContents,
142       std::vector<std::pair<PathRef, llvm::StringRef>> ExtraFiles = {},
143       bool ExpectErrors = false) {
144     MockFSProvider FS;
145     ErrorCheckingDiagConsumer DiagConsumer;
146     MockCompilationDatabase CDB;
147     ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
148     for (const auto &FileWithContents : ExtraFiles)
149       FS.Files[testPath(FileWithContents.first)] = FileWithContents.second;
150 
151     auto SourceFilename = testPath(SourceFileRelPath);
152     Server.addDocument(SourceFilename, SourceContents);
153     auto Result = dumpASTWithoutMemoryLocs(Server, SourceFilename);
154     EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
155     EXPECT_EQ(ExpectErrors, DiagConsumer.hadErrorInLastDiags());
156     return Result;
157   }
158 };
159 
TEST_F(ClangdVFSTest,Parse)160 TEST_F(ClangdVFSTest, Parse) {
161   // FIXME: figure out a stable format for AST dumps, so that we can check the
162   // output of the dump itself is equal to the expected one, not just that it's
163   // different.
164   auto Empty = parseSourceAndDumpAST("foo.cpp", "", {});
165   auto OneDecl = parseSourceAndDumpAST("foo.cpp", "int a;", {});
166   auto SomeDecls = parseSourceAndDumpAST("foo.cpp", "int a; int b; int c;", {});
167   EXPECT_NE(Empty, OneDecl);
168   EXPECT_NE(Empty, SomeDecls);
169   EXPECT_NE(SomeDecls, OneDecl);
170 
171   auto Empty2 = parseSourceAndDumpAST("foo.cpp", "");
172   auto OneDecl2 = parseSourceAndDumpAST("foo.cpp", "int a;");
173   auto SomeDecls2 = parseSourceAndDumpAST("foo.cpp", "int a; int b; int c;");
174   EXPECT_EQ(Empty, Empty2);
175   EXPECT_EQ(OneDecl, OneDecl2);
176   EXPECT_EQ(SomeDecls, SomeDecls2);
177 }
178 
TEST_F(ClangdVFSTest,ParseWithHeader)179 TEST_F(ClangdVFSTest, ParseWithHeader) {
180   parseSourceAndDumpAST("foo.cpp", "#include \"foo.h\"", {},
181                         /*ExpectErrors=*/true);
182   parseSourceAndDumpAST("foo.cpp", "#include \"foo.h\"", {{"foo.h", ""}},
183                         /*ExpectErrors=*/false);
184 
185   const auto SourceContents = R"cpp(
186 #include "foo.h"
187 int b = a;
188 )cpp";
189   parseSourceAndDumpAST("foo.cpp", SourceContents, {{"foo.h", ""}},
190                         /*ExpectErrors=*/true);
191   parseSourceAndDumpAST("foo.cpp", SourceContents, {{"foo.h", "int a;"}},
192                         /*ExpectErrors=*/false);
193 }
194 
TEST_F(ClangdVFSTest,Reparse)195 TEST_F(ClangdVFSTest, Reparse) {
196   MockFSProvider FS;
197   ErrorCheckingDiagConsumer DiagConsumer;
198   MockCompilationDatabase CDB;
199   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
200 
201   const auto SourceContents = R"cpp(
202 #include "foo.h"
203 int b = a;
204 )cpp";
205 
206   auto FooCpp = testPath("foo.cpp");
207 
208   FS.Files[testPath("foo.h")] = "int a;";
209   FS.Files[FooCpp] = SourceContents;
210 
211   Server.addDocument(FooCpp, SourceContents);
212   auto DumpParse1 = dumpASTWithoutMemoryLocs(Server, FooCpp);
213   ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
214   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
215 
216   Server.addDocument(FooCpp, "");
217   auto DumpParseEmpty = dumpASTWithoutMemoryLocs(Server, FooCpp);
218   ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
219   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
220 
221   Server.addDocument(FooCpp, SourceContents);
222   auto DumpParse2 = dumpASTWithoutMemoryLocs(Server, FooCpp);
223   ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
224   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
225 
226   EXPECT_EQ(DumpParse1, DumpParse2);
227   EXPECT_NE(DumpParse1, DumpParseEmpty);
228 }
229 
TEST_F(ClangdVFSTest,ReparseOnHeaderChange)230 TEST_F(ClangdVFSTest, ReparseOnHeaderChange) {
231   MockFSProvider FS;
232   ErrorCheckingDiagConsumer DiagConsumer;
233   MockCompilationDatabase CDB;
234   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
235 
236   const auto SourceContents = R"cpp(
237 #include "foo.h"
238 int b = a;
239 )cpp";
240 
241   auto FooCpp = testPath("foo.cpp");
242   auto FooH = testPath("foo.h");
243 
244   FS.Files[FooH] = "int a;";
245   FS.Files[FooCpp] = SourceContents;
246 
247   Server.addDocument(FooCpp, SourceContents);
248   auto DumpParse1 = dumpASTWithoutMemoryLocs(Server, FooCpp);
249   ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
250   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
251 
252   FS.Files[FooH] = "";
253   Server.addDocument(FooCpp, SourceContents);
254   auto DumpParseDifferent = dumpASTWithoutMemoryLocs(Server, FooCpp);
255   ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
256   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
257 
258   FS.Files[FooH] = "int a;";
259   Server.addDocument(FooCpp, SourceContents);
260   auto DumpParse2 = dumpASTWithoutMemoryLocs(Server, FooCpp);
261   ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
262   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
263 
264   EXPECT_EQ(DumpParse1, DumpParse2);
265   EXPECT_NE(DumpParse1, DumpParseDifferent);
266 }
267 
TEST_F(ClangdVFSTest,PropagatesContexts)268 TEST_F(ClangdVFSTest, PropagatesContexts) {
269   static Key<int> Secret;
270   struct FSProvider : public FileSystemProvider {
271     IntrusiveRefCntPtr<llvm::vfs::FileSystem> getFileSystem() const override {
272       Got = Context::current().getExisting(Secret);
273       return buildTestFS({});
274     }
275     mutable int Got;
276   } FS;
277   struct DiagConsumer : public DiagnosticsConsumer {
278     void onDiagnosticsReady(PathRef File,
279                             std::vector<Diag> Diagnostics) override {
280       Got = Context::current().getExisting(Secret);
281     }
282     int Got;
283   } DiagConsumer;
284   MockCompilationDatabase CDB;
285 
286   // Verify that the context is plumbed to the FS provider and diagnostics.
287   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
288   {
289     WithContextValue Entrypoint(Secret, 42);
290     Server.addDocument(testPath("foo.cpp"), "void main(){}");
291   }
292   ASSERT_TRUE(Server.blockUntilIdleForTest());
293   EXPECT_EQ(FS.Got, 42);
294   EXPECT_EQ(DiagConsumer.Got, 42);
295 }
296 
297 // Only enable this test on Unix
298 #ifdef LLVM_ON_UNIX
TEST_F(ClangdVFSTest,SearchLibDir)299 TEST_F(ClangdVFSTest, SearchLibDir) {
300   // Checks that searches for GCC installation is done through vfs.
301   MockFSProvider FS;
302   ErrorCheckingDiagConsumer DiagConsumer;
303   MockCompilationDatabase CDB;
304   CDB.ExtraClangFlags.insert(CDB.ExtraClangFlags.end(),
305                              {"-xc++", "-target", "x86_64-linux-unknown",
306                               "-m64", "--gcc-toolchain=/randomusr",
307                               "-stdlib=libstdc++"});
308   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
309 
310   // Just a random gcc version string
311   SmallString<8> Version("4.9.3");
312 
313   // A lib dir for gcc installation
314   SmallString<64> LibDir("/randomusr/lib/gcc/x86_64-linux-gnu");
315   llvm::sys::path::append(LibDir, Version);
316 
317   // Put crtbegin.o into LibDir/64 to trick clang into thinking there's a gcc
318   // installation there.
319   SmallString<64> DummyLibFile;
320   llvm::sys::path::append(DummyLibFile, LibDir, "64", "crtbegin.o");
321   FS.Files[DummyLibFile] = "";
322 
323   SmallString<64> IncludeDir("/randomusr/include/c++");
324   llvm::sys::path::append(IncludeDir, Version);
325 
326   SmallString<64> StringPath;
327   llvm::sys::path::append(StringPath, IncludeDir, "string");
328   FS.Files[StringPath] = "class mock_string {};";
329 
330   auto FooCpp = testPath("foo.cpp");
331   const auto SourceContents = R"cpp(
332 #include <string>
333 mock_string x;
334 )cpp";
335   FS.Files[FooCpp] = SourceContents;
336 
337   runAddDocument(Server, FooCpp, SourceContents);
338   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
339 
340   const auto SourceContentsWithError = R"cpp(
341 #include <string>
342 std::string x;
343 )cpp";
344   runAddDocument(Server, FooCpp, SourceContentsWithError);
345   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
346 }
347 #endif // LLVM_ON_UNIX
348 
TEST_F(ClangdVFSTest,ForceReparseCompileCommand)349 TEST_F(ClangdVFSTest, ForceReparseCompileCommand) {
350   MockFSProvider FS;
351   ErrorCheckingDiagConsumer DiagConsumer;
352   MockCompilationDatabase CDB;
353   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
354 
355   auto FooCpp = testPath("foo.cpp");
356   const auto SourceContents1 = R"cpp(
357 template <class T>
358 struct foo { T x; };
359 )cpp";
360   const auto SourceContents2 = R"cpp(
361 template <class T>
362 struct bar { T x; };
363 )cpp";
364 
365   FS.Files[FooCpp] = "";
366 
367   // First parse files in C mode and check they produce errors.
368   CDB.ExtraClangFlags = {"-xc"};
369   runAddDocument(Server, FooCpp, SourceContents1);
370   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
371   runAddDocument(Server, FooCpp, SourceContents2);
372   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
373 
374   // Now switch to C++ mode.
375   CDB.ExtraClangFlags = {"-xc++"};
376   runAddDocument(Server, FooCpp, SourceContents2, WantDiagnostics::Auto);
377   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
378   // Subsequent addDocument calls should finish without errors too.
379   runAddDocument(Server, FooCpp, SourceContents1);
380   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
381   runAddDocument(Server, FooCpp, SourceContents2);
382   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
383 }
384 
TEST_F(ClangdVFSTest,ForceReparseCompileCommandDefines)385 TEST_F(ClangdVFSTest, ForceReparseCompileCommandDefines) {
386   MockFSProvider FS;
387   ErrorCheckingDiagConsumer DiagConsumer;
388   MockCompilationDatabase CDB;
389   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
390 
391   auto FooCpp = testPath("foo.cpp");
392   const auto SourceContents = R"cpp(
393 #ifdef WITH_ERROR
394 this
395 #endif
396 
397 int main() { return 0; }
398 )cpp";
399   FS.Files[FooCpp] = "";
400 
401   // Parse with define, we expect to see the errors.
402   CDB.ExtraClangFlags = {"-DWITH_ERROR"};
403   runAddDocument(Server, FooCpp, SourceContents);
404   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
405 
406   // Parse without the define, no errors should be produced.
407   CDB.ExtraClangFlags = {};
408   runAddDocument(Server, FooCpp, SourceContents, WantDiagnostics::Auto);
409   ASSERT_TRUE(Server.blockUntilIdleForTest());
410   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
411   // Subsequent addDocument call should finish without errors too.
412   runAddDocument(Server, FooCpp, SourceContents);
413   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
414 }
415 
416 // Test ClangdServer.reparseOpenedFiles.
TEST_F(ClangdVFSTest,ReparseOpenedFiles)417 TEST_F(ClangdVFSTest, ReparseOpenedFiles) {
418   Annotations FooSource(R"cpp(
419 #ifdef MACRO
420 static void $one[[bob]]() {}
421 #else
422 static void $two[[bob]]() {}
423 #endif
424 
425 int main () { bo^b (); return 0; }
426 )cpp");
427 
428   Annotations BarSource(R"cpp(
429 #ifdef MACRO
430 this is an error
431 #endif
432 )cpp");
433 
434   Annotations BazSource(R"cpp(
435 int hello;
436 )cpp");
437 
438   MockFSProvider FS;
439   MockCompilationDatabase CDB;
440   MultipleErrorCheckingDiagConsumer DiagConsumer;
441   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
442 
443   auto FooCpp = testPath("foo.cpp");
444   auto BarCpp = testPath("bar.cpp");
445   auto BazCpp = testPath("baz.cpp");
446 
447   FS.Files[FooCpp] = "";
448   FS.Files[BarCpp] = "";
449   FS.Files[BazCpp] = "";
450 
451   CDB.ExtraClangFlags = {"-DMACRO=1"};
452   Server.addDocument(FooCpp, FooSource.code());
453   Server.addDocument(BarCpp, BarSource.code());
454   Server.addDocument(BazCpp, BazSource.code());
455   ASSERT_TRUE(Server.blockUntilIdleForTest());
456 
457   EXPECT_THAT(DiagConsumer.filesWithDiags(),
458               UnorderedElementsAre(Pair(FooCpp, false), Pair(BarCpp, true),
459                                    Pair(BazCpp, false)));
460 
461   auto Locations = runLocateSymbolAt(Server, FooCpp, FooSource.point());
462   EXPECT_TRUE(bool(Locations));
463   EXPECT_THAT(*Locations, ElementsAre(DeclAt(FooCpp, FooSource.range("one"))));
464 
465   // Undefine MACRO, close baz.cpp.
466   CDB.ExtraClangFlags.clear();
467   DiagConsumer.clear();
468   Server.removeDocument(BazCpp);
469   Server.addDocument(FooCpp, FooSource.code(), WantDiagnostics::Auto);
470   Server.addDocument(BarCpp, BarSource.code(), WantDiagnostics::Auto);
471   ASSERT_TRUE(Server.blockUntilIdleForTest());
472 
473   EXPECT_THAT(DiagConsumer.filesWithDiags(),
474               UnorderedElementsAre(Pair(FooCpp, false), Pair(BarCpp, false)));
475 
476   Locations = runLocateSymbolAt(Server, FooCpp, FooSource.point());
477   EXPECT_TRUE(bool(Locations));
478   EXPECT_THAT(*Locations, ElementsAre(DeclAt(FooCpp, FooSource.range("two"))));
479 }
480 
TEST_F(ClangdVFSTest,MemoryUsage)481 TEST_F(ClangdVFSTest, MemoryUsage) {
482   MockFSProvider FS;
483   ErrorCheckingDiagConsumer DiagConsumer;
484   MockCompilationDatabase CDB;
485   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
486 
487   Path FooCpp = testPath("foo.cpp");
488   const auto SourceContents = R"cpp(
489 struct Something {
490   int method();
491 };
492 )cpp";
493   Path BarCpp = testPath("bar.cpp");
494 
495   FS.Files[FooCpp] = "";
496   FS.Files[BarCpp] = "";
497 
498   EXPECT_THAT(Server.getUsedBytesPerFile(), IsEmpty());
499 
500   Server.addDocument(FooCpp, SourceContents);
501   Server.addDocument(BarCpp, SourceContents);
502   ASSERT_TRUE(Server.blockUntilIdleForTest());
503 
504   EXPECT_THAT(Server.getUsedBytesPerFile(),
505               UnorderedElementsAre(Pair(FooCpp, Gt(0u)), Pair(BarCpp, Gt(0u))));
506 
507   Server.removeDocument(FooCpp);
508   ASSERT_TRUE(Server.blockUntilIdleForTest());
509   EXPECT_THAT(Server.getUsedBytesPerFile(), ElementsAre(Pair(BarCpp, Gt(0u))));
510 
511   Server.removeDocument(BarCpp);
512   ASSERT_TRUE(Server.blockUntilIdleForTest());
513   EXPECT_THAT(Server.getUsedBytesPerFile(), IsEmpty());
514 }
515 
TEST_F(ClangdVFSTest,InvalidCompileCommand)516 TEST_F(ClangdVFSTest, InvalidCompileCommand) {
517   MockFSProvider FS;
518   ErrorCheckingDiagConsumer DiagConsumer;
519   MockCompilationDatabase CDB;
520 
521   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
522 
523   auto FooCpp = testPath("foo.cpp");
524   // clang cannot create CompilerInvocation if we pass two files in the
525   // CompileCommand. We pass the file in ExtraFlags once and CDB adds another
526   // one in getCompileCommand().
527   CDB.ExtraClangFlags.push_back(FooCpp);
528 
529   // Clang can't parse command args in that case, but we shouldn't crash.
530   runAddDocument(Server, FooCpp, "int main() {}");
531 
532   EXPECT_EQ(runDumpAST(Server, FooCpp), "<no-ast>");
533   EXPECT_ERROR(runLocateSymbolAt(Server, FooCpp, Position()));
534   EXPECT_ERROR(runFindDocumentHighlights(Server, FooCpp, Position()));
535   EXPECT_ERROR(runRename(Server, FooCpp, Position(), "new_name"));
536   // Identifier-based fallback completion.
537   EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, Position(),
538                                        clangd::CodeCompleteOptions()))
539                   .Completions,
540               ElementsAre(Field(&CodeCompletion::Name, "int"),
541                           Field(&CodeCompletion::Name, "main")));
542   auto SigHelp = runSignatureHelp(Server, FooCpp, Position());
543   ASSERT_TRUE(bool(SigHelp)) << "signatureHelp returned an error";
544   EXPECT_THAT(SigHelp->signatures, IsEmpty());
545 }
546 
547 class ClangdThreadingTest : public ClangdVFSTest {};
548 
TEST_F(ClangdThreadingTest,StressTest)549 TEST_F(ClangdThreadingTest, StressTest) {
550   // Without 'static' clang gives an error for a usage inside TestDiagConsumer.
551   static const unsigned FilesCount = 5;
552   const unsigned RequestsCount = 500;
553   // Blocking requests wait for the parsing to complete, they slow down the test
554   // dramatically, so they are issued rarely. Each
555   // BlockingRequestInterval-request will be a blocking one.
556   const unsigned BlockingRequestInterval = 40;
557 
558   const auto SourceContentsWithoutErrors = R"cpp(
559 int a;
560 int b;
561 int c;
562 int d;
563 )cpp";
564 
565   const auto SourceContentsWithErrors = R"cpp(
566 int a = x;
567 int b;
568 int c;
569 int d;
570 )cpp";
571 
572   // Giving invalid line and column number should not crash ClangdServer, but
573   // just to make sure we're sometimes hitting the bounds inside the file we
574   // limit the intervals of line and column number that are generated.
575   unsigned MaxLineForFileRequests = 7;
576   unsigned MaxColumnForFileRequests = 10;
577 
578   std::vector<std::string> FilePaths;
579   MockFSProvider FS;
580   for (unsigned I = 0; I < FilesCount; ++I) {
581     std::string Name = std::string("Foo") + std::to_string(I) + ".cpp";
582     FS.Files[Name] = "";
583     FilePaths.push_back(testPath(Name));
584   }
585 
586   struct FileStat {
587     unsigned HitsWithoutErrors = 0;
588     unsigned HitsWithErrors = 0;
589     bool HadErrorsInLastDiags = false;
590   };
591 
592   class TestDiagConsumer : public DiagnosticsConsumer {
593   public:
594     TestDiagConsumer() : Stats(FilesCount, FileStat()) {}
595 
596     void onDiagnosticsReady(PathRef File,
597                             std::vector<Diag> Diagnostics) override {
598       StringRef FileIndexStr = llvm::sys::path::stem(File);
599       ASSERT_TRUE(FileIndexStr.consume_front("Foo"));
600 
601       unsigned long FileIndex = std::stoul(FileIndexStr.str());
602 
603       bool HadError = diagsContainErrors(Diagnostics);
604 
605       std::lock_guard<std::mutex> Lock(Mutex);
606       if (HadError)
607         Stats[FileIndex].HitsWithErrors++;
608       else
609         Stats[FileIndex].HitsWithoutErrors++;
610       Stats[FileIndex].HadErrorsInLastDiags = HadError;
611     }
612 
613     std::vector<FileStat> takeFileStats() {
614       std::lock_guard<std::mutex> Lock(Mutex);
615       return std::move(Stats);
616     }
617 
618   private:
619     std::mutex Mutex;
620     std::vector<FileStat> Stats;
621   };
622 
623   struct RequestStats {
624     unsigned RequestsWithoutErrors = 0;
625     unsigned RequestsWithErrors = 0;
626     bool LastContentsHadErrors = false;
627     bool FileIsRemoved = true;
628   };
629 
630   std::vector<RequestStats> ReqStats;
631   ReqStats.reserve(FilesCount);
632   for (unsigned FileIndex = 0; FileIndex < FilesCount; ++FileIndex)
633     ReqStats.emplace_back();
634 
635   TestDiagConsumer DiagConsumer;
636   {
637     MockCompilationDatabase CDB;
638     ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
639 
640     // Prepare some random distributions for the test.
641     std::random_device RandGen;
642 
643     std::uniform_int_distribution<unsigned> FileIndexDist(0, FilesCount - 1);
644     // Pass a text that contains compiler errors to addDocument in about 20% of
645     // all requests.
646     std::bernoulli_distribution ShouldHaveErrorsDist(0.2);
647     // Line and Column numbers for requests that need them.
648     std::uniform_int_distribution<int> LineDist(0, MaxLineForFileRequests);
649     std::uniform_int_distribution<int> ColumnDist(0, MaxColumnForFileRequests);
650 
651     // Some helpers.
652     auto UpdateStatsOnAddDocument = [&](unsigned FileIndex, bool HadErrors) {
653       auto &Stats = ReqStats[FileIndex];
654 
655       if (HadErrors)
656         ++Stats.RequestsWithErrors;
657       else
658         ++Stats.RequestsWithoutErrors;
659       Stats.LastContentsHadErrors = HadErrors;
660       Stats.FileIsRemoved = false;
661     };
662 
663     auto UpdateStatsOnRemoveDocument = [&](unsigned FileIndex) {
664       auto &Stats = ReqStats[FileIndex];
665 
666       Stats.FileIsRemoved = true;
667     };
668 
669     auto AddDocument = [&](unsigned FileIndex, bool SkipCache) {
670       bool ShouldHaveErrors = ShouldHaveErrorsDist(RandGen);
671       Server.addDocument(FilePaths[FileIndex],
672                          ShouldHaveErrors ? SourceContentsWithErrors
673                                           : SourceContentsWithoutErrors,
674                          WantDiagnostics::Auto);
675       UpdateStatsOnAddDocument(FileIndex, ShouldHaveErrors);
676     };
677 
678     // Various requests that we would randomly run.
679     auto AddDocumentRequest = [&]() {
680       unsigned FileIndex = FileIndexDist(RandGen);
681       AddDocument(FileIndex, /*SkipCache=*/false);
682     };
683 
684     auto ForceReparseRequest = [&]() {
685       unsigned FileIndex = FileIndexDist(RandGen);
686       AddDocument(FileIndex, /*SkipCache=*/true);
687     };
688 
689     auto RemoveDocumentRequest = [&]() {
690       unsigned FileIndex = FileIndexDist(RandGen);
691       // Make sure we don't violate the ClangdServer's contract.
692       if (ReqStats[FileIndex].FileIsRemoved)
693         AddDocument(FileIndex, /*SkipCache=*/false);
694 
695       Server.removeDocument(FilePaths[FileIndex]);
696       UpdateStatsOnRemoveDocument(FileIndex);
697     };
698 
699     auto CodeCompletionRequest = [&]() {
700       unsigned FileIndex = FileIndexDist(RandGen);
701       // Make sure we don't violate the ClangdServer's contract.
702       if (ReqStats[FileIndex].FileIsRemoved)
703         AddDocument(FileIndex, /*SkipCache=*/false);
704 
705       Position Pos;
706       Pos.line = LineDist(RandGen);
707       Pos.character = ColumnDist(RandGen);
708       // FIXME(ibiryukov): Also test async completion requests.
709       // Simply putting CodeCompletion into async requests now would make
710       // tests slow, since there's no way to cancel previous completion
711       // requests as opposed to AddDocument/RemoveDocument, which are implicitly
712       // cancelled by any subsequent AddDocument/RemoveDocument request to the
713       // same file.
714       cantFail(runCodeComplete(Server, FilePaths[FileIndex], Pos,
715                                clangd::CodeCompleteOptions()));
716     };
717 
718     auto LocateSymbolRequest = [&]() {
719       unsigned FileIndex = FileIndexDist(RandGen);
720       // Make sure we don't violate the ClangdServer's contract.
721       if (ReqStats[FileIndex].FileIsRemoved)
722         AddDocument(FileIndex, /*SkipCache=*/false);
723 
724       Position Pos;
725       Pos.line = LineDist(RandGen);
726       Pos.character = ColumnDist(RandGen);
727 
728       ASSERT_TRUE(!!runLocateSymbolAt(Server, FilePaths[FileIndex], Pos));
729     };
730 
731     std::vector<std::function<void()>> AsyncRequests = {
732         AddDocumentRequest, ForceReparseRequest, RemoveDocumentRequest};
733     std::vector<std::function<void()>> BlockingRequests = {
734         CodeCompletionRequest, LocateSymbolRequest};
735 
736     // Bash requests to ClangdServer in a loop.
737     std::uniform_int_distribution<int> AsyncRequestIndexDist(
738         0, AsyncRequests.size() - 1);
739     std::uniform_int_distribution<int> BlockingRequestIndexDist(
740         0, BlockingRequests.size() - 1);
741     for (unsigned I = 1; I <= RequestsCount; ++I) {
742       if (I % BlockingRequestInterval != 0) {
743         // Issue an async request most of the time. It should be fast.
744         unsigned RequestIndex = AsyncRequestIndexDist(RandGen);
745         AsyncRequests[RequestIndex]();
746       } else {
747         // Issue a blocking request once in a while.
748         auto RequestIndex = BlockingRequestIndexDist(RandGen);
749         BlockingRequests[RequestIndex]();
750       }
751     }
752     ASSERT_TRUE(Server.blockUntilIdleForTest());
753   }
754 
755   // Check some invariants about the state of the program.
756   std::vector<FileStat> Stats = DiagConsumer.takeFileStats();
757   for (unsigned I = 0; I < FilesCount; ++I) {
758     if (!ReqStats[I].FileIsRemoved) {
759       ASSERT_EQ(Stats[I].HadErrorsInLastDiags,
760                 ReqStats[I].LastContentsHadErrors);
761     }
762 
763     ASSERT_LE(Stats[I].HitsWithErrors, ReqStats[I].RequestsWithErrors);
764     ASSERT_LE(Stats[I].HitsWithoutErrors, ReqStats[I].RequestsWithoutErrors);
765   }
766 }
767 
TEST_F(ClangdVFSTest,CheckSourceHeaderSwitch)768 TEST_F(ClangdVFSTest, CheckSourceHeaderSwitch) {
769   MockFSProvider FS;
770   ErrorCheckingDiagConsumer DiagConsumer;
771   MockCompilationDatabase CDB;
772   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
773 
774   auto SourceContents = R"cpp(
775   #include "foo.h"
776   int b = a;
777   )cpp";
778 
779   auto FooCpp = testPath("foo.cpp");
780   auto FooH = testPath("foo.h");
781   auto Invalid = testPath("main.cpp");
782 
783   FS.Files[FooCpp] = SourceContents;
784   FS.Files[FooH] = "int a;";
785   FS.Files[Invalid] = "int main() { \n return 0; \n }";
786 
787   Optional<Path> PathResult = Server.switchSourceHeader(FooCpp);
788   EXPECT_TRUE(PathResult.hasValue());
789   ASSERT_EQ(PathResult.getValue(), FooH);
790 
791   PathResult = Server.switchSourceHeader(FooH);
792   EXPECT_TRUE(PathResult.hasValue());
793   ASSERT_EQ(PathResult.getValue(), FooCpp);
794 
795   SourceContents = R"c(
796   #include "foo.HH"
797   int b = a;
798   )c";
799 
800   // Test with header file in capital letters and different extension, source
801   // file with different extension
802   auto FooC = testPath("bar.c");
803   auto FooHH = testPath("bar.HH");
804 
805   FS.Files[FooC] = SourceContents;
806   FS.Files[FooHH] = "int a;";
807 
808   PathResult = Server.switchSourceHeader(FooC);
809   EXPECT_TRUE(PathResult.hasValue());
810   ASSERT_EQ(PathResult.getValue(), FooHH);
811 
812   // Test with both capital letters
813   auto Foo2C = testPath("foo2.C");
814   auto Foo2HH = testPath("foo2.HH");
815   FS.Files[Foo2C] = SourceContents;
816   FS.Files[Foo2HH] = "int a;";
817 
818   PathResult = Server.switchSourceHeader(Foo2C);
819   EXPECT_TRUE(PathResult.hasValue());
820   ASSERT_EQ(PathResult.getValue(), Foo2HH);
821 
822   // Test with source file as capital letter and .hxx header file
823   auto Foo3C = testPath("foo3.C");
824   auto Foo3HXX = testPath("foo3.hxx");
825 
826   SourceContents = R"c(
827   #include "foo3.hxx"
828   int b = a;
829   )c";
830 
831   FS.Files[Foo3C] = SourceContents;
832   FS.Files[Foo3HXX] = "int a;";
833 
834   PathResult = Server.switchSourceHeader(Foo3C);
835   EXPECT_TRUE(PathResult.hasValue());
836   ASSERT_EQ(PathResult.getValue(), Foo3HXX);
837 
838   // Test if asking for a corresponding file that doesn't exist returns an empty
839   // string.
840   PathResult = Server.switchSourceHeader(Invalid);
841   EXPECT_FALSE(PathResult.hasValue());
842 }
843 
TEST_F(ClangdThreadingTest,NoConcurrentDiagnostics)844 TEST_F(ClangdThreadingTest, NoConcurrentDiagnostics) {
845   class NoConcurrentAccessDiagConsumer : public DiagnosticsConsumer {
846   public:
847     std::atomic<int> Count = {0};
848 
849     NoConcurrentAccessDiagConsumer(std::promise<void> StartSecondReparse)
850         : StartSecondReparse(std::move(StartSecondReparse)) {}
851 
852     void onDiagnosticsReady(PathRef, std::vector<Diag>) override {
853       ++Count;
854       std::unique_lock<std::mutex> Lock(Mutex, std::try_to_lock_t());
855       ASSERT_TRUE(Lock.owns_lock())
856           << "Detected concurrent onDiagnosticsReady calls for the same file.";
857 
858       // If we started the second parse immediately, it might cancel the first.
859       // So we don't allow it to start until the first has delivered diags...
860       if (FirstRequest) {
861         FirstRequest = false;
862         StartSecondReparse.set_value();
863         // ... but then we wait long enough that the callbacks would overlap.
864         std::this_thread::sleep_for(std::chrono::milliseconds(50));
865       }
866     }
867 
868   private:
869     std::mutex Mutex;
870     bool FirstRequest = true;
871     std::promise<void> StartSecondReparse;
872   };
873 
874   const auto SourceContentsWithoutErrors = R"cpp(
875 int a;
876 int b;
877 int c;
878 int d;
879 )cpp";
880 
881   const auto SourceContentsWithErrors = R"cpp(
882 int a = x;
883 int b;
884 int c;
885 int d;
886 )cpp";
887 
888   auto FooCpp = testPath("foo.cpp");
889   MockFSProvider FS;
890   FS.Files[FooCpp] = "";
891 
892   std::promise<void> StartSecondPromise;
893   std::future<void> StartSecond = StartSecondPromise.get_future();
894 
895   NoConcurrentAccessDiagConsumer DiagConsumer(std::move(StartSecondPromise));
896   MockCompilationDatabase CDB;
897   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
898   Server.addDocument(FooCpp, SourceContentsWithErrors);
899   StartSecond.wait();
900   Server.addDocument(FooCpp, SourceContentsWithoutErrors);
901   ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
902   ASSERT_EQ(DiagConsumer.Count, 2); // Sanity check - we actually ran both?
903 }
904 
TEST_F(ClangdVFSTest,FormatCode)905 TEST_F(ClangdVFSTest, FormatCode) {
906   MockFSProvider FS;
907   ErrorCheckingDiagConsumer DiagConsumer;
908   MockCompilationDatabase CDB;
909   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
910 
911   auto Path = testPath("foo.cpp");
912   std::string Code = R"cpp(
913 #include "x.h"
914 #include "y.h"
915 
916 void f(  )  {}
917 )cpp";
918   std::string Expected = R"cpp(
919 #include "x.h"
920 #include "y.h"
921 
922 void f() {}
923 )cpp";
924   FS.Files[Path] = Code;
925   runAddDocument(Server, Path, Code);
926 
927   auto Replaces = Server.formatFile(Code, Path);
928   EXPECT_TRUE(static_cast<bool>(Replaces));
929   auto Changed = tooling::applyAllReplacements(Code, *Replaces);
930   EXPECT_TRUE(static_cast<bool>(Changed));
931   EXPECT_EQ(Expected, *Changed);
932 }
933 
TEST_F(ClangdVFSTest,ChangedHeaderFromISystem)934 TEST_F(ClangdVFSTest, ChangedHeaderFromISystem) {
935   MockFSProvider FS;
936   ErrorCheckingDiagConsumer DiagConsumer;
937   MockCompilationDatabase CDB;
938   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
939 
940   auto SourcePath = testPath("source/foo.cpp");
941   auto HeaderPath = testPath("headers/foo.h");
942   FS.Files[HeaderPath] = "struct X { int bar; };";
943   Annotations Code(R"cpp(
944     #include "foo.h"
945 
946     int main() {
947       X().ba^
948     })cpp");
949   CDB.ExtraClangFlags.push_back("-xc++");
950   CDB.ExtraClangFlags.push_back("-isystem" + testPath("headers"));
951 
952   runAddDocument(Server, SourcePath, Code.code());
953   auto Completions = cantFail(runCodeComplete(Server, SourcePath, Code.point(),
954                                               clangd::CodeCompleteOptions()))
955                          .Completions;
956   EXPECT_THAT(Completions, ElementsAre(Field(&CodeCompletion::Name, "bar")));
957   // Update the header and rerun addDocument to make sure we get the updated
958   // files.
959   FS.Files[HeaderPath] = "struct X { int bar; int baz; };";
960   runAddDocument(Server, SourcePath, Code.code());
961   Completions = cantFail(runCodeComplete(Server, SourcePath, Code.point(),
962                                          clangd::CodeCompleteOptions()))
963                     .Completions;
964   // We want to make sure we see the updated version.
965   EXPECT_THAT(Completions, ElementsAre(Field(&CodeCompletion::Name, "bar"),
966                                        Field(&CodeCompletion::Name, "baz")));
967 }
968 
969 // FIXME(ioeric): make this work for windows again.
970 #ifndef _WIN32
971 // Check that running code completion doesn't stat() a bunch of files from the
972 // preamble again. (They should be using the preamble's stat-cache)
TEST(ClangdTests,PreambleVFSStatCache)973 TEST(ClangdTests, PreambleVFSStatCache) {
974   class ListenStatsFSProvider : public FileSystemProvider {
975   public:
976     ListenStatsFSProvider(llvm::StringMap<unsigned> &CountStats)
977         : CountStats(CountStats) {}
978 
979     IntrusiveRefCntPtr<llvm::vfs::FileSystem> getFileSystem() const override {
980       class ListenStatVFS : public llvm::vfs::ProxyFileSystem {
981       public:
982         ListenStatVFS(IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
983                       llvm::StringMap<unsigned> &CountStats)
984             : ProxyFileSystem(std::move(FS)), CountStats(CountStats) {}
985 
986         llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
987         openFileForRead(const Twine &Path) override {
988           ++CountStats[llvm::sys::path::filename(Path.str())];
989           return ProxyFileSystem::openFileForRead(Path);
990         }
991         llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override {
992           ++CountStats[llvm::sys::path::filename(Path.str())];
993           return ProxyFileSystem::status(Path);
994         }
995 
996       private:
997         llvm::StringMap<unsigned> &CountStats;
998       };
999 
1000       return IntrusiveRefCntPtr<ListenStatVFS>(
1001           new ListenStatVFS(buildTestFS(Files), CountStats));
1002     }
1003 
1004     // If relative paths are used, they are resolved with testPath().
1005     llvm::StringMap<std::string> Files;
1006     llvm::StringMap<unsigned> &CountStats;
1007   };
1008 
1009   llvm::StringMap<unsigned> CountStats;
1010   ListenStatsFSProvider FS(CountStats);
1011   ErrorCheckingDiagConsumer DiagConsumer;
1012   MockCompilationDatabase CDB;
1013   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1014 
1015   auto SourcePath = testPath("foo.cpp");
1016   auto HeaderPath = testPath("foo.h");
1017   FS.Files[HeaderPath] = "struct TestSym {};";
1018   Annotations Code(R"cpp(
1019     #include "foo.h"
1020 
1021     int main() {
1022       TestSy^
1023     })cpp");
1024 
1025   runAddDocument(Server, SourcePath, Code.code());
1026 
1027   unsigned Before = CountStats["foo.h"];
1028   EXPECT_GT(Before, 0u);
1029   auto Completions = cantFail(runCodeComplete(Server, SourcePath, Code.point(),
1030                                               clangd::CodeCompleteOptions()))
1031                          .Completions;
1032   EXPECT_EQ(CountStats["foo.h"], Before);
1033   EXPECT_THAT(Completions,
1034               ElementsAre(Field(&CodeCompletion::Name, "TestSym")));
1035 }
1036 #endif
1037 
TEST_F(ClangdVFSTest,FlagsWithPlugins)1038 TEST_F(ClangdVFSTest, FlagsWithPlugins) {
1039   MockFSProvider FS;
1040   ErrorCheckingDiagConsumer DiagConsumer;
1041   MockCompilationDatabase CDB;
1042   CDB.ExtraClangFlags = {
1043       "-Xclang",
1044       "-add-plugin",
1045       "-Xclang",
1046       "random-plugin",
1047   };
1048   OverlayCDB OCDB(&CDB);
1049   ClangdServer Server(OCDB, FS, DiagConsumer, ClangdServer::optsForTest());
1050 
1051   auto FooCpp = testPath("foo.cpp");
1052   const auto SourceContents = "int main() { return 0; }";
1053   FS.Files[FooCpp] = FooCpp;
1054   Server.addDocument(FooCpp, SourceContents);
1055   auto Result = dumpASTWithoutMemoryLocs(Server, FooCpp);
1056   EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
1057   EXPECT_NE(Result, "<no-ast>");
1058 }
1059 
TEST_F(ClangdVFSTest,FallbackWhenPreambleIsNotReady)1060 TEST_F(ClangdVFSTest, FallbackWhenPreambleIsNotReady) {
1061   MockFSProvider FS;
1062   ErrorCheckingDiagConsumer DiagConsumer;
1063   MockCompilationDatabase CDB;
1064   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1065 
1066   auto FooCpp = testPath("foo.cpp");
1067   Annotations Code(R"cpp(
1068     namespace ns { int xyz; }
1069     using namespace ns;
1070     int main() {
1071        xy^
1072     })cpp");
1073   FS.Files[FooCpp] = FooCpp;
1074 
1075   auto Opts = clangd::CodeCompleteOptions();
1076   Opts.RunParser = CodeCompleteOptions::ParseIfReady;
1077 
1078   // This will make compile command broken and preamble absent.
1079   CDB.ExtraClangFlags = {"yolo.cc"};
1080   Server.addDocument(FooCpp, Code.code());
1081   ASSERT_TRUE(Server.blockUntilIdleForTest());
1082   auto Res = cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts));
1083   EXPECT_EQ(Res.Context, CodeCompletionContext::CCC_Recovery);
1084   // Identifier-based fallback completion doesn't know about "symbol" scope.
1085   EXPECT_THAT(Res.Completions,
1086               ElementsAre(AllOf(Field(&CodeCompletion::Name, "xyz"),
1087                                 Field(&CodeCompletion::Scope, ""))));
1088 
1089   // Make the compile command work again.
1090   CDB.ExtraClangFlags = {"-std=c++11"};
1091   Server.addDocument(FooCpp, Code.code());
1092   ASSERT_TRUE(Server.blockUntilIdleForTest());
1093   EXPECT_THAT(
1094       cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts)).Completions,
1095       ElementsAre(AllOf(Field(&CodeCompletion::Name, "xyz"),
1096                         Field(&CodeCompletion::Scope, "ns::"))));
1097 
1098   // Now force identifier-based completion.
1099   Opts.RunParser = CodeCompleteOptions::NeverParse;
1100   EXPECT_THAT(
1101       cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts)).Completions,
1102       ElementsAre(AllOf(Field(&CodeCompletion::Name, "xyz"),
1103                         Field(&CodeCompletion::Scope, ""))));
1104 }
1105 
TEST_F(ClangdVFSTest,FallbackWhenWaitingForCompileCommand)1106 TEST_F(ClangdVFSTest, FallbackWhenWaitingForCompileCommand) {
1107   MockFSProvider FS;
1108   ErrorCheckingDiagConsumer DiagConsumer;
1109   // Returns compile command only when notified.
1110   class DelayedCompilationDatabase : public GlobalCompilationDatabase {
1111   public:
1112     DelayedCompilationDatabase(Notification &CanReturnCommand)
1113         : CanReturnCommand(CanReturnCommand) {}
1114 
1115     llvm::Optional<tooling::CompileCommand>
1116     getCompileCommand(PathRef File) const override {
1117       // FIXME: make this timeout and fail instead of waiting forever in case
1118       // something goes wrong.
1119       CanReturnCommand.wait();
1120       auto FileName = llvm::sys::path::filename(File);
1121       std::vector<std::string> CommandLine = {"clangd", "-ffreestanding", File};
1122       return {tooling::CompileCommand(llvm::sys::path::parent_path(File),
1123                                       FileName, std::move(CommandLine), "")};
1124     }
1125 
1126     std::vector<std::string> ExtraClangFlags;
1127 
1128   private:
1129     Notification &CanReturnCommand;
1130   };
1131 
1132   Notification CanReturnCommand;
1133   DelayedCompilationDatabase CDB(CanReturnCommand);
1134   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
1135 
1136   auto FooCpp = testPath("foo.cpp");
1137   Annotations Code(R"cpp(
1138     namespace ns { int xyz; }
1139     using namespace ns;
1140     int main() {
1141        xy^
1142     })cpp");
1143   FS.Files[FooCpp] = FooCpp;
1144   Server.addDocument(FooCpp, Code.code());
1145 
1146   // Sleep for some time to make sure code completion is not run because update
1147   // hasn't been scheduled.
1148   std::this_thread::sleep_for(std::chrono::milliseconds(10));
1149   auto Opts = clangd::CodeCompleteOptions();
1150   Opts.RunParser = CodeCompleteOptions::ParseIfReady;
1151 
1152   auto Res = cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts));
1153   EXPECT_EQ(Res.Context, CodeCompletionContext::CCC_Recovery);
1154 
1155   CanReturnCommand.notify();
1156   ASSERT_TRUE(Server.blockUntilIdleForTest());
1157   EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, Code.point(),
1158                                        clangd::CodeCompleteOptions()))
1159                   .Completions,
1160               ElementsAre(AllOf(Field(&CodeCompletion::Name, "xyz"),
1161                                 Field(&CodeCompletion::Scope, "ns::"))));
1162 }
1163 
1164 } // namespace
1165 } // namespace clangd
1166 } // namespace clang
1167