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