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