• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ConfigProvider = &CfgProvider;
352   OverlayCDB CDB(/*Base=*/nullptr, /*FallbackFlags=*/{},
353                  tooling::ArgumentsAdjuster(CommandMangler::forTests()));
354   MockFS FS;
355   ClangdServer Server(CDB, FS, Opts);
356   // foo.cc sees the expected definition, as FOO is defined.
357   Server.addDocument(testPath("foo.cc"), Example.code());
358   auto Result = runLocateSymbolAt(Server, testPath("foo.cc"), Example.point());
359   ASSERT_TRUE(bool(Result)) << Result.takeError();
360   ASSERT_THAT(*Result, SizeIs(1));
361   EXPECT_EQ(Result->front().PreferredDeclaration.range, Example.range());
362   // bar.cc gets a different result, as FOO is not defined.
363   Server.addDocument(testPath("bar.cc"), Example.code());
364   Result = runLocateSymbolAt(Server, testPath("bar.cc"), Example.point());
365   ASSERT_TRUE(bool(Result)) << Result.takeError();
366   ASSERT_THAT(*Result, SizeIs(1));
367   EXPECT_NE(Result->front().PreferredDeclaration.range, Example.range());
368 }
369 
TEST(ClangdServerTest,PropagatesVersion)370 TEST(ClangdServerTest, PropagatesVersion) {
371   MockCompilationDatabase CDB;
372   MockFS FS;
373   struct Callbacks : public ClangdServer::Callbacks {
374     void onDiagnosticsReady(PathRef File, llvm::StringRef Version,
375                             std::vector<Diag> Diagnostics) override {
376       Got = Version.str();
377     }
378     std::string Got = "";
379   } Callbacks;
380 
381   // Verify that the version is plumbed to diagnostics.
382   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &Callbacks);
383   runAddDocument(Server, testPath("foo.cpp"), "void main(){}", "42");
384   EXPECT_EQ(Callbacks.Got, "42");
385 }
386 
387 // Only enable this test on Unix
388 #ifdef LLVM_ON_UNIX
TEST(ClangdServerTest,SearchLibDir)389 TEST(ClangdServerTest, SearchLibDir) {
390   // Checks that searches for GCC installation is done through vfs.
391   MockFS FS;
392   ErrorCheckingCallbacks DiagConsumer;
393   MockCompilationDatabase CDB;
394   CDB.ExtraClangFlags.insert(CDB.ExtraClangFlags.end(),
395                              {"-xc++", "-target", "x86_64-linux-unknown",
396                               "-m64", "--gcc-toolchain=/randomusr",
397                               "-stdlib=libstdc++"});
398   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
399 
400   // Just a random gcc version string
401   SmallString<8> Version("4.9.3");
402 
403   // A lib dir for gcc installation
404   SmallString<64> LibDir("/randomusr/lib/gcc/x86_64-linux-gnu");
405   llvm::sys::path::append(LibDir, Version);
406 
407   // Put crtbegin.o into LibDir/64 to trick clang into thinking there's a gcc
408   // installation there.
409   SmallString<64> DummyLibFile;
410   llvm::sys::path::append(DummyLibFile, LibDir, "64", "crtbegin.o");
411   FS.Files[DummyLibFile] = "";
412 
413   SmallString<64> IncludeDir("/randomusr/include/c++");
414   llvm::sys::path::append(IncludeDir, Version);
415 
416   SmallString<64> StringPath;
417   llvm::sys::path::append(StringPath, IncludeDir, "string");
418   FS.Files[StringPath] = "class mock_string {};";
419 
420   auto FooCpp = testPath("foo.cpp");
421   const auto SourceContents = R"cpp(
422 #include <string>
423 mock_string x;
424 )cpp";
425   FS.Files[FooCpp] = SourceContents;
426 
427   runAddDocument(Server, FooCpp, SourceContents);
428   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
429 
430   const auto SourceContentsWithError = R"cpp(
431 #include <string>
432 std::string x;
433 )cpp";
434   runAddDocument(Server, FooCpp, SourceContentsWithError);
435   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
436 }
437 #endif // LLVM_ON_UNIX
438 
TEST(ClangdServerTest,ForceReparseCompileCommand)439 TEST(ClangdServerTest, ForceReparseCompileCommand) {
440   MockFS FS;
441   ErrorCheckingCallbacks DiagConsumer;
442   MockCompilationDatabase CDB;
443   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
444 
445   auto FooCpp = testPath("foo.cpp");
446   const auto SourceContents1 = R"cpp(
447 template <class T>
448 struct foo { T x; };
449 )cpp";
450   const auto SourceContents2 = R"cpp(
451 template <class T>
452 struct bar { T x; };
453 )cpp";
454 
455   FS.Files[FooCpp] = "";
456 
457   // First parse files in C mode and check they produce errors.
458   CDB.ExtraClangFlags = {"-xc"};
459   runAddDocument(Server, FooCpp, SourceContents1);
460   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
461   runAddDocument(Server, FooCpp, SourceContents2);
462   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
463 
464   // Now switch to C++ mode.
465   CDB.ExtraClangFlags = {"-xc++"};
466   runAddDocument(Server, FooCpp, SourceContents2);
467   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
468   // Subsequent addDocument calls should finish without errors too.
469   runAddDocument(Server, FooCpp, SourceContents1);
470   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
471   runAddDocument(Server, FooCpp, SourceContents2);
472   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
473 }
474 
TEST(ClangdServerTest,ForceReparseCompileCommandDefines)475 TEST(ClangdServerTest, ForceReparseCompileCommandDefines) {
476   MockFS FS;
477   ErrorCheckingCallbacks DiagConsumer;
478   MockCompilationDatabase CDB;
479   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
480 
481   auto FooCpp = testPath("foo.cpp");
482   const auto SourceContents = R"cpp(
483 #ifdef WITH_ERROR
484 this
485 #endif
486 
487 int main() { return 0; }
488 )cpp";
489   FS.Files[FooCpp] = "";
490 
491   // Parse with define, we expect to see the errors.
492   CDB.ExtraClangFlags = {"-DWITH_ERROR"};
493   runAddDocument(Server, FooCpp, SourceContents);
494   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
495 
496   // Parse without the define, no errors should be produced.
497   CDB.ExtraClangFlags = {};
498   runAddDocument(Server, FooCpp, SourceContents);
499   ASSERT_TRUE(Server.blockUntilIdleForTest());
500   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
501   // Subsequent addDocument call should finish without errors too.
502   runAddDocument(Server, FooCpp, SourceContents);
503   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
504 }
505 
506 // Test ClangdServer.reparseOpenedFiles.
TEST(ClangdServerTest,ReparseOpenedFiles)507 TEST(ClangdServerTest, ReparseOpenedFiles) {
508   Annotations FooSource(R"cpp(
509 #ifdef MACRO
510 static void $one[[bob]]() {}
511 #else
512 static void $two[[bob]]() {}
513 #endif
514 
515 int main () { bo^b (); return 0; }
516 )cpp");
517 
518   Annotations BarSource(R"cpp(
519 #ifdef MACRO
520 this is an error
521 #endif
522 )cpp");
523 
524   Annotations BazSource(R"cpp(
525 int hello;
526 )cpp");
527 
528   MockFS FS;
529   MockCompilationDatabase CDB;
530   MultipleErrorCheckingCallbacks DiagConsumer;
531   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
532 
533   auto FooCpp = testPath("foo.cpp");
534   auto BarCpp = testPath("bar.cpp");
535   auto BazCpp = testPath("baz.cpp");
536 
537   FS.Files[FooCpp] = "";
538   FS.Files[BarCpp] = "";
539   FS.Files[BazCpp] = "";
540 
541   CDB.ExtraClangFlags = {"-DMACRO=1"};
542   Server.addDocument(FooCpp, FooSource.code());
543   Server.addDocument(BarCpp, BarSource.code());
544   Server.addDocument(BazCpp, BazSource.code());
545   ASSERT_TRUE(Server.blockUntilIdleForTest());
546 
547   EXPECT_THAT(DiagConsumer.filesWithDiags(),
548               UnorderedElementsAre(Pair(FooCpp, false), Pair(BarCpp, true),
549                                    Pair(BazCpp, false)));
550 
551   auto Locations = runLocateSymbolAt(Server, FooCpp, FooSource.point());
552   EXPECT_TRUE(bool(Locations));
553   EXPECT_THAT(*Locations, ElementsAre(DeclAt(FooCpp, FooSource.range("one"))));
554 
555   // Undefine MACRO, close baz.cpp.
556   CDB.ExtraClangFlags.clear();
557   DiagConsumer.clear();
558   Server.removeDocument(BazCpp);
559   Server.addDocument(FooCpp, FooSource.code());
560   Server.addDocument(BarCpp, BarSource.code());
561   ASSERT_TRUE(Server.blockUntilIdleForTest());
562 
563   EXPECT_THAT(DiagConsumer.filesWithDiags(),
564               UnorderedElementsAre(Pair(FooCpp, false), Pair(BarCpp, false)));
565 
566   Locations = runLocateSymbolAt(Server, FooCpp, FooSource.point());
567   EXPECT_TRUE(bool(Locations));
568   EXPECT_THAT(*Locations, ElementsAre(DeclAt(FooCpp, FooSource.range("two"))));
569 }
570 
571 MATCHER_P4(Stats, Name, UsesMemory, PreambleBuilds, ASTBuilds, "") {
572   return arg.first() == Name &&
573          (arg.second.UsedBytesAST + arg.second.UsedBytesPreamble != 0) ==
574              UsesMemory &&
575          std::tie(arg.second.PreambleBuilds, ASTBuilds) ==
576              std::tie(PreambleBuilds, ASTBuilds);
577 }
578 
TEST(ClangdServerTest,FileStats)579 TEST(ClangdServerTest, FileStats) {
580   MockFS FS;
581   ErrorCheckingCallbacks DiagConsumer;
582   MockCompilationDatabase CDB;
583   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
584 
585   Path FooCpp = testPath("foo.cpp");
586   const auto SourceContents = R"cpp(
587 struct Something {
588   int method();
589 };
590 )cpp";
591   Path BarCpp = testPath("bar.cpp");
592 
593   FS.Files[FooCpp] = "";
594   FS.Files[BarCpp] = "";
595 
596   EXPECT_THAT(Server.fileStats(), IsEmpty());
597 
598   Server.addDocument(FooCpp, SourceContents);
599   Server.addDocument(BarCpp, SourceContents);
600   ASSERT_TRUE(Server.blockUntilIdleForTest());
601 
602   EXPECT_THAT(Server.fileStats(),
603               UnorderedElementsAre(Stats(FooCpp, true, 1, 1),
604                                    Stats(BarCpp, true, 1, 1)));
605 
606   Server.removeDocument(FooCpp);
607   ASSERT_TRUE(Server.blockUntilIdleForTest());
608   EXPECT_THAT(Server.fileStats(), ElementsAre(Stats(BarCpp, true, 1, 1)));
609 
610   Server.removeDocument(BarCpp);
611   ASSERT_TRUE(Server.blockUntilIdleForTest());
612   EXPECT_THAT(Server.fileStats(), IsEmpty());
613 }
614 
TEST(ClangdServerTest,InvalidCompileCommand)615 TEST(ClangdServerTest, InvalidCompileCommand) {
616   MockFS FS;
617   ErrorCheckingCallbacks DiagConsumer;
618   MockCompilationDatabase CDB;
619 
620   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
621 
622   auto FooCpp = testPath("foo.cpp");
623   // clang cannot create CompilerInvocation if we pass two files in the
624   // CompileCommand. We pass the file in ExtraFlags once and CDB adds another
625   // one in getCompileCommand().
626   CDB.ExtraClangFlags.push_back(FooCpp);
627 
628   // Clang can't parse command args in that case, but we shouldn't crash.
629   runAddDocument(Server, FooCpp, "int main() {}");
630 
631   EXPECT_EQ(dumpAST(Server, FooCpp), "<no-ast>");
632   EXPECT_ERROR(runLocateSymbolAt(Server, FooCpp, Position()));
633   EXPECT_ERROR(runFindDocumentHighlights(Server, FooCpp, Position()));
634   EXPECT_ERROR(runRename(Server, FooCpp, Position(), "new_name",
635                          clangd::RenameOptions()));
636   EXPECT_ERROR(runSignatureHelp(Server, FooCpp, Position()));
637   // Identifier-based fallback completion.
638   EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, Position(),
639                                        clangd::CodeCompleteOptions()))
640                   .Completions,
641               ElementsAre(Field(&CodeCompletion::Name, "int"),
642                           Field(&CodeCompletion::Name, "main")));
643 }
644 
TEST(ClangdThreadingTest,StressTest)645 TEST(ClangdThreadingTest, StressTest) {
646   // Without 'static' clang gives an error for a usage inside TestDiagConsumer.
647   static const unsigned FilesCount = 5;
648   const unsigned RequestsCount = 500;
649   // Blocking requests wait for the parsing to complete, they slow down the test
650   // dramatically, so they are issued rarely. Each
651   // BlockingRequestInterval-request will be a blocking one.
652   const unsigned BlockingRequestInterval = 40;
653 
654   const auto SourceContentsWithoutErrors = R"cpp(
655 int a;
656 int b;
657 int c;
658 int d;
659 )cpp";
660 
661   const auto SourceContentsWithErrors = R"cpp(
662 int a = x;
663 int b;
664 int c;
665 int d;
666 )cpp";
667 
668   // Giving invalid line and column number should not crash ClangdServer, but
669   // just to make sure we're sometimes hitting the bounds inside the file we
670   // limit the intervals of line and column number that are generated.
671   unsigned MaxLineForFileRequests = 7;
672   unsigned MaxColumnForFileRequests = 10;
673 
674   std::vector<std::string> FilePaths;
675   MockFS FS;
676   for (unsigned I = 0; I < FilesCount; ++I) {
677     std::string Name = std::string("Foo") + std::to_string(I) + ".cpp";
678     FS.Files[Name] = "";
679     FilePaths.push_back(testPath(Name));
680   }
681 
682   struct FileStat {
683     unsigned HitsWithoutErrors = 0;
684     unsigned HitsWithErrors = 0;
685     bool HadErrorsInLastDiags = false;
686   };
687 
688   class TestDiagConsumer : public ClangdServer::Callbacks {
689   public:
690     TestDiagConsumer() : Stats(FilesCount, FileStat()) {}
691 
692     void onDiagnosticsReady(PathRef File, llvm::StringRef Version,
693                             std::vector<Diag> Diagnostics) override {
694       StringRef FileIndexStr = llvm::sys::path::stem(File);
695       ASSERT_TRUE(FileIndexStr.consume_front("Foo"));
696 
697       unsigned long FileIndex = std::stoul(FileIndexStr.str());
698 
699       bool HadError = diagsContainErrors(Diagnostics);
700 
701       std::lock_guard<std::mutex> Lock(Mutex);
702       if (HadError)
703         Stats[FileIndex].HitsWithErrors++;
704       else
705         Stats[FileIndex].HitsWithoutErrors++;
706       Stats[FileIndex].HadErrorsInLastDiags = HadError;
707     }
708 
709     std::vector<FileStat> takeFileStats() {
710       std::lock_guard<std::mutex> Lock(Mutex);
711       return std::move(Stats);
712     }
713 
714   private:
715     std::mutex Mutex;
716     std::vector<FileStat> Stats;
717   };
718 
719   struct RequestStats {
720     unsigned RequestsWithoutErrors = 0;
721     unsigned RequestsWithErrors = 0;
722     bool LastContentsHadErrors = false;
723     bool FileIsRemoved = true;
724   };
725 
726   std::vector<RequestStats> ReqStats;
727   ReqStats.reserve(FilesCount);
728   for (unsigned FileIndex = 0; FileIndex < FilesCount; ++FileIndex)
729     ReqStats.emplace_back();
730 
731   TestDiagConsumer DiagConsumer;
732   {
733     MockCompilationDatabase CDB;
734     ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
735 
736     // Prepare some random distributions for the test.
737     std::random_device RandGen;
738 
739     std::uniform_int_distribution<unsigned> FileIndexDist(0, FilesCount - 1);
740     // Pass a text that contains compiler errors to addDocument in about 20% of
741     // all requests.
742     std::bernoulli_distribution ShouldHaveErrorsDist(0.2);
743     // Line and Column numbers for requests that need them.
744     std::uniform_int_distribution<int> LineDist(0, MaxLineForFileRequests);
745     std::uniform_int_distribution<int> ColumnDist(0, MaxColumnForFileRequests);
746 
747     // Some helpers.
748     auto UpdateStatsOnAddDocument = [&](unsigned FileIndex, bool HadErrors) {
749       auto &Stats = ReqStats[FileIndex];
750 
751       if (HadErrors)
752         ++Stats.RequestsWithErrors;
753       else
754         ++Stats.RequestsWithoutErrors;
755       Stats.LastContentsHadErrors = HadErrors;
756       Stats.FileIsRemoved = false;
757     };
758 
759     auto UpdateStatsOnRemoveDocument = [&](unsigned FileIndex) {
760       auto &Stats = ReqStats[FileIndex];
761 
762       Stats.FileIsRemoved = true;
763     };
764 
765     auto AddDocument = [&](unsigned FileIndex, bool SkipCache) {
766       bool ShouldHaveErrors = ShouldHaveErrorsDist(RandGen);
767       Server.addDocument(FilePaths[FileIndex],
768                          ShouldHaveErrors ? SourceContentsWithErrors
769                                           : SourceContentsWithoutErrors);
770       UpdateStatsOnAddDocument(FileIndex, ShouldHaveErrors);
771     };
772 
773     // Various requests that we would randomly run.
774     auto AddDocumentRequest = [&]() {
775       unsigned FileIndex = FileIndexDist(RandGen);
776       AddDocument(FileIndex, /*SkipCache=*/false);
777     };
778 
779     auto ForceReparseRequest = [&]() {
780       unsigned FileIndex = FileIndexDist(RandGen);
781       AddDocument(FileIndex, /*SkipCache=*/true);
782     };
783 
784     auto RemoveDocumentRequest = [&]() {
785       unsigned FileIndex = FileIndexDist(RandGen);
786       // Make sure we don't violate the ClangdServer's contract.
787       if (ReqStats[FileIndex].FileIsRemoved)
788         AddDocument(FileIndex, /*SkipCache=*/false);
789 
790       Server.removeDocument(FilePaths[FileIndex]);
791       UpdateStatsOnRemoveDocument(FileIndex);
792     };
793 
794     auto CodeCompletionRequest = [&]() {
795       unsigned FileIndex = FileIndexDist(RandGen);
796       // Make sure we don't violate the ClangdServer's contract.
797       if (ReqStats[FileIndex].FileIsRemoved)
798         AddDocument(FileIndex, /*SkipCache=*/false);
799 
800       Position Pos;
801       Pos.line = LineDist(RandGen);
802       Pos.character = ColumnDist(RandGen);
803       // FIXME(ibiryukov): Also test async completion requests.
804       // Simply putting CodeCompletion into async requests now would make
805       // tests slow, since there's no way to cancel previous completion
806       // requests as opposed to AddDocument/RemoveDocument, which are implicitly
807       // cancelled by any subsequent AddDocument/RemoveDocument request to the
808       // same file.
809       cantFail(runCodeComplete(Server, FilePaths[FileIndex], Pos,
810                                clangd::CodeCompleteOptions()));
811     };
812 
813     auto LocateSymbolRequest = [&]() {
814       unsigned FileIndex = FileIndexDist(RandGen);
815       // Make sure we don't violate the ClangdServer's contract.
816       if (ReqStats[FileIndex].FileIsRemoved)
817         AddDocument(FileIndex, /*SkipCache=*/false);
818 
819       Position Pos;
820       Pos.line = LineDist(RandGen);
821       Pos.character = ColumnDist(RandGen);
822 
823       ASSERT_TRUE(!!runLocateSymbolAt(Server, FilePaths[FileIndex], Pos));
824     };
825 
826     std::vector<std::function<void()>> AsyncRequests = {
827         AddDocumentRequest, ForceReparseRequest, RemoveDocumentRequest};
828     std::vector<std::function<void()>> BlockingRequests = {
829         CodeCompletionRequest, LocateSymbolRequest};
830 
831     // Bash requests to ClangdServer in a loop.
832     std::uniform_int_distribution<int> AsyncRequestIndexDist(
833         0, AsyncRequests.size() - 1);
834     std::uniform_int_distribution<int> BlockingRequestIndexDist(
835         0, BlockingRequests.size() - 1);
836     for (unsigned I = 1; I <= RequestsCount; ++I) {
837       if (I % BlockingRequestInterval != 0) {
838         // Issue an async request most of the time. It should be fast.
839         unsigned RequestIndex = AsyncRequestIndexDist(RandGen);
840         AsyncRequests[RequestIndex]();
841       } else {
842         // Issue a blocking request once in a while.
843         auto RequestIndex = BlockingRequestIndexDist(RandGen);
844         BlockingRequests[RequestIndex]();
845       }
846     }
847     ASSERT_TRUE(Server.blockUntilIdleForTest());
848   }
849 
850   // Check some invariants about the state of the program.
851   std::vector<FileStat> Stats = DiagConsumer.takeFileStats();
852   for (unsigned I = 0; I < FilesCount; ++I) {
853     if (!ReqStats[I].FileIsRemoved) {
854       ASSERT_EQ(Stats[I].HadErrorsInLastDiags,
855                 ReqStats[I].LastContentsHadErrors);
856     }
857 
858     ASSERT_LE(Stats[I].HitsWithErrors, ReqStats[I].RequestsWithErrors);
859     ASSERT_LE(Stats[I].HitsWithoutErrors, ReqStats[I].RequestsWithoutErrors);
860   }
861 }
862 
TEST(ClangdThreadingTest,NoConcurrentDiagnostics)863 TEST(ClangdThreadingTest, NoConcurrentDiagnostics) {
864   class NoConcurrentAccessDiagConsumer : public ClangdServer::Callbacks {
865   public:
866     std::atomic<int> Count = {0};
867 
868     NoConcurrentAccessDiagConsumer(std::promise<void> StartSecondReparse)
869         : StartSecondReparse(std::move(StartSecondReparse)) {}
870 
871     void onDiagnosticsReady(PathRef, llvm::StringRef,
872                             std::vector<Diag>) override {
873       ++Count;
874       std::unique_lock<std::mutex> Lock(Mutex, std::try_to_lock_t());
875       ASSERT_TRUE(Lock.owns_lock())
876           << "Detected concurrent onDiagnosticsReady calls for the same file.";
877 
878       // If we started the second parse immediately, it might cancel the first.
879       // So we don't allow it to start until the first has delivered diags...
880       if (FirstRequest) {
881         FirstRequest = false;
882         StartSecondReparse.set_value();
883         // ... but then we wait long enough that the callbacks would overlap.
884         std::this_thread::sleep_for(std::chrono::milliseconds(50));
885       }
886     }
887 
888   private:
889     std::mutex Mutex;
890     bool FirstRequest = true;
891     std::promise<void> StartSecondReparse;
892   };
893 
894   const auto SourceContentsWithoutErrors = R"cpp(
895 int a;
896 int b;
897 int c;
898 int d;
899 )cpp";
900 
901   const auto SourceContentsWithErrors = R"cpp(
902 int a = x;
903 int b;
904 int c;
905 int d;
906 )cpp";
907 
908   auto FooCpp = testPath("foo.cpp");
909   MockFS FS;
910   FS.Files[FooCpp] = "";
911 
912   std::promise<void> StartSecondPromise;
913   std::future<void> StartSecond = StartSecondPromise.get_future();
914 
915   NoConcurrentAccessDiagConsumer DiagConsumer(std::move(StartSecondPromise));
916   MockCompilationDatabase CDB;
917   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
918   Server.addDocument(FooCpp, SourceContentsWithErrors);
919   StartSecond.wait();
920   Server.addDocument(FooCpp, SourceContentsWithoutErrors);
921   ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
922   ASSERT_EQ(DiagConsumer.Count, 2); // Sanity check - we actually ran both?
923 }
924 
TEST(ClangdServerTest,FormatCode)925 TEST(ClangdServerTest, FormatCode) {
926   MockFS FS;
927   ErrorCheckingCallbacks DiagConsumer;
928   MockCompilationDatabase CDB;
929   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
930 
931   auto Path = testPath("foo.cpp");
932   std::string Code = R"cpp(
933 #include "x.h"
934 #include "y.h"
935 
936 void f(  )  {}
937 )cpp";
938   std::string Expected = R"cpp(
939 #include "x.h"
940 #include "y.h"
941 
942 void f() {}
943 )cpp";
944   FS.Files[Path] = Code;
945   runAddDocument(Server, Path, Code);
946 
947   auto Replaces = runFormatFile(Server, Path, Code);
948   EXPECT_TRUE(static_cast<bool>(Replaces));
949   auto Changed = tooling::applyAllReplacements(Code, *Replaces);
950   EXPECT_TRUE(static_cast<bool>(Changed));
951   EXPECT_EQ(Expected, *Changed);
952 }
953 
TEST(ClangdServerTest,ChangedHeaderFromISystem)954 TEST(ClangdServerTest, ChangedHeaderFromISystem) {
955   MockFS FS;
956   ErrorCheckingCallbacks DiagConsumer;
957   MockCompilationDatabase CDB;
958   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
959 
960   auto SourcePath = testPath("source/foo.cpp");
961   auto HeaderPath = testPath("headers/foo.h");
962   FS.Files[HeaderPath] = "struct X { int bar; };";
963   Annotations Code(R"cpp(
964     #include "foo.h"
965 
966     int main() {
967       X().ba^
968     })cpp");
969   CDB.ExtraClangFlags.push_back("-xc++");
970   CDB.ExtraClangFlags.push_back("-isystem" + testPath("headers"));
971 
972   runAddDocument(Server, SourcePath, Code.code());
973   auto Completions = cantFail(runCodeComplete(Server, SourcePath, Code.point(),
974                                               clangd::CodeCompleteOptions()))
975                          .Completions;
976   EXPECT_THAT(Completions, ElementsAre(Field(&CodeCompletion::Name, "bar")));
977   // Update the header and rerun addDocument to make sure we get the updated
978   // files.
979   FS.Files[HeaderPath] = "struct X { int bar; int baz; };";
980   runAddDocument(Server, SourcePath, Code.code());
981   Completions = cantFail(runCodeComplete(Server, SourcePath, Code.point(),
982                                          clangd::CodeCompleteOptions()))
983                     .Completions;
984   // We want to make sure we see the updated version.
985   EXPECT_THAT(Completions, ElementsAre(Field(&CodeCompletion::Name, "bar"),
986                                        Field(&CodeCompletion::Name, "baz")));
987 }
988 
989 // FIXME(ioeric): make this work for windows again.
990 #ifndef _WIN32
991 // Check that running code completion doesn't stat() a bunch of files from the
992 // preamble again. (They should be using the preamble's stat-cache)
TEST(ClangdTests,PreambleVFSStatCache)993 TEST(ClangdTests, PreambleVFSStatCache) {
994   class StatRecordingFS : public ThreadsafeFS {
995     llvm::StringMap<unsigned> &CountStats;
996 
997   public:
998     // If relative paths are used, they are resolved with testPath().
999     llvm::StringMap<std::string> Files;
1000 
1001     StatRecordingFS(llvm::StringMap<unsigned> &CountStats)
1002         : CountStats(CountStats) {}
1003 
1004   private:
1005     IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl() const override {
1006       class StatRecordingVFS : public llvm::vfs::ProxyFileSystem {
1007       public:
1008         StatRecordingVFS(IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
1009                          llvm::StringMap<unsigned> &CountStats)
1010             : ProxyFileSystem(std::move(FS)), CountStats(CountStats) {}
1011 
1012         llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
1013         openFileForRead(const Twine &Path) override {
1014           ++CountStats[llvm::sys::path::filename(Path.str())];
1015           return ProxyFileSystem::openFileForRead(Path);
1016         }
1017         llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override {
1018           ++CountStats[llvm::sys::path::filename(Path.str())];
1019           return ProxyFileSystem::status(Path);
1020         }
1021 
1022       private:
1023         llvm::StringMap<unsigned> &CountStats;
1024       };
1025 
1026       return IntrusiveRefCntPtr<StatRecordingVFS>(
1027           new StatRecordingVFS(buildTestFS(Files), CountStats));
1028     }
1029   };
1030 
1031   llvm::StringMap<unsigned> CountStats;
1032   StatRecordingFS FS(CountStats);
1033   ErrorCheckingCallbacks DiagConsumer;
1034   MockCompilationDatabase CDB;
1035   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
1036 
1037   auto SourcePath = testPath("foo.cpp");
1038   auto HeaderPath = testPath("foo.h");
1039   FS.Files[HeaderPath] = "struct TestSym {};";
1040   Annotations Code(R"cpp(
1041     #include "foo.h"
1042 
1043     int main() {
1044       TestSy^
1045     })cpp");
1046 
1047   runAddDocument(Server, SourcePath, Code.code());
1048 
1049   unsigned Before = CountStats["foo.h"];
1050   EXPECT_GT(Before, 0u);
1051   auto Completions = cantFail(runCodeComplete(Server, SourcePath, Code.point(),
1052                                               clangd::CodeCompleteOptions()))
1053                          .Completions;
1054   EXPECT_EQ(CountStats["foo.h"], Before);
1055   EXPECT_THAT(Completions,
1056               ElementsAre(Field(&CodeCompletion::Name, "TestSym")));
1057 }
1058 #endif
1059 
TEST(ClangdServerTest,FallbackWhenPreambleIsNotReady)1060 TEST(ClangdServerTest, FallbackWhenPreambleIsNotReady) {
1061   MockFS FS;
1062   ErrorCheckingCallbacks DiagConsumer;
1063   MockCompilationDatabase CDB;
1064   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
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(ClangdServerTest,FallbackWhenWaitingForCompileCommand)1106 TEST(ClangdServerTest, FallbackWhenWaitingForCompileCommand) {
1107   MockFS FS;
1108   ErrorCheckingCallbacks 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",
1122                                               std::string(File)};
1123       return {tooling::CompileCommand(llvm::sys::path::parent_path(File),
1124                                       FileName, std::move(CommandLine), "")};
1125     }
1126 
1127     std::vector<std::string> ExtraClangFlags;
1128 
1129   private:
1130     Notification &CanReturnCommand;
1131   };
1132 
1133   Notification CanReturnCommand;
1134   DelayedCompilationDatabase CDB(CanReturnCommand);
1135   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
1136 
1137   auto FooCpp = testPath("foo.cpp");
1138   Annotations Code(R"cpp(
1139     namespace ns { int xyz; }
1140     using namespace ns;
1141     int main() {
1142        xy^
1143     })cpp");
1144   FS.Files[FooCpp] = FooCpp;
1145   Server.addDocument(FooCpp, Code.code());
1146 
1147   // Sleep for some time to make sure code completion is not run because update
1148   // hasn't been scheduled.
1149   std::this_thread::sleep_for(std::chrono::milliseconds(10));
1150   auto Opts = clangd::CodeCompleteOptions();
1151   Opts.RunParser = CodeCompleteOptions::ParseIfReady;
1152 
1153   auto Res = cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts));
1154   EXPECT_EQ(Res.Context, CodeCompletionContext::CCC_Recovery);
1155 
1156   CanReturnCommand.notify();
1157   ASSERT_TRUE(Server.blockUntilIdleForTest());
1158   EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, Code.point(),
1159                                        clangd::CodeCompleteOptions()))
1160                   .Completions,
1161               ElementsAre(AllOf(Field(&CodeCompletion::Name, "xyz"),
1162                                 Field(&CodeCompletion::Scope, "ns::"))));
1163 }
1164 
TEST(ClangdServerTest,CustomAction)1165 TEST(ClangdServerTest, CustomAction) {
1166   OverlayCDB CDB(/*Base=*/nullptr);
1167   MockFS FS;
1168   ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
1169 
1170   Server.addDocument(testPath("foo.cc"), "void x();");
1171   Decl::Kind XKind = Decl::TranslationUnit;
1172   EXPECT_THAT_ERROR(runCustomAction(Server, testPath("foo.cc"),
1173                                     [&](InputsAndAST AST) {
1174                                       XKind = findDecl(AST.AST, "x").getKind();
1175                                     }),
1176                     llvm::Succeeded());
1177   EXPECT_EQ(XKind, Decl::Function);
1178 }
1179 
1180 // Tests fails when built with asan due to stack overflow. So skip running the
1181 // test as a workaround.
1182 #if !defined(__has_feature) || !__has_feature(address_sanitizer)
TEST(ClangdServerTest,TestStackOverflow)1183 TEST(ClangdServerTest, TestStackOverflow) {
1184   MockFS FS;
1185   ErrorCheckingCallbacks DiagConsumer;
1186   MockCompilationDatabase CDB;
1187   ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer);
1188 
1189   const char *SourceContents = R"cpp(
1190     constexpr int foo() { return foo(); }
1191     static_assert(foo());
1192   )cpp";
1193 
1194   auto FooCpp = testPath("foo.cpp");
1195   FS.Files[FooCpp] = SourceContents;
1196 
1197   Server.addDocument(FooCpp, SourceContents);
1198   ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
1199   // check that we got a constexpr depth error, and not crashed by stack
1200   // overflow
1201   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
1202 }
1203 #endif
1204 
TEST(ClangdServer,TidyOverrideTest)1205 TEST(ClangdServer, TidyOverrideTest) {
1206   struct DiagsCheckingCallback : public ClangdServer::Callbacks {
1207   public:
1208     void onDiagnosticsReady(PathRef File, llvm::StringRef Version,
1209                             std::vector<Diag> Diagnostics) override {
1210       std::lock_guard<std::mutex> Lock(Mutex);
1211       HadDiagsInLastCallback = !Diagnostics.empty();
1212     }
1213 
1214     std::mutex Mutex;
1215     bool HadDiagsInLastCallback = false;
1216   } DiagConsumer;
1217 
1218   MockFS FS;
1219   // These checks don't work well in clangd, even if configured they shouldn't
1220   // run.
1221   FS.Files[testPath(".clang-tidy")] = R"(
1222     Checks: -*,bugprone-use-after-move,llvm-header-guard
1223   )";
1224   MockCompilationDatabase CDB;
1225   std::vector<TidyProvider> Stack;
1226   Stack.push_back(provideClangTidyFiles(FS));
1227   Stack.push_back(disableUnusableChecks());
1228   TidyProvider Provider = combine(std::move(Stack));
1229   CDB.ExtraClangFlags = {"-xc++"};
1230   auto Opts = ClangdServer::optsForTest();
1231   Opts.ClangTidyProvider = Provider;
1232   ClangdServer Server(CDB, FS, Opts, &DiagConsumer);
1233   const char *SourceContents = R"cpp(
1234     struct Foo { Foo(); Foo(Foo&); Foo(Foo&&); };
1235     namespace std { Foo&& move(Foo&); }
1236     void foo() {
1237       Foo x;
1238       Foo y = std::move(x);
1239       Foo z = x;
1240     })cpp";
1241   Server.addDocument(testPath("foo.h"), SourceContents);
1242   ASSERT_TRUE(Server.blockUntilIdleForTest());
1243   EXPECT_FALSE(DiagConsumer.HadDiagsInLastCallback);
1244 }
1245 
TEST(ClangdServer,MemoryUsageTest)1246 TEST(ClangdServer, MemoryUsageTest) {
1247   MockFS FS;
1248   MockCompilationDatabase CDB;
1249   ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
1250 
1251   auto FooCpp = testPath("foo.cpp");
1252   Server.addDocument(FooCpp, "");
1253   ASSERT_TRUE(Server.blockUntilIdleForTest());
1254 
1255   llvm::BumpPtrAllocator Alloc;
1256   MemoryTree MT(&Alloc);
1257   Server.profile(MT);
1258   ASSERT_TRUE(MT.children().count("tuscheduler"));
1259   EXPECT_TRUE(MT.child("tuscheduler").children().count(FooCpp));
1260 }
1261 } // namespace
1262 } // namespace clangd
1263 } // namespace clang
1264