clang-tools  11.0.0
FileIndexTests.cpp
Go to the documentation of this file.
1 //===-- FileIndexTests.cpp ---------------------------*- 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 "AST.h"
10 #include "Annotations.h"
11 #include "Compiler.h"
12 #include "Headers.h"
13 #include "ParsedAST.h"
14 #include "SyncAPI.h"
15 #include "TestFS.h"
16 #include "TestTU.h"
17 #include "URI.h"
19 #include "index/FileIndex.h"
20 #include "index/Index.h"
21 #include "index/Ref.h"
22 #include "index/Relation.h"
23 #include "index/Serialization.h"
24 #include "index/Symbol.h"
25 #include "support/Threading.h"
26 #include "clang/Frontend/CompilerInvocation.h"
27 #include "clang/Frontend/Utils.h"
28 #include "clang/Index/IndexSymbol.h"
29 #include "clang/Lex/Preprocessor.h"
30 #include "clang/Tooling/CompilationDatabase.h"
31 #include "gmock/gmock.h"
32 #include "gtest/gtest.h"
33 #include <utility>
34 
35 using ::testing::_;
36 using ::testing::AllOf;
37 using ::testing::Contains;
38 using ::testing::ElementsAre;
39 using ::testing::IsEmpty;
40 using ::testing::Pair;
41 using ::testing::UnorderedElementsAre;
42 
43 MATCHER_P(RefRange, Range, "") {
44  return std::make_tuple(arg.Location.Start.line(), arg.Location.Start.column(),
45  arg.Location.End.line(), arg.Location.End.column()) ==
46  std::make_tuple(Range.start.line, Range.start.character,
47  Range.end.line, Range.end.character);
48 }
49 MATCHER_P(FileURI, F, "") { return llvm::StringRef(arg.Location.FileURI) == F; }
50 MATCHER_P(DeclURI, U, "") {
51  return llvm::StringRef(arg.CanonicalDeclaration.FileURI) == U;
52 }
53 MATCHER_P(DefURI, U, "") {
54  return llvm::StringRef(arg.Definition.FileURI) == U;
55 }
56 MATCHER_P(QName, N, "") { return (arg.Scope + arg.Name).str() == N; }
57 MATCHER_P(NumReferences, N, "") { return arg.References == N; }
58 MATCHER_P(hasOrign, O, "") { return bool(arg.Origin & O); }
59 
60 namespace clang {
61 namespace clangd {
62 namespace {
63 ::testing::Matcher<const RefSlab &>
64 RefsAre(std::vector<::testing::Matcher<Ref>> Matchers) {
65  return ElementsAre(::testing::Pair(_, UnorderedElementsAreArray(Matchers)));
66 }
67 
68 Symbol symbol(llvm::StringRef ID) {
69  Symbol Sym;
70  Sym.ID = SymbolID(ID);
71  Sym.Name = ID;
72  return Sym;
73 }
74 
75 std::unique_ptr<SymbolSlab> numSlab(int Begin, int End) {
77  for (int i = Begin; i <= End; i++)
78  Slab.insert(symbol(std::to_string(i)));
79  return std::make_unique<SymbolSlab>(std::move(Slab).build());
80 }
81 
82 std::unique_ptr<RefSlab> refSlab(const SymbolID &ID, const char *Path) {
83  RefSlab::Builder Slab;
84  Ref R;
85  R.Location.FileURI = Path;
86  R.Kind = RefKind::Reference;
87  Slab.insert(ID, R);
88  return std::make_unique<RefSlab>(std::move(Slab).build());
89 }
90 
91 TEST(FileSymbolsTest, UpdateAndGet) {
92  FileSymbols FS;
93  EXPECT_THAT(runFuzzyFind(*FS.buildIndex(IndexType::Light), ""), IsEmpty());
94 
95  FS.update("f1", numSlab(1, 3), refSlab(SymbolID("1"), "f1.cc"), nullptr,
96  false);
97  EXPECT_THAT(runFuzzyFind(*FS.buildIndex(IndexType::Light), ""),
98  UnorderedElementsAre(QName("1"), QName("2"), QName("3")));
99  EXPECT_THAT(getRefs(*FS.buildIndex(IndexType::Light), SymbolID("1")),
100  RefsAre({FileURI("f1.cc")}));
101 }
102 
103 TEST(FileSymbolsTest, Overlap) {
104  FileSymbols FS;
105  FS.update("f1", numSlab(1, 3), nullptr, nullptr, false);
106  FS.update("f2", numSlab(3, 5), nullptr, nullptr, false);
107  for (auto Type : {IndexType::Light, IndexType::Heavy})
108  EXPECT_THAT(runFuzzyFind(*FS.buildIndex(Type), ""),
109  UnorderedElementsAre(QName("1"), QName("2"), QName("3"),
110  QName("4"), QName("5")));
111 }
112 
113 TEST(FileSymbolsTest, MergeOverlap) {
114  FileSymbols FS;
115  auto OneSymboSlab = [](Symbol Sym) {
117  S.insert(Sym);
118  return std::make_unique<SymbolSlab>(std::move(S).build());
119  };
120  auto X1 = symbol("x");
121  X1.CanonicalDeclaration.FileURI = "file:///x1";
122  auto X2 = symbol("x");
123  X2.Definition.FileURI = "file:///x2";
124 
125  FS.update("f1", OneSymboSlab(X1), nullptr, nullptr, false);
126  FS.update("f2", OneSymboSlab(X2), nullptr, nullptr, false);
127  for (auto Type : {IndexType::Light, IndexType::Heavy})
128  EXPECT_THAT(
129  runFuzzyFind(*FS.buildIndex(Type, DuplicateHandling::Merge), "x"),
130  UnorderedElementsAre(
131  AllOf(QName("x"), DeclURI("file:///x1"), DefURI("file:///x2"))));
132 }
133 
134 TEST(FileSymbolsTest, SnapshotAliveAfterRemove) {
135  FileSymbols FS;
136 
137  SymbolID ID("1");
138  FS.update("f1", numSlab(1, 3), refSlab(ID, "f1.cc"), nullptr, false);
139 
140  auto Symbols = FS.buildIndex(IndexType::Light);
141  EXPECT_THAT(runFuzzyFind(*Symbols, ""),
142  UnorderedElementsAre(QName("1"), QName("2"), QName("3")));
143  EXPECT_THAT(getRefs(*Symbols, ID), RefsAre({FileURI("f1.cc")}));
144 
145  FS.update("f1", nullptr, nullptr, nullptr, false);
146  auto Empty = FS.buildIndex(IndexType::Light);
147  EXPECT_THAT(runFuzzyFind(*Empty, ""), IsEmpty());
148  EXPECT_THAT(getRefs(*Empty, ID), ElementsAre());
149 
150  EXPECT_THAT(runFuzzyFind(*Symbols, ""),
151  UnorderedElementsAre(QName("1"), QName("2"), QName("3")));
152  EXPECT_THAT(getRefs(*Symbols, ID), RefsAre({FileURI("f1.cc")}));
153 }
154 
155 // Adds Basename.cpp, which includes Basename.h, which contains Code.
156 void update(FileIndex &M, llvm::StringRef Basename, llvm::StringRef Code) {
157  TestTU File;
158  File.Filename = (Basename + ".cpp").str();
159  File.HeaderFilename = (Basename + ".h").str();
160  File.HeaderCode = std::string(Code);
161  auto AST = File.build();
162  M.updatePreamble(testPath(File.Filename), /*Version=*/"null",
163  AST.getASTContext(), AST.getPreprocessorPtr(),
164  AST.getCanonicalIncludes());
165 }
166 
167 TEST(FileIndexTest, CustomizedURIScheme) {
168  FileIndex M;
169  update(M, "f", "class string {};");
170 
171  EXPECT_THAT(runFuzzyFind(M, ""), ElementsAre(DeclURI("unittest:///f.h")));
172 }
173 
174 TEST(FileIndexTest, IndexAST) {
175  FileIndex M;
176  update(M, "f1", "namespace ns { void f() {} class X {}; }");
177 
178  FuzzyFindRequest Req;
179  Req.Query = "";
180  Req.Scopes = {"ns::"};
181  EXPECT_THAT(runFuzzyFind(M, Req),
182  UnorderedElementsAre(QName("ns::f"), QName("ns::X")));
183 }
184 
185 TEST(FileIndexTest, NoLocal) {
186  FileIndex M;
187  update(M, "f1", "namespace ns { void f() { int local = 0; } class X {}; }");
188 
189  EXPECT_THAT(
190  runFuzzyFind(M, ""),
191  UnorderedElementsAre(QName("ns"), QName("ns::f"), QName("ns::X")));
192 }
193 
194 TEST(FileIndexTest, IndexMultiASTAndDeduplicate) {
195  FileIndex M;
196  update(M, "f1", "namespace ns { void f() {} class X {}; }");
197  update(M, "f2", "namespace ns { void ff() {} class X {}; }");
198 
199  FuzzyFindRequest Req;
200  Req.Scopes = {"ns::"};
201  EXPECT_THAT(
202  runFuzzyFind(M, Req),
203  UnorderedElementsAre(QName("ns::f"), QName("ns::X"), QName("ns::ff")));
204 }
205 
206 TEST(FileIndexTest, ClassMembers) {
207  FileIndex M;
208  update(M, "f1", "class X { static int m1; int m2; static void f(); };");
209 
210  EXPECT_THAT(runFuzzyFind(M, ""),
211  UnorderedElementsAre(QName("X"), QName("X::m1"), QName("X::m2"),
212  QName("X::f")));
213 }
214 
215 TEST(FileIndexTest, IncludeCollected) {
216  FileIndex M;
217  update(
218  M, "f",
219  "// IWYU pragma: private, include <the/good/header.h>\nclass string {};");
220 
221  auto Symbols = runFuzzyFind(M, "");
222  EXPECT_THAT(Symbols, ElementsAre(_));
223  EXPECT_THAT(Symbols.begin()->IncludeHeaders.front().IncludeHeader,
224  "<the/good/header.h>");
225 }
226 
227 TEST(FileIndexTest, HasSystemHeaderMappingsInPreamble) {
228  TestTU TU;
229  TU.HeaderCode = "class Foo{};";
230  TU.HeaderFilename = "algorithm";
231 
232  auto Symbols = runFuzzyFind(*TU.index(), "");
233  EXPECT_THAT(Symbols, ElementsAre(_));
234  EXPECT_THAT(Symbols.begin()->IncludeHeaders.front().IncludeHeader,
235  "<algorithm>");
236 }
237 
238 TEST(FileIndexTest, TemplateParamsInLabel) {
239  auto Source = R"cpp(
240 template <class Ty>
241 class vector {
242 };
243 
244 template <class Ty, class Arg>
245 vector<Ty> make_vector(Arg A) {}
246 )cpp";
247 
248  FileIndex M;
249  update(M, "f", Source);
250 
251  auto Symbols = runFuzzyFind(M, "");
252  EXPECT_THAT(Symbols,
253  UnorderedElementsAre(QName("vector"), QName("make_vector")));
254  auto It = Symbols.begin();
255  Symbol Vector = *It++;
256  Symbol MakeVector = *It++;
257  if (MakeVector.Name == "vector")
258  std::swap(MakeVector, Vector);
259 
260  EXPECT_EQ(Vector.Signature, "<class Ty>");
261  EXPECT_EQ(Vector.CompletionSnippetSuffix, "<${1:class Ty}>");
262 
263  EXPECT_EQ(MakeVector.Signature, "<class Ty>(Arg A)");
264  EXPECT_EQ(MakeVector.CompletionSnippetSuffix, "<${1:class Ty}>(${2:Arg A})");
265 }
266 
267 TEST(FileIndexTest, RebuildWithPreamble) {
268  auto FooCpp = testPath("foo.cpp");
269  auto FooH = testPath("foo.h");
270  // Preparse ParseInputs.
271  ParseInputs PI;
272  PI.CompileCommand.Directory = testRoot();
273  PI.CompileCommand.Filename = FooCpp;
274  PI.CompileCommand.CommandLine = {"clang", "-xc++", FooCpp};
275 
276  MockFS FS;
277  FS.Files[FooCpp] = "";
278  FS.Files[FooH] = R"cpp(
279  namespace ns_in_header {
280  int func_in_header();
281  }
282  )cpp";
283  PI.TFS = &FS;
284 
285  PI.Contents = R"cpp(
286  #include "foo.h"
287  namespace ns_in_source {
288  int func_in_source();
289  }
290  )cpp";
291 
292  // Rebuild the file.
293  IgnoreDiagnostics IgnoreDiags;
295 
296  FileIndex Index;
297  bool IndexUpdated = false;
298  buildPreamble(FooCpp, *CI, PI,
299  /*StoreInMemory=*/true,
300  [&](ASTContext &Ctx, std::shared_ptr<Preprocessor> PP,
301  const CanonicalIncludes &CanonIncludes) {
302  EXPECT_FALSE(IndexUpdated)
303  << "Expected only a single index update";
304  IndexUpdated = true;
305  Index.updatePreamble(FooCpp, /*Version=*/"null", Ctx,
306  std::move(PP), CanonIncludes);
307  });
308  ASSERT_TRUE(IndexUpdated);
309 
310  // Check the index contains symbols from the preamble, but not from the main
311  // file.
312  FuzzyFindRequest Req;
313  Req.Query = "";
314  Req.Scopes = {"", "ns_in_header::"};
315 
316  EXPECT_THAT(runFuzzyFind(Index, Req),
317  UnorderedElementsAre(QName("ns_in_header"),
318  QName("ns_in_header::func_in_header")));
319 }
320 
321 TEST(FileIndexTest, Refs) {
322  const char *HeaderCode = "class Foo {};";
323  Annotations MainCode(R"cpp(
324  void f() {
325  $foo[[Foo]] foo;
326  }
327  )cpp");
328 
329  auto Foo =
330  findSymbol(TestTU::withHeaderCode(HeaderCode).headerSymbols(), "Foo");
331 
332  RefsRequest Request;
333  Request.IDs = {Foo.ID};
334 
335  FileIndex Index;
336  // Add test.cc
337  TestTU Test;
338  Test.HeaderCode = HeaderCode;
339  Test.Code = std::string(MainCode.code());
340  Test.Filename = "test.cc";
341  auto AST = Test.build();
342  Index.updateMain(Test.Filename, AST);
343  // Add test2.cc
344  TestTU Test2;
345  Test2.HeaderCode = HeaderCode;
346  Test2.Code = std::string(MainCode.code());
347  Test2.Filename = "test2.cc";
348  AST = Test2.build();
349  Index.updateMain(Test2.Filename, AST);
350 
351  EXPECT_THAT(getRefs(Index, Foo.ID),
352  RefsAre({AllOf(RefRange(MainCode.range("foo")),
353  FileURI("unittest:///test.cc")),
354  AllOf(RefRange(MainCode.range("foo")),
355  FileURI("unittest:///test2.cc"))}));
356 }
357 
358 TEST(FileIndexTest, MacroRefs) {
359  Annotations HeaderCode(R"cpp(
360  #define $def1[[HEADER_MACRO]](X) (X+1)
361  )cpp");
362  Annotations MainCode(R"cpp(
363  #define $def2[[MAINFILE_MACRO]](X) (X+1)
364  void f() {
365  int a = $ref1[[HEADER_MACRO]](2);
366  int b = $ref2[[MAINFILE_MACRO]](1);
367  }
368  )cpp");
369 
370  FileIndex Index;
371  // Add test.cc
372  TestTU Test;
373  Test.HeaderCode = std::string(HeaderCode.code());
374  Test.Code = std::string(MainCode.code());
375  Test.Filename = "test.cc";
376  auto AST = Test.build();
377  Index.updateMain(Test.Filename, AST);
378 
379  auto HeaderMacro = findSymbol(Test.headerSymbols(), "HEADER_MACRO");
380  EXPECT_THAT(getRefs(Index, HeaderMacro.ID),
381  RefsAre({AllOf(RefRange(MainCode.range("ref1")),
382  FileURI("unittest:///test.cc"))}));
383 
384  auto MainFileMacro = findSymbol(Test.headerSymbols(), "MAINFILE_MACRO");
385  EXPECT_THAT(getRefs(Index, MainFileMacro.ID),
386  RefsAre({AllOf(RefRange(MainCode.range("def2")),
387  FileURI("unittest:///test.cc")),
388  AllOf(RefRange(MainCode.range("ref2")),
389  FileURI("unittest:///test.cc"))}));
390 }
391 
392 TEST(FileIndexTest, CollectMacros) {
393  FileIndex M;
394  update(M, "f", "#define CLANGD 1");
395  EXPECT_THAT(runFuzzyFind(M, ""), Contains(QName("CLANGD")));
396 }
397 
398 TEST(FileIndexTest, Relations) {
399  TestTU TU;
400  TU.Filename = "f.cpp";
401  TU.HeaderFilename = "f.h";
402  TU.HeaderCode = "class A {}; class B : public A {};";
403  auto AST = TU.build();
404  FileIndex Index;
405  Index.updatePreamble(testPath(TU.Filename), /*Version=*/"null",
406  AST.getASTContext(), AST.getPreprocessorPtr(),
407  AST.getCanonicalIncludes());
408  SymbolID A = findSymbol(TU.headerSymbols(), "A").ID;
409  uint32_t Results = 0;
410  RelationsRequest Req;
411  Req.Subjects.insert(A);
412  Req.Predicate = RelationKind::BaseOf;
413  Index.relations(Req, [&](const SymbolID &, const Symbol &) { ++Results; });
414  EXPECT_EQ(Results, 1u);
415 }
416 
417 TEST(FileIndexTest, ReferencesInMainFileWithPreamble) {
418  TestTU TU;
419  TU.HeaderCode = "class Foo{};";
420  Annotations Main(R"cpp(
421  void f() {
422  [[Foo]] foo;
423  }
424  )cpp");
425  TU.Code = std::string(Main.code());
426  auto AST = TU.build();
427  FileIndex Index;
428  Index.updateMain(testPath(TU.Filename), AST);
429 
430  // Expect to see references in main file, references in headers are excluded
431  // because we only index main AST.
432  EXPECT_THAT(getRefs(Index, findSymbol(TU.headerSymbols(), "Foo").ID),
433  RefsAre({RefRange(Main.range())}));
434 }
435 
436 TEST(FileIndexTest, MergeMainFileSymbols) {
437  const char *CommonHeader = "void foo();";
438  TestTU Header = TestTU::withCode(CommonHeader);
439  TestTU Cpp = TestTU::withCode("void foo() {}");
440  Cpp.Filename = "foo.cpp";
441  Cpp.HeaderFilename = "foo.h";
442  Cpp.HeaderCode = CommonHeader;
443 
444  FileIndex Index;
445  auto HeaderAST = Header.build();
446  auto CppAST = Cpp.build();
447  Index.updateMain(testPath("foo.h"), HeaderAST);
448  Index.updateMain(testPath("foo.cpp"), CppAST);
449 
450  auto Symbols = runFuzzyFind(Index, "");
451  // Check foo is merged, foo in Cpp wins (as we see the definition there).
452  EXPECT_THAT(Symbols, ElementsAre(AllOf(DeclURI("unittest:///foo.h"),
453  DefURI("unittest:///foo.cpp"),
454  hasOrign(SymbolOrigin::Merge))));
455 }
456 
457 TEST(FileSymbolsTest, CountReferencesNoRefSlabs) {
458  FileSymbols FS;
459  FS.update("f1", numSlab(1, 3), nullptr, nullptr, true);
460  FS.update("f2", numSlab(1, 3), nullptr, nullptr, false);
461  EXPECT_THAT(
463  ""),
464  UnorderedElementsAre(AllOf(QName("1"), NumReferences(0u)),
465  AllOf(QName("2"), NumReferences(0u)),
466  AllOf(QName("3"), NumReferences(0u))));
467 }
468 
469 TEST(FileSymbolsTest, CountReferencesWithRefSlabs) {
470  FileSymbols FS;
471  FS.update("f1cpp", numSlab(1, 3), refSlab(SymbolID("1"), "f1.cpp"), nullptr,
472  true);
473  FS.update("f1h", numSlab(1, 3), refSlab(SymbolID("1"), "f1.h"), nullptr,
474  false);
475  FS.update("f2cpp", numSlab(1, 3), refSlab(SymbolID("2"), "f2.cpp"), nullptr,
476  true);
477  FS.update("f2h", numSlab(1, 3), refSlab(SymbolID("2"), "f2.h"), nullptr,
478  false);
479  FS.update("f3cpp", numSlab(1, 3), refSlab(SymbolID("3"), "f3.cpp"), nullptr,
480  true);
481  FS.update("f3h", numSlab(1, 3), refSlab(SymbolID("3"), "f3.h"), nullptr,
482  false);
483  EXPECT_THAT(
485  ""),
486  UnorderedElementsAre(AllOf(QName("1"), NumReferences(1u)),
487  AllOf(QName("2"), NumReferences(1u)),
488  AllOf(QName("3"), NumReferences(1u))));
489 }
490 
491 TEST(FileIndexTest, StalePreambleSymbolsDeleted) {
492  FileIndex M;
493  TestTU File;
494  File.HeaderFilename = "a.h";
495 
496  File.Filename = "f1.cpp";
497  File.HeaderCode = "int a;";
498  auto AST = File.build();
499  M.updatePreamble(testPath(File.Filename), /*Version=*/"null",
500  AST.getASTContext(), AST.getPreprocessorPtr(),
501  AST.getCanonicalIncludes());
502  EXPECT_THAT(runFuzzyFind(M, ""), UnorderedElementsAre(QName("a")));
503 
504  File.Filename = "f2.cpp";
505  File.HeaderCode = "int b;";
506  AST = File.build();
507  M.updatePreamble(testPath(File.Filename), /*Version=*/"null",
508  AST.getASTContext(), AST.getPreprocessorPtr(),
509  AST.getCanonicalIncludes());
510  EXPECT_THAT(runFuzzyFind(M, ""), UnorderedElementsAre(QName("b")));
511 }
512 
513 // Verifies that concurrent calls to updateMain don't "lose" any updates.
514 TEST(FileIndexTest, Threadsafety) {
515  FileIndex M;
516  Notification Go;
517 
518  constexpr int Count = 10;
519  {
520  // Set up workers to concurrently call updateMain() with separate files.
521  AsyncTaskRunner Pool;
522  for (unsigned I = 0; I < Count; ++I) {
523  auto TU = TestTU::withCode(llvm::formatv("int xxx{0};", I).str());
524  TU.Filename = llvm::formatv("x{0}.c", I).str();
525  Pool.runAsync(TU.Filename, [&, Filename(testPath(TU.Filename)),
526  AST(TU.build())]() mutable {
527  Go.wait();
528  M.updateMain(Filename, AST);
529  });
530  }
531  // On your marks, get set...
532  Go.notify();
533  }
534 
535  EXPECT_THAT(runFuzzyFind(M, "xxx"), ::testing::SizeIs(Count));
536 }
537 
538 TEST(FileShardedIndexTest, Sharding) {
539  auto AHeaderUri = URI::create(testPath("a.h")).toString();
540  auto BHeaderUri = URI::create(testPath("b.h")).toString();
541  auto BSourceUri = URI::create(testPath("b.cc")).toString();
542 
543  auto Sym1 = symbol("1");
544  Sym1.CanonicalDeclaration.FileURI = AHeaderUri.c_str();
545 
546  auto Sym2 = symbol("2");
547  Sym2.CanonicalDeclaration.FileURI = BHeaderUri.c_str();
548  Sym2.Definition.FileURI = BSourceUri.c_str();
549 
550  IndexFileIn IF;
551  {
553  // Should be stored in only a.h
554  B.insert(Sym1);
555  // Should be stored in both b.h and b.cc
556  B.insert(Sym2);
557  IF.Symbols.emplace(std::move(B).build());
558  }
559  {
560  // Should be stored in b.cc
561  IF.Refs.emplace(std::move(*refSlab(Sym1.ID, BSourceUri.c_str())));
562  }
563  {
565  // Should be stored in a.h
566  B.insert(Relation{Sym1.ID, RelationKind::BaseOf, Sym2.ID});
567  // Should be stored in b.h
568  B.insert(Relation{Sym2.ID, RelationKind::BaseOf, Sym1.ID});
569  // Dangling relation should be dropped.
570  B.insert(Relation{symbol("3").ID, RelationKind::BaseOf, Sym1.ID});
571  IF.Relations.emplace(std::move(B).build());
572  }
573 
574  IF.Sources.emplace();
575  IncludeGraph &IG = *IF.Sources;
576  {
577  // b.cc includes b.h
578  auto &Node = IG[BSourceUri];
579  Node.DirectIncludes = {BHeaderUri};
580  Node.URI = BSourceUri;
581  }
582  {
583  // b.h includes a.h
584  auto &Node = IG[BHeaderUri];
585  Node.DirectIncludes = {AHeaderUri};
586  Node.URI = BHeaderUri;
587  }
588  {
589  // a.h includes nothing.
590  auto &Node = IG[AHeaderUri];
591  Node.DirectIncludes = {};
592  Node.URI = AHeaderUri;
593  }
594 
595  IF.Cmd = tooling::CompileCommand(testRoot(), "b.cc", {"clang"}, "out");
596 
597  FileShardedIndex ShardedIndex(std::move(IF));
598  ASSERT_THAT(ShardedIndex.getAllSources(),
599  UnorderedElementsAre(AHeaderUri, BHeaderUri, BSourceUri));
600 
601  {
602  auto Shard = ShardedIndex.getShard(AHeaderUri);
603  ASSERT_TRUE(Shard);
604  EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(QName("1")));
605  EXPECT_THAT(*Shard->Refs, IsEmpty());
606  EXPECT_THAT(
607  *Shard->Relations,
608  UnorderedElementsAre(Relation{Sym1.ID, RelationKind::BaseOf, Sym2.ID}));
609  ASSERT_THAT(Shard->Sources->keys(), UnorderedElementsAre(AHeaderUri));
610  EXPECT_THAT(Shard->Sources->lookup(AHeaderUri).DirectIncludes, IsEmpty());
611  EXPECT_TRUE(Shard->Cmd.hasValue());
612  }
613  {
614  auto Shard = ShardedIndex.getShard(BHeaderUri);
615  ASSERT_TRUE(Shard);
616  EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(QName("2")));
617  EXPECT_THAT(*Shard->Refs, IsEmpty());
618  EXPECT_THAT(
619  *Shard->Relations,
620  UnorderedElementsAre(Relation{Sym2.ID, RelationKind::BaseOf, Sym1.ID}));
621  ASSERT_THAT(Shard->Sources->keys(),
622  UnorderedElementsAre(BHeaderUri, AHeaderUri));
623  EXPECT_THAT(Shard->Sources->lookup(BHeaderUri).DirectIncludes,
624  UnorderedElementsAre(AHeaderUri));
625  EXPECT_TRUE(Shard->Cmd.hasValue());
626  }
627  {
628  auto Shard = ShardedIndex.getShard(BSourceUri);
629  ASSERT_TRUE(Shard);
630  EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(QName("2")));
631  EXPECT_THAT(*Shard->Refs, UnorderedElementsAre(Pair(Sym1.ID, _)));
632  EXPECT_THAT(*Shard->Relations, IsEmpty());
633  ASSERT_THAT(Shard->Sources->keys(),
634  UnorderedElementsAre(BSourceUri, BHeaderUri));
635  EXPECT_THAT(Shard->Sources->lookup(BSourceUri).DirectIncludes,
636  UnorderedElementsAre(BHeaderUri));
637  EXPECT_TRUE(Shard->Cmd.hasValue());
638  }
639 }
640 } // namespace
641 } // namespace clangd
642 } // namespace clang
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
clang::clangd::TEST
TEST(BackgroundQueueTest, Priority)
Definition: BackgroundIndexTests.cpp:704
Headers.h
clang::clangd::runFuzzyFind
SymbolSlab runFuzzyFind(const SymbolIndex &Index, llvm::StringRef Query)
Definition: SyncAPI.cpp:121
clang::clangd::RelationKind::BaseOf
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
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:471
clang::clangd::testPath
std::string testPath(PathRef File, llvm::sys::path::Style Style)
Definition: TestFS.cpp:82
clang::clangd::Symbol::ID
SymbolID ID
The ID of the symbol.
Definition: Symbol.h:38
Refs
RefSlab Refs
Definition: SymbolCollectorTests.cpp:296
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:20
clang::clangd::ParsedAST::getPreprocessorPtr
std::shared_ptr< Preprocessor > getPreprocessorPtr()
Definition: ParsedAST.cpp:479
Index.h
CI
std::unique_ptr< CompilerInvocation > CI
Definition: TUScheduler.cpp:320
clang::clangd::URI::create
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
Definition: URI.cpp:196
TestTU.h
Filename
std::string Filename
Filename as a string.
Definition: IncludeOrderCheck.cpp:39
clang::clangd::ParsedAST::getCanonicalIncludes
const CanonicalIncludes & getCanonicalIncludes() const
Definition: ParsedAST.cpp:531
Ctx
Context Ctx
Definition: TUScheduler.cpp:324
MATCHER_P
MATCHER_P(RefRange, Range, "")
Definition: FileIndexTests.cpp:43
clang::clangd::RefsAre
::testing::Matcher< const RefSlab & > RefsAre(std::vector<::testing::Matcher< Ref >> Matchers)
Definition: BackgroundIndexTests.cpp:37
clang::clangd::ParsedAST::build
static llvm::Optional< ParsedAST > build(llvm::StringRef Filename, const ParseInputs &Inputs, std::unique_ptr< clang::CompilerInvocation > CI, llvm::ArrayRef< Diag > CompilerInvocationDiags, std::shared_ptr< const PreambleData > Preamble)
Attempts to run Clang and store the parsed AST.
Definition: ParsedAST.cpp:246
clang::clangd::TestTU::withHeaderCode
static TestTU withHeaderCode(llvm::StringRef HeaderCode)
Definition: TestTU.h:41
Relation.h
clang::clangd::getRefs
RefSlab getRefs(const SymbolIndex &Index, SymbolID ID)
Definition: SyncAPI.cpp:134
Code
std::string Code
Definition: FindTargetTests.cpp:67
CanonicalIncludes.h
clang::clangd::testRoot
const char * testRoot()
Definition: TestFS.cpp:74
clang::clangd::SymbolIndex::relations
virtual void relations(const RelationsRequest &Req, llvm::function_ref< void(const SymbolID &Subject, const Symbol &Object)> Callback) const =0
Finds all relations (S, P, O) stored in the index such that S is among Req.Subjects and P is Req....
Builder
CodeCompletionBuilder Builder
Definition: CodeCompletionStringsTests.cpp:35
clang::clangd::buildPreamble
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation CI, const ParseInputs &Inputs, bool StoreInMemory, PreambleParsedCallback PreambleCallback)
Build a preamble for the new inputs unless an old one can be reused.
Definition: Preamble.cpp:321
FS
MockFS FS
Definition: ClangdLSPServerTests.cpp:66
TestFS.h
Threading.h
SyncAPI.h
clang::clangd::RefKind::Reference
Serialization.h
Results
std::vector< CodeCompletionResult > Results
Definition: CodeComplete.cpp:712
clang::doc::SymbolID
std::array< uint8_t, 20 > SymbolID
Definition: Representation.h:30
clang::clangd::TestTU::withCode
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:35
clang::clangd::DuplicateHandling::Merge
FileIndex.h
Annotations.h
Symbol.h
clang::tidy::bugprone::PP
static Preprocessor * PP
Definition: BadSignalToKillThreadCheck.cpp:29
clang::clangd::buildCompilerInvocation
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
Definition: Compiler.cpp:45
Index
const SymbolIndex * Index
Definition: Dexp.cpp:95
Compiler.h
clang::clangd::Empty
Definition: FuzzyMatch.h:42
Ref.h
clang::clangd::SymbolSlab::begin
const_iterator begin() const
Definition: Symbol.h:185
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
Symbols
SymbolSlab Symbols
Definition: SymbolCollectorTests.cpp:295
clang::clangd::IncludeGraph
llvm::StringMap< IncludeGraphNode > IncludeGraph
Definition: Headers.h:86
clang::clangd::MockFS::Files
llvm::StringMap< std::string > Files
Definition: TestFS.h:41
clang::clangd::symbol
Symbol symbol(llvm::StringRef QName)
Definition: TestIndex.cpp:16
URI.h
clang::clangd::IndexType::Heavy
clang::clangd::findSymbol
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
Definition: TestTU.cpp:144
IgnoreDiags
IgnoringDiagConsumer IgnoreDiags
Definition: HeadersTests.cpp:128
clang::clangd::IndexType::Light
AST.h
ParsedAST.h