clang-tools  12.0.0git
SymbolCollectorTests.cpp
Go to the documentation of this file.
1 //===-- SymbolCollectorTests.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 "Annotations.h"
10 #include "TestFS.h"
11 #include "TestTU.h"
12 #include "index/SymbolCollector.h"
13 #include "clang/Basic/FileManager.h"
14 #include "clang/Basic/FileSystemOptions.h"
15 #include "clang/Frontend/CompilerInstance.h"
16 #include "clang/Index/IndexingAction.h"
17 #include "clang/Index/IndexingOptions.h"
18 #include "clang/Tooling/Tooling.h"
19 #include "llvm/ADT/IntrusiveRefCntPtr.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/VirtualFileSystem.h"
24 #include "gmock/gmock-matchers.h"
25 #include "gmock/gmock-more-matchers.h"
26 #include "gmock/gmock.h"
27 #include "gtest/gtest.h"
28 
29 #include <memory>
30 #include <string>
31 
32 namespace clang {
33 namespace clangd {
34 namespace {
35 
36 using ::testing::_;
37 using ::testing::AllOf;
38 using ::testing::Contains;
39 using ::testing::Each;
40 using ::testing::ElementsAre;
41 using ::testing::Field;
42 using ::testing::IsEmpty;
43 using ::testing::Not;
44 using ::testing::Pair;
45 using ::testing::UnorderedElementsAre;
46 using ::testing::UnorderedElementsAreArray;
47 
48 // GMock helpers for matching Symbol.
49 MATCHER_P(Labeled, Label, "") {
50  return (arg.Name + arg.Signature).str() == Label;
51 }
52 MATCHER_P(ReturnType, D, "") { return arg.ReturnType == D; }
53 MATCHER_P(Doc, D, "") { return arg.Documentation == D; }
54 MATCHER_P(Snippet, S, "") {
55  return (arg.Name + arg.CompletionSnippetSuffix).str() == S;
56 }
57 MATCHER_P(QName, Name, "") { return (arg.Scope + arg.Name).str() == Name; }
58 MATCHER_P(TemplateArgs, TemplArgs, "") {
59  return arg.TemplateSpecializationArgs == TemplArgs;
60 }
61 MATCHER_P(DeclURI, P, "") {
62  return StringRef(arg.CanonicalDeclaration.FileURI) == P;
63 }
64 MATCHER_P(DefURI, P, "") { return StringRef(arg.Definition.FileURI) == P; }
65 MATCHER(IncludeHeader, "") { return !arg.IncludeHeaders.empty(); }
66 MATCHER_P(IncludeHeader, P, "") {
67  return (arg.IncludeHeaders.size() == 1) &&
68  (arg.IncludeHeaders.begin()->IncludeHeader == P);
69 }
70 MATCHER_P2(IncludeHeaderWithRef, IncludeHeader, References, "") {
71  return (arg.IncludeHeader == IncludeHeader) && (arg.References == References);
72 }
73 bool rangesMatch(const SymbolLocation &Loc, const Range &R) {
74  return std::make_tuple(Loc.Start.line(), Loc.Start.column(), Loc.End.line(),
75  Loc.End.column()) ==
76  std::make_tuple(R.start.line, R.start.character, R.end.line,
77  R.end.character);
78 }
79 MATCHER_P(DeclRange, Pos, "") {
80  return rangesMatch(arg.CanonicalDeclaration, Pos);
81 }
82 MATCHER_P(DefRange, Pos, "") { return rangesMatch(arg.Definition, Pos); }
83 MATCHER_P(RefCount, R, "") { return int(arg.References) == R; }
84 MATCHER_P(ForCodeCompletion, IsIndexedForCodeCompletion, "") {
85  return static_cast<bool>(arg.Flags & Symbol::IndexedForCodeCompletion) ==
86  IsIndexedForCodeCompletion;
87 }
88 MATCHER(Deprecated, "") { return arg.Flags & Symbol::Deprecated; }
89 MATCHER(ImplementationDetail, "") {
90  return arg.Flags & Symbol::ImplementationDetail;
91 }
92 MATCHER(VisibleOutsideFile, "") {
93  return static_cast<bool>(arg.Flags & Symbol::VisibleOutsideFile);
94 }
95 MATCHER(RefRange, "") {
96  const Ref &Pos = ::testing::get<0>(arg);
97  const Range &Range = ::testing::get<1>(arg);
98  return rangesMatch(Pos.Location, Range);
99 }
100 MATCHER_P2(OverriddenBy, Subject, Object, "") {
101  return arg == Relation{Subject.ID, RelationKind::OverriddenBy, Object.ID};
102 }
103 ::testing::Matcher<const std::vector<Ref> &>
104 HaveRanges(const std::vector<Range> Ranges) {
105  return ::testing::UnorderedPointwise(RefRange(), Ranges);
106 }
107 
108 class ShouldCollectSymbolTest : public ::testing::Test {
109 public:
110  void build(llvm::StringRef HeaderCode, llvm::StringRef Code = "") {
111  File.HeaderFilename = HeaderName;
112  File.Filename = FileName;
113  File.HeaderCode = std::string(HeaderCode);
114  File.Code = std::string(Code);
115  AST = File.build();
116  }
117 
118  // build() must have been called.
119  bool shouldCollect(llvm::StringRef Name, bool Qualified = true) {
120  assert(AST.hasValue());
121  const NamedDecl &ND =
122  Qualified ? findDecl(*AST, Name) : findUnqualifiedDecl(*AST, Name);
123  const SourceManager &SM = AST->getSourceManager();
124  bool MainFile = isInsideMainFile(ND.getBeginLoc(), SM);
126  ND, AST->getASTContext(), SymbolCollector::Options(), MainFile);
127  }
128 
129 protected:
130  std::string HeaderName = "f.h";
131  std::string FileName = "f.cpp";
132  TestTU File;
133  llvm::Optional<ParsedAST> AST; // Initialized after build.
134 };
135 
136 TEST_F(ShouldCollectSymbolTest, ShouldCollectSymbol) {
137  build(R"(
138  namespace nx {
139  class X{};
140  auto f() { int Local; } // auto ensures function body is parsed.
141  struct { int x; } var;
142  }
143  )",
144  R"(
145  class InMain {};
146  namespace { class InAnonymous {}; }
147  static void g();
148  )");
149  auto AST = File.build();
150  EXPECT_TRUE(shouldCollect("nx"));
151  EXPECT_TRUE(shouldCollect("nx::X"));
152  EXPECT_TRUE(shouldCollect("nx::f"));
153  EXPECT_TRUE(shouldCollect("InMain"));
154  EXPECT_TRUE(shouldCollect("InAnonymous", /*Qualified=*/false));
155  EXPECT_TRUE(shouldCollect("g"));
156 
157  EXPECT_FALSE(shouldCollect("Local", /*Qualified=*/false));
158 }
159 
160 TEST_F(ShouldCollectSymbolTest, NoPrivateProtoSymbol) {
161  HeaderName = "f.proto.h";
162  build(
163  R"(// Generated by the protocol buffer compiler. DO NOT EDIT!
164  namespace nx {
165  class Top_Level {};
166  class TopLevel {};
167  enum Kind {
168  KIND_OK,
169  Kind_Not_Ok,
170  };
171  })");
172  EXPECT_TRUE(shouldCollect("nx::TopLevel"));
173  EXPECT_TRUE(shouldCollect("nx::Kind::KIND_OK"));
174  EXPECT_TRUE(shouldCollect("nx::Kind"));
175 
176  EXPECT_FALSE(shouldCollect("nx::Top_Level"));
177  EXPECT_FALSE(shouldCollect("nx::Kind::Kind_Not_Ok"));
178 }
179 
180 TEST_F(ShouldCollectSymbolTest, DoubleCheckProtoHeaderComment) {
181  HeaderName = "f.proto.h";
182  build(R"(
183  namespace nx {
184  class Top_Level {};
185  enum Kind {
186  Kind_Fine
187  };
188  }
189  )");
190  EXPECT_TRUE(shouldCollect("nx::Top_Level"));
191  EXPECT_TRUE(shouldCollect("nx::Kind_Fine"));
192 }
193 
194 class SymbolIndexActionFactory : public tooling::FrontendActionFactory {
195 public:
196  SymbolIndexActionFactory(SymbolCollector::Options COpts,
197  CommentHandler *PragmaHandler)
198  : COpts(std::move(COpts)), PragmaHandler(PragmaHandler) {}
199 
200  std::unique_ptr<FrontendAction> create() override {
201  class IndexAction : public ASTFrontendAction {
202  public:
203  IndexAction(std::shared_ptr<index::IndexDataConsumer> DataConsumer,
204  const index::IndexingOptions &Opts,
205  CommentHandler *PragmaHandler)
206  : DataConsumer(std::move(DataConsumer)), Opts(Opts),
208 
209  std::unique_ptr<ASTConsumer>
210  CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override {
211  if (PragmaHandler)
212  CI.getPreprocessor().addCommentHandler(PragmaHandler);
213  return createIndexingASTConsumer(DataConsumer, Opts,
214  CI.getPreprocessorPtr());
215  }
216 
217  bool BeginInvocation(CompilerInstance &CI) override {
218  // Make the compiler parse all comments.
219  CI.getLangOpts().CommentOpts.ParseAllComments = true;
220  return true;
221  }
222 
223  private:
224  std::shared_ptr<index::IndexDataConsumer> DataConsumer;
225  index::IndexingOptions Opts;
226  CommentHandler *PragmaHandler;
227  };
228  index::IndexingOptions IndexOpts;
229  IndexOpts.SystemSymbolFilter =
230  index::IndexingOptions::SystemSymbolFilterKind::All;
231  IndexOpts.IndexFunctionLocals = false;
232  Collector = std::make_shared<SymbolCollector>(COpts);
233  return std::make_unique<IndexAction>(Collector, std::move(IndexOpts),
234  PragmaHandler);
235  }
236 
237  std::shared_ptr<SymbolCollector> Collector;
238  SymbolCollector::Options COpts;
239  CommentHandler *PragmaHandler;
240 };
241 
242 class SymbolCollectorTest : public ::testing::Test {
243 public:
244  SymbolCollectorTest()
246  TestHeaderName(testPath("symbol.h")),
247  TestFileName(testPath("symbol.cc")) {
249  TestFileURI = URI::create(TestFileName).toString();
250  }
251 
252  // Note that unlike TestTU, no automatic header guard is added.
253  // HeaderCode should start with #pragma once to be treated as modular.
254  bool runSymbolCollector(llvm::StringRef HeaderCode, llvm::StringRef MainCode,
255  const std::vector<std::string> &ExtraArgs = {}) {
256  llvm::IntrusiveRefCntPtr<FileManager> Files(
257  new FileManager(FileSystemOptions(), InMemoryFileSystem));
258 
259  auto Factory = std::make_unique<SymbolIndexActionFactory>(
261 
262  std::vector<std::string> Args = {"symbol_collector", "-fsyntax-only",
263  "-xc++", "-include", TestHeaderName};
264  Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
265  // This allows to override the "-xc++" with something else, i.e.
266  // -xobjective-c++.
267  Args.push_back(TestFileName);
268 
269  tooling::ToolInvocation Invocation(
270  Args, Factory->create(), Files.get(),
271  std::make_shared<PCHContainerOperations>());
272 
274  llvm::MemoryBuffer::getMemBuffer(HeaderCode));
275  InMemoryFileSystem->addFile(TestFileName, 0,
276  llvm::MemoryBuffer::getMemBuffer(MainCode));
277  Invocation.run();
278  Symbols = Factory->Collector->takeSymbols();
279  Refs = Factory->Collector->takeRefs();
280  Relations = Factory->Collector->takeRelations();
281  return true;
282  }
283 
284 protected:
285  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
286  std::string TestHeaderName;
287  std::string TestHeaderURI;
288  std::string TestFileName;
289  std::string TestFileURI;
290  SymbolSlab Symbols;
291  RefSlab Refs;
292  RelationSlab Relations;
293  SymbolCollector::Options CollectorOpts;
294  std::unique_ptr<CommentHandler> PragmaHandler;
295 };
296 
297 TEST_F(SymbolCollectorTest, CollectSymbols) {
298  const std::string Header = R"(
299  class Foo {
300  Foo() {}
301  Foo(int a) {}
302  void f();
303  friend void f1();
304  friend class Friend;
305  Foo& operator=(const Foo&);
306  ~Foo();
307  class Nested {
308  void f();
309  };
310  };
311  class Friend {
312  };
313 
314  void f1();
315  inline void f2() {}
316  static const int KInt = 2;
317  const char* kStr = "123";
318 
319  namespace {
320  void ff() {} // ignore
321  }
322 
323  void f1() {}
324 
325  namespace foo {
326  // Type alias
327  typedef int int32;
328  using int32_t = int32;
329 
330  // Variable
331  int v1;
332 
333  // Namespace
334  namespace bar {
335  int v2;
336  }
337  // Namespace alias
338  namespace baz = bar;
339 
340  using bar::v2;
341  } // namespace foo
342  )";
343  runSymbolCollector(Header, /*Main=*/"");
344  EXPECT_THAT(Symbols,
345  UnorderedElementsAreArray(
346  {AllOf(QName("Foo"), ForCodeCompletion(true)),
347  AllOf(QName("Foo::Foo"), ForCodeCompletion(false)),
348  AllOf(QName("Foo::Foo"), ForCodeCompletion(false)),
349  AllOf(QName("Foo::f"), ForCodeCompletion(false)),
350  AllOf(QName("Foo::~Foo"), ForCodeCompletion(false)),
351  AllOf(QName("Foo::operator="), ForCodeCompletion(false)),
352  AllOf(QName("Foo::Nested"), ForCodeCompletion(false)),
353  AllOf(QName("Foo::Nested::f"), ForCodeCompletion(false)),
354 
355  AllOf(QName("Friend"), ForCodeCompletion(true)),
356  AllOf(QName("f1"), ForCodeCompletion(true)),
357  AllOf(QName("f2"), ForCodeCompletion(true)),
358  AllOf(QName("KInt"), ForCodeCompletion(true)),
359  AllOf(QName("kStr"), ForCodeCompletion(true)),
360  AllOf(QName("foo"), ForCodeCompletion(true)),
361  AllOf(QName("foo::bar"), ForCodeCompletion(true)),
362  AllOf(QName("foo::int32"), ForCodeCompletion(true)),
363  AllOf(QName("foo::int32_t"), ForCodeCompletion(true)),
364  AllOf(QName("foo::v1"), ForCodeCompletion(true)),
365  AllOf(QName("foo::bar::v2"), ForCodeCompletion(true)),
366  AllOf(QName("foo::v2"), ForCodeCompletion(true)),
367  AllOf(QName("foo::baz"), ForCodeCompletion(true))}));
368 }
369 
370 TEST_F(SymbolCollectorTest, FileLocal) {
371  const std::string Header = R"(
372  class Foo {};
373  namespace {
374  class Ignored {};
375  }
376  void bar();
377  )";
378  const std::string Main = R"(
379  class ForwardDecl;
380  void bar() {}
381  static void a();
382  class B {};
383  namespace {
384  void c();
385  }
386  )";
387  runSymbolCollector(Header, Main);
388  EXPECT_THAT(Symbols,
389  UnorderedElementsAre(
390  AllOf(QName("Foo"), VisibleOutsideFile()),
391  AllOf(QName("bar"), VisibleOutsideFile()),
392  AllOf(QName("a"), Not(VisibleOutsideFile())),
393  AllOf(QName("B"), Not(VisibleOutsideFile())),
394  AllOf(QName("c"), Not(VisibleOutsideFile())),
395  // FIXME: ForwardDecl likely *is* visible outside.
396  AllOf(QName("ForwardDecl"), Not(VisibleOutsideFile()))));
397 }
398 
399 TEST_F(SymbolCollectorTest, Template) {
400  Annotations Header(R"(
401  // Primary template and explicit specialization are indexed, instantiation
402  // is not.
403  template <class T, class U> struct [[Tmpl]] {T $xdecl[[x]] = 0;};
404  template <> struct $specdecl[[Tmpl]]<int, bool> {};
405  template <class U> struct $partspecdecl[[Tmpl]]<bool, U> {};
406  extern template struct Tmpl<float, bool>;
407  template struct Tmpl<double, bool>;
408  )");
409  runSymbolCollector(Header.code(), /*Main=*/"");
410  EXPECT_THAT(Symbols,
411  UnorderedElementsAre(
412  AllOf(QName("Tmpl"), DeclRange(Header.range()),
413  ForCodeCompletion(true)),
414  AllOf(QName("Tmpl"), DeclRange(Header.range("specdecl")),
415  ForCodeCompletion(false)),
416  AllOf(QName("Tmpl"), DeclRange(Header.range("partspecdecl")),
417  ForCodeCompletion(false)),
418  AllOf(QName("Tmpl::x"), DeclRange(Header.range("xdecl")),
419  ForCodeCompletion(false))));
420 }
421 
422 TEST_F(SymbolCollectorTest, TemplateArgs) {
423  Annotations Header(R"(
424  template <class X> class $barclasstemp[[Bar]] {};
425  template <class T, class U, template<typename> class Z, int Q>
426  struct [[Tmpl]] { T $xdecl[[x]] = 0; };
427 
428  // template-template, non-type and type full spec
429  template <> struct $specdecl[[Tmpl]]<int, bool, Bar, 3> {};
430 
431  // template-template, non-type and type partial spec
432  template <class U, int T> struct $partspecdecl[[Tmpl]]<bool, U, Bar, T> {};
433  // instantiation
434  extern template struct Tmpl<float, bool, Bar, 8>;
435  // instantiation
436  template struct Tmpl<double, bool, Bar, 2>;
437 
438  template <typename ...> class $fooclasstemp[[Foo]] {};
439  // parameter-packs full spec
440  template<> class $parampack[[Foo]]<Bar<int>, int, double> {};
441  // parameter-packs partial spec
442  template<class T> class $parampackpartial[[Foo]]<T, T> {};
443 
444  template <int ...> class $bazclasstemp[[Baz]] {};
445  // non-type parameter-packs full spec
446  template<> class $parampacknontype[[Baz]]<3, 5, 8> {};
447  // non-type parameter-packs partial spec
448  template<int T> class $parampacknontypepartial[[Baz]]<T, T> {};
449 
450  template <template <class> class ...> class $fozclasstemp[[Foz]] {};
451  // template-template parameter-packs full spec
452  template<> class $parampacktempltempl[[Foz]]<Bar, Bar> {};
453  // template-template parameter-packs partial spec
454  template<template <class> class T>
455  class $parampacktempltemplpartial[[Foz]]<T, T> {};
456  )");
457  runSymbolCollector(Header.code(), /*Main=*/"");
458  EXPECT_THAT(
459  Symbols,
460  AllOf(
461  Contains(AllOf(QName("Tmpl"), TemplateArgs("<int, bool, Bar, 3>"),
462  DeclRange(Header.range("specdecl")),
463  ForCodeCompletion(false))),
464  Contains(AllOf(QName("Tmpl"), TemplateArgs("<bool, U, Bar, T>"),
465  DeclRange(Header.range("partspecdecl")),
466  ForCodeCompletion(false))),
467  Contains(AllOf(QName("Foo"), TemplateArgs("<Bar<int>, int, double>"),
468  DeclRange(Header.range("parampack")),
469  ForCodeCompletion(false))),
470  Contains(AllOf(QName("Foo"), TemplateArgs("<T, T>"),
471  DeclRange(Header.range("parampackpartial")),
472  ForCodeCompletion(false))),
473  Contains(AllOf(QName("Baz"), TemplateArgs("<3, 5, 8>"),
474  DeclRange(Header.range("parampacknontype")),
475  ForCodeCompletion(false))),
476  Contains(AllOf(QName("Baz"), TemplateArgs("<T, T>"),
477  DeclRange(Header.range("parampacknontypepartial")),
478  ForCodeCompletion(false))),
479  Contains(AllOf(QName("Foz"), TemplateArgs("<Bar, Bar>"),
480  DeclRange(Header.range("parampacktempltempl")),
481  ForCodeCompletion(false))),
482  Contains(AllOf(QName("Foz"), TemplateArgs("<T, T>"),
483  DeclRange(Header.range("parampacktempltemplpartial")),
484  ForCodeCompletion(false)))));
485 }
486 
487 TEST_F(SymbolCollectorTest, ObjCSymbols) {
488  const std::string Header = R"(
489  @interface Person
490  - (void)someMethodName:(void*)name1 lastName:(void*)lName;
491  @end
492 
493  @implementation Person
494  - (void)someMethodName:(void*)name1 lastName:(void*)lName{
495  int foo;
496  ^(int param){ int bar; };
497  }
498  @end
499 
500  @interface Person (MyCategory)
501  - (void)someMethodName2:(void*)name2;
502  @end
503 
504  @implementation Person (MyCategory)
505  - (void)someMethodName2:(void*)name2 {
506  int foo2;
507  }
508  @end
509 
510  @protocol MyProtocol
511  - (void)someMethodName3:(void*)name3;
512  @end
513  )";
514  TestFileName = testPath("test.m");
515  runSymbolCollector(Header, /*Main=*/"", {"-fblocks", "-xobjective-c++"});
516  EXPECT_THAT(Symbols,
517  UnorderedElementsAre(
518  QName("Person"), QName("Person::someMethodName:lastName:"),
519  QName("MyCategory"), QName("Person::someMethodName2:"),
520  QName("MyProtocol"), QName("MyProtocol::someMethodName3:")));
521 }
522 
523 TEST_F(SymbolCollectorTest, ObjCPropertyImpl) {
524  const std::string Header = R"(
525  @interface Container
526  @property(nonatomic) int magic;
527  @end
528 
529  @implementation Container
530  @end
531  )";
532  TestFileName = testPath("test.m");
533  runSymbolCollector(Header, /*Main=*/"", {"-xobjective-c++"});
534  EXPECT_THAT(Symbols, Contains(QName("Container")));
535  EXPECT_THAT(Symbols, Contains(QName("Container::magic")));
536  // FIXME: Results also contain Container::_magic on some platforms.
537  // Figure out why it's platform-dependent.
538 }
539 
540 TEST_F(SymbolCollectorTest, ObjCLocations) {
541  Annotations Header(R"(
542  // Declared in header, defined in main.
543  @interface $dogdecl[[Dog]]
544  @end
545  @interface $fluffydecl[[Dog]] (Fluffy)
546  @end
547  )");
548  Annotations Main(R"(
549  @interface Dog ()
550  @end
551  @implementation $dogdef[[Dog]]
552  @end
553  @implementation $fluffydef[[Dog]] (Fluffy)
554  @end
555  // Category with no declaration (only implementation).
556  @implementation $ruff[[Dog]] (Ruff)
557  @end
558  // Implicitly defined interface.
559  @implementation $catdog[[CatDog]]
560  @end
561  )");
562  runSymbolCollector(Header.code(), Main.code(),
563  {"-xobjective-c++", "-Wno-objc-root-class"});
564  EXPECT_THAT(Symbols,
565  UnorderedElementsAre(
566  AllOf(QName("Dog"), DeclRange(Header.range("dogdecl")),
567  DefRange(Main.range("dogdef"))),
568  AllOf(QName("Fluffy"), DeclRange(Header.range("fluffydecl")),
569  DefRange(Main.range("fluffydef"))),
570  AllOf(QName("CatDog"), DeclRange(Main.range("catdog")),
571  DefRange(Main.range("catdog"))),
572  AllOf(QName("Ruff"), DeclRange(Main.range("ruff")),
573  DefRange(Main.range("ruff")))));
574 }
575 
576 TEST_F(SymbolCollectorTest, ObjCForwardDecls) {
577  Annotations Header(R"(
578  // Forward declared in header, declared and defined in main.
579  @protocol Barker;
580  @class Dog;
581  // Never fully declared so Clang latches onto this decl.
582  @class $catdogdecl[[CatDog]];
583  )");
584  Annotations Main(R"(
585  @protocol $barkerdecl[[Barker]]
586  - (void)woof;
587  @end
588  @interface $dogdecl[[Dog]]<Barker>
589  - (void)woof;
590  @end
591  @implementation $dogdef[[Dog]]
592  - (void)woof {}
593  @end
594  @implementation $catdogdef[[CatDog]]
595  @end
596  )");
597  runSymbolCollector(Header.code(), Main.code(),
598  {"-xobjective-c++", "-Wno-objc-root-class"});
599  EXPECT_THAT(Symbols,
600  UnorderedElementsAre(
601  AllOf(QName("CatDog"), DeclRange(Header.range("catdogdecl")),
602  DefRange(Main.range("catdogdef"))),
603  AllOf(QName("Dog"), DeclRange(Main.range("dogdecl")),
604  DefRange(Main.range("dogdef"))),
605  AllOf(QName("Barker"), DeclRange(Main.range("barkerdecl"))),
606  QName("Barker::woof"), QName("Dog::woof")));
607 }
608 
609 TEST_F(SymbolCollectorTest, ObjCClassExtensions) {
610  Annotations Header(R"(
611  @interface $catdecl[[Cat]]
612  @end
613  )");
614  Annotations Main(R"(
615  @interface Cat ()
616  - (void)meow;
617  @end
618  @interface Cat ()
619  - (void)pur;
620  @end
621  )");
622  runSymbolCollector(Header.code(), Main.code(),
623  {"-xobjective-c++", "-Wno-objc-root-class"});
624  EXPECT_THAT(Symbols,
625  UnorderedElementsAre(
626  AllOf(QName("Cat"), DeclRange(Header.range("catdecl"))),
627  QName("Cat::meow"), QName("Cat::pur")));
628 }
629 
630 TEST_F(SymbolCollectorTest, Locations) {
631  Annotations Header(R"cpp(
632  // Declared in header, defined in main.
633  extern int $xdecl[[X]];
634  class $clsdecl[[Cls]];
635  void $printdecl[[print]]();
636 
637  // Declared in header, defined nowhere.
638  extern int $zdecl[[Z]];
639 
640  void $foodecl[[fo\
641 o]]();
642  )cpp");
643  Annotations Main(R"cpp(
644  int $xdef[[X]] = 42;
645  class $clsdef[[Cls]] {};
646  void $printdef[[print]]() {}
647 
648  // Declared/defined in main only.
649  int $ydecl[[Y]];
650  )cpp");
651  runSymbolCollector(Header.code(), Main.code());
652  EXPECT_THAT(Symbols,
653  UnorderedElementsAre(
654  AllOf(QName("X"), DeclRange(Header.range("xdecl")),
655  DefRange(Main.range("xdef"))),
656  AllOf(QName("Cls"), DeclRange(Header.range("clsdecl")),
657  DefRange(Main.range("clsdef"))),
658  AllOf(QName("print"), DeclRange(Header.range("printdecl")),
659  DefRange(Main.range("printdef"))),
660  AllOf(QName("Z"), DeclRange(Header.range("zdecl"))),
661  AllOf(QName("foo"), DeclRange(Header.range("foodecl"))),
662  AllOf(QName("Y"), DeclRange(Main.range("ydecl")))));
663 }
664 
665 TEST_F(SymbolCollectorTest, Refs) {
666  Annotations Header(R"(
667  #define MACRO(X) (X + 1)
668  class Foo {
669  public:
670  Foo() {}
671  Foo(int);
672  };
673  class Bar;
674  void func();
675 
676  namespace NS {} // namespace ref is ignored
677  )");
678  Annotations Main(R"(
679  class $bar[[Bar]] {};
680 
681  void $func[[func]]();
682 
683  void fff() {
684  $foo[[Foo]] foo;
685  $bar[[Bar]] bar;
686  $func[[func]]();
687  int abc = 0;
688  $foo[[Foo]] foo2 = abc;
689  abc = $macro[[MACRO]](1);
690  }
691  )");
692  Annotations SymbolsOnlyInMainCode(R"(
693  #define FUNC(X) (X+1)
694  int a;
695  void b() {}
696  static const int c = FUNC(1);
697  class d {};
698  )");
701  runSymbolCollector(Header.code(),
702  (Main.code() + SymbolsOnlyInMainCode.code()).str());
703  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "Foo").ID,
704  HaveRanges(Main.ranges("foo")))));
705  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "Bar").ID,
706  HaveRanges(Main.ranges("bar")))));
707  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "func").ID,
708  HaveRanges(Main.ranges("func")))));
709  EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(Symbols, "NS").ID, _))));
710  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "MACRO").ID,
711  HaveRanges(Main.ranges("macro")))));
712  // - (a, b) externally visible and should have refs.
713  // - (c, FUNC) externally invisible and had no refs collected.
714  auto MainSymbols =
715  TestTU::withHeaderCode(SymbolsOnlyInMainCode.code()).headerSymbols();
716  EXPECT_THAT(Refs, Contains(Pair(findSymbol(MainSymbols, "a").ID, _)));
717  EXPECT_THAT(Refs, Contains(Pair(findSymbol(MainSymbols, "b").ID, _)));
718  EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(MainSymbols, "c").ID, _))));
719  EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(MainSymbols, "FUNC").ID, _))));
720 
721  // Run the collector again with CollectMainFileRefs = true.
722  // We need to recreate InMemoryFileSystem because runSymbolCollector()
723  // calls MemoryBuffer::getMemBuffer(), which makes the buffers unusable
724  // after runSymbolCollector() exits.
727  runSymbolCollector(Header.code(),
728  (Main.code() + SymbolsOnlyInMainCode.code()).str());
729  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "a").ID, _)));
730  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "b").ID, _)));
731  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "c").ID, _)));
732  // However, references to main-file macros are not collected.
733  EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(Symbols, "FUNC").ID, _))));
734 }
735 
736 TEST_F(SymbolCollectorTest, RefContainers) {
737  Annotations Code(R"cpp(
738  int $toplevel1[[f1]](int);
739  void f2() {
740  (void) $ref1a[[f1]](1);
741  auto fptr = &$ref1b[[f1]];
742  }
743  int $toplevel2[[v1]] = $ref2[[f1]](2);
744  void f3(int arg = $ref3[[f1]](3));
745  struct S1 {
746  int $classscope1[[member1]] = $ref4[[f1]](4);
747  int $classscope2[[member2]] = 42;
748  };
749  constexpr int f4(int x) { return x + 1; }
750  template <int I = $ref5[[f4]](0)> struct S2 {};
751  S2<$ref6[[f4]](0)> v2;
752  S2<$ref7a[[f4]](0)> f5(S2<$ref7b[[f4]](0)>);
753  namespace N {
754  void $namespacescope1[[f6]]();
755  int $namespacescope2[[v3]];
756  }
757  )cpp");
760  runSymbolCollector("", Code.code());
761  auto FindRefWithRange = [&](Range R) -> Optional<Ref> {
762  for (auto &Entry : Refs) {
763  for (auto &Ref : Entry.second) {
764  if (rangesMatch(Ref.Location, R))
765  return Ref;
766  }
767  }
768  return llvm::None;
769  };
770  auto Container = [&](llvm::StringRef RangeName) {
771  auto Ref = FindRefWithRange(Code.range(RangeName));
772  EXPECT_TRUE(bool(Ref));
773  return Ref->Container;
774  };
775  EXPECT_EQ(Container("ref1a"),
776  findSymbol(Symbols, "f2").ID); // function body (call)
777  EXPECT_EQ(Container("ref1b"),
778  findSymbol(Symbols, "f2").ID); // function body (address-of)
779  EXPECT_EQ(Container("ref2"),
780  findSymbol(Symbols, "v1").ID); // variable initializer
781  EXPECT_EQ(Container("ref3"),
782  findSymbol(Symbols, "f3").ID); // function parameter default value
783  EXPECT_EQ(Container("ref4"),
784  findSymbol(Symbols, "S1::member1").ID); // member initializer
785  EXPECT_EQ(Container("ref5"),
786  findSymbol(Symbols, "S2").ID); // template parameter default value
787  EXPECT_EQ(Container("ref6"),
788  findSymbol(Symbols, "v2").ID); // type of variable
789  EXPECT_EQ(Container("ref7a"),
790  findSymbol(Symbols, "f5").ID); // return type of function
791  EXPECT_EQ(Container("ref7b"),
792  findSymbol(Symbols, "f5").ID); // parameter type of function
793 
794  EXPECT_FALSE(Container("classscope1").isNull());
795  EXPECT_FALSE(Container("namespacescope1").isNull());
796 
797  EXPECT_EQ(Container("toplevel1"), Container("toplevel2"));
798  EXPECT_EQ(Container("classscope1"), Container("classscope2"));
799  EXPECT_EQ(Container("namespacescope1"), Container("namespacescope2"));
800 
801  EXPECT_NE(Container("toplevel1"), Container("namespacescope1"));
802  EXPECT_NE(Container("toplevel1"), Container("classscope1"));
803  EXPECT_NE(Container("classscope1"), Container("namespacescope1"));
804 }
805 
806 TEST_F(SymbolCollectorTest, MacroRefInHeader) {
807  Annotations Header(R"(
808  #define $foo[[FOO]](X) (X + 1)
809  #define $bar[[BAR]](X) (X + 2)
810 
811  // Macro defined multiple times.
812  #define $ud1[[UD]] 1
813  int ud_1 = $ud1[[UD]];
814  #undef UD
815 
816  #define $ud2[[UD]] 2
817  int ud_2 = $ud2[[UD]];
818  #undef UD
819 
820  // Macros from token concatenations not included.
821  #define $concat[[CONCAT]](X) X##A()
822  #define $prepend[[PREPEND]](X) MACRO##X()
823  #define $macroa[[MACROA]]() 123
824  int B = $concat[[CONCAT]](MACRO);
825  int D = $prepend[[PREPEND]](A);
826 
827  void fff() {
828  int abc = $foo[[FOO]](1) + $bar[[BAR]]($foo[[FOO]](1));
829  }
830  )");
833  // Need this to get the SymbolID for macros for tests.
835 
836  runSymbolCollector(Header.code(), "");
837 
838  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "FOO").ID,
839  HaveRanges(Header.ranges("foo")))));
840  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "BAR").ID,
841  HaveRanges(Header.ranges("bar")))));
842  // No unique ID for multiple symbols named UD. Check for ranges only.
843  EXPECT_THAT(Refs, Contains(Pair(_, HaveRanges(Header.ranges("ud1")))));
844  EXPECT_THAT(Refs, Contains(Pair(_, HaveRanges(Header.ranges("ud2")))));
845  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "CONCAT").ID,
846  HaveRanges(Header.ranges("concat")))));
847  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "PREPEND").ID,
848  HaveRanges(Header.ranges("prepend")))));
849  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "MACROA").ID,
850  HaveRanges(Header.ranges("macroa")))));
851 }
852 
853 TEST_F(SymbolCollectorTest, MacroRefWithoutCollectingSymbol) {
854  Annotations Header(R"(
855  #define $foo[[FOO]](X) (X + 1)
856  int abc = $foo[[FOO]](1);
857  )");
860  CollectorOpts.CollectMacro = false;
861  runSymbolCollector(Header.code(), "");
862  EXPECT_THAT(Refs, Contains(Pair(_, HaveRanges(Header.ranges("foo")))));
863 }
864 
865 TEST_F(SymbolCollectorTest, MacrosWithRefFilter) {
866  Annotations Header("#define $macro[[MACRO]](X) (X + 1)");
867  Annotations Main("void foo() { int x = $macro[[MACRO]](1); }");
869  runSymbolCollector(Header.code(), Main.code());
870  EXPECT_THAT(Refs, IsEmpty());
871 }
872 
873 TEST_F(SymbolCollectorTest, SpelledReferences) {
874  struct {
875  llvm::StringRef Header;
876  llvm::StringRef Main;
877  llvm::StringRef TargetSymbolName;
878  } TestCases[] = {
879  {
880  R"cpp(
881  struct Foo;
882  #define MACRO Foo
883  )cpp",
884  R"cpp(
885  struct $spelled[[Foo]] {
886  $spelled[[Foo]]();
887  ~$spelled[[Foo]]();
888  };
889  $spelled[[Foo]] Variable1;
890  $implicit[[MACRO]] Variable2;
891  )cpp",
892  "Foo",
893  },
894  {
895  R"cpp(
896  class Foo {
897  public:
898  Foo() = default;
899  };
900  )cpp",
901  R"cpp(
902  void f() { Foo $implicit[[f]]; f = $spelled[[Foo]]();}
903  )cpp",
904  "Foo::Foo" /// constructor.
905  },
906  };
909  for (const auto& T : TestCases) {
910  Annotations Header(T.Header);
911  Annotations Main(T.Main);
912  // Reset the file system.
914  runSymbolCollector(Header.code(), Main.code());
915 
916  const auto SpelledRanges = Main.ranges("spelled");
917  const auto ImplicitRanges = Main.ranges("implicit");
918  RefSlab::Builder SpelledSlabBuilder, ImplicitSlabBuilder;
919  const auto TargetID = findSymbol(Symbols, T.TargetSymbolName).ID;
920  for (const auto &SymbolAndRefs : Refs) {
921  const auto ID = SymbolAndRefs.first;
922  if (ID != TargetID)
923  continue;
924  for (const auto &Ref : SymbolAndRefs.second)
925  if ((Ref.Kind & RefKind::Spelled) != RefKind::Unknown)
926  SpelledSlabBuilder.insert(ID, Ref);
927  else
928  ImplicitSlabBuilder.insert(ID, Ref);
929  }
930  const auto SpelledRefs = std::move(SpelledSlabBuilder).build(),
931  ImplicitRefs = std::move(ImplicitSlabBuilder).build();
932  EXPECT_THAT(SpelledRefs,
933  Contains(Pair(TargetID, HaveRanges(SpelledRanges))));
934  EXPECT_THAT(ImplicitRefs,
935  Contains(Pair(TargetID, HaveRanges(ImplicitRanges))));
936  }
937 }
938 
939 TEST_F(SymbolCollectorTest, NameReferences) {
942  Annotations Header(R"(
943  class [[Foo]] {
944  public:
945  [[Foo]]() {}
946  ~[[Foo]]() {}
947  };
948  )");
950  runSymbolCollector(Header.code(), "");
951  // When we find references for class Foo, we expect to see all
952  // constructor/destructor references.
953  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "Foo").ID,
954  HaveRanges(Header.ranges()))));
955 }
956 
957 TEST_F(SymbolCollectorTest, RefsOnMacros) {
958  // Refs collected from SymbolCollector behave in the same way as
959  // AST-based xrefs.
962  Annotations Header(R"(
963  #define TYPE(X) X
964  #define FOO Foo
965  #define CAT(X, Y) X##Y
966  class [[Foo]] {};
967  void test() {
968  TYPE([[Foo]]) foo;
969  [[FOO]] foo2;
970  TYPE(TYPE([[Foo]])) foo3;
971  [[CAT]](Fo, o) foo4;
972  }
973  )");
975  runSymbolCollector(Header.code(), "");
976  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "Foo").ID,
977  HaveRanges(Header.ranges()))));
978 }
979 
980 TEST_F(SymbolCollectorTest, HeaderAsMainFile) {
982  Annotations Header(R"(
983  class $Foo[[Foo]] {};
984 
985  void $Func[[Func]]() {
986  $Foo[[Foo]] fo;
987  }
988  )");
989  // We should collect refs to main-file symbols in all cases:
990 
991  // 1. The main file is normal .cpp file.
992  TestFileName = testPath("foo.cpp");
993  runSymbolCollector("", Header.code());
994  EXPECT_THAT(Refs,
995  UnorderedElementsAre(Pair(findSymbol(Symbols, "Foo").ID,
996  HaveRanges(Header.ranges("Foo"))),
997  Pair(findSymbol(Symbols, "Func").ID,
998  HaveRanges(Header.ranges("Func")))));
999 
1000  // 2. Run the .h file as main file.
1001  TestFileName = testPath("foo.h");
1002  runSymbolCollector("", Header.code(),
1003  /*ExtraArgs=*/{"-xobjective-c++-header"});
1004  EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Foo"), QName("Func")));
1005  EXPECT_THAT(Refs,
1006  UnorderedElementsAre(Pair(findSymbol(Symbols, "Foo").ID,
1007  HaveRanges(Header.ranges("Foo"))),
1008  Pair(findSymbol(Symbols, "Func").ID,
1009  HaveRanges(Header.ranges("Func")))));
1010 
1011  // 3. Run the .hh file as main file (without "-x c++-header").
1012  TestFileName = testPath("foo.hh");
1013  runSymbolCollector("", Header.code());
1014  EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Foo"), QName("Func")));
1015  EXPECT_THAT(Refs,
1016  UnorderedElementsAre(Pair(findSymbol(Symbols, "Foo").ID,
1017  HaveRanges(Header.ranges("Foo"))),
1018  Pair(findSymbol(Symbols, "Func").ID,
1019  HaveRanges(Header.ranges("Func")))));
1020 }
1021 
1022 TEST_F(SymbolCollectorTest, RefsInHeaders) {
1025  CollectorOpts.CollectMacro = true;
1026  Annotations Header(R"(
1027  #define $macro[[MACRO]](x) (x+1)
1028  class $foo[[Foo]] {};
1029  )");
1030  runSymbolCollector(Header.code(), "");
1031  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "Foo").ID,
1032  HaveRanges(Header.ranges("foo")))));
1033  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "MACRO").ID,
1034  HaveRanges(Header.ranges("macro")))));
1035 }
1036 
1037 TEST_F(SymbolCollectorTest, BaseOfRelations) {
1038  std::string Header = R"(
1039  class Base {};
1040  class Derived : public Base {};
1041  )";
1042  runSymbolCollector(Header, /*Main=*/"");
1043  const Symbol &Base = findSymbol(Symbols, "Base");
1044  const Symbol &Derived = findSymbol(Symbols, "Derived");
1045  EXPECT_THAT(Relations,
1046  Contains(Relation{Base.ID, RelationKind::BaseOf, Derived.ID}));
1047 }
1048 
1049 TEST_F(SymbolCollectorTest, OverrideRelationsSimpleInheritance) {
1050  std::string Header = R"cpp(
1051  class A {
1052  virtual void foo();
1053  };
1054  class B : public A {
1055  void foo() override; // A::foo
1056  virtual void bar();
1057  };
1058  class C : public B {
1059  void bar() override; // B::bar
1060  };
1061  class D: public C {
1062  void foo() override; // B::foo
1063  void bar() override; // C::bar
1064  };
1065  )cpp";
1066  runSymbolCollector(Header, /*Main=*/"");
1067  const Symbol &AFoo = findSymbol(Symbols, "A::foo");
1068  const Symbol &BFoo = findSymbol(Symbols, "B::foo");
1069  const Symbol &DFoo = findSymbol(Symbols, "D::foo");
1070 
1071  const Symbol &BBar = findSymbol(Symbols, "B::bar");
1072  const Symbol &CBar = findSymbol(Symbols, "C::bar");
1073  const Symbol &DBar = findSymbol(Symbols, "D::bar");
1074 
1075  std::vector<Relation> Result;
1076  for (const Relation &R : Relations)
1077  if (R.Predicate == RelationKind::OverriddenBy)
1078  Result.push_back(R);
1079  EXPECT_THAT(Result, UnorderedElementsAre(
1080  OverriddenBy(AFoo, BFoo), OverriddenBy(BBar, CBar),
1081  OverriddenBy(BFoo, DFoo), OverriddenBy(CBar, DBar)));
1082 }
1083 
1084 TEST_F(SymbolCollectorTest, OverrideRelationsMultipleInheritance) {
1085  std::string Header = R"cpp(
1086  class A {
1087  virtual void foo();
1088  };
1089  class B {
1090  virtual void bar();
1091  };
1092  class C : public B {
1093  void bar() override; // B::bar
1094  virtual void baz();
1095  }
1096  class D : public A, C {
1097  void foo() override; // A::foo
1098  void bar() override; // C::bar
1099  void baz() override; // C::baz
1100  };
1101  )cpp";
1102  runSymbolCollector(Header, /*Main=*/"");
1103  const Symbol &AFoo = findSymbol(Symbols, "A::foo");
1104  const Symbol &BBar = findSymbol(Symbols, "B::bar");
1105  const Symbol &CBar = findSymbol(Symbols, "C::bar");
1106  const Symbol &CBaz = findSymbol(Symbols, "C::baz");
1107  const Symbol &DFoo = findSymbol(Symbols, "D::foo");
1108  const Symbol &DBar = findSymbol(Symbols, "D::bar");
1109  const Symbol &DBaz = findSymbol(Symbols, "D::baz");
1110 
1111  std::vector<Relation> Result;
1112  for (const Relation &R : Relations)
1113  if (R.Predicate == RelationKind::OverriddenBy)
1114  Result.push_back(R);
1115  EXPECT_THAT(Result, UnorderedElementsAre(
1116  OverriddenBy(BBar, CBar), OverriddenBy(AFoo, DFoo),
1117  OverriddenBy(CBar, DBar), OverriddenBy(CBaz, DBaz)));
1118 }
1119 
1120 TEST_F(SymbolCollectorTest, CountReferences) {
1121  const std::string Header = R"(
1122  class W;
1123  class X {};
1124  class Y;
1125  class Z {}; // not used anywhere
1126  Y* y = nullptr; // used in header doesn't count
1127  #define GLOBAL_Z(name) Z name;
1128  )";
1129  const std::string Main = R"(
1130  W* w = nullptr;
1131  W* w2 = nullptr; // only one usage counts
1132  X x();
1133  class V;
1134  class Y{}; // definition doesn't count as a reference
1135  V* v = nullptr;
1136  GLOBAL_Z(z); // Not a reference to Z, we don't spell the type.
1137  )";
1139  runSymbolCollector(Header, Main);
1140  EXPECT_THAT(
1141  Symbols,
1142  UnorderedElementsAreArray(
1143  {AllOf(QName("W"), RefCount(1)), AllOf(QName("X"), RefCount(1)),
1144  AllOf(QName("Y"), RefCount(0)), AllOf(QName("Z"), RefCount(0)),
1145  AllOf(QName("y"), RefCount(0)), AllOf(QName("z"), RefCount(0)),
1146  AllOf(QName("x"), RefCount(0)), AllOf(QName("w"), RefCount(0)),
1147  AllOf(QName("w2"), RefCount(0)), AllOf(QName("V"), RefCount(1)),
1148  AllOf(QName("v"), RefCount(0))}));
1149 }
1150 
1151 TEST_F(SymbolCollectorTest, SymbolRelativeNoFallback) {
1152  runSymbolCollector("class Foo {};", /*Main=*/"");
1153  EXPECT_THAT(Symbols, UnorderedElementsAre(
1154  AllOf(QName("Foo"), DeclURI(TestHeaderURI))));
1155 }
1156 
1157 TEST_F(SymbolCollectorTest, SymbolRelativeWithFallback) {
1158  TestHeaderName = "x.h";
1159  TestFileName = "x.cpp";
1162  runSymbolCollector("class Foo {};", /*Main=*/"");
1163  EXPECT_THAT(Symbols, UnorderedElementsAre(
1164  AllOf(QName("Foo"), DeclURI(TestHeaderURI))));
1165 }
1166 
1167 TEST_F(SymbolCollectorTest, UnittestURIScheme) {
1168  // Use test URI scheme from URITests.cpp
1169  TestHeaderName = testPath("x.h");
1170  TestFileName = testPath("x.cpp");
1171  runSymbolCollector("class Foo {};", /*Main=*/"");
1172  EXPECT_THAT(Symbols, UnorderedElementsAre(
1173  AllOf(QName("Foo"), DeclURI("unittest:///x.h"))));
1174 }
1175 
1176 TEST_F(SymbolCollectorTest, IncludeEnums) {
1177  const std::string Header = R"(
1178  enum {
1179  Red
1180  };
1181  enum Color {
1182  Green
1183  };
1184  enum class Color2 {
1185  Yellow
1186  };
1187  namespace ns {
1188  enum {
1189  Black
1190  };
1191  }
1192  )";
1193  runSymbolCollector(Header, /*Main=*/"");
1194  EXPECT_THAT(Symbols,
1195  UnorderedElementsAre(
1196  AllOf(QName("Red"), ForCodeCompletion(true)),
1197  AllOf(QName("Color"), ForCodeCompletion(true)),
1198  AllOf(QName("Green"), ForCodeCompletion(true)),
1199  AllOf(QName("Color2"), ForCodeCompletion(true)),
1200  AllOf(QName("Color2::Yellow"), ForCodeCompletion(false)),
1201  AllOf(QName("ns"), ForCodeCompletion(true)),
1202  AllOf(QName("ns::Black"), ForCodeCompletion(true))));
1203 }
1204 
1205 TEST_F(SymbolCollectorTest, NamelessSymbols) {
1206  const std::string Header = R"(
1207  struct {
1208  int a;
1209  } Foo;
1210  )";
1211  runSymbolCollector(Header, /*Main=*/"");
1212  EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Foo"),
1213  QName("(anonymous struct)::a")));
1214 }
1215 
1216 TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
1217 
1218  Annotations Header(R"(
1219  #define FF(name) \
1220  class name##_Test {};
1221 
1222  $expansion[[FF]](abc);
1223 
1224  #define FF2() \
1225  class $spelling[[Test]] {};
1226 
1227  FF2();
1228  )");
1229 
1230  runSymbolCollector(Header.code(), /*Main=*/"");
1231  EXPECT_THAT(Symbols,
1232  UnorderedElementsAre(
1233  AllOf(QName("abc_Test"), DeclRange(Header.range("expansion")),
1234  DeclURI(TestHeaderURI)),
1235  AllOf(QName("Test"), DeclRange(Header.range("spelling")),
1236  DeclURI(TestHeaderURI))));
1237 }
1238 
1239 TEST_F(SymbolCollectorTest, SymbolFormedByCLI) {
1240  Annotations Header(R"(
1241  #ifdef NAME
1242  class $expansion[[NAME]] {};
1243  #endif
1244  )");
1245  runSymbolCollector(Header.code(), /*Main=*/"", /*ExtraArgs=*/{"-DNAME=name"});
1246  EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(
1247  QName("name"), DeclRange(Header.range("expansion")),
1248  DeclURI(TestHeaderURI))));
1249 }
1250 
1251 TEST_F(SymbolCollectorTest, SymbolsInMainFile) {
1252  const std::string Main = R"(
1253  class Foo {};
1254  void f1();
1255  inline void f2() {}
1256 
1257  namespace {
1258  void ff() {}
1259  }
1260  namespace foo {
1261  namespace {
1262  class Bar {};
1263  }
1264  }
1265  void main_f() {}
1266  void f1() {}
1267  )";
1268  runSymbolCollector(/*Header=*/"", Main);
1269  EXPECT_THAT(Symbols, UnorderedElementsAre(
1270  QName("Foo"), QName("f1"), QName("f2"), QName("ff"),
1271  QName("foo"), QName("foo::Bar"), QName("main_f")));
1272 }
1273 
1274 TEST_F(SymbolCollectorTest, Documentation) {
1275  const std::string Header = R"(
1276  // Doc Foo
1277  class Foo {
1278  // Doc f
1279  int f();
1280  };
1281  )";
1283  runSymbolCollector(Header, /* Main */ "");
1284  EXPECT_THAT(Symbols,
1285  UnorderedElementsAre(
1286  AllOf(QName("Foo"), Doc("Doc Foo"), ForCodeCompletion(true)),
1287  AllOf(QName("Foo::f"), Doc(""), ReturnType(""),
1288  ForCodeCompletion(false))));
1289 
1291  runSymbolCollector(Header, /* Main */ "");
1292  EXPECT_THAT(Symbols,
1293  UnorderedElementsAre(
1294  AllOf(QName("Foo"), Doc("Doc Foo"), ForCodeCompletion(true)),
1295  AllOf(QName("Foo::f"), Doc("Doc f"), ReturnType(""),
1296  ForCodeCompletion(false))));
1297 }
1298 
1299 TEST_F(SymbolCollectorTest, ClassMembers) {
1300  const std::string Header = R"(
1301  class Foo {
1302  void f() {}
1303  void g();
1304  static void sf() {}
1305  static void ssf();
1306  static int x;
1307  };
1308  )";
1309  const std::string Main = R"(
1310  void Foo::g() {}
1311  void Foo::ssf() {}
1312  )";
1313  runSymbolCollector(Header, Main);
1314  EXPECT_THAT(
1315  Symbols,
1316  UnorderedElementsAre(
1317  QName("Foo"),
1318  AllOf(QName("Foo::f"), ReturnType(""), ForCodeCompletion(false)),
1319  AllOf(QName("Foo::g"), ReturnType(""), ForCodeCompletion(false)),
1320  AllOf(QName("Foo::sf"), ReturnType(""), ForCodeCompletion(false)),
1321  AllOf(QName("Foo::ssf"), ReturnType(""), ForCodeCompletion(false)),
1322  AllOf(QName("Foo::x"), ReturnType(""), ForCodeCompletion(false))));
1323 }
1324 
1325 TEST_F(SymbolCollectorTest, Scopes) {
1326  const std::string Header = R"(
1327  namespace na {
1328  class Foo {};
1329  namespace nb {
1330  class Bar {};
1331  }
1332  }
1333  )";
1334  runSymbolCollector(Header, /*Main=*/"");
1335  EXPECT_THAT(Symbols,
1336  UnorderedElementsAre(QName("na"), QName("na::nb"),
1337  QName("na::Foo"), QName("na::nb::Bar")));
1338 }
1339 
1340 TEST_F(SymbolCollectorTest, ExternC) {
1341  const std::string Header = R"(
1342  extern "C" { class Foo {}; }
1343  namespace na {
1344  extern "C" { class Bar {}; }
1345  }
1346  )";
1347  runSymbolCollector(Header, /*Main=*/"");
1348  EXPECT_THAT(Symbols, UnorderedElementsAre(QName("na"), QName("Foo"),
1349  QName("na::Bar")));
1350 }
1351 
1352 TEST_F(SymbolCollectorTest, SkipInlineNamespace) {
1353  const std::string Header = R"(
1354  namespace na {
1355  inline namespace nb {
1356  class Foo {};
1357  }
1358  }
1359  namespace na {
1360  // This is still inlined.
1361  namespace nb {
1362  class Bar {};
1363  }
1364  }
1365  )";
1366  runSymbolCollector(Header, /*Main=*/"");
1367  EXPECT_THAT(Symbols,
1368  UnorderedElementsAre(QName("na"), QName("na::nb"),
1369  QName("na::Foo"), QName("na::Bar")));
1370 }
1371 
1372 TEST_F(SymbolCollectorTest, SymbolWithDocumentation) {
1373  const std::string Header = R"(
1374  namespace nx {
1375  /// Foo comment.
1376  int ff(int x, double y) { return 0; }
1377  }
1378  )";
1379  runSymbolCollector(Header, /*Main=*/"");
1380  EXPECT_THAT(
1381  Symbols,
1382  UnorderedElementsAre(
1383  QName("nx"), AllOf(QName("nx::ff"), Labeled("ff(int x, double y)"),
1384  ReturnType("int"), Doc("Foo comment."))));
1385 }
1386 
1387 TEST_F(SymbolCollectorTest, Snippet) {
1388  const std::string Header = R"(
1389  namespace nx {
1390  void f() {}
1391  int ff(int x, double y) { return 0; }
1392  }
1393  )";
1394  runSymbolCollector(Header, /*Main=*/"");
1395  EXPECT_THAT(Symbols,
1396  UnorderedElementsAre(
1397  QName("nx"),
1398  AllOf(QName("nx::f"), Labeled("f()"), Snippet("f()")),
1399  AllOf(QName("nx::ff"), Labeled("ff(int x, double y)"),
1400  Snippet("ff(${1:int x}, ${2:double y})"))));
1401 }
1402 
1403 TEST_F(SymbolCollectorTest, IncludeHeaderSameAsFileURI) {
1405  runSymbolCollector("#pragma once\nclass Foo {};", /*Main=*/"");
1406  EXPECT_THAT(Symbols, UnorderedElementsAre(
1407  AllOf(QName("Foo"), DeclURI(TestHeaderURI))));
1408  EXPECT_THAT(Symbols.begin()->IncludeHeaders,
1409  UnorderedElementsAre(IncludeHeaderWithRef(TestHeaderURI, 1u)));
1410 }
1411 
1412 TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
1414  CanonicalIncludes Includes;
1415  auto Language = LangOptions();
1416  Language.CPlusPlus = true;
1417  Includes.addSystemHeadersMapping(Language);
1418  CollectorOpts.Includes = &Includes;
1419  runSymbolCollector(
1420  R"cpp(
1421  namespace std {
1422  class string {};
1423  // Move overloads have special handling.
1424  template <typename T> T&& move(T&&);
1425  template <typename I, typename O> O move(I, I, O);
1426  }
1427  )cpp",
1428  /*Main=*/"");
1429  for (const auto &S : Symbols)
1430  llvm::errs() << S.Scope << S.Name << " in " << S.IncludeHeaders.size()
1431  << "\n";
1432  EXPECT_THAT(
1433  Symbols,
1434  UnorderedElementsAre(
1435  QName("std"),
1436  AllOf(QName("std::string"), DeclURI(TestHeaderURI),
1437  IncludeHeader("<string>")),
1438  AllOf(Labeled("move(T &&)"), IncludeHeader("<utility>")),
1439  AllOf(Labeled("move(I, I, O)"), IncludeHeader("<algorithm>"))));
1440 }
1441 
1442 TEST_F(SymbolCollectorTest, IWYUPragma) {
1444  CanonicalIncludes Includes;
1445  PragmaHandler = collectIWYUHeaderMaps(&Includes);
1446  CollectorOpts.Includes = &Includes;
1447  const std::string Header = R"(
1448  // IWYU pragma: private, include the/good/header.h
1449  class Foo {};
1450  )";
1451  runSymbolCollector(Header, /*Main=*/"");
1452  EXPECT_THAT(Symbols, UnorderedElementsAre(
1453  AllOf(QName("Foo"), DeclURI(TestHeaderURI),
1454  IncludeHeader("\"the/good/header.h\""))));
1455 }
1456 
1457 TEST_F(SymbolCollectorTest, IWYUPragmaWithDoubleQuotes) {
1459  CanonicalIncludes Includes;
1460  PragmaHandler = collectIWYUHeaderMaps(&Includes);
1461  CollectorOpts.Includes = &Includes;
1462  const std::string Header = R"(
1463  // IWYU pragma: private, include "the/good/header.h"
1464  class Foo {};
1465  )";
1466  runSymbolCollector(Header, /*Main=*/"");
1467  EXPECT_THAT(Symbols, UnorderedElementsAre(
1468  AllOf(QName("Foo"), DeclURI(TestHeaderURI),
1469  IncludeHeader("\"the/good/header.h\""))));
1470 }
1471 
1472 TEST_F(SymbolCollectorTest, SkipIncFileWhenCanonicalizeHeaders) {
1474  CanonicalIncludes Includes;
1475  Includes.addMapping(TestHeaderName, "<canonical>");
1476  CollectorOpts.Includes = &Includes;
1477  auto IncFile = testPath("test.inc");
1478  auto IncURI = URI::create(IncFile).toString();
1479  InMemoryFileSystem->addFile(IncFile, 0,
1480  llvm::MemoryBuffer::getMemBuffer("class X {};"));
1481  runSymbolCollector("#include \"test.inc\"\nclass Y {};", /*Main=*/"",
1482  /*ExtraArgs=*/{"-I", testRoot()});
1483  EXPECT_THAT(Symbols,
1484  UnorderedElementsAre(AllOf(QName("X"), DeclURI(IncURI),
1485  IncludeHeader("<canonical>")),
1486  AllOf(QName("Y"), DeclURI(TestHeaderURI),
1487  IncludeHeader("<canonical>"))));
1488 }
1489 
1490 TEST_F(SymbolCollectorTest, MainFileIsHeaderWhenSkipIncFile) {
1492  // To make this case as hard as possible, we won't tell clang main is a
1493  // header. No extension, no -x c++-header.
1494  TestFileName = testPath("no_ext_main");
1495  TestFileURI = URI::create(TestFileName).toString();
1496  auto IncFile = testPath("test.inc");
1497  auto IncURI = URI::create(IncFile).toString();
1498  InMemoryFileSystem->addFile(IncFile, 0,
1499  llvm::MemoryBuffer::getMemBuffer("class X {};"));
1500  runSymbolCollector("", R"cpp(
1501  // Can't use #pragma once in a main file clang doesn't think is a header.
1502  #ifndef MAIN_H_
1503  #define MAIN_H_
1504  #include "test.inc"
1505  #endif
1506  )cpp",
1507  /*ExtraArgs=*/{"-I", testRoot()});
1508  EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("X"), DeclURI(IncURI),
1509  IncludeHeader(TestFileURI))));
1510 }
1511 
1512 TEST_F(SymbolCollectorTest, IncFileInNonHeader) {
1514  TestFileName = testPath("main.cc");
1515  TestFileURI = URI::create(TestFileName).toString();
1516  auto IncFile = testPath("test.inc");
1517  auto IncURI = URI::create(IncFile).toString();
1518  InMemoryFileSystem->addFile(IncFile, 0,
1519  llvm::MemoryBuffer::getMemBuffer("class X {};"));
1520  runSymbolCollector("", R"cpp(
1521  #include "test.inc"
1522  )cpp",
1523  /*ExtraArgs=*/{"-I", testRoot()});
1524  EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("X"), DeclURI(IncURI),
1525  Not(IncludeHeader()))));
1526 }
1527 
1528 // Features that depend on header-guards are fragile. Header guards are only
1529 // recognized when the file ends, so we have to defer checking for them.
1530 TEST_F(SymbolCollectorTest, HeaderGuardDetected) {
1532  CollectorOpts.CollectMacro = true;
1533  runSymbolCollector(R"cpp(
1534  #ifndef HEADER_GUARD_
1535  #define HEADER_GUARD_
1536 
1537  // Symbols are seen before the header guard is complete.
1538  #define MACRO
1539  int decl();
1540 
1541  #endif // Header guard is recognized here.
1542  )cpp",
1543  "");
1544  EXPECT_THAT(Symbols, Not(Contains(QName("HEADER_GUARD_"))));
1545  EXPECT_THAT(Symbols, Each(IncludeHeader()));
1546 }
1547 
1548 TEST_F(SymbolCollectorTest, NonModularHeader) {
1549  auto TU = TestTU::withHeaderCode("int x();");
1550  EXPECT_THAT(TU.headerSymbols(), ElementsAre(IncludeHeader()));
1551 
1552  // Files missing include guards aren't eligible for insertion.
1553  TU.ImplicitHeaderGuard = false;
1554  EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(IncludeHeader())));
1555 
1556  // We recognize some patterns of trying to prevent insertion.
1557  TU = TestTU::withHeaderCode(R"cpp(
1558 #ifndef SECRET
1559 #error "This file isn't safe to include directly"
1560 #endif
1561  int x();
1562  )cpp");
1563  TU.ExtraArgs.push_back("-DSECRET"); // *we're* able to include it.
1564  EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(IncludeHeader())));
1565 }
1566 
1567 TEST_F(SymbolCollectorTest, AvoidUsingFwdDeclsAsCanonicalDecls) {
1569  Annotations Header(R"(
1570  #pragma once
1571  // Forward declarations of TagDecls.
1572  class C;
1573  struct S;
1574  union U;
1575 
1576  // Canonical declarations.
1577  class $cdecl[[C]] {};
1578  struct $sdecl[[S]] {};
1579  union $udecl[[U]] {int $xdecl[[x]]; bool $ydecl[[y]];};
1580  )");
1581  runSymbolCollector(Header.code(), /*Main=*/"");
1582  EXPECT_THAT(
1583  Symbols,
1584  UnorderedElementsAre(
1585  AllOf(QName("C"), DeclURI(TestHeaderURI),
1586  DeclRange(Header.range("cdecl")), IncludeHeader(TestHeaderURI),
1587  DefURI(TestHeaderURI), DefRange(Header.range("cdecl"))),
1588  AllOf(QName("S"), DeclURI(TestHeaderURI),
1589  DeclRange(Header.range("sdecl")), IncludeHeader(TestHeaderURI),
1590  DefURI(TestHeaderURI), DefRange(Header.range("sdecl"))),
1591  AllOf(QName("U"), DeclURI(TestHeaderURI),
1592  DeclRange(Header.range("udecl")), IncludeHeader(TestHeaderURI),
1593  DefURI(TestHeaderURI), DefRange(Header.range("udecl"))),
1594  AllOf(QName("U::x"), DeclURI(TestHeaderURI),
1595  DeclRange(Header.range("xdecl")), DefURI(TestHeaderURI),
1596  DefRange(Header.range("xdecl"))),
1597  AllOf(QName("U::y"), DeclURI(TestHeaderURI),
1598  DeclRange(Header.range("ydecl")), DefURI(TestHeaderURI),
1599  DefRange(Header.range("ydecl")))));
1600 }
1601 
1602 TEST_F(SymbolCollectorTest, ClassForwardDeclarationIsCanonical) {
1604  runSymbolCollector(/*Header=*/"#pragma once\nclass X;",
1605  /*Main=*/"class X {};");
1606  EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(
1607  QName("X"), DeclURI(TestHeaderURI),
1608  IncludeHeader(TestHeaderURI), DefURI(TestFileURI))));
1609 }
1610 
1611 TEST_F(SymbolCollectorTest, UTF16Character) {
1612  // ö is 2-bytes.
1613  Annotations Header(/*Header=*/"class [[pörk]] {};");
1614  runSymbolCollector(Header.code(), /*Main=*/"");
1615  EXPECT_THAT(Symbols, UnorderedElementsAre(
1616  AllOf(QName("pörk"), DeclRange(Header.range()))));
1617 }
1618 
1619 TEST_F(SymbolCollectorTest, DoNotIndexSymbolsInFriendDecl) {
1620  Annotations Header(R"(
1621  namespace nx {
1622  class $z[[Z]] {};
1623  class X {
1624  friend class Y;
1625  friend class Z;
1626  friend void foo();
1627  friend void $bar[[bar]]() {}
1628  };
1629  class $y[[Y]] {};
1630  void $foo[[foo]]();
1631  }
1632  )");
1633  runSymbolCollector(Header.code(), /*Main=*/"");
1634 
1635  EXPECT_THAT(Symbols,
1636  UnorderedElementsAre(
1637  QName("nx"), QName("nx::X"),
1638  AllOf(QName("nx::Y"), DeclRange(Header.range("y"))),
1639  AllOf(QName("nx::Z"), DeclRange(Header.range("z"))),
1640  AllOf(QName("nx::foo"), DeclRange(Header.range("foo"))),
1641  AllOf(QName("nx::bar"), DeclRange(Header.range("bar")))));
1642 }
1643 
1644 TEST_F(SymbolCollectorTest, ReferencesInFriendDecl) {
1645  const std::string Header = R"(
1646  class X;
1647  class Y;
1648  )";
1649  const std::string Main = R"(
1650  class C {
1651  friend ::X;
1652  friend class Y;
1653  };
1654  )";
1656  runSymbolCollector(Header, Main);
1657  EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("X"), RefCount(1)),
1658  AllOf(QName("Y"), RefCount(1)),
1659  AllOf(QName("C"), RefCount(0))));
1660 }
1661 
1662 TEST_F(SymbolCollectorTest, Origin) {
1664  runSymbolCollector("class Foo {};", /*Main=*/"");
1665  EXPECT_THAT(Symbols, UnorderedElementsAre(
1667  runSymbolCollector("#define FOO", /*Main=*/"");
1668  EXPECT_THAT(Symbols, UnorderedElementsAre(
1670 }
1671 
1672 TEST_F(SymbolCollectorTest, CollectMacros) {
1674  Annotations Header(R"(
1675  #pragma once
1676  #define X 1
1677  #define $mac[[MAC]](x) int x
1678  #define $used[[USED]](y) float y;
1679 
1680  MAC(p);
1681  )");
1682 
1683  Annotations Main(R"(
1684  #define $main[[MAIN]] 1
1685  USED(t);
1686  )");
1688  CollectorOpts.CollectMacro = true;
1689  runSymbolCollector(Header.code(), Main.code());
1690  EXPECT_THAT(
1691  Symbols,
1692  UnorderedElementsAre(
1693  QName("p"), QName("t"),
1694  AllOf(QName("X"), DeclURI(TestHeaderURI),
1695  IncludeHeader(TestHeaderURI)),
1696  AllOf(Labeled("MAC(x)"), RefCount(0),
1697 
1698  DeclRange(Header.range("mac")), VisibleOutsideFile()),
1699  AllOf(Labeled("USED(y)"), RefCount(1),
1700  DeclRange(Header.range("used")), VisibleOutsideFile()),
1701  AllOf(Labeled("MAIN"), RefCount(0), DeclRange(Main.range("main")),
1702  Not(VisibleOutsideFile()))));
1703 }
1704 
1705 TEST_F(SymbolCollectorTest, DeprecatedSymbols) {
1706  const std::string Header = R"(
1707  void TestClangc() __attribute__((deprecated("", "")));
1708  void TestClangd();
1709  )";
1710  runSymbolCollector(Header, /**/ "");
1711  EXPECT_THAT(Symbols, UnorderedElementsAre(
1712  AllOf(QName("TestClangc"), Deprecated()),
1713  AllOf(QName("TestClangd"), Not(Deprecated()))));
1714 }
1715 
1716 TEST_F(SymbolCollectorTest, ImplementationDetail) {
1717  const std::string Header = R"(
1718  #define DECL_NAME(x, y) x##_##y##_Decl
1719  #define DECL(x, y) class DECL_NAME(x, y) {};
1720  DECL(X, Y); // X_Y_Decl
1721 
1722  class Public {};
1723  )";
1724  runSymbolCollector(Header, /**/ "");
1725  EXPECT_THAT(Symbols,
1726  UnorderedElementsAre(
1727  AllOf(QName("X_Y_Decl"), ImplementationDetail()),
1728  AllOf(QName("Public"), Not(ImplementationDetail()))));
1729 }
1730 
1731 TEST_F(SymbolCollectorTest, UsingDecl) {
1732  const char *Header = R"(
1733  void foo();
1734  namespace std {
1735  using ::foo;
1736  })";
1737  runSymbolCollector(Header, /**/ "");
1738  EXPECT_THAT(Symbols, Contains(QName("std::foo")));
1739 }
1740 
1741 TEST_F(SymbolCollectorTest, CBuiltins) {
1742  // In C, printf in stdio.h is a redecl of an implicit builtin.
1743  const char *Header = R"(
1744  extern int printf(const char*, ...);
1745  )";
1746  runSymbolCollector(Header, /**/ "", {"-xc"});
1747  EXPECT_THAT(Symbols, Contains(QName("printf")));
1748 }
1749 
1750 TEST_F(SymbolCollectorTest, InvalidSourceLoc) {
1751  const char *Header = R"(
1752  void operator delete(void*)
1753  __attribute__((__externally_visible__));)";
1754  runSymbolCollector(Header, /**/ "");
1755  EXPECT_THAT(Symbols, Contains(QName("operator delete")));
1756 }
1757 
1758 TEST_F(SymbolCollectorTest, BadUTF8) {
1759  // Extracted from boost/spirit/home/support/char_encoding/iso8859_1.hpp
1760  // This looks like UTF-8 and fools clang, but has high-ISO-8859-1 comments.
1761  const char *Header = "int PUNCT = 0;\n"
1762  "/* \xa1 */ int types[] = { /* \xa1 */PUNCT };";
1765  runSymbolCollector(Header, "");
1766  EXPECT_THAT(Symbols, Contains(AllOf(QName("types"), Doc("\xef\xbf\xbd "))));
1767  EXPECT_THAT(Symbols, Contains(QName("PUNCT")));
1768  // Reference is stored, although offset within line is not reliable.
1769  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "PUNCT").ID, _)));
1770 }
1771 
1772 TEST_F(SymbolCollectorTest, MacrosInHeaders) {
1773  CollectorOpts.CollectMacro = true;
1774  TestFileName = testPath("test.h");
1775  runSymbolCollector("", "#define X");
1776  EXPECT_THAT(Symbols,
1777  UnorderedElementsAre(AllOf(QName("X"), ForCodeCompletion(true))));
1778 }
1779 
1780 // Regression test for a crash-bug we used to have.
1781 TEST_F(SymbolCollectorTest, UndefOfModuleMacro) {
1782  auto TU = TestTU::withCode(R"cpp(#include "bar.h")cpp");
1783  TU.AdditionalFiles["bar.h"] = R"cpp(
1784  #include "foo.h"
1785  #undef X
1786  )cpp";
1787  TU.AdditionalFiles["foo.h"] = "#define X 1";
1788  TU.AdditionalFiles["module.map"] = R"cpp(
1789  module foo {
1790  header "foo.h"
1791  export *
1792  }
1793  )cpp";
1794  TU.ExtraArgs.push_back("-fmodules");
1795  TU.ExtraArgs.push_back("-fmodule-map-file=" + testPath("module.map"));
1796  TU.OverlayRealFileSystemForModules = true;
1797 
1798  TU.build();
1799  // We mostly care about not crashing, but verify that we didn't insert garbage
1800  // about X too.
1801  EXPECT_THAT(TU.headerSymbols(), Not(Contains(QName("X"))));
1802 }
1803 
1804 } // namespace
1805 } // namespace clangd
1806 } // namespace clang
std::unique_ptr< CommentHandler > collectIWYUHeaderMaps(CanonicalIncludes *Includes)
Returns a CommentHandler that parses pragma comment on include files to determine when we should incl...
std::string Code
MATCHER_P(Named, N, "")
std::string HeaderName
SymbolCollector::Options CollectorOpts
std::string FileName
llvm::IntrusiveRefCntPtr< llvm::vfs::InMemoryFileSystem > InMemoryFileSystem
std::string TestHeaderName
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
Definition: SourceCode.cpp:417
Symbol is visible to other files (not e.g. a static helper function).
Definition: Symbol.h:125
std::string Snippet
Documents should not be synced at all.
SourceLocation Loc
const NamedDecl & findUnqualifiedDecl(ParsedAST &AST, llvm::StringRef Name)
Definition: TestTU.cpp:229
llvm::json::Object Args
Definition: Trace.cpp:139
std::string TestHeaderURI
SymbolID ID
The ID of the symbol.
Definition: Symbol.h:38
std::unique_ptr< CompilerInvocation > CI
std::string MainFile
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
Symbol is an implementation detail.
Definition: Symbol.h:123
SymbolCollector::Options COpts
std::string FallbackDir
When symbol paths cannot be resolved to absolute paths (e.g.
static TestTU withHeaderCode(llvm::StringRef HeaderCode)
Definition: TestTU.h:42
Whether or not this symbol is meant to be used for the code completion.
Definition: Symbol.h:119
MATCHER_P2(hasFlag, Flag, Path, "")
bool StoreAllDocumentation
If set to true, SymbolCollector will collect doc for all symbols.
std::string testPath(PathRef File, llvm::sys::path::Style Style)
Definition: TestFS.cpp:82
MATCHER(Declared, "")
static constexpr llvm::StringLiteral Name
const char * testRoot()
Definition: TestFS.cpp:74
RelationSlab Relations
std::shared_ptr< SymbolCollector > Collector
SymbolSlab Symbols
std::string ReturnType
Position Pos
Definition: SourceCode.cpp:650
bool CollectMainFileRefs
Collect references to main-file symbols.
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:36
CodeCompletionBuilder Builder
static bool shouldCollectSymbol(const NamedDecl &ND, const ASTContext &ASTCtx, const Options &Opts, bool IsMainFileSymbol)
Returns true is ND should be collected.
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
Definition: URI.cpp:211
bool RefsInHeaders
If set to true, SymbolCollector will collect all refs (from main file and included headers); otherwis...
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
unsigned References
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
Definition: TestTU.cpp:168
const_iterator begin() const
Definition: Symbol.h:185
CharSourceRange Range
SourceRange for the file name.
std::string TestFileName
std::string TestFileURI
Indicates if the symbol is deprecated.
Definition: Symbol.h:121
RefSlab Refs
std::unique_ptr< GlobalCompilationDatabase > Base
SymbolOrigin Origin
Where this symbol came from. Usually an index provides a constant value.
Definition: Symbol.h:61
const CanonicalIncludes * Includes
If set, this is used to map symbol #include path to a potentially different #include path.
RefKind RefFilter
The symbol ref kinds that will be collected.
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
Definition: TestTU.cpp:189
static char ID
Definition: Logger.cpp:74
CommentHandler * PragmaHandler