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