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