clang-tools  16.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);
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  class Color3 {
1320  enum {
1321  Blue
1322  };
1323  };
1324  )";
1325  runSymbolCollector(Header, /*Main=*/"");
1326  EXPECT_THAT(Symbols,
1327  UnorderedElementsAre(
1328  AllOf(qName("Red"), forCodeCompletion(true)),
1329  AllOf(qName("Color"), forCodeCompletion(true)),
1330  AllOf(qName("Green"), forCodeCompletion(true)),
1331  AllOf(qName("Color2"), forCodeCompletion(true)),
1332  AllOf(qName("Color2::Yellow"), forCodeCompletion(true)),
1333  AllOf(qName("ns"), forCodeCompletion(true)),
1334  AllOf(qName("ns::Black"), forCodeCompletion(true)),
1335  AllOf(qName("Color3"), forCodeCompletion(true)),
1336  AllOf(qName("Color3::Blue"), forCodeCompletion(true))));
1337 }
1338 
1339 TEST_F(SymbolCollectorTest, NamelessSymbols) {
1340  const std::string Header = R"(
1341  struct {
1342  int a;
1343  } Foo;
1344  )";
1345  runSymbolCollector(Header, /*Main=*/"");
1346  EXPECT_THAT(Symbols, UnorderedElementsAre(qName("Foo"),
1347  qName("(anonymous struct)::a")));
1348 }
1349 
1350 TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
1351 
1352  Annotations Header(R"(
1353  #define FF(name) \
1354  class name##_Test {};
1355 
1356  $expansion[[FF]](abc);
1357 
1358  #define FF2() \
1359  class $spelling[[Test]] {};
1360 
1361  FF2();
1362  )");
1363 
1364  runSymbolCollector(Header.code(), /*Main=*/"");
1365  EXPECT_THAT(Symbols,
1366  UnorderedElementsAre(
1367  AllOf(qName("abc_Test"), declRange(Header.range("expansion")),
1368  declURI(TestHeaderURI)),
1369  AllOf(qName("Test"), declRange(Header.range("spelling")),
1370  declURI(TestHeaderURI))));
1371 }
1372 
1373 TEST_F(SymbolCollectorTest, SymbolFormedByCLI) {
1374  Annotations Header(R"(
1375  #ifdef NAME
1376  class $expansion[[NAME]] {};
1377  #endif
1378  )");
1379  runSymbolCollector(Header.code(), /*Main=*/"", /*ExtraArgs=*/{"-DNAME=name"});
1380  EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(
1381  qName("name"), declRange(Header.range("expansion")),
1382  declURI(TestHeaderURI))));
1383 }
1384 
1385 TEST_F(SymbolCollectorTest, SymbolsInMainFile) {
1386  const std::string Main = R"(
1387  class Foo {};
1388  void f1();
1389  inline void f2() {}
1390 
1391  namespace {
1392  void ff() {}
1393  }
1394  namespace foo {
1395  namespace {
1396  class Bar {};
1397  }
1398  }
1399  void main_f() {}
1400  void f1() {}
1401  )";
1402  runSymbolCollector(/*Header=*/"", Main);
1403  EXPECT_THAT(Symbols, UnorderedElementsAre(
1404  qName("Foo"), qName("f1"), qName("f2"), qName("ff"),
1405  qName("foo"), qName("foo::Bar"), qName("main_f")));
1406 }
1407 
1408 TEST_F(SymbolCollectorTest, Documentation) {
1409  const std::string Header = R"(
1410  // doc Foo
1411  class Foo {
1412  // doc f
1413  int f();
1414  };
1415  )";
1417  runSymbolCollector(Header, /* Main */ "");
1418  EXPECT_THAT(Symbols,
1419  UnorderedElementsAre(
1420  AllOf(qName("Foo"), doc("doc Foo"), forCodeCompletion(true)),
1421  AllOf(qName("Foo::f"), doc(""), returnType(""),
1422  forCodeCompletion(false))));
1423 
1425  runSymbolCollector(Header, /* Main */ "");
1426  EXPECT_THAT(Symbols,
1427  UnorderedElementsAre(
1428  AllOf(qName("Foo"), doc("doc Foo"), forCodeCompletion(true)),
1429  AllOf(qName("Foo::f"), doc("doc f"), returnType(""),
1430  forCodeCompletion(false))));
1431 }
1432 
1433 TEST_F(SymbolCollectorTest, ClassMembers) {
1434  const std::string Header = R"(
1435  class Foo {
1436  void f() {}
1437  void g();
1438  static void sf() {}
1439  static void ssf();
1440  static int x;
1441  };
1442  )";
1443  const std::string Main = R"(
1444  void Foo::g() {}
1445  void Foo::ssf() {}
1446  )";
1447  runSymbolCollector(Header, Main);
1448  EXPECT_THAT(
1449  Symbols,
1450  UnorderedElementsAre(
1451  qName("Foo"),
1452  AllOf(qName("Foo::f"), returnType(""), forCodeCompletion(false)),
1453  AllOf(qName("Foo::g"), returnType(""), forCodeCompletion(false)),
1454  AllOf(qName("Foo::sf"), returnType(""), forCodeCompletion(false)),
1455  AllOf(qName("Foo::ssf"), returnType(""), forCodeCompletion(false)),
1456  AllOf(qName("Foo::x"), returnType(""), forCodeCompletion(false))));
1457 }
1458 
1459 TEST_F(SymbolCollectorTest, Scopes) {
1460  const std::string Header = R"(
1461  namespace na {
1462  class Foo {};
1463  namespace nb {
1464  class Bar {};
1465  }
1466  }
1467  )";
1468  runSymbolCollector(Header, /*Main=*/"");
1469  EXPECT_THAT(Symbols,
1470  UnorderedElementsAre(qName("na"), qName("na::nb"),
1471  qName("na::Foo"), qName("na::nb::Bar")));
1472 }
1473 
1474 TEST_F(SymbolCollectorTest, ExternC) {
1475  const std::string Header = R"(
1476  extern "C" { class Foo {}; }
1477  namespace na {
1478  extern "C" { class Bar {}; }
1479  }
1480  )";
1481  runSymbolCollector(Header, /*Main=*/"");
1482  EXPECT_THAT(Symbols, UnorderedElementsAre(qName("na"), qName("Foo"),
1483  qName("na::Bar")));
1484 }
1485 
1486 TEST_F(SymbolCollectorTest, SkipInlineNamespace) {
1487  const std::string Header = R"(
1488  namespace na {
1489  inline namespace nb {
1490  class Foo {};
1491  }
1492  }
1493  namespace na {
1494  // This is still inlined.
1495  namespace nb {
1496  class Bar {};
1497  }
1498  }
1499  )";
1500  runSymbolCollector(Header, /*Main=*/"");
1501  EXPECT_THAT(Symbols,
1502  UnorderedElementsAre(qName("na"), qName("na::nb"),
1503  qName("na::Foo"), qName("na::Bar")));
1504 }
1505 
1506 TEST_F(SymbolCollectorTest, SymbolWithDocumentation) {
1507  const std::string Header = R"(
1508  namespace nx {
1509  /// Foo comment.
1510  int ff(int x, double y) { return 0; }
1511  }
1512  )";
1513  runSymbolCollector(Header, /*Main=*/"");
1514  EXPECT_THAT(
1515  Symbols,
1516  UnorderedElementsAre(
1517  qName("nx"), AllOf(qName("nx::ff"), labeled("ff(int x, double y)"),
1518  returnType("int"), doc("Foo comment."))));
1519 }
1520 
1521 TEST_F(SymbolCollectorTest, snippet) {
1522  const std::string Header = R"(
1523  namespace nx {
1524  void f() {}
1525  int ff(int x, double y) { return 0; }
1526  }
1527  )";
1528  runSymbolCollector(Header, /*Main=*/"");
1529  EXPECT_THAT(Symbols,
1530  UnorderedElementsAre(
1531  qName("nx"),
1532  AllOf(qName("nx::f"), labeled("f()"), snippet("f()")),
1533  AllOf(qName("nx::ff"), labeled("ff(int x, double y)"),
1534  snippet("ff(${1:int x}, ${2:double y})"))));
1535 }
1536 
1537 TEST_F(SymbolCollectorTest, IncludeHeaderSameAsFileURI) {
1539  runSymbolCollector("#pragma once\nclass Foo {};", /*Main=*/"");
1540  EXPECT_THAT(Symbols, UnorderedElementsAre(
1541  AllOf(qName("Foo"), declURI(TestHeaderURI))));
1542  EXPECT_THAT(Symbols.begin()->IncludeHeaders,
1543  UnorderedElementsAre(IncludeHeaderWithRef(TestHeaderURI, 1u)));
1544 }
1545 
1546 TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
1548  CanonicalIncludes Includes;
1549  auto Language = LangOptions();
1550  Language.CPlusPlus = true;
1551  Includes.addSystemHeadersMapping(Language);
1552  CollectorOpts.Includes = &Includes;
1553  runSymbolCollector(
1554  R"cpp(
1555  namespace std {
1556  class string {};
1557  // Move overloads have special handling.
1558  template <typename _T> T&& move(_T&& __value);
1559  template <typename _I, typename _O> _O move(_I, _I, _O);
1560  }
1561  )cpp",
1562  /*Main=*/"");
1563  EXPECT_THAT(
1564  Symbols,
1565  UnorderedElementsAre(
1566  qName("std"),
1567  AllOf(qName("std::string"), declURI(TestHeaderURI),
1568  includeHeader("<string>")),
1569  // Parameter names are demangled.
1570  AllOf(labeled("move(T &&value)"), includeHeader("<utility>")),
1571  AllOf(labeled("move(I, I, O)"), includeHeader("<algorithm>"))));
1572 }
1573 
1574 TEST_F(SymbolCollectorTest, IWYUPragma) {
1576  CanonicalIncludes Includes;
1577  PragmaHandler = collectIWYUHeaderMaps(&Includes);
1578  CollectorOpts.Includes = &Includes;
1579  const std::string Header = R"(
1580  // IWYU pragma: private, include the/good/header.h
1581  class Foo {};
1582  )";
1583  runSymbolCollector(Header, /*Main=*/"");
1584  EXPECT_THAT(Symbols, UnorderedElementsAre(
1585  AllOf(qName("Foo"), declURI(TestHeaderURI),
1586  includeHeader("\"the/good/header.h\""))));
1587 }
1588 
1589 TEST_F(SymbolCollectorTest, IWYUPragmaWithDoubleQuotes) {
1591  CanonicalIncludes Includes;
1592  PragmaHandler = collectIWYUHeaderMaps(&Includes);
1593  CollectorOpts.Includes = &Includes;
1594  const std::string Header = R"(
1595  // IWYU pragma: private, include "the/good/header.h"
1596  class Foo {};
1597  )";
1598  runSymbolCollector(Header, /*Main=*/"");
1599  EXPECT_THAT(Symbols, UnorderedElementsAre(
1600  AllOf(qName("Foo"), declURI(TestHeaderURI),
1601  includeHeader("\"the/good/header.h\""))));
1602 }
1603 
1604 TEST_F(SymbolCollectorTest, SkipIncFileWhenCanonicalizeHeaders) {
1605  auto IncFile = testPath("test.inc");
1606  auto IncURI = URI::create(IncFile).toString();
1607  InMemoryFileSystem->addFile(IncFile, 0,
1608  llvm::MemoryBuffer::getMemBuffer("class X {};"));
1609  llvm::IntrusiveRefCntPtr<FileManager> Files(
1610  new FileManager(FileSystemOptions(), InMemoryFileSystem));
1611  std::string HeaderCode = "#include \"test.inc\"\nclass Y {};";
1612  InMemoryFileSystem->addFile(TestHeaderName, 0,
1613  llvm::MemoryBuffer::getMemBuffer(HeaderCode));
1614  auto File = Files->getFileRef(TestHeaderName);
1615  ASSERT_THAT_EXPECTED(File, llvm::Succeeded());
1616  CanonicalIncludes Includes;
1617  Includes.addMapping(*File, "<canonical>");
1619  CollectorOpts.Includes = &Includes;
1620  runSymbolCollector(HeaderCode, /*Main=*/"",
1621  /*ExtraArgs=*/{"-I", testRoot()});
1622  EXPECT_THAT(Symbols,
1623  UnorderedElementsAre(AllOf(qName("X"), declURI(IncURI),
1624  includeHeader("<canonical>")),
1625  AllOf(qName("Y"), declURI(TestHeaderURI),
1626  includeHeader("<canonical>"))));
1627 }
1628 
1629 TEST_F(SymbolCollectorTest, MainFileIsHeaderWhenSkipIncFile) {
1631  // To make this case as hard as possible, we won't tell clang main is a
1632  // header. No extension, no -x c++-header.
1633  TestFileName = testPath("no_ext_main");
1634  TestFileURI = URI::create(TestFileName).toString();
1635  auto IncFile = testPath("test.inc");
1636  auto IncURI = URI::create(IncFile).toString();
1637  InMemoryFileSystem->addFile(IncFile, 0,
1638  llvm::MemoryBuffer::getMemBuffer("class X {};"));
1639  runSymbolCollector("", R"cpp(
1640  // Can't use #pragma once in a main file clang doesn't think is a header.
1641  #ifndef MAIN_H_
1642  #define MAIN_H_
1643  #include "test.inc"
1644  #endif
1645  )cpp",
1646  /*ExtraArgs=*/{"-I", testRoot()});
1647  EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(qName("X"), declURI(IncURI),
1648  includeHeader(TestFileURI))));
1649 }
1650 
1651 TEST_F(SymbolCollectorTest, IncFileInNonHeader) {
1653  TestFileName = testPath("main.cc");
1654  TestFileURI = URI::create(TestFileName).toString();
1655  auto IncFile = testPath("test.inc");
1656  auto IncURI = URI::create(IncFile).toString();
1657  InMemoryFileSystem->addFile(IncFile, 0,
1658  llvm::MemoryBuffer::getMemBuffer("class X {};"));
1659  runSymbolCollector("", R"cpp(
1660  #include "test.inc"
1661  )cpp",
1662  /*ExtraArgs=*/{"-I", testRoot()});
1663  EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(qName("X"), declURI(IncURI),
1664  Not(includeHeader()))));
1665 }
1666 
1667 // Features that depend on header-guards are fragile. Header guards are only
1668 // recognized when the file ends, so we have to defer checking for them.
1669 TEST_F(SymbolCollectorTest, HeaderGuardDetected) {
1671  CollectorOpts.CollectMacro = true;
1672  runSymbolCollector(R"cpp(
1673  #ifndef HEADER_GUARD_
1674  #define HEADER_GUARD_
1675 
1676  // Symbols are seen before the header guard is complete.
1677  #define MACRO
1678  int decl();
1679 
1680  #endif // Header guard is recognized here.
1681  )cpp",
1682  "");
1683  EXPECT_THAT(Symbols, Not(Contains(qName("HEADER_GUARD_"))));
1684  EXPECT_THAT(Symbols, Each(includeHeader()));
1685 }
1686 
1687 TEST_F(SymbolCollectorTest, NonModularHeader) {
1688  auto TU = TestTU::withHeaderCode("int x();");
1689  EXPECT_THAT(TU.headerSymbols(), ElementsAre(includeHeader()));
1690 
1691  // Files missing include guards aren't eligible for insertion.
1692  TU.ImplicitHeaderGuard = false;
1693  EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(includeHeader())));
1694 
1695  // We recognize some patterns of trying to prevent insertion.
1696  TU = TestTU::withHeaderCode(R"cpp(
1697 #ifndef SECRET
1698 #error "This file isn't safe to include directly"
1699 #endif
1700  int x();
1701  )cpp");
1702  TU.ExtraArgs.push_back("-DSECRET"); // *we're* able to include it.
1703  EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(includeHeader())));
1704 }
1705 
1706 TEST_F(SymbolCollectorTest, AvoidUsingFwdDeclsAsCanonicalDecls) {
1708  Annotations Header(R"(
1709  #pragma once
1710  // Forward declarations of TagDecls.
1711  class C;
1712  struct S;
1713  union U;
1714 
1715  // Canonical declarations.
1716  class $cdecl[[C]] {};
1717  struct $sdecl[[S]] {};
1718  union $udecl[[U]] {int $xdecl[[x]]; bool $ydecl[[y]];};
1719  )");
1720  runSymbolCollector(Header.code(), /*Main=*/"");
1721  EXPECT_THAT(
1722  Symbols,
1723  UnorderedElementsAre(
1724  AllOf(qName("C"), declURI(TestHeaderURI),
1725  declRange(Header.range("cdecl")), includeHeader(TestHeaderURI),
1726  defURI(TestHeaderURI), defRange(Header.range("cdecl"))),
1727  AllOf(qName("S"), declURI(TestHeaderURI),
1728  declRange(Header.range("sdecl")), includeHeader(TestHeaderURI),
1729  defURI(TestHeaderURI), defRange(Header.range("sdecl"))),
1730  AllOf(qName("U"), declURI(TestHeaderURI),
1731  declRange(Header.range("udecl")), includeHeader(TestHeaderURI),
1732  defURI(TestHeaderURI), defRange(Header.range("udecl"))),
1733  AllOf(qName("U::x"), declURI(TestHeaderURI),
1734  declRange(Header.range("xdecl")), defURI(TestHeaderURI),
1735  defRange(Header.range("xdecl"))),
1736  AllOf(qName("U::y"), declURI(TestHeaderURI),
1737  declRange(Header.range("ydecl")), defURI(TestHeaderURI),
1738  defRange(Header.range("ydecl")))));
1739 }
1740 
1741 TEST_F(SymbolCollectorTest, ClassForwardDeclarationIsCanonical) {
1743  runSymbolCollector(/*Header=*/"#pragma once\nclass X;",
1744  /*Main=*/"class X {};");
1745  EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(
1746  qName("X"), declURI(TestHeaderURI),
1747  includeHeader(TestHeaderURI), defURI(TestFileURI))));
1748 }
1749 
1750 TEST_F(SymbolCollectorTest, UTF16Character) {
1751  // ö is 2-bytes.
1752  Annotations Header(/*Header=*/"class [[pörk]] {};");
1753  runSymbolCollector(Header.code(), /*Main=*/"");
1754  EXPECT_THAT(Symbols, UnorderedElementsAre(
1755  AllOf(qName("pörk"), declRange(Header.range()))));
1756 }
1757 
1758 TEST_F(SymbolCollectorTest, DoNotIndexSymbolsInFriendDecl) {
1759  Annotations Header(R"(
1760  namespace nx {
1761  class $z[[Z]] {};
1762  class X {
1763  friend class Y;
1764  friend class Z;
1765  friend void foo();
1766  friend void $bar[[bar]]() {}
1767  };
1768  class $y[[Y]] {};
1769  void $foo[[foo]]();
1770  }
1771  )");
1772  runSymbolCollector(Header.code(), /*Main=*/"");
1773 
1774  EXPECT_THAT(Symbols,
1775  UnorderedElementsAre(
1776  qName("nx"), qName("nx::X"),
1777  AllOf(qName("nx::Y"), declRange(Header.range("y"))),
1778  AllOf(qName("nx::Z"), declRange(Header.range("z"))),
1779  AllOf(qName("nx::foo"), declRange(Header.range("foo"))),
1780  AllOf(qName("nx::bar"), declRange(Header.range("bar")))));
1781 }
1782 
1783 TEST_F(SymbolCollectorTest, ReferencesInFriendDecl) {
1784  const std::string Header = R"(
1785  class X;
1786  class Y;
1787  )";
1788  const std::string Main = R"(
1789  class C {
1790  friend ::X;
1791  friend class Y;
1792  };
1793  )";
1795  runSymbolCollector(Header, Main);
1796  EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(qName("X"), refCount(1)),
1797  AllOf(qName("Y"), refCount(1)),
1798  AllOf(qName("C"), refCount(0))));
1799 }
1800 
1801 TEST_F(SymbolCollectorTest, Origin) {
1803  runSymbolCollector("class Foo {};", /*Main=*/"");
1804  EXPECT_THAT(Symbols, UnorderedElementsAre(
1806  runSymbolCollector("#define FOO", /*Main=*/"");
1807  EXPECT_THAT(Symbols, UnorderedElementsAre(
1809 }
1810 
1811 TEST_F(SymbolCollectorTest, CollectMacros) {
1813  Annotations Header(R"(
1814  #pragma once
1815  #define X 1
1816  #define $mac[[MAC]](x) int x
1817  #define $used[[USED]](y) float y;
1818 
1819  MAC(p);
1820  )");
1821 
1822  Annotations Main(R"(
1823  #define $main[[MAIN]] 1
1824  USED(t);
1825  )");
1827  CollectorOpts.CollectMacro = true;
1828  runSymbolCollector(Header.code(), Main.code());
1829  EXPECT_THAT(
1830  Symbols,
1831  UnorderedElementsAre(
1832  qName("p"), qName("t"),
1833  AllOf(qName("X"), declURI(TestHeaderURI),
1834  includeHeader(TestHeaderURI)),
1835  AllOf(labeled("MAC(x)"), refCount(0),
1836 
1837  declRange(Header.range("mac")), visibleOutsideFile()),
1838  AllOf(labeled("USED(y)"), refCount(1),
1839  declRange(Header.range("used")), visibleOutsideFile()),
1840  AllOf(labeled("MAIN"), refCount(0), declRange(Main.range("main")),
1841  Not(visibleOutsideFile()))));
1842 }
1843 
1844 TEST_F(SymbolCollectorTest, DeprecatedSymbols) {
1845  const std::string Header = R"(
1846  void TestClangc() __attribute__((deprecated("", "")));
1847  void TestClangd();
1848  )";
1849  runSymbolCollector(Header, /**/ "");
1850  EXPECT_THAT(Symbols, UnorderedElementsAre(
1851  AllOf(qName("TestClangc"), deprecated()),
1852  AllOf(qName("TestClangd"), Not(deprecated()))));
1853 }
1854 
1855 TEST_F(SymbolCollectorTest, implementationDetail) {
1856  const std::string Header = R"(
1857  #define DECL_NAME(x, y) x##_##y##_Decl
1858  #define DECL(x, y) class DECL_NAME(x, y) {};
1859  DECL(X, Y); // X_Y_Decl
1860 
1861  class Public {};
1862  )";
1863  runSymbolCollector(Header, /**/ "");
1864  EXPECT_THAT(Symbols,
1865  UnorderedElementsAre(
1866  AllOf(qName("X_Y_Decl"), implementationDetail()),
1867  AllOf(qName("Public"), Not(implementationDetail()))));
1868 }
1869 
1870 TEST_F(SymbolCollectorTest, UsingDecl) {
1871  const char *Header = R"(
1872  void foo();
1873  namespace std {
1874  using ::foo;
1875  })";
1876  runSymbolCollector(Header, /**/ "");
1877  EXPECT_THAT(Symbols, Contains(qName("std::foo")));
1878 }
1879 
1880 TEST_F(SymbolCollectorTest, CBuiltins) {
1881  // In C, printf in stdio.h is a redecl of an implicit builtin.
1882  const char *Header = R"(
1883  extern int printf(const char*, ...);
1884  )";
1885  runSymbolCollector(Header, /**/ "", {"-xc"});
1886  EXPECT_THAT(Symbols, Contains(qName("printf")));
1887 }
1888 
1889 TEST_F(SymbolCollectorTest, InvalidSourceLoc) {
1890  const char *Header = R"(
1891  void operator delete(void*)
1892  __attribute__((__externally_visible__));)";
1893  runSymbolCollector(Header, /**/ "");
1894  EXPECT_THAT(Symbols, Contains(qName("operator delete")));
1895 }
1896 
1897 TEST_F(SymbolCollectorTest, BadUTF8) {
1898  // Extracted from boost/spirit/home/support/char_encoding/iso8859_1.hpp
1899  // This looks like UTF-8 and fools clang, but has high-ISO-8859-1 comments.
1900  const char *Header = "int PUNCT = 0;\n"
1901  "/* \xa1 */ int types[] = { /* \xa1 */PUNCT };";
1904  runSymbolCollector(Header, "");
1905  EXPECT_THAT(Symbols, Contains(AllOf(qName("types"), doc("\xef\xbf\xbd "))));
1906  EXPECT_THAT(Symbols, Contains(qName("PUNCT")));
1907  // Reference is stored, although offset within line is not reliable.
1908  EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "PUNCT").ID, _)));
1909 }
1910 
1911 TEST_F(SymbolCollectorTest, MacrosInHeaders) {
1912  CollectorOpts.CollectMacro = true;
1913  TestFileName = testPath("test.h");
1914  runSymbolCollector("", "#define X");
1915  EXPECT_THAT(Symbols,
1916  UnorderedElementsAre(AllOf(qName("X"), forCodeCompletion(true))));
1917 }
1918 
1919 // Regression test for a crash-bug we used to have.
1920 TEST_F(SymbolCollectorTest, UndefOfModuleMacro) {
1921  auto TU = TestTU::withCode(R"cpp(#include "bar.h")cpp");
1922  TU.AdditionalFiles["bar.h"] = R"cpp(
1923  #include "foo.h"
1924  #undef X
1925  )cpp";
1926  TU.AdditionalFiles["foo.h"] = "#define X 1";
1927  TU.AdditionalFiles["module.map"] = R"cpp(
1928  module foo {
1929  header "foo.h"
1930  export *
1931  }
1932  )cpp";
1933  TU.ExtraArgs.push_back("-fmodules");
1934  TU.ExtraArgs.push_back("-fmodule-map-file=" + testPath("module.map"));
1935  TU.OverlayRealFileSystemForModules = true;
1936 
1937  TU.build();
1938  // We mostly care about not crashing, but verify that we didn't insert garbage
1939  // about X too.
1940  EXPECT_THAT(TU.headerSymbols(), Not(Contains(qName("X"))));
1941 }
1942 
1943 TEST_F(SymbolCollectorTest, NoCrashOnObjCMethodCStyleParam) {
1944  auto TU = TestTU::withCode(R"objc(
1945  @interface Foo
1946  - (void)fun:(bool)foo, bool bar;
1947  @end
1948  )objc");
1949  TU.ExtraArgs.push_back("-xobjective-c++");
1950 
1951  TU.build();
1952  // We mostly care about not crashing.
1953  EXPECT_THAT(TU.headerSymbols(),
1954  UnorderedElementsAre(qName("Foo"), qName("Foo::fun:")));
1955 }
1956 
1957 TEST_F(SymbolCollectorTest, Reserved) {
1958  const char *Header = R"cpp(
1959  void __foo();
1960  namespace _X { int secret; }
1961  )cpp";
1962 
1964  runSymbolCollector("", Header);
1965  EXPECT_THAT(Symbols, UnorderedElementsAre(qName("__foo"), qName("_X"),
1966  qName("_X::secret")));
1967 
1969  runSymbolCollector("", Header); //
1970  EXPECT_THAT(Symbols, IsEmpty());
1971 }
1972 
1973 TEST_F(SymbolCollectorTest, Concepts) {
1974  const char *Header = R"cpp(
1975  template <class T>
1976  concept A = sizeof(T) <= 8;
1977  )cpp";
1978  runSymbolCollector("", Header, {"-std=c++20"});
1979  EXPECT_THAT(Symbols,
1980  UnorderedElementsAre(AllOf(
1981  qName("A"), hasKind(clang::index::SymbolKind::Concept))));
1982 }
1983 
1984 } // namespace
1985 } // namespace clangd
1986 } // 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:39
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:708
clang::clangd::findDecl
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
Definition: TestTU.cpp:221
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:31
clang::clangd::MATCHER_P2
MATCHER_P2(hasFlag, Flag, Path, "")
Definition: GlobalCompilationDatabaseTests.cpp:444
References
unsigned References
Definition: CodeComplete.cpp:183
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:165
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:467
clang::clangd::SymbolKind::Object
@ Object
TestHeaderURI
std::string TestHeaderURI
Definition: SymbolCollectorTests.cpp:308
CI
std::unique_ptr< CompilerInvocation > CI
Definition: TUScheduler.cpp:549
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
Container
std::string Container
Definition: SymbolInfoTests.cpp:24
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:262
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:427
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:418
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:136
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:187
clang::clangd::SymbolCollector::Options::FallbackDir
std::string FallbackDir
When symbol paths cannot be resolved to absolute paths (e.g.
Definition: SymbolCollector.h:56