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