xref: /llvm-project/clang-tools-extra/clangd/unittests/ClangdTests.cpp (revision efdb3ae23247850d3886e3708400f0d991ed59e1)
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 "ClangdServer.h"
11 #include "CodeComplete.h"
12 #include "CompileCommands.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 "refactor/Tweak.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 "clang/Tooling/Core/Replacement.h"
28 #include "llvm/ADT/ArrayRef.h"
29 #include "llvm/ADT/SmallVector.h"
30 #include "llvm/ADT/StringMap.h"
31 #include "llvm/ADT/StringRef.h"
32 #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
33 #include "llvm/Support/Allocator.h"
34 #include "llvm/Support/Error.h"
35 #include "llvm/Support/Path.h"
36 #include "llvm/Support/Regex.h"
37 #include "llvm/Support/VirtualFileSystem.h"
38 #include "llvm/Testing/Support/Error.h"
39 #include "gmock/gmock.h"
40 #include "gtest/gtest.h"
41 #include <algorithm>
42 #include <chrono>
43 #include <iostream>
44 #include <optional>
45 #include <random>
46 #include <string>
47 #include <thread>
48 #include <vector>
49 
50 namespace clang {
51 namespace clangd {
52 
53 namespace {
54 
55 using ::testing::AllOf;
56 using ::testing::ElementsAre;
57 using ::testing::Field;
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 
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:
79   void onDiagnosticsReady(PathRef File, llvm::StringRef Version,
80                           llvm::ArrayRef<Diag> Diagnostics) override {
81     bool HadError = diagsContainErrors(Diagnostics);
82     std::lock_guard<std::mutex> Lock(Mutex);
83     HadErrorInLastDiags = HadError;
84   }
85 
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:
100   void onDiagnosticsReady(PathRef File, llvm::StringRef Version,
101                           llvm::ArrayRef<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.
111   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 
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
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 
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 
165 std::string dumpASTWithoutMemoryLocs(ClangdServer &Server, PathRef File) {
166   return replacePtrsInDump(dumpAST(Server, File));
167 }
168 
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 
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 
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 
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 
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 
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                             llvm::ArrayRef<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 
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                  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 
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                             llvm::ArrayRef<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
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-unknown-linux-gnu",
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> MockLibFile;
411   llvm::sys::path::append(MockLibFile, LibDir, "64", "crtbegin.o");
412   FS.Files[MockLibFile] = "";
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 
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 
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.
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 
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 
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 in this case.
625   CDB.ExtraClangFlags.push_back("-###");
626 
627   // Clang can't parse command args in that case, but we shouldn't crash.
628   runAddDocument(Server, FooCpp, "int main() {}");
629 
630   EXPECT_EQ(dumpAST(Server, FooCpp), "<no-ast>");
631   EXPECT_ERROR(runLocateSymbolAt(Server, FooCpp, Position()));
632   EXPECT_ERROR(runFindDocumentHighlights(Server, FooCpp, Position()));
633   EXPECT_ERROR(runRename(Server, FooCpp, Position(), "new_name",
634                          clangd::RenameOptions()));
635   EXPECT_ERROR(
636       runSignatureHelp(Server, FooCpp, Position(), MarkupKind::PlainText));
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 
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                             llvm::ArrayRef<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 
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                             llvm::ArrayRef<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 
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, /*Rng=*/std::nullopt);
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 
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)
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 
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 = {"-###"};
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 
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     std::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 
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)
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 
1205 TEST(ClangdServer, TidyOverrideTest) {
1206   struct DiagsCheckingCallback : public ClangdServer::Callbacks {
1207   public:
1208     void onDiagnosticsReady(PathRef File, llvm::StringRef Version,
1209                             llvm::ArrayRef<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 
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 
1262 TEST(ClangdServer, RespectsTweakFormatting) {
1263   static constexpr const char *TweakID = "ModuleTweak";
1264   static constexpr const char *NewContents = "{not;\nformatted;}";
1265 
1266   // Contributes a tweak that generates a non-formatted insertion and disables
1267   // formatting.
1268   struct TweakContributingModule final : public FeatureModule {
1269     struct ModuleTweak final : public Tweak {
1270       const char *id() const override { return TweakID; }
1271       bool prepare(const Selection &Sel) override { return true; }
1272       Expected<Effect> apply(const Selection &Sel) override {
1273         auto &SM = Sel.AST->getSourceManager();
1274         llvm::StringRef FilePath = SM.getFilename(Sel.Cursor);
1275         tooling::Replacements Reps;
1276         llvm::cantFail(
1277             Reps.add(tooling::Replacement(FilePath, 0, 0, NewContents)));
1278         auto E = llvm::cantFail(Effect::mainFileEdit(SM, std::move(Reps)));
1279         E.FormatEdits = false;
1280         return E;
1281       }
1282       std::string title() const override { return id(); }
1283       llvm::StringLiteral kind() const override {
1284         return llvm::StringLiteral("");
1285       };
1286     };
1287 
1288     void contributeTweaks(std::vector<std::unique_ptr<Tweak>> &Out) override {
1289       Out.emplace_back(new ModuleTweak);
1290     }
1291   };
1292 
1293   MockFS FS;
1294   MockCompilationDatabase CDB;
1295   auto Opts = ClangdServer::optsForTest();
1296   FeatureModuleSet Set;
1297   Set.add(std::make_unique<TweakContributingModule>());
1298   Opts.FeatureModules = &Set;
1299   ClangdServer Server(CDB, FS, Opts);
1300 
1301   auto FooCpp = testPath("foo.cpp");
1302   Server.addDocument(FooCpp, "");
1303   ASSERT_TRUE(Server.blockUntilIdleForTest());
1304 
1305   // Ensure that disabled formatting is respected.
1306   Notification N;
1307   Server.applyTweak(FooCpp, {}, TweakID, [&](llvm::Expected<Tweak::Effect> E) {
1308     ASSERT_TRUE(static_cast<bool>(E));
1309     EXPECT_THAT(llvm::cantFail(E->ApplyEdits.lookup(FooCpp).apply()),
1310                 NewContents);
1311     N.notify();
1312   });
1313   N.wait();
1314 }
1315 
1316 TEST(ClangdServer, InactiveRegions) {
1317   struct InactiveRegionsCallback : ClangdServer::Callbacks {
1318     std::vector<std::vector<Range>> FoundInactiveRegions;
1319 
1320     void onInactiveRegionsReady(PathRef FIle,
1321                                 std::vector<Range> InactiveRegions) override {
1322       FoundInactiveRegions.push_back(std::move(InactiveRegions));
1323     }
1324   };
1325 
1326   MockFS FS;
1327   MockCompilationDatabase CDB;
1328   CDB.ExtraClangFlags.push_back("-DCMDMACRO");
1329   auto Opts = ClangdServer::optsForTest();
1330   Opts.PublishInactiveRegions = true;
1331   InactiveRegionsCallback Callback;
1332   ClangdServer Server(CDB, FS, Opts, &Callback);
1333   Annotations Source(R"cpp(
1334 #define PREAMBLEMACRO 42
1335 #if PREAMBLEMACRO > 40
1336   #define ACTIVE
1337 #else
1338 $inactive1[[  #define INACTIVE]]
1339 #endif
1340 int endPreamble;
1341 #ifndef CMDMACRO
1342 $inactive2[[    int inactiveInt;]]
1343 #endif
1344 #undef CMDMACRO
1345 #ifdef CMDMACRO
1346 $inactive3[[  int inactiveInt2;]]
1347 #elif PREAMBLEMACRO > 0
1348   int activeInt1;
1349   int activeInt2;
1350 #else
1351 $inactive4[[  int inactiveInt3;]]
1352 #endif
1353 #ifdef CMDMACRO
1354 #endif  // empty inactive range, gets dropped
1355   )cpp");
1356   Server.addDocument(testPath("foo.cpp"), Source.code());
1357   ASSERT_TRUE(Server.blockUntilIdleForTest());
1358   EXPECT_THAT(Callback.FoundInactiveRegions,
1359               ElementsAre(ElementsAre(
1360                   Source.range("inactive1"), Source.range("inactive2"),
1361                   Source.range("inactive3"), Source.range("inactive4"))));
1362 }
1363 
1364 } // namespace
1365 } // namespace clangd
1366 } // namespace clang
1367