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