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